Creating Image From Browser Based Svg In D3

blog-banner

Prerequisite: To understand this blog, basic knowledge of javascript and d3 js are required.

In this blog, I am going to provide steps to create image from d3 chart or svg.

Nowadays, charts are widely used to represent data in attractive way for different surveys and analysis on the website.

Currently, there are many open source javascript plugins available to create different charts. One of widely used is D3. D3 is used to create variety of chart like bar chart, pie chart, scatter diagram, venn diagram etc. I am not going to explain how to use d3 to generate different types of chart as there are lots of code examples available on web. Here I am going to explain How to generate Image from d3 chart or in general from svg.

D3 uses svg to generate chart from given data. But what if you want to see same chart later after month or year. Because d3 create svg which is rendered on browser if you want see later we need to generate chart again for given data.

So generating chart again and again is very cumbersome. Most common solution is to create image from d3 chart and save that image either giving download option or store on server side so user can check them later.

Following are the steps to create image from svg or d3 chart.

Step 1 : Create blob object from svg

After creating d3 chart, first step is to create blob object from svg. Below is the code snippet to create blob :

var doctype = '<?xml version="1.0" standalone="no"?>'
             + '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">';

var source = (new XMLSerializer()).serializeToString(d3.select('svg').node());

var blob = new Blob([ doctype + source], { type: 'image/svg+xml' });

Here blob type is image/svg+xml. At some blogs I found that type mentioned is 'image/svg+xml;charset=utf-8', but if you specify charset in type then it’s not working in safari. So simply keeping image/svg+xml works on all browsers.

Note : To create image which include all styles and css from svg, you need to define style under svg tag in <defs> tag.

Here is a script to define style under svg :

d3.select("svg").append("defs").append("style").attr("type","text/css").html("[define style here]");

Step 2 : Create image object from blob

var url = window.URL.createObjectURL(blob);
var img = new Image();
img.src =  url;

Step 3 : Read image and create canvas element from it

img.onload = function(){
  var canvas = d3.select('body').append('canvas').node();
  canvas.width = 680;
  canvas.height = 530;

  var ctx = canvas.getContext('2d');
  
  // draw image on canvas
  ctx.drawImage(img, 0, 0);
  var canvasUrl = canvas.toDataURL("image/png");
  canvas.remove();
  // ajax call to send canvas(base64) url to server. Or create anchor tag to give download option 
}

Here, canvasUrl is your base64 encoded image url.You can use it for href of anchor tag to give download option or you can send encoded url to server side for storing image somehwhere.

Step 4: Java code to get base64 url and create image file on server.

// get base64 url
String data = request.getParameter("canvasUrl");

int index = data.indexOf(",");

// remove prefix before ‘,’ so we get base64 string
data = data.substring((index+1));

byte[] bytes =  Base64.getDecoder().decode(data);
File imageFile = new File(“file path”);
FileOutputStream fileOutputStream = null;

try {
     fileOutputStream = new  FileOutputStream(imageFile);
     fileOutputStream.write(bytes);
} catch (Exception e) {
   e.printStackTrace();
} finally {
   if(fileOutputStream != null) {
      fileOutputStream.flush();
      fileOutputStream.close();
   }
}

Final Code:

1. Script :

var doctype = '<?xml version="1.0" standalone="no"?>'
             + '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">';

var source = (new XMLSerializer()).serializeToString(d3.select('svg').node());
var blob = new Blob([ doctype + source], { type: 'image/svg+xml' });

var url = window.URL.createObjectURL(blob);
var img = new Image();

img.onload = function(){
  var canvas = d3.select('body').append('canvas').node();
  canvas.width = 680;
  canvas.height = 530;
  
  var ctx = canvas.getContext('2d');
  
  // draw image on canvas
  ctx.drawImage(img, 0, 0);
  var canvasUrl = canvas.toDataURL("image/png");
  canvas.remove();
  // ajax call to send canvas(base64) url to server. Or create anchor tag to give download option 
}
img.src =  url;

2. Server Side Code :

// get base64 url
String data = request.getParameter("canvasUrl");

int index = data.indexOf(",");

// remove prefix before ‘,’ so we get base64 string
data = data.substring((index+1));

byte[] bytes =  Base64.getDecoder().decode(data);
File imageFile = new File(“file path”);
FileOutputStream fileOutputStream = null;

try {
     fileOutputStream = new  FileOutputStream(imageFile);
     fileOutputStream.write(bytes);
} catch (Exception e) {
   e.printStackTrace();
} finally {
   if(fileOutputStream != null) {
      fileOutputStream.flush();
      fileOutputStream.close();
   }
}
Contact us

For Your Business Requirements

Text to Identify Refresh CAPTCHA
Background Image Close Button

2 - 4 October 2024

Hall: 10, Booth: #B8 Brussels, Belgium