Skip to content

Instantly share code, notes, and snippets.

@shimizu
Last active February 17, 2023 12:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shimizu/eb8829e8e35216d890c501bd698e87ce to your computer and use it in GitHub Desktop.
Save shimizu/eb8829e8e35216d890c501bd698e87ce to your computer and use it in GitHub Desktop.
download.js
export defaul function() {
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 prefix = {
xmlns: "http://www.w3.org/2000/xmlns/",
xlink: "http://www.w3.org/1999/xlink",
svg: "http://www.w3.org/2000/svg"
};
var _debug = false;
var _fileName = "chart";
function instance(_selection) {
var svg = _selection.node();
var _emptySvg, _emptySvgDeclarationComputed;
var _copyChart;
function createEmptySVG() {
_emptySvg = window.document.createElementNS(prefix.svg, "svg");
window.document.body.appendChild(_emptySvg);
_emptySvgDeclarationComputed = getComputedStyle(_emptySvg);
}
function createCopySVG() {
_copyChart = d3
.select("body")
.append("div")
.html(svg.outerHTML)
.node();
}
function traverse(obj) {
var tree = [];
tree.push(obj);
visit(obj);
function visit(node) {
if (node && node.hasChildNodes()) {
var child = node.firstChild;
while (child) {
if (child.nodeType === 1 && child.nodeName != "SCRIPT") {
tree.push(child);
visit(child);
}
child = child.nextSibling;
}
}
}
return tree;
}
function explicitlySetStyle(element) {
if (element.nodeName == "image") convertDataURIs(element);
var cSSStyleDeclarationComputed = getComputedStyle(element);
var attributes = Object.keys(element.attributes).map(function(i) {
return element.attributes[i].name;
});
var i, len;
var computedStyleStr = "";
for (i = 0, len = cSSStyleDeclarationComputed.length; i < len; i++) {
var key = cSSStyleDeclarationComputed[i];
var value = cSSStyleDeclarationComputed.getPropertyValue(key);
if (
!attributes.some(function(k) {
return k === key;
}) &&
value !== _emptySvgDeclarationComputed.getPropertyValue(key)
) {
computedStyleStr += key + ":" + value + ";";
}
}
element.setAttribute("style", computedStyleStr);
}
function convertDataURIs(imgElement) {
var canvas = document.createElement("canvas");
canvas.width =
imgElement.farthestViewportElement.attributes.width.nodeValue;
canvas.height =
imgElement.farthestViewportElement.attributes.height.nodeValue;
canvas.getContext("2d").drawImage(imgElement, 0, 0);
var dataURI = canvas.toDataURL("image/png");
imgElement.setAttribute("xlink:href", dataURI);
}
function downloadingSVG(source) {
var svg = d3
.select(source)
.select("svg")
.attr("xmlns", prefix.svg)
.attr("version", "1.1")
.node();
var blobObject = new Blob(
[doctype + new XMLSerializer().serializeToString(svg)],
{ type: "text/xml" }
);
var url = window.URL.createObjectURL(blobObject);
var a = d3.select("body").append("a");
a.attr("class", "downloadLink")
.attr("download", _fileName + ".svg")
.attr("href", url)
.text("test")
.style("display", "none");
a.node().click();
setTimeout(function() {
window.URL.revokeObjectURL(url);
a.remove();
}, 10);
}
function downloadingPNG(source) {
var svg = d3
.select(source)
.select("svg")
.attr("xmlns", prefix.svg)
.attr("version", "1.1")
.node();
var data_uri =
"data:image/svg+xml;utf8," +
encodeURIComponent(new XMLSerializer().serializeToString(svg));
var canvas = d3
.select("body")
.append("canvas")
.attr("id", "drawingArea")
.attr("width", svg.clientWidth)
.attr("height", svg.clientHeight);
if (!_debug) canvas.style("display", "none");
var context = canvas.node().getContext("2d");
var img = new Image();
img.src = data_uri;
img.addEventListener("load", downloaded, false);
function downloaded() {
context.drawImage(img, 0, 0);
var url = canvas.node().toDataURL("image/png");
var a = d3
.select("body")
.append("a")
.attr("id", "downloadLink");
a.attr("class", "downloadLink")
.attr("download", _fileName + ".png")
.attr("href", url)
.text("test")
.style("display", "none");
a.node().click();
if (!_debug)
setTimeout(function() {
window.URL.revokeObjectURL(url);
canvas.remove();
a.remove();
}, 10);
}
}
/**
* @callback downloadSVG
* @desc svgをダウンロードする
*/
_selection.downloadSVG = function(fileName) {
if (fileName) _fileName = fileName;
createEmptySVG();
createCopySVG();
var allElements = traverse(_copyChart);
var i = allElements.length;
while (i--) {
explicitlySetStyle(allElements[i]);
}
downloadingSVG(_copyChart);
if (!_debug) {
d3.select(_copyChart).remove();
d3.select(_emptySvg).remove();
}
};
/**
* @callback downloadPNG
* @desc pngをダウンロードする
*/
_selection.downloadPNG = function(fileName) {
if (fileName) _fileName = fileName;
createEmptySVG();
createCopySVG();
var allElements = traverse(_copyChart);
var i = allElements.length;
while (i--) {
explicitlySetStyle(allElements[i]);
}
downloadingPNG(_copyChart);
if (!_debug) {
d3.select(_copyChart).remove();
d3.select(_emptySvg).remove();
}
};
}
/**
* デバッグ機能の有効・無効を設定する
* @param {Boolean} flag 有効, 無効を渡す
*/
instance.debug = function(_arg) {
if (!arguments.length) return _debug;
_debug = _arg;
return this;
};
return instance;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment