Dhaval
Dhaval

Reputation: 89

SVG tag convert to PNG image with download

I used the D3 chart for display the tree chart so it's works fine now but i need to download this svg chat as image.

Chart html like:

<svg width="960" height="30000">
    <g transform="translate(120,20)">
        <path>......</path>
        <path>......</path>
        <path>......</path>
         ......
         ...... 
    </g>
</svg>

My svg html is much longer so i put the code structure only.

I used this code for download :

d3.select('#saveButton').on('click', function(){
        // alert('test');
        var svgString = getSVGString(svg.node());
        // console.log(svgString);
        svgString2Image( svgString, 2*width, 2*height, 'png', save ); // passes Blob and filesize String to the callback

        function save( dataBlob, filesize ){
            saveAs( dataBlob, 'D3 vis exported to PNG.png' ); // FileSaver.js function
        }
    });

So would you please let me know how i can download the svg chart as image.

Upvotes: 2

Views: 5384

Answers (1)

Gerardo BLANCO
Gerardo BLANCO

Reputation: 5648

The next link has a great way of solving your problem. Solution

It contains two main function.

  1. SVG String
  2. String to Image

I think you are using the same code i just added, as you count with the save download function. The thing here is what else you have on your code. As you can see, this code actually downloads the png end result. Lets work from here and find you a solution.

// Let's create a mock visualization
var width = 300, height = 300;
var circleSizeMax = 15;
var rMax = Math.min(width,height)/2 - circleSizeMax;

var radius 	= d3.scale.linear().range([0,rMax]);
var angle 	= d3.scale.linear().range([0,2*Math.PI]);
var size 	= d3.scale.linear().range([0,circleSizeMax]);
var color 	= d3.scale.ordinal().range(['#fcfb3c','#fcf900','#ff825a','#ffd2cb','#71d362','#ffd16f','#ff3d5d','#ff7218','#04b3f3','#bce5ac','#6e0215','#69D2E7','#A7DBDB','#E0E4CC','#F38630','#E94C6F','#542733','#5A6A62','#C6D5CD','#DB3340','#E8B71A','#F7EAC8','#1FDA9A','#588C73','#F2E394','#F2AE72','#D96459','#D0C91F','#85C4B9','#008BBA','#DF514C','#00C8F8','#59C4C5','#FFC33C','#FBE2B4','#5E412F','#FCEBB6','#78C0A8','#F07818','#DE4D4E','#DA4624','#DE593A','#FFD041','#B1EB00','#53BBF4','#FF85CB','#FF432E','#354458','#3A9AD9','#29ABA4','#E9E0D6','#4298B5','#ADC4CC','#92B06A','#E19D29','#BCCF02','#5BB12F','#73C5E1','#9B539C','#FFA200','#00A03E','#24A8AC','#0087CB','#260126','#59323C','#F2EEB3','#BFAF80','#BFF073','#0DC9F7','#7F7F7F','#F05B47','#3B3A35','#20457C','#5E3448','#FB6648','#E45F56','#A3D39C','#7ACCC8','#4AAAA5','#DC2742','#AFA577','#ABA918','#8BAD39','#F2671F','#C91B26','#9C0F5F','#60047A','#0F5959','#17A697','#638CA6','#8FD4D9','#83AA30','#1499D3','#4D6684','#3D3D3D','#333333','#424242','#00CCD6','#EFEFEF','#CCC51C','#FFE600','#F05A28','#B9006E','#F17D80','#737495','#68A8AD','#C4D4AF']);
var x = function(d) { return radius( d.r ) * Math.cos( angle( d.angle ) ); };
var y = function(d) { return radius( d.r ) * Math.sin( angle( d.angle ) ); };

var svg = d3.select('body').append('svg')
	.attr('width', width)
	.attr('height',height);

var chart = svg.append('g').attr('transform','translate('+[width/2,height/2]+')');

var data = d3.range(150).map( function(d) { return {r: Math.random(), angle: Math.random(), size: Math.random() }; });

chart.selectAll('cirle')
	.data(data).enter()
	.append('circle')
	.attr('class','blendCircle')
	.attr({
		cx: x,
		cy: y,
		r: function(d) { return size(d.size); },
		fill: function(d,i) { return color(i); }
	});


// Set-up the export button
d3.select('#saveButton').on('click', function(){
	var svgString = getSVGString(svg.node());
	svgString2Image( svgString, 2*width, 2*height, 'png', save ); // passes Blob and filesize String to the callback

	function save( dataBlob, filesize ){
		saveAs( dataBlob, 'D3 vis exported to PNG.png' ); // FileSaver.js function
	}
});

// Below are the functions that handle actual exporting:
// getSVGString ( svgNode ) and svgString2Image( svgString, width, height, format, callback )
function getSVGString( svgNode ) {
	svgNode.setAttribute('xlink', 'http://www.w3.org/1999/xlink');
	var cssStyleText = getCSSStyles( svgNode );
	appendCSS( cssStyleText, svgNode );

	var serializer = new XMLSerializer();
	var svgString = serializer.serializeToString(svgNode);
	svgString = svgString.replace(/(\w+)?:?xlink=/g, 'xmlns:xlink='); // Fix root xlink without namespace
	svgString = svgString.replace(/NS\d+:href/g, 'xlink:href'); // Safari NS namespace fix

	return svgString;

	function getCSSStyles( parentElement ) {
		var selectorTextArr = [];

		// Add Parent element Id and Classes to the list
		selectorTextArr.push( '#'+parentElement.id );
		for (var c = 0; c < parentElement.classList.length; c++)
				if ( !contains('.'+parentElement.classList[c], selectorTextArr) )
					selectorTextArr.push( '.'+parentElement.classList[c] );

		// Add Children element Ids and Classes to the list
		var nodes = parentElement.getElementsByTagName("*");
		for (var i = 0; i < nodes.length; i++) {
			var id = nodes[i].id;
			if ( !contains('#'+id, selectorTextArr) )
				selectorTextArr.push( '#'+id );

			var classes = nodes[i].classList;
			for (var c = 0; c < classes.length; c++)
				if ( !contains('.'+classes[c], selectorTextArr) )
					selectorTextArr.push( '.'+classes[c] );
		}

		// Extract CSS Rules
		var extractedCSSText = "";
		for (var i = 0; i < document.styleSheets.length; i++) {
			var s = document.styleSheets[i];
			
			try {
			    if(!s.cssRules) continue;
			} catch( e ) {
		    		if(e.name !== 'SecurityError') throw e; // for Firefox
		    		continue;
		    	}

			var cssRules = s.cssRules;
			for (var r = 0; r < cssRules.length; r++) {
				if ( contains( cssRules[r].selectorText, selectorTextArr ) )
					extractedCSSText += cssRules[r].cssText;
			}
		}
		

		return extractedCSSText;

		function contains(str,arr) {
			return arr.indexOf( str ) === -1 ? false : true;
		}

	}

	function appendCSS( cssText, element ) {
		var styleElement = document.createElement("style");
		styleElement.setAttribute("type","text/css"); 
		styleElement.innerHTML = cssText;
		var refNode = element.hasChildNodes() ? element.children[0] : null;
		element.insertBefore( styleElement, refNode );
	}
}


function svgString2Image( svgString, width, height, format, callback ) {
	var format = format ? format : 'png';

	var imgsrc = 'data:image/svg+xml;base64,'+ btoa( unescape( encodeURIComponent( svgString ) ) ); // Convert SVG string to data URL

	var canvas = document.createElement("canvas");
	var context = canvas.getContext("2d");

	canvas.width = width;
	canvas.height = height;

	var image = new Image();
	image.onload = function() {
		context.clearRect ( 0, 0, width, height );
		context.drawImage(image, 0, 0, width, height);

		canvas.toBlob( function(blob) {
			var filesize = Math.round( blob.length/1024 ) + ' KB';
			if ( callback ) callback( blob, filesize );
		});

		
	};

	image.src = imgsrc;
}
<!DOCTYPE html>
<html lang="en">

<head>
	<title>How to properly export SVG D3 visualization to PNG or JPEG</title>
  <meta charset="utf-8">
  <script src="https://cdn.rawgit.com/eligrey/canvas-toBlob.js/f1a01896135ab378aa5c0118eadd81da55e698d8/canvas-toBlob.js"></script>
	 <script src="https://cdn.rawgit.com/eligrey/FileSaver.js/e9d941381475b5df8b7d7691013401e171014e89/FileSaver.min.js"></script>
	<script src="https://d3js.org/d3.v3.min.js"></script>
 	<style type="text/css">
 		.blendCircle {
 			mix-blend-mode: multiply;
 		}
 	</style>
 </head>

<body>
<div>
<button id='saveButton'>Export my D3 visualization to PNG</button>
</div>
</body>

</html>

Upvotes: 1

Related Questions