Just imagine building Google Maps for a large building floor plan with 3000 rooms.
I need to display up to 3000 rectangles (the best would be to also be able to render random polygons, but at this point, this is not the biggest issue). Each of them should have events attached to them such as mouseover and click that will have some effects on other dom elements on the page. I also need to be able to zoom in and out.
I know I can do it with SVG (Raphael.js), plain divs rendering or canvas.
I am wondering if anyone has specific recommendations to make for what I am trying to build. It needs to render fast enough (around 1 second or so) on the slowest browsers. (IE8,Firefox 3.6 and hopefully IE7, even though I am not dreaming too much...)
Thanks for the help,
Nicolas.
PS: So far, I have experienced that rendering 3000 rectangles takes up to 7 seconds on IE8 with Raphael.js, which is rather slow. It also seems than rendering plain div is up to 6 times faster on IE8.
3000 DOM objects with events attached is going to be very painful for some machines to handle. Generally once you get into the "thousands" range the performance of DOM-based solutions (divs, SVG) gets really bad. It is nigh impossible to get good loading times with that many DOM elements.
The performance of excanvas itself is also really bad. The second there is any animation the performance of excanvas turns awful. Since excanvas merely mimicks Canvas by making VML (SVG), its going to be at least just as slow (and almost always slower) than doing just SVG/VML alone.
See my answer here for a detailed analysis: HTML5 Canvas vs. SVG vs. div
I believe that one of the requirements on your list has got to go. The number of objects, the performance, or the platform.
My suggestion to you would be to drop support for the older browsers if possible and go with Canvas.
Related
I develop a small application to test CSS3 and translate3d. The idea is to render several DIVs moving randomly on the screen. It's kind of particle system, I know I could probably use WebGL or Canvas to have better performances but I also want it to work smoothly on mobile browsers hence I thought that DOM manipulation would be better for performances.
You will find the result after a couple of hours at this url
I'd like to reach the best performance possible to increase the number of DIVs.
But here is my problem, I have a "rendering issue" that I spotted when I used TimeLine on Chrome or Safari. From time to time the whole page is rendered generating a small lag perceptible on Safari iPhone or Chrome Android+iPhone.
So if one of you one is up for the challenge don't hesitate I tried many things but I didn't figure out how to avoid this expensive redraw.
BTW, if one of you have extra ideas to optimize this snippets don't hesitate to reply.
Thanks
---------- UPDATE 1 ----------
Based on Ariya advices I updated by code (url) and added another test using only top/left.
Based on the FPS counter provided by Chrome I can see that the fps is more stable using top/left properties with almost the same framerate.
Do you have any idea if I could optimize the CSS3 version to have even better performances? I though that css3 with GPU Acceleration would be faster I probably did something wrong.
---------- UPDATE 2 ----------
I updated my code to use requestAnimFrame and only fire it when I need to redraw.
And I found what is killing the perf gray gradient background that I defined in the css was redraw often and killing the performance.
However top/left seems still better than CSS transition :( from a pure performance point of view.
When looking at the Timeline profile in Google Chrome's Developer Tools, it's evident that there is a lot of style recalculation. This is to be blamed at this particular line:
lastSheet.insertRule('#-webkit-keyframes '+keyframeName+' { ....
In other words, continuously changing the style sheet is expensive. Since the element animation in this example is about moving them around, rather than using keyframe-based animation I would recommend simplifying to simple transition.
I am trying to choose the right technology to use for updating a project that basically renders thousands of points in a zoomable, pannable graph. The current implementation, using Protovis, is underperformant. Check it out here:
http://www.planethunters.org/classify
There are about 2000 points when fully zoomed out. Try using the handles on the bottom to zoom in a bit, and drag it to pan around. You will see that it is quite choppy and your CPU usage probably goes up to 100% on one core unless you have a really fast computer. Each change to the focus area calls a redraw to protovis which is pretty darn slow and is worse with more points drawn.
I would like to make some updates to the interface as well as change the underlying visualization technology to be more responsive with animation and interaction. From the following article, it seems like the choice is between another SVG-based library, or a canvas-based one:
http://www.sitepoint.com/how-to-choose-between-canvas-and-svg/
d3.js, which grew out of Protovis, is SVG-based and is supposed to be better at rendering animations. However, I'm dubious as to how much better and what its performance ceiling is. For that reason, I'm also considering a more complete overhaul using a canvas-based library like KineticJS. However, before I get too far into using one approach or another, I'd like to hear from someone who has done a similar web application with this much data and get their opinion.
The most important thing is performance, with a secondary focus on ease of adding other interaction features and programming the animation. There will probably be no more than 2000 points at once, with those small error bars on each one. Zooming in, out, and panning around need to be smooth. If the most recent SVG libraries are decent at this, then perhaps the ease of using d3 will outweigh the increased setup for KineticJS, etc. But if there is a huge performance advantage to using a canvas, especially for people with slower computers, then I would definitely prefer to go that way.
Example of app made by the NYTimes that uses SVG, but still animates acceptably smoothly:
http://www.nytimes.com/interactive/2012/05/17/business/dealbook/how-the-facebook-offering-compares.html . If I can get that performance and not have to write my own canvas drawing code, I would probably go for SVG.
I noticed that some users have used a hybrid of d3.js manipulation combined with canvas rendering. However, I can't find much documentation about this online or get in contact with the OP of that post. If anyone has any experience doing this kind of DOM-to-Canvas (demo, code) implementation, I would like to hear from you as well. It seems to be a good hybrid of being able to manipulate data and having custom control over how to render it (and therefore performance), but I'm wondering if having to load everything into the DOM is still going to slow things down.
I know that there are some existing questions that are similar to this one, but none of them exactly ask the same thing. Thanks for your help.
Follow-up: the implementation I ended up using is at https://github.com/zooniverse/LightCurves
Fortunately, drawing 2000 circles is a pretty easy example to test. So here are four possible implementations, two each of Canvas and SVG:
Canvas geometric zooming
Canvas semantic zooming
SVG geometric zooming
SVG semantic zooming
These examples use D3's zoom behavior to implement zooming and panning. Aside from whether the circles are rendered in Canvas or SVG, the other major distinction is whether you use geometric or semantic zooming.
Geometric zooming means you apply a single transform to the entire viewport: when you zoom in, circles become bigger. Semantic zooming in contrast means you apply transforms to each circle individually: when you zoom in, the circles remain the same size but they spread out. Planethunters.org currently uses semantic zooming, but it might be useful to consider other cases.
Geometric zooming simplifies the implementation: you apply a translate and scale once, and then all the circles are re-rendered. The SVG implementation is particularly simple, updating a single "transform" attribute. The performance of both geometric zooming examples feels more than adequate. For semantic zooming, you'll notice that D3 is significantly faster than Protovis. This is because it's doing a lot less work for each zoom event. (The Protovis version has to recalculate all attributes on all elements.) The Canvas-based semantic zooming is a bit more zippy than SVG, but SVG semantic zooming still feels responsive.
Yet there is no magic bullet for performance, and these four possible approaches don't begin to cover the full space of possibilities. For example, you could combine geometric and semantic zooming, using the geometric approach for panning (updating the "transform" attribute) and only redrawing individual circles while zooming. You could probably even combine one or more of these techniques with CSS3 transforms to add some hardware acceleration (as in the hierarchical edge bundling example), although that can be tricky to implement and may introduce visual artifacts.
Still, my personal preference is to keep as much in SVG as possible, and use Canvas only for the "inner loop" when rendering is the bottleneck. SVG has so many conveniences for development—such as CSS, data-joins and the element inspector—that it is often premature optimization to start with Canvas. Combining Canvas with SVG, as in the Facebook IPO visualization you linked, is a flexible way to retain most of these conveniences while still eking out the best performance. I also used this technique in Cubism.js, where the special case of time-series visualization lends itself well to bitmap caching.
As these examples show, you can use D3 with Canvas, even though parts of D3 are SVG-specific. See also this force-directed graph and this collision detection example.
I think that in your case the decision between canvas and svg is not like a decision between »riding a Horse« or driving a »Porsche«. For me it is more like the decision about the cars color.
Let me explain:
Assuming that, based on the framework the operations
draw a star,
add a star and
remove a star
take linear time. So, if your decision of the framework was good it is a bit faster, otherwise a bit slower.
If you go on assuming that the framework is just fast, than it becomes totally obvious that the lack of performance is caused be the high amount of stars and handling them is something none of the frameworks can do for you, at least I do not know about this.
What I want to say is that the base of the problem leads to a basic problem of computational geometry, namely: range searching and another one of computer graphics: level of detail.
To solve your performance problem you need to implement a good preprocessor which is able to find very fast which stars to display and is perhaps able to cluster stars which are close together, depending on the zoom. The only thing that keeps your view vivid and fast is keeping the number of stars to draw as low possible.
As you stated, that the most important thing is performance, than I would tend to use canvas, because it works without DOM operations. It also offers the opportunity to use webGL, what increases graphic performance a lot.
BTW: did you check paper.js? It uses canvas, but emulates vector graphics.
PS: In this Book you can find a very detailed discussion about graphics on the web, the technologies, pros and cons of canvas, SVG and DHTML.
I recently worked on a near-realtime dashboard (refresh every 5 seconds) and chose to use charts that render using canvas.
We tried Highcharts(SVG based JavaScript Charting library) and CanvasJS(Canvas based JavaScript Charting library). Although Highcharts is a fantastic charting API and offers way more features we decided to use CanvasJS.
We needed to display at least 15 minutes of data per chart (with option to pick range of max two hours).
So for 15 minutes: 900 points(data point per second) x2(line and bar combination chart) x4 charts = 7200 points total.
Using chrome profiler, with CanvasJS the memory never went above 30MB while with Highcharts memory usage exceeded 600MB.
Also with refresh time of 5 seconds CanvasJS rendering was allot more responsive then Highcharts.
We used one timer (setInterval 5 seconds) to make 4 REST API calls to pull the data from back end server which connected to Elasticsearch. Each chart updated as data is received by JQuery.post().
That said for offline reports I would go with Highcharts since its more flexible API.
There's also Zing charts which claims to use either SVG or Canvas but haven't looked at them.
Canvas should be considered when performance is really critical. SVG for flexibility. Not that canvas frameworks aren't flexible, but it takes allot more work for canvas framework to get the same functionality as an svg framework.
Might also look into Meteor Charts, which is built on top of the uber fast KineticJS framework: http://meteorcharts.com/
I also found when we print to PDF a page with SVG graphics, the resulting PDF still contains a vector-based image, while if you print a page with Canvas graphics, the image in the resulting PDF file is rasterized.
For our website, we are developing a "component" that would display images in a similar fashion to Time Machine on Mac OS X. So it will be many images on top of each other, positioned slightly differently and with a smooth animation as you scroll forward and backward.
We have a spike implementation with CSS3 animations but it's not very smooth in Firefox and IE9 is not supported at all (though we may live with it if the other options are even worse).
We are considering implementation in SVG or Canvas but don't have much experience with it so I thought we'd ask first. So:
Requirements:
It must be fast. The animation must be smooth and that is a hard requirement.
It should be supported in as many browsers as possible.
Required browsers are Chrome 20+, Firefox 14+ and IE10+.
We would very much like to have support for IE9 too but can live without it if absolutely necessary.
Opera is nice to have but not necessary.
Options and our current experience / opinion on them:
CSS3 - seems like the "appropriate" technology for the task but unfortunately the implementation doesn't work so well. Maybe we have inefficiencies in our prototype code but the support seems quite different between different browsers at the moment.
SVG - at least it's vector graphics / DOM elements but we don't have any experience with it.
Canvas - we hope that it should perform well as it is used even for games but we can't quite imagine how would all the pixel redrawing work. Maybe we should use some libraries like processingjs?
Flash or other plugins - I happen to know Flash quite well and I know that the Time Machine-like effect would be quite an easy task there but we'd rather stay away from plugins at the moment.
Thanks for advice.
If the size of the component does not have to be very large, but can be limited to say around 800x600 pixels, then it sounds like Canvas should be up to the job.
If you only draw (scaled) bitmaps to the Canvas then performance is very good in my experience, even on iPad2. Performance only really starts to suffer at higher resolutions (1920x1080 and above), so if you use it for a fullscreen feature you need to watch out! Also, fancy features such as drop shadow etc. can slow down performance considerably as well.
Canvas has very few quirks between browsers, so it will almost certainly be less painful than using CSS3 or SVG in terms of getting it to work as expected across a wide range of browsers.
I would recommend whipping together a quick and dirty prototype with Canvas to see if it will meet your first requirement regarding performance.
If you decide to go with Canvas, I would definitely recommend using a library. Since you know Flash quite well you might want to take a look at EaselJS. It has a display list inspired by Flash, and the performance cost of using it is negligible in most cases. You also get basic events for interactivity. Also, if you go with EaselJS, it would be quite simple to port the code to Flash later if you decide to.
Are you looking for something like this? It uses SMIL animation so you'd have to integrate something like fakesmile to get IE support.
I hope this isn't too open ended.
I'm wondering if there is a better (more battery-friendly) way of doing this --
I have a small HTML 5 game, drawn in a canvas (let's say 500x500). I have some objects whose positions I update every 50ms or so. My current implementation re-draws the entire canvas every 50ms. I can't imagine that being very good for battery life on mobile platforms.
Is there a better way to do this? This must be a common pattern with games.
EDIT:
as requested, here are some more updates:
Right now, the objects are geometric primitives drawn via arcs and lines. I'm not opposed to making these small png/jpg/gif files instead of that'd help out. These are small graphics -- just 15x15 or so.
As the game progresses, more and more of the screen changes at a time. However, at the start, the screen changes relatively slowly (the objects randomly moved a few pixels every 50ms).
Nearly every game with continuous animation like this redraws everything every frame; clever updating algorithms are only applicable when a small part of the screen is changing and there is a nice rule to figure out what is overlapping that part.
Here is some general optimization advice:
Make sure that as much as possible of your graphics are handled by the GPU and not the CPU. (This may be impossible if the user's browser does not use the GPU for 2D canvas rendering, but you can expect upgrades may change that as HTML5 gaming gains popularity.)
This means that you should avoid elaborate clever algorithms in favor of doing as little work as possible in JS code — except that avoiding performing a lot of drawing when it is easy to determine that it will be invisible (e.g. outside the bounds of the screen) is generally worthwhile.
If your target platforms support it (generally not the case for current mobile devices), try using WebGL instead of 2D Canvas. You will have to do more detail work, but WebGL allows you to use operations which are much more likely to be provided efficiently by the GPU hardware.
If your game becomes idle — that is, nothing is actually animating at the moment — stop redrawing. Stop your update loop until the user interacts with the game or a timeout occurs.
It may be helpful for you to add to your question details of what types of graphics you are drawing (e.g. are you using sprites, or geometric primitives? Are you drawing images rotated/scaled? Does most of the screen change or just a few small objects? Are you blending many layers?) and perhaps even a screenshot or two; then we can suggest what sort of optimizations are suitable for your particular game.
Don't draw a background, make it an image and set the CSS background-image of the canvas.
Using requestAnimationFrame should help with battery life.
http://paulirish.com/2011/requestanimationframe-for-smart-animating/
Only do a redraw if something has actually changed. If you haven't already, introduce the concept of invalidations. (ie, the canvas is valid so nothing redraws until something moves. Anything moving within the window of the canvas causes the canvas to become invalid, thus needing a redraw)
If you want to be battery friendly you can use Crafty. This game engine is using modern CSS3 technology so it doesn't need to update a canvas all the time. Look at this example game here.
The way you don't want to redraw entire canvas every frame, it only can be the "Dirty-Check" or "Dirty Matrix" algorithms.
Dirty-check seems more efficient than entire redraw. but I think it depends on your render implementation.
it is not necessary to use it if you are using canvas2D to render. Nearly every game has complex sprites and animation. if you use dirty-check, when a part of sprite or background map need to update, you have to figure out what is overlapping this part. and then clearRect this small area of canvas, and then redraw every sprite or map. etc, what is overlapping.
It means your had to run canvas render api more times than normal render implementation because of the overlapping part. And Canvas2d render performance usually does't sounds efficient.
But if you use WebGL, that maybe quite difference. even though I am not family with WebGL, I do knew that maybe more efficient. Dirty-Check should be a good Choice to match your propose.
I am developing a jQtouch app and each request done via ajax creates a new div in the document for the loaded content. Only a single div is shown at any one time.
How many div's can I have before the app starts getting unresponsive and slow?
Anyone have any ideas on this?
EDIT: Its an iPad app running on Safari, and it would be less than 1000 div's with very basic content
I've had tens of thousands, maybe even a hundred thousand divs, on screen at once.
Performance is either fine, or bad, depending on:
Parsed from HTML or generated Dynamically in JavaScript?
Parsed from HTML means you have a LARGE html source, and this can make browsers hang. Generated in JS is surprisingly fast, even on Internet Explorer, which is the slowest of all browsers for JS.
To be honest, if you really need an absolute answer to this question, then you might want to reconsider your design.
No answer given here will be right, as it depends upon many factors that are specific to your application. E.g. heavy vs. little CSS use, size of the divs, amount of actual graphics rendering required per div, target browser/platform, number of DOM event listeners etc..
Just because you can doesn't mean that you should! :-)
As others have said, there's really no answer.
However, in this talk about the Google Maps API version 3, the speaker brings up the number ten thousand several times, as a basic threshold for browser unhappiness.
http://code.google.com/apis/maps/documentation/javascript/
Without defining a particular environment, it's not possible to answer your question.
And even then, anything anyone tells you is just a guess. You need to do your own testing on real-world configurations with different browsers and hardware. You'll also need to establish some performance benchmarks to decide what "too slow" even means.
I've been able to add several thousand divs without a problem. Depends on what you'll be doing afterwards, of course, and the memory on the client machine. Everyone else is right about that.
As Harpo said, 10K is probably a good ceiling. At one time, I noticed speed problems starting at about 4K divs, but hardware has improved since then.
And, as Neil N said, adding the divs via scripting is better than having a huge HTML source.
And, to answer Harpo's comment, one way to "break it up" so that JS doesn't lock the page and produce a "page is running slowly" error is to call a timer at the end of each "add a div" routine, and the timer in turn calls your "add a div" function again.
Now, MY question is: is it possible to "paint" so that you don't need to add thousands of divs? This can be done with the canvas tag with some browsers, but I don't think it's possible with VML (the excanvas project) on IE. Or is it? I think VML "paints" by adding new elements to the DOM, at which point you may as well use DIVs, unless it's a simple shape.
Is it possible to alter the source of an image via scripting? (the image in the DOM, of course -- not the original image on the server.)