-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to speed up drawing thousands of elements #55
Comments
Ah! I'll see if I can plot more areas instead of relying on replotting all thousand elements under the single stable path. Maybe I can just split the grid up into chunks so that the nodes are plotted in their grids, but the edges would be the only thing plotted in the large all-encompassing area. That should take the rendering time down by half. Unfortunately, I still can't seem to get the line to tell that it's been clicked. I've tried using
|
Hi @seydar, I'm kojix2, working with Ruby and libui-ng bindings. Your demo is very beautiful. I want to see if I can make your app faster. If possible, it would be helpful if you could share a piece of code that can reproduce the problem. If you could do so, it would make it easier for us to benchmark based on a real-world example. |
@kojix2 my code above can reproduce the problem if you change But, the startup time being slow is unrelated to libui. To see the slowdown in libui, after the app starts (takes 15-30 seconds with 1000 nodes), click the "Refresh Nodes" button on top. It takes about 1 second to redraw all points with different colors. Ideally, it would happen in under 200ms. BTW, if you want, you could have the app startup Ruby code store the nodes initially generated in a yml file, and the next time you start the app, you could load the nodes from the yml file instead of taking a long time to generate them. Another slowdown example to look into is if you try to use the "Area Image" feature (which breaks down an image into many 1 pixel rectangles), it takes a while to render an image, and more time if the image is bigger: https://github.com/AndyObtiva/glimmer-dsl-libui#area-image |
Here is a version of the app above that caches objects through Ruby Marshal so that after the first time starting the app and closing it, the second time, it starts much more quickly. That should help you with testing the node rendering performance. require 'glimmer-dsl-libui'
class ThousandNodeGraph
include Glimmer::LibUI::Application
WIDTH = 872
HEIGHT = 512
PADDING_X = 20
PADDING_Y = 20
NODE_COUNT = 1000
FILE = 'nodes'
before_body do
@file_content = File.read(FILE) rescue ''
if @file_content.empty?
@points = NODE_COUNT.times.map do |n|
x = rand(WIDTH - 2*PADDING_X) + PADDING_X
y = rand(HEIGHT - 2*PADDING_Y) + PADDING_Y
[x, y]
end
pairs = (@points.size - 1).times.map do |n|
@points.rotate(n).zip(@points)
end.flatten(1)
pairs.reject! {|pair| PerfectShape::Point.new(pair.first).point_distance(pair.last) < 30 }
pairs.sort_by! {|pair| PerfectShape::Point.new(pair.first).point_distance(pair.last) }
@lines = pairs.take(NODE_COUNT)
file_content_hash = { points: @points, lines: @lines }
@file_content = Marshal.dump(file_content_hash)
File.write(FILE, @file_content)
else
file_content_hash = Marshal.load(@file_content)
@points = file_content_hash[:points]
@lines = file_content_hash[:lines]
end
end
body {
window("Thousand Node Graph", WIDTH + 2*PADDING_X, HEIGHT + 2*PADDING_Y) {
vertical_box {
button {
stretchy false
text 'Refresh Nodes'
on_clicked do
refresh_nodes
end
}
@area = area {
on_draw do
nodes
end
on_mouse_up do |mouse_event|
the_line = @line_shapes.find {|shape| shape.include?(mouse_event[:x], mouse_event[:y]) }
if the_line
message = "(#{the_line.x}, #{the_line.y}), (#{the_line.end_x}, #{the_line.end_y})"
msg_box('Line Selected!', message)
end
end
}
}
}
}
def nodes
@points.each_with_index do |point, index|
circle_center_x = point.first
circle_center_y = point.last
circle_radius = 3
circle(circle_center_x, circle_center_y, circle_radius) {
stroke :black, thickness: 2
}
circle_radius = 2
circle(circle_center_x, circle_center_y, circle_radius) {
fill rand(256), rand(256), rand(256)
}
end
@line_shapes = []
@lines.each_with_index do |pair|
@line_shapes << line(pair.first.first, pair.first.last, pair.last.first, pair.last.last) {
stroke rand(256), rand(256), rand(256), thickness: rand(3) + 2
}
end
end
def refresh_nodes
@area.queue_redraw_all
end
end
ThousandNodeGraph.launch |
@AndyObtiva |
I display a graph like this:
And it has 1000 nodes and 999 edges. It gets a little slow when redrawing, and I was wondering if there's a better way for me to display the elements (circles and lines) — maybe the slowness when changing the screen size is simply part of life.
I am plotting nodes as circles, edges as lines, all within
on_draw
in anarea
.(Also: is there a good way to detect when a user clicks on a line? It has the method for it, but I'm unable to trigger it, no matter how wide I make the line or how large I set the distance_tolerance)
The text was updated successfully, but these errors were encountered: