解説
Last active
February 24, 2017 22:13
-
-
Save shimizu/fda228d7229df38673cc6d5c12776cf4 to your computer and use it in GitHub Desktop.
SVG download module
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: mit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function createDownloader(){ | |
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" | |
} | |
function exports(_selection) { | |
var svg = _selection.node() | |
var w = svg.clientWidth, h = svg.clientHeight | |
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.innerHTML) | |
.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) { | |
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 downloadSVG(source) { | |
var filename = "chart.svg"; | |
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" }) | |
if (navigator.appVersion.toString().indexOf('.NET') > 0){ //IE hack | |
window.navigator.msSaveBlob(blobObject, filename) | |
}else { | |
var url = window.URL.createObjectURL(blobObject) | |
var a = d3.select("body").append("a") | |
a.attr("class", "downloadLink") | |
.attr("download", "chart.svg") | |
.attr("href", url) | |
.text("test") | |
.style("display", "none") | |
a.node().click() | |
setTimeout(function() { | |
window.URL.revokeObjectURL(url) | |
a.remove() | |
}, 10); | |
} | |
} | |
function downloadPNG(source) { | |
var filename = "chart.png"; | |
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", w) | |
.attr("height", h) | |
.style("display", "none") | |
var context = canvas.node().getContext("2d") | |
var download = function() { | |
if (navigator.appVersion.toString().indexOf('.NET') > 0){ | |
canvg(document.getElementById('drawingArea'), (new XMLSerializer()).serializeToString(svg)) | |
var dataURI2Blob = function(dataURI, dataTYPE) { | |
var binary = atob(dataURI.split(',')[1]), array = []; | |
for(var i = 0; i < binary.length; i++) array.push(binary.charCodeAt(i)); | |
return new Blob([new Uint8Array(array)], {type: dataTYPE}); | |
} | |
var data_uri = canvas.node().toDataURL("image/png") | |
var blobObject = dataURI2Blob(data_uri, "image/png") | |
window.navigator.msSaveBlob(blobObject, filename) | |
}else { | |
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) | |
.attr("href", url) | |
.text("test") | |
.style("display", "none") | |
a.node().click() | |
setTimeout(function() { | |
window.URL.revokeObjectURL(url) | |
canvas.remove() | |
a.remove() | |
}, 10); | |
} | |
} | |
var img = new Image(); | |
img.src = data_uri | |
if (navigator.appVersion.toString().indexOf('.NET') > 0){ //IE hack | |
d3.select(img).attr("onload", download) | |
}else{ | |
img.addEventListener('load', download, false) | |
} | |
} | |
/** | |
* @callback downloadSVG | |
* @desc svgをダウンロードする | |
*/ | |
_selection.downloadSVG = function(){ | |
createEmptySVG() | |
createCopySVG() | |
var allElements = traverse(_copyChart) | |
var i = allElements.length; | |
while (i--){ | |
explicitlySetStyle(allElements[i]); | |
} | |
downloadSVG(_copyChart) | |
d3.select(_copyChart).remove() | |
d3.select(_emptySvg).remove() | |
} | |
/** | |
* @callback downloadPNG | |
* @desc pngをダウンロードする | |
*/ | |
_selection.downloadPNG = function(){ | |
createEmptySVG() | |
createCopySVG() | |
var allElements = traverse(_copyChart) | |
var i = allElements.length; | |
while (i--){ | |
explicitlySetStyle(allElements[i]); | |
} | |
downloadPNG(_copyChart) | |
d3.select(_copyChart).remove() | |
d3.select(_emptySvg).remove() | |
} | |
} | |
return exports | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"/> | |
<style> | |
html, body { | |
width: 100%; | |
height: 100%; | |
padding: 0px; | |
margin: 0px; | |
} | |
#chart { | |
width: 960px; | |
height: 400px; | |
} | |
.bg { | |
fill:white; | |
} | |
.bar { | |
fill:skyblue; | |
} | |
.axisLayer .axis .domain { | |
stroke: #333333; | |
} | |
.axisLayer .tick line { | |
stroke: #333333; | |
stroke-width: 1px; | |
} | |
.axisLayer .tick text { | |
fill: #333333; | |
font-size: 14px; | |
letter-spacing: .05em; | |
} | |
.axisLayer .label { | |
font-size: 12px; | |
font-weight: normal; | |
letter-spacing: .05em; | |
} | |
.backgroundLayer .grid line { | |
stroke: #cccccc; | |
stroke-dasharray: 3,3; | |
} | |
.backgroundLayer .grid .domain { | |
stroke: none; | |
} | |
</style> | |
</head> | |
<body> | |
<button id="update">updarte</button> | |
<div id="chart"></div> | |
<button id="downloadSVG">SVG Download</button> | |
<button id="downloadPNG">PNG Download</button> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/4.3.0/d3.min.js"></script> | |
<script src="//bl.ocks.org/shimizu/raw/0b526eab82263c8443108c33e454d221/nChart.js"></script> | |
<script src="createDownloader.js"></script> | |
<script> | |
!(function(){ | |
"use strict" | |
var data = generateData() | |
var BarChart = nChart.createVStackBarChart() | |
.baseMargin({top:20, left:0, bottom:20, right:0}) | |
.plotMargin({top:20, left:100, bottom:20, right:100}) | |
.x(function(d){ return d["年"] }) | |
.s(function(d){ return d["国名"] }) | |
.y(function(d){ return d["値"] }) | |
var Axis = nChart.createAxis() | |
.yAxisGridVisible(true) | |
var downloader = createDownloader() | |
var selector = d3.selectAll("#chart") | |
.datum(data) | |
.call(BarChart) | |
.call(Axis) | |
.call(downloader) | |
d3.select("#update").on("click", function(){ | |
selector.update(generateData()) | |
}) | |
d3.select("#downloadSVG").on("click", selector.downloadSVG ) | |
d3.select("#downloadPNG").on("click", selector.downloadPNG ) | |
function generateData(){ | |
return Array.prototype.concat.apply([], ["日本", "アメリカ", "フランス"].map(function(country){ | |
var array = [2001,2002,2003,2004].map(function(year){ | |
var value = ~~(Math.random() * 100) | |
return {"国名":country, "年":year, "値":value} | |
}) | |
return array | |
})) | |
} | |
}()); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment