Skip to main content

Mobomo webinars-now on demand! | learn more.

Downloadable SVG in PNG format

Recently, I worked on some interesting features, we use Highcharts and/or Raphaeljs to build complex charts, including bar chart, scatter chart or heat map, etc. In an extreme sample, we build a complicated one-page charting engine by which user is able to compose a group of conditions and then render a meaningful chart according to what are selected. It's pretty cool.

Meanwhile, client is willing to download these generated charts on individual chart level. They also want to have an ability to share the individual chart as a link or even as a piece of HTML code. What's the best solution to add these functionalities? Well, we did try many solutions for the features, let me show you how we make it finally.

Start from a HTML template

Above HTML code is the generated content on my page, I will mainly explain the solution based on it. Here is also a sample SVG file: sample.svg, you can use it to go through the whole senario if you want to experiment by yourself.

Deal with SVG via HTML5 Canvas

HighCharts and Rapheal are JS libaries by which you are able to generate complex SVG charts, normally, people can not download a svg file directly, and it's also not a popular image format for sharing around. We'd better convert it to a PNG or JPG image, as PNG and JPG format is downloadable from web page. I will take PNG format as a sample in this post.

How to convert a SVG image to a PNG image? Mainly, you can do the convertion job from server side. There is a SVG toolkit provided by Apache which is named as Batik. But I don't like this solution, it's a bit comoplex to install Batik and make it work with Ruby on Rails. I'd like to work the convertion out via pure javascript. Yes, use canvg to move all SVG information to a HTML5 Canvas object.

Using the HTML5 canvas element, you can create all sorts of cool graphics client-side on the fly using Javascript. There is a neat function on the the canvas object called toDataURL(). This functions encodes the image data as a base64 encoded PNG file and returns it as a data: URI. By using the data:URI string, you can make it a downloadable PNG file.

There is also a libary to help you do so, it's Canvas2Image that can convert canvas to image as BMP, PNG or JPEG format.

Customize default filename while downloading

Canvas2Image lib will implement a pop out window to allow you download the data:URI as a PNG image file with a default name download, which is not acceptable by our client, I have to figure out a way to customize the downloadable filename.

It might be easy if you just want to cover your Chrome or Firefox user, as there is a download attribute for <a> tag, when you set it as something like <a src='the data:uri string' download='test.png'> then you will get the default filename in this the case when you click the download link.

I am not lucky, I have to cover IE9 at least. So I need to push the data:uri to server, then I can render the data with specific headers(see below code), that will make the downloadable file with a customized file name.

Pay attention to above html2canvas([$(".hidden_container")[0]],{ … }) parts. It helps to convert whole HTML code to a canvas based on html2canvas lib, that's our case as we have to wrap up some HTML code out side the the charts.

A trick to overcome IE9 issue

When you work on IE9, the canvg fails to translate the SVG to Canvas, it seems IE9's DOMParser() is not able to parse the SVG successfully. After some search from Google, we found only one line code will resove the SVG parser issue. Just replace some invalid string in SVG data as below:

Conclusion

To summarize this post, you are suggested to use several JS libs above to convert SVG to Canvas, then convert Canvas to PNG file, if you also want to customize a piece of HTML code out side the SVG chart, then you are able to convert HTML to Canvas, then again from Canvas to PNG, when you want to set a customized filename for the generated PNG file, you have to send the data:uri string onto server side, then rewrite the response headers, all these handling will implement a downloading feature for you.

Categories
Author

Data visualization is a big part of what we do at Intridea, and in this post I'm sharing what we used to build a world choropleth map in one of our client projects.

What is Raphael ?

Raphael is a small JS library that makes it easy to create vector graphics on the web. It's also (conveniently) compatible with major browsers including IE 6.0. You may have heard about d3.js, another popular data visualization tool which is built on HTML5 and CSS3. We didn't use it because it has some compatibility issues with IE. In this particular use case we needed IE compatibility.

Basic Usage of Raphael

Create Canvas:

Add Elements: elements are created with paper instance we create last step, you can create rect, circle, text, path, etc.

You can actually chain call the method around element which will handful for show codes:

Draw a path:

Before we start building our world choropleth map you may want to check out the demo here. The world map is built with lots of paths; for the paths of countries around the world we need to have countries paths data and luckily we can find that in http://raphaeljs.com/world/world.js

The HTML:

<div id="world_map_container"></div> 

The Coffeescript Code:

bindHoverToCountry method is used to bind hover events on the country path which will be used to highlight the country when mouse hover the country and display tooltip

You can download the code in github https://github.com/intridea/raphael-choropleth-map. The full codebase is developed with Backbone and Raphael. You can find the Raphael code in https://github.com/intridea/raphael-choropleth-map/blob/master/app/assets/javascripts/views/map_view.js.coffee.

Resources:

raphaeljs.com/reference.html

raphaeljs.com/world

Categories
Author
1
Subscribe to Raphaeljs