Assuming a relatively modern, SVG-supporting desktop browser and an SVG consisting of hundreds of similar, simple nodes:
The document could be set up as many individual shape elements (<circle>, <line>, etc.) with their own attributes defined.
The document could be set up as a few <symbol> elements and many individual <use> instances that place them and size them appropriately (W3 spec).
I understand the semantic and code-maintenance reasons to use <symbols>/<use>, but I'm not concerned with those now, I'm strictly trying to optimize rendering, transformation and DOM update performance. I could see <symbol> working similar to reusing sprites in Flash, conserving memory and being generally a good practice. However, I'd be surprised if browser vendors have been thinking this way (and this isn't really the intent of the feature).
Edit: I am not expecting the base symbols to be changed or added to over the life-cycle of the SVG, only the instance locations, sizes, etc
Are there any clear patterns to <symbol>/<use> performance?
How idiosyncratic is it to individual browser implementations?
Are there differences between reusing <symbol> vs <g> vs nested <svg>?
Rohit Kalkur compared rendering speed of the creation of 5000 SVG symbols using use against directly creating the SVG symbol's shapes, see here. It turns out that rendering SVG shapes using use was almost 50% slower. He reasons that:
The use element takes nodes from within the SVG document, and
duplicates them in a non-exposed DOM
Given this, I assume that using SVG symbols is at best as performant as manually creating the symbolss shape.
I would advise you to not nest <use> elements deeply. That is known to cause slowdowns in most browsers, see here and here.
In the general case though it should be fast, at least as long as the template itself isn't changed much (since if you do then each of the instances need to be updated too, and each of them can differ from the rest due to CSS inheritance).
Between <svg> and <symbol> there isn't that big of a difference on a functional level, they both allow you to define a coordinate system (via the 'viewBox' attribute). A <g> element doesn't let you do that. Note that <symbol> elements are invisible unless referenced by a <use>, whereas <svg> and <g> are both visible per default. However, in most cases it's advisable to make the template be a child of a <defs> element.
If you change the contents of a g or svg element then a UI can look at the area the old contents were drawn in and where the update will be drawn to and simply redraw those two areas, even redraw only once if they are the same e.g. changing the colour of a shape.
If you update the contents of a symbol then all the instances must be redrawn. It's harder to do that by calculating for each instance where the old and new parts to redraw are as the areas may be affected by transforms and simpler to just redraw all parts of all instances. Some browsers may do the former and some the latter.
In either case, a UI must at a minimum track the changes in the symbol and propagate those changes to all the instances. That's more than likely to have some overhead.
Of course, if you're just moving individual symbol instances and the contents are static then no tracking is required and performance is likely to be similar.
Related
I'm building out some responsive SVG-based components (based around Backbone views). The convention I'm using is that when a component is created, it is provided with a DOM element to render itself into. When rendering, the component checks the size of the DOM element and fills the entire available space.
I was using g elements, but they don't have their own width and height; they just match their contents. So I made a hack where I would append a rect that was the size I needed. This works pretty well, but it is hacky.
Today I discovered that svg elements can be nested just like g, but they're also able to have their own width and height. I just tested it out and it seems to work great. Are there any downsides I'm missing creating a bunch of nested svg elements like this?
No. There shouldn't be any downsides to using nested <svg> elements. But your description of what you are doing is rather vague, so I can't guarantee that you won't strike any in your particular use case.
Does SVG performance degrade with the number of separate SVG elements in the DOM ?
I would like the draw a whole bunch of little SVG images which will not need any interaction, but I also have one "main" SVG which will need interaction. As I add more non-interactive SVGs, will the performance of the main one get worse ?
OK I made two SVGs, one with hundreds of elements and one with nothing. Interaction with the blank SVG was noticeably slow when the 2nd SVG was in the DOM, even if it was hidden.
I'm considering implementing my own (toy) MVC framework, mainly just for practise and to have fun with it. I worked with such frameworks in the past but when thinking about how I would go about it a couple of questions arose.
So what puzzles me the most is how I should tackle the drawing of the visual elements. My idea was to implement each item's drawing logic in the item's class, organize them into a tree structure, like in WPF and and pass down some sort of canvas that the elements can draw on when traverse the tree.
I'm having doubts though, whether I should pass a canvas down an entire visual tree. Another interesting thing is the handling of overlaping elements and which to draw first. I thought the visual tree would take care of that by drawing elemtns in the order they appear in a depth first search. But then I thought that the newest element should be on top no matter how close it is to the root in the tree.
So basically I couldn't really find anything on implementation best practises or details when it comes to drawing the elements and I could use some friendly advice on this or if you could point to some material that covers this it would be more than welcome.
The MVC pattern typically doesn't tackle such granular details. It ultimately comes down to decomposing the problem into three broad domains: data and logic, user input, and user output.
I'm having doubts though, whether I should pass a canvas down an
entire visual tree.
How come? From a performance or coupling/responsibility perspective?
If it's performance, this is a very solid start. You do have to descend down the tree and redraw everything by default, but that can be mitigated by turning your hierarchy into an accelerator and keeping track of which portions of the screen/canvas/image need to be redrawn ("dirty regions"). Only descend down the branches that overlap this dirty region.
For the dirty regions, you can break up your canvas into a grid. As widgets need updating, mark the region(s) they occupy as needing to be redrawn. Only redraw widgets occupying those grid cells which are marked as needing to be redrawn. If you want to get really elaborate and mitigate overdraw to a minimum, you can use a quad-tree (but typically overkill for all but the most dynamic kind of systems with elaborate animating content and things like that).
It might be tempting to make this problem easier to solve to double-buffer everything and have children draw into their parents' canvases, but that's a route to gain some immediate performance in exchange for a large performance barrier at a design-level in the form of memory consumption and cache efficiency. I don't recommend this approach: double-buffer the window contents to avoid flickery artifacts, but not every single control inside of it.
If it's about coupling and responsibilities, often it's overkill from a UI context to try to decouple the rendering of a widget from the widget itself. Decoupling rendering from entities is common in game architectures through entity-component systems which would provide rendering components (typically in the form of dumb data) and defer the rendering functionality to systems, but those take a great deal of work upfront to implement for tremendous flexibility which you might never need in this kind of context.
Another interesting thing is the handling of overlaping elements and
which to draw first. I thought the visual tree would take care of that
by drawing elemtns in the order they appear in a depth first search.
But then I thought that the newest element should be on top no matter
how close it is to the root in the tree.
The tree doesn't have to be this rigid thing. You can send siblings to the front of a child list or to the back to affect drawing order. Typically z-order changes don't occur so frequently and most of the time you'd be better off this way than transferring a great overhead to sorting the drawing on the fly as you are rendering.
Mostly I just recommend keeping it simple, especially if this is your first attempt constructing a general-purpose MVC framework. You're far more likely to err on the side of making things too complicated and painting yourself in a corner. Simple designs are pliable designs.
Assuming a relatively modern, SVG-supporting desktop browser and an SVG consisting of hundreds of similar, simple nodes:
The document could be set up as many individual shape elements (<circle>, <line>, etc.) with their own attributes defined.
The document could be set up as a few <symbol> elements and many individual <use> instances that place them and size them appropriately (W3 spec).
I understand the semantic and code-maintenance reasons to use <symbols>/<use>, but I'm not concerned with those now, I'm strictly trying to optimize rendering, transformation and DOM update performance. I could see <symbol> working similar to reusing sprites in Flash, conserving memory and being generally a good practice. However, I'd be surprised if browser vendors have been thinking this way (and this isn't really the intent of the feature).
Edit: I am not expecting the base symbols to be changed or added to over the life-cycle of the SVG, only the instance locations, sizes, etc
Are there any clear patterns to <symbol>/<use> performance?
How idiosyncratic is it to individual browser implementations?
Are there differences between reusing <symbol> vs <g> vs nested <svg>?
Rohit Kalkur compared rendering speed of the creation of 5000 SVG symbols using use against directly creating the SVG symbol's shapes, see here. It turns out that rendering SVG shapes using use was almost 50% slower. He reasons that:
The use element takes nodes from within the SVG document, and
duplicates them in a non-exposed DOM
Given this, I assume that using SVG symbols is at best as performant as manually creating the symbolss shape.
I would advise you to not nest <use> elements deeply. That is known to cause slowdowns in most browsers, see here and here.
In the general case though it should be fast, at least as long as the template itself isn't changed much (since if you do then each of the instances need to be updated too, and each of them can differ from the rest due to CSS inheritance).
Between <svg> and <symbol> there isn't that big of a difference on a functional level, they both allow you to define a coordinate system (via the 'viewBox' attribute). A <g> element doesn't let you do that. Note that <symbol> elements are invisible unless referenced by a <use>, whereas <svg> and <g> are both visible per default. However, in most cases it's advisable to make the template be a child of a <defs> element.
If you change the contents of a g or svg element then a UI can look at the area the old contents were drawn in and where the update will be drawn to and simply redraw those two areas, even redraw only once if they are the same e.g. changing the colour of a shape.
If you update the contents of a symbol then all the instances must be redrawn. It's harder to do that by calculating for each instance where the old and new parts to redraw are as the areas may be affected by transforms and simpler to just redraw all parts of all instances. Some browsers may do the former and some the latter.
In either case, a UI must at a minimum track the changes in the symbol and propagate those changes to all the instances. That's more than likely to have some overhead.
Of course, if you're just moving individual symbol instances and the contents are static then no tracking is required and performance is likely to be similar.
Scenario: I have SVG image that I can zoom-in and zoom-out. Depending on the zoom, I will display more/less details on the visible part.
The question is: should I take care of not displaying details on the parts that are not currently visible (out of the screen), or the rendering engine is smart enough to skip (clip) those parts before they are rendered?
Yes, browsers are usually clever enough to not render things outside the viewport area.
Note however that the browser still needs to traverse the entire document tree, so even things outside the viewport area can have an impact. It's usually enough to mark the non-interesting subtrees with display="none" to let the browser skip over them when traversing. On small documents that's usually not something that you need to worry about.
I guess clipping will always be applied to the current viewport. But you are probably changing the DOM by updating with the detail visibility changes and restricting that to the visible parts only can make a difference.
The easiest way to find this out is to measure, though. Make two prototypes, one with manual clipping, one without and look for differences in rendering speed in various renderers.