I would like to implement a simple download/export function that will convert and save a rendered svg word cloud as a png in my Angular app.
I am making use of d3 word cloud generator done by Jason Davies and a simplified script by Julien Renaux.
I am trying to add a simple export feature, using iweczek's save-svg-as-an-image export function, but somewhere I am missing something.
This is my Angular WordCloud Directive, including the export function at the bottom (scope.exportToPNG
):
'use strict';
/**
* @ngdoc: function
* @name: portalDashboardApp.directive:ogWordCloud
* @description: Word Cloud Generator based on the d3 word cloud generator done by Jason Davies and a simplified script by Julien Renaux
* Directive of the portalDashboardApp
*/
angular.module('portalDashboardApp')
.directive('ogWordCloud', function () {
return {
restrict: 'E',
replace: true,
templateUrl: './socialMedia.module/socialMedia.templates/WordCloudTemplate.html',
scope: {
words: '='
},
link: function (scope) {
var fill = d3.scale.category20b();
var w = window.innerWidth - 238,
h = 400;
var max,
fontSize;
var layout = d3.layout.cloud()
.timeInterval(Infinity)
.size([w, h])
.fontSize(function (d) {
return fontSize(+d.value);
})
.text(function (d) {
return d.key;
})
.on("end", draw);
var svg = d3.select("#wordCloudVisualisation").append("svg")
.attr("width", w)
.attr("height", h)
.attr("xmlns", 'http://www.w3.org/2000/svg')
.attr("xmlns:xlink", 'http://www.w3.org/1999/xlink')
.attr("version", '1.1')
.attr("id", "wordCloudSVG");
var wordCloudVisualisation = svg.append("g").attr("transform", "translate(" + [w >> 1, h >> 1] + ")");
update();
window.onresize = function (event) {
update();
};
var tags = [];
scope.$watch('words', function () {
tags = scope.words;
}, true);
function draw(data, bounds) {
var w = window.innerWidth - 238,
h = 400;
svg.attr("width", w).attr("height", h);
var scale = bounds ? Math.min(
w / Math.abs(bounds[1].x - w / 2),
w / Math.abs(bounds[0].x - w / 2),
h / Math.abs(bounds[1].y - h / 2),
h / Math.abs(bounds[0].y - h / 2)) / 2 : 1;
var text = wordCloudVisualisation.selectAll("text")
.data(data, function (d) {
return d.text.toLowerCase();
});
text.transition()
.duration(1000)
.attr("transform", function (d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.style("font-size", function (d) {
return d.size + "px";
});
text.enter().append("text")
.attr("text-anchor", "middle")
.attr("transform", function (d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.style("font-size", function (d) {
return d.size + "px";
})
.style("opacity", 1e-6)
.transition()
.duration(1000)
.style("opacity", 1);
text.style("font-family", function (d) {
return d.font;
})
.style("fill", function (d) {
return fill(d.text.toLowerCase());
})
.text(function (d) {
return d.text;
});
wordCloudVisualisation.transition().attr("transform", "translate(" + [w >> 1, h >> 1] + ")scale(" + scale + ")");
}
function update() {
layout.font('impact').spiral('archimedean');
fontSize = d3.scale['sqrt']().range([10, 100]);
if (scope.words.length) {
fontSize.domain([+scope.words[scope.words.length - 1].value || 1, +scope.words[0].value]);
}
layout.stop().words(scope.words).start();
}
//////////////////////////////////////////////////////////////////
scope.exportToPNG = function () {
var html = d3.select("svg") //svg
.attr("version", 1.1)
.attr("xmlns", "http://www.w3.org/2000/svg")
.node().parentNode.innerHTML;
var imgsrc = 'data:image/svg+xml;base64,' + btoa(html);
var img = '<img src="' + imgsrc + '">';
d3.select("#svgdataurl").html(img);
var canvas = document.querySelector("canvas"),
context = canvas.getContext("2d");
var image = new Image;
image.src = imgsrc;
image.onload = function () {
context.drawImage(image, 0, 0);
var canvasdata = canvas.toDataURL("image/png");
var pngimg = '<img src="' + canvasdata + '">';
d3.select("#pngdataurl").html(pngimg);
var a = document.createElement("a");
a.download = "sample.png";
a.href = canvasdata;
a.click();
};
}
}
};
});
This is my directive template:
<div id="wordCloud">
<button class="basicButton" ng-click="exportToPNG()">Export to .PNG</button>
<div id="wordCloudVisualisation"></div>
<canvas id="canvas"></canvas>
<h2>svgdataurl</h2>
<div id="svgdataurl"></div>
<h2>pngdataurl</h2>
<div id="pngdataurl"></div>
</div>
As is, the code generates an broken image (like when an image is missing from a placeholder on a website) in Chrome. In IE it creates an image in my "svgdataurl" but bombs out. I believe it is not compatible with IE.