我想实现一个简单的下载/导出功能,它将在我的Angular应用程序中将渲染的svg词云转换并保存为png。
我正在使用由Jason Davies完成的d3字云生成器和Julien Renaux的简化脚本。
我正在尝试添加一个简单的导出功能,使用iweczek的save-svg-as-an-image export function,但某处我错过了一些东西。
这是我的Angular WordCloud指令,包括底部的导出功能(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();
};
}
}
};
});
这是我的指示模板:
<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>
按原样,代码会在Chrome中生成损坏的图像(例如,当网站上的占位符中缺少图像时)。在IE中,它在我的“svgdataurl”中创建了一个图像,但却炸毁了。我认为它与IE不兼容。
答案 0 :(得分:2)
由于以下帖子,我能够解决我的问题:
Save inline SVG as JPEG/PNG/SVG
https://gist.github.com/gustavohenke/9073132
以下是我的完整解决方案:
我的Angular指令:
'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.exportToPNG2 = function () {
var svg = document.querySelector('#wordCloudSVG'); //svg
var canvas = document.createElement("canvas");
var svgSize = svg.getBoundingClientRect();
canvas.width = svgSize.width;
canvas.height = svgSize.height;
var ctx = canvas.getContext('2d');
var data = new XMLSerializer().serializeToString(svg);
var DOMURL = window.URL || window.webkitURL || window;
var img = new Image();
var svgBlob = new Blob([data], { type: 'image/svg+xml;charset=utf-8' });
var url = DOMURL.createObjectURL(svgBlob);
img.onload = function () {
ctx.drawImage(img, 0, 0);
DOMURL.revokeObjectURL(url);
var imgURI = canvas
.toDataURL('image/png')
.replace('image/png', 'image/octet-stream');
triggerDownload(imgURI);
};
img.src = url;
}
function triggerDownload(imgURI) {
var evt = new MouseEvent('click', {
view: window,
bubbles: false,
cancelable: true
});
var a = document.createElement('a');
a.setAttribute('download', 'MY_COOL_IMAGE.png');
a.setAttribute('href', imgURI);
a.setAttribute('target', '_blank');
a.dispatchEvent(evt);
}
}
};
});
我的指示模板:
<div id="wordCloud">
<button class="basicButton" ng-click="exportToPNG2()">Export to .PNG</button>
<div id="wordCloudVisualisation"></div>
<canvas id="WordCloudCanvas"></canvas>
</div>
我希望这有助于其他人!
答案 1 :(得分:0)
你的指令外是否存在div #svgdataurl
和#pngdataurl
?如果没有,您应该将它们包含在指令模板中。在您关注的示例中,它们已经出现在页面上,而不是由click
函数创建。
您还可以查看刚刚发布的类似工具Mike Bostock,该工具使用canvas.toBlob()
:https://github.com/mbostock/svjimmy/blob/master/index.js。