I have a large chart produced with Raphael, that I want to display in a printer-friendly page. With smaller charts this works beautifully even down to IE7 (min requirement).
But if the chart is too long vertically it doesn't split across pages, instead the bottom is just cut off; this happens in all browsers.
Any suggestions as to how I might solve this problem? Preferably without just making it smaller.
Thanks
What you want to achieve is not directly possible. Raphael container element marks overflow:hidden style and as such for browsers that considers partial page split as overflow, it would be very difficult to split the output - especially if the overflow is horizontal.
As a workaround, you may convert Raphael's SVG into canvas by using the canvg JS library. Canvas, being a single raster element, will allow seamless overflow.
You can have a look at this fiddle where I use FusionCharts' (internally using Raphael) SVG to output to a canvas.
canvg("myCanvasElementId", myRaphaelPaper.canvas.parentNode.innerHTML);
In the above code snippet, I assume that you already have a canvas element with id myCanvasElementId and a Raphael paper called myRaphaelPaper.
Refer to this fiddle where I have rendered Raphael SVG and exported it to canvas and then made it visible only for CSS print media. The Raphael element is made to render 15in by 15in to overflow document.
Note that this will be limited to modern browsers supporting canvas.
Related
I have a website which sends about 7 megs of json data to the client, where d3 (actually dimplejs) charts are rendered. The page is getting to be pretty slow and simply doesn't work in some browsers.
I'm thinking of rendering the svg in the server, instead of having the client browser do it. I've seen several references this technique. However, since labels, bar widths and so many elements depend the pixel height and width of the chart, and these dimensions are not known until client's browser renders the page, how do people handle such issues?
I'm not a web/front-end developer normally so I don't know if I'm missing something obvious or if my assumptions are wrong.
The simplest thing is to take the rendered <svg> and add a viewBox attribute to it. That allows you to specify how you want the browser to scale/stretch or crop the <svg> when it's placed inside a parent container (eg <div>).
Anything beyond that — like selectively scaling or repositioning text or rects or axes — can only be achieved the "hard" way; i.e. with code that has some awareness of the chart's semantics and programmatically alters certain svg attributes to react to container size.
Finally, and this is a long-shot: If you have full control of the output (I'm guessing your don't, since you're using dimple), you could attempt using a combination of absolute and percentage units to size and position things, as conceptually demonstrated here
Soooo, what I'm trying to do is essentially a jigsaw puzzle. On the left side is an area with a stack of a dozen or so overlapping .png files of "ripped" paper pieces (all different irregular shapes with alpha) that when put together, in order on the right side, form a sheet of paper with notes on it. A visual (disregard rotated pieces):
Nothing new I know, but my two main caveats in developing this are that it has to work in ie8+ and on touch devices. So this means no flash (where this would of been very easy) and no canvas (stupid ie); which leaves me with js and maybe svg?
The drag and drop part in js is easy enough but the issue I'm having is that, as I'm sure you know, the alpha channel is ignored and the irregular ripped piece is actually a rectangle. Which makes this unusable given that pieces are a stack with pieces overlapping each other.
I can do granular hit detection on the drop by using an image map and setting a variable on rollover.
I've looked around a lot (here + google) and tried some ideas but I'm unable to solve the irregular shape select/drag issue. Any ideas?
Thanks for your time.
Low-tech solution
Nested elements with absolute position
If you're willing to spend a little extra time, there's a way to achieve this fairly closely, without having to use Flash, Canvas, SVG, or even image maps. And unlike an image map, it allows you to nest related content inside each hotspot if needed (e.g., pop-ups).
In the simplest case, you could use a single rectangular hyperlink hotspot for each piece of the puzzle. Obviously that greatly limits the range of shapes you can support (without interfering with overlapping elements).
But, if you take that hyperlink tag and give it a number of span tag children, and give each one absolute position (relative to the hyperlink), and apply the appropriate portion of the image to the background, then you can "construct" irregular image shapes that occupy a single irregular hotspot, with relatively-little interference with overlapping elements.
In effect, the image (with areas of transparency) is treated as a sprite file, with the hyperlink tag and the child span tags each occupying one portion of the "sprite file". Most of the transparent parts of the image will not be occupied by the hyperlink tag or the span tags.
Most shapes can probably be built using a hyperlink tag and 4 - 10 spans. Granted, the more irregular the shapes are, the more spans it will tend to require.
I've done this before, to create hotspots for each of the states on a US map, without using an image map (or Flash, Canvas, SVG), and it wasn't nearly as problematic as you'd think. It just requires a bit of time to figure out the details of how to break up each shape into the right number of rectangles.
The catch
Rounding error on mobile devices
Here's the catch, and it's a doozy. When a web page is scaled on mobile devices (and a regular page is almost always scaled on smaller devices), that introduces a rounding error that causes the px placement of the hyperlink tag and the span tags to possibly vary by at least 1 pixel horizontally and/or vertically. This also happens if desktop browsers are scaled; it's just that desktop browsers are not often scaled.
What would happen is that you would tend to wind up with 1 pixel or so of separation (or overlap) between the different parts of each shape. In many cases, that will tend to be very obvious and not acceptable visually. And depending on the implementation, the locations can vary by as much as 2px or 3px. When it occurs it's difficult to solve, and there are limits to how much of it can be solved.
Last I checked, Firefox is the only browser that's smart enough about rounding px values on scaled pages to avoid this problem. Hopefully other browsers will eventually support it better, as even simple pages often suffer from rounding errors.
The solution
Separate the images from the hotspots
The rounding error isn't much of a problem with hotspots (where precision isn't important). Where it really causes problems is with images (when you see an image not lining up where it should).
It may be possible to avoid the worst of the image rounding errors by doing the following:
Have one set of HTML code for the hotspots, same as described above, except don't display any part of the images in the hotspots. Give them all transparent backgrounds.
Have another set of HTML code for the images. Each one would be a single rectangular element that displays all of the image.
Place each image at the same position as the related hotspot.
Make sure the set of hotspots and the set of images both have the same z-index order. All of the hotspots will be on top of all of the images, but within the hotspots and within the images the order needs to be consistent.
When the hotspot for a piece is dragged, update the position of the related image to keep them at the same location. In effect, the image shadows the hotspot while it's being dragged.
Isn't ExplorerCanvas an option for you? I would think that that would allow you to create a canvas-based solution. That will be much better than anything done with plain html element manipulation through javascript
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
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).
I'm currently reading up on the canvas, but I'm finding it hard to find practical benefits of using canvas, when a lot can be done using simple css overlays/JavaScript (+ jquery lib).
This is probably because I don't know the FULL practicalities of using canvas.
Looking at this game:
http://www.pirateslovedaisies.com/
Could someone help explain how and why canvas is being used as opposed to just css?
This is a 4k js/canvas demo I wrote to experiment with the 2d context (here is a video if your browser doesn't work). I tested it only on chrome, opera, firefox, safari and nexus one browser.
Note that no external resources are loaded (i.e. the texture and the raytraced envmap are built dynamically), so this is just a single self-contained 4096 bytes HTML file.
You can do something like that with DIVs?
But indeed I agree that the game you linked IMO could be done also with DIVs; apparently there are no transformations - not even in the falling daisy loading scene - and the action areas for the pirates are just circles. Not sure but could be that even shooting only happens at fixed angles.
Canvas could have been used instead for:
Drawing general sloped lines and polygons (the map could be created dinamically from a compact description or could have been generated randomly). Shooting could be done at any angle...
Procedural image creation (e.g. textures or special pixel effects)
Gradients, texture mapping
General 2d matrix transforms
Of course a game using an image+DIVs approach is probably way easier to make (a lot of photoshop and simple xy animation).
Creating tons of HTML elements is extremely slow and memory-hungry. The canvas object is made for graphics operations and thus optimized for it. Besides that.. how would you draw a curve with plain HTML/CSS? ;)
Using <canvas> you have a per-pixel control of what's shown on the screen. You don't have to deal with specific browser CSS or DOM compatibility.
Also, that's actually a pretty similar programming model to 2D non-browser games, like those created using SDL o DirectDraw.
Here's a game I wrote in a few hours using Canvas; note that the scaling of the tiles, the anti-aliasing of the lines, is perfect. This would not be the case with image tiles that were being resized by the browser.
Click the tiles to rotate them in an attempt to make all connections. Click the row of buttons at the top for a new board of a different size; click the row of buttons below that for a new board with different numbers of connections.
The game concept is not mine, only the implementation.