Choosing right technology (SVG vs Canvas) - javascript

I'm writing an app for shape manipulation, such that after creating simple shapes the user can create more complex ones by clipping the shapes against each other (i.e. combining two circles together into a figure 8 stored using a single path rather than a group, or performing intersection of two circles to create a "bite" mark), and am trying to decide on a graphics library to use.
SVG seems to handle 80% of the functionality I need out of the box (shape storage, movement, rotation, scaling). The problem is that the other 20% (using clipping to create a new set of complex polygons) seems impossible to achieve without recreating SVG functionality in my own modules (I'd have to store the shape once for drawing inside SVG, and once for processing clipping myself). I could be wrong about SVG, but by reading about Raphael library (based on SVG), it seems like it only handles clipping using a rectangle, and even that clipping is temporary (it only renders part of the shape, but still stores entire shape to be rerendered once the clipping rectangle is moved). Perhaps I'm just confused about SVG standard, but even retrieving/parsing the paths to compute a new path using subsets of previous paths seems non-obvious in SVG (there is a Subpath() function, but I don't see anything to find the points of intersection of two polygon perimeters, or combine several subpaths into a single path).
As a result, Canvas seems like a better alternative since it doesn't introduce the extra overhead by keeping track of shapes I'd already have to keep track of to make my own clipping implementation work. Not only that, I've already implemented the polygon class that can be moved, rotated, and scaled. Canvas has some other issues, however (I'd have to implement my own redraw method, which I'm sure will not be as efficient as SVG one that takes advantage of browser-specific frameworks in Chrome and Firefox; and I'd have to accept IE incompatibility which is handled for free with libraries like Raphael).
Thanks

This may address what you're mentioning.
Clipping can be done using non-rectangular objects using the 'clipPath' element.
For example, I have element with id of 'clipper' that defines what to clip out, and a path that is subject to the clipping. Not sure if they intersect in this snippet.
<g clip-rule="nonzero">
<clipPath id="clipper">
<ellipse rx="70" ry="95" clip-rule="evenodd"/>
</clipPath>
<!-- stuff to be clipped -->
<path clip-path="url(#clipper)" d="M-100 0 a100 50"/>
</g>
This is just a snippet from something I have. Hope it helps.

Seems to me that you are trying to do 2D constructive geometry. Since SVG runs in retained mode, the objects you draw are stored and then the various operations performed. With Canvas you are running against a bit map so the changes are effected immediately. Since your users will in turn perform more operations on your simpler shapes to create ever more complex ones Canvas should in the long term be a better fit.
The only outstanding question is what will be done with those objects once your users are finished with them. If you zoom the image it will get the jaggies. SVG will avoid that problem but you trade-off with greater complexity and performance impact.

Both svg and canvas are a vector graphical technology.Each one having some different functionality.
Canvas
Canvas is a bitmap with an immediate modegraphics application programming interface (API) for drawing on it. Canvas is a “fire and forget” model that renders its graphics directly to its bitmap and then subsequently has no sense of the shapes that were drawn; only the resulting bitmap stays around.
More Information about canvas - http://www.queryhome.com/51054/about-html5-canvas
SVG
SVG is used to describe Scalable Vector Graphics
SVG is known as a retained mode graphics model persisting in an in-memory model. Analogous to HTML, SVG builds an object model of elements, attributes, and styles. When the element appears in an HTML5 document, it behaves like an inline block and is part of the HTML document tree.
More Information about SVG - http://www.queryhome.com/50869/about-svg-part-1
See here for more information about canvas vs svg in detail - Comparing svg vs canvas

You're right - you'll have to mathematically perform the clipping and creation of new shapes regardless of whether you use SVG or Canvas. I'm biased, it seems like it would be more useful to use SVG since you also get things like DOM events on the shapes (mouse, dragging) and serialization into a graphical format for free.

Related

HTML5 SVG vs Canvas for big number of lines?

Question:
Is canvas more suitable than svg in the following case?
Case:
I'm drawing a chart (using d3js library) similar to this one (but with much more data):
http://mbostock.github.com/d3/talk/20111116/iris-parallel.html
It's based on an svg and it works fine for several thousands of lines (up to 5000), adding more lines (svg path) decreases the performance dramatically (scrolling in the page becomes slow)
Keep in mind: That I need to add mouse events (which is handy in svg)
Generally svg is better suited for vector images, like in your example. However canvas has a lot of benefits in modern browsers such as hardware acceleration, so for drawing the lines, as long as zooming, panning ect. isn't required performance will be using canvas.
Mouse events can be a pain using canvas, since you have to manually keep track of everything, so with 5000+ points using canvas it wont be fun. The trade off however will be once the points are drawn, assuming you only draw them once the page will behave fine regardless of the number of lines, since they are all drawn to a raster image and aren't part of the DOM.
Honestly though the best way to find it is to test what you currently have using canvas.
When performance becomes a problem, switching to canvas might be an option. In this case you can draw the canvas once. Afterwards it's pretty much treated like an image. Drawing might take some time, but afterwards it can be scaled pretty quickly. Note that it is possible to draw a rendered SVG to a canvas using the context.drawImage method (example). So you could keep your SVG generation code to create an SVG in the background, and then draw it to the canvas.
But keep in mind that it won't scale as beautiful as an SVG as soon as it is on the canvas. When the user zooms in, it will get blurry or pixely, depending on how the browser scales graphics.
Click events on canvas can be handled in two ways. Either keep an array of click targets, and add an onclick event handler to the canvas. When a click occurs, iterate the array and check which one is closest to the click coordinates.
The other option is to use hit regions. These have to be defined as polygonal paths.
+1 to everything said above. I've seen some amazing performance increases when using canvas over SVG and over compositing images using the DOM.
About manipulating the canvas image with mouse events, I imagine the best approach for an image such as you are describing is to abstract it away using a library like the following:
http://paperjs.org
http://kineticjs.com
http://www.createjs.com/#!/EaselJS
Keep your code away from the canvas itself and let a library do the thinking for you.

clip-path in Raphaël.js

How can I use clip-path with Raphaël.js like this example. It seams that Raphael.js has only clip-rect in it.
You can cut a hole through a path drawn shape.
This is a technique known as donut holes and you can see an example on my index page
If this looks difficult it is not
See the information database and the technique labelled donut holes
My site index is
http://www.irunmywebsite.com/
Err it used to be.
Now you can find a multiple clip path (Imagine seeing a view through several holes}
The carousel and the thumbnail holder are just one path...
See the Raphael Crousel
A much better example I include below. The central blue region has several holes cut into it. This has multi purpose usage.
It is part of what I call a DOM / SVG hybrid solution.
Cut multi purpose holes for a variety of reasons
I don't think you can do it via Raphael. You can do it by manipulating the DOM directly, but you will loose the ability to call Raphael methods for that element.
I find Raphael a bit obsolete, now that IE supports SVG. You can do much more with plain javascript and and the SVG specification.
If, like in the example image, it's a raster image (png, gif, jpg... bitmap pixel images) you are trying to clip, it's actually really easy. In Raphael 2, you just set the fill to point at the image file. It uses it as a background image.
If you want to crop an image or photograph with a Raphael path or shape like a clipping mask or clip-path for image files, just set the image as the path's fill.
somepath.attr({fill: 'someimage.png'});
Limitations (AFAIK):
Only one image per path
Only one path per image (use compound paths for complex masks)
Things like background position aren't easy - see this question for more
I think it's impossible to stop the image repeating

Pixel level access with Pixastic and RaphaelJS

I'm working on an image editor and I have to create some pixel manipulation methods applied on RaphaelJS images. I am considering using Pixastic library for pixel manipulation.
The problem is the I cannot link RaphaelJS image to Pixastic since RaphaelJS creates a SVG element and Pixastic requires an 'img' tag.
I have tried something like this but with no success
img = r.image("Assets/test.jpg", 40, 40, 260, 150);
img.node=Pixastic.process(img.node, "desaturate");
There's not really currently an easy way to do this. As mentioned already, in many browsers you can output to Canvas and then perform pixel-level transformations, but this transition from SVG to Canvas is destructive, as you have gone from a retained-mode context to an immediate-mode context, and you therefore lose all the niceties of the retained mode API, such as being able to register event listeners on individual shapes, or have a high-level API for transforming individual shapes (or groups of shapes).
However, if you don't need the element-level event handling, you might look into the dojox.gfx library, which provides a high-level, retained-mode, SVG-inspired API for drawing shapes, but also has a Canvas backend (VML and Silverlight too). I believe it is not possible to register event listeners on individual shapes when using the Canvas output, but you would be able to register an event handler on the root canvas element. It might be possible to then apply transformations with Pixtastic, but you might need to hack into the dojox.gfx Canvas render code a bit.
You might also look into SVG filters, which is as close to native support for pixel-level, raster graphics-style manipulation as it gets with SVG.
I also believe they're currently trying to combine the two specifications somewhat to make such work possible: http://lists.w3.org/Archives/Public/public-canvas-api/2011AprJun/0117.html
You could try drawing the svg to a canvas element check near the end of this article https://developer.mozilla.org/en/drawing_graphics_with_canvas. Then outputting the canvas to a base 64 encoded image. Not having worked with either RaphaelJS or pixastic I am not sure how well this would work.

Pie, bar, line: SVG/VML better than Canvas

I need to choose a library for "standard" charting: pies, lines and bars.
From what I've read, it seems to me that the best format is SVG/VML, like Highcharts for example. SVG is becoming standard across all major browsers, now that IE 9 accepts it. It seems easier to rescale and export than Canvas.
Still, I see that several charting libraries rely on Canvas. Am I missing something? Is there any reason for considering Canvas over SVG for such applications?
You can generally achieve the same results with either. Both end up drawing pixels to the screen for the user. The major differentiators are that HTML5 Canvas gives you pixel-level control over the results (both reading and writing), while SVG is a retained-mode graphics API that makes it very easy to handle events or manipulate the artwork with JavaScript or SMIL Animation and have all redrawing taken care of for you.
In general, I'd suggest using HTML5 Canvas if you:
need pixel-level control over effects (e.g. blurring or blending)
have a very large number of data points that will be presented once (and perhaps panned), but are otherwise static
Use SVG if you:
want complex objects drawn on the screen to be associated with events (e.g. move over a data point to see a tooltip)
want the result to print well at high resolution
need to animate the shapes of various graph parts independently
will be including text in your output that you want to be indexed by search engines
want to use XML and/or XSLT to produce the output
Canvas isn't needed unless you want heavy manipulation/animation or are going to have 10,000+ charts. More on performance analysis here.
It is also important to make the distinction: Charting and diagramming are two different things. Displaying a few bar charts is very different from (for instance) making diagramming flowcharts with 10,000+ movable, link-able, potentially-animated objects.
Every SVG element is a DOM element, and adding 10,000 or 100,000 nodes to the DOM causes incredible slowdown. But adding that many elements to Canvas is entirely doable, and can be quite fast.
In case it may have confused you: RaphaelJS (in my opinion the best charting SVG Library) makes use of the word canvas, but that is no way related to the HTML <canvas> element.
In the past two years, my preference has been to use svg, as I mainly deal with relatively small datasets to build pies, column charts or maps.
However one advantage I have found with canvas is the ability to save the chart as an image thanks to the toDataURL method. I haven't found an equivalent for svg, and it seems that the best way to save an svg chart client side is to convert it to canvas first (using for example canvg).

Raphael cumulative vs absolute scaling/rotation/translation?

I'm trying to draw an interactive map in Javascript, using Raphael to do the heavy lifting.
The map background is a fairly complicated thing containing a grid, the map elements, labels, etc. On top of this I'm then going to draw the stuff the user is actually working with. Because the background is complex, I don't want to have to rerender it every frame. So, after drawing it I would like to reuse those drawing elements, merely changing the translation, rotation, scaling of the background as the user pans, zooms, etc.
Unfortunately I'm rather confused by Raphael's transformation primitives: they're not behaving as I would expect. If I call scale(), the scaling appears to apply to the original size of the drawing element; but translate() is cumulative, so it applies to the previous translation. rotate() can be either, as it has an option I can set...
Is it possible to do absolute translation? That is, to be able to specify the absolute coordinates of the new center of my objects (which are usually paths)? Failing that, is keeping track of the old location so I can apply a delta when I want to move it to the new location a reasonable way of doing this?
Or would I be better off simply rerendering the whole thing every frame? (I see suggestions that Raphael isn't good at transformations of complex drawings, as most of it is done in Javascript; looking at the SVG that's being produced, I see that the translation appears to be getting backed into the path data, which would bear this out...)
(BTW, FWIW I'm using the GWT Raphael interface for all this.)
You can use Element.attr to set absolute positions. Just change x and y properties:
myElement.attr("x", myX);
myElement.attr("y", myY);
I've used the raphael-zpd plugin with success. I'm not sure if that will plug into GWT - you could check out their source code and adapt it to your use case.
Project: https://github.com/somnidea/raphael-zpd
Source: https://github.com/somnidea/raphael-zpd/blob/master/raphael-zpd.js

Categories

Resources