forked from mbostock's block: Wrapping Long Labels
forked from f94f's block: Barras Estado
| license: gpl-3.0 | |
| scrolling: |
forked from mbostock's block: Wrapping Long Labels
forked from f94f's block: Barras Estado
| 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 | |
| } |
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <style> | |
| .bar-pe { | |
| fill: #0075ea; | |
| } | |
| .bar-to { | |
| fill: #008e2d; | |
| } | |
| .bar-pa { | |
| fill: #ffa500; | |
| } | |
| .bar-re { | |
| fill: #FF0000; | |
| } | |
| .bar-pe:hover { | |
| fill: #56aafe; | |
| } | |
| .bar-to:hover { | |
| fill: #00BC3C; | |
| } | |
| .bar-pa:hover { | |
| fill: #ffbb3d; | |
| } | |
| .bar-re:hover { | |
| fill: #ff1e1e; | |
| } | |
| /*tooltip*/ | |
| .show { | |
| display: block; | |
| } | |
| .hidden { | |
| display: none; | |
| } | |
| .tooltip { | |
| background-color: #333; | |
| padding: 4px 8px; | |
| position: absolute; | |
| color: #fff; | |
| opacity: 0.8; | |
| z-index: 100; | |
| } | |
| .title { | |
| font: bold 14px "Helvetica Neue", Helvetica, Arial, sans-serif; | |
| } | |
| .axis { | |
| font: 10px sans-serif; | |
| } | |
| .axis path, | |
| .axis line { | |
| fill: none; | |
| stroke: #000; | |
| stroke-dasharray: 2px 2px; | |
| } | |
| .x.axis path { | |
| display: none; | |
| } | |
| </style> | |
| <body> | |
| <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 src="//d3js.org/d3.v4.min.js"></script> | |
| <script> | |
| var puntos = [ | |
| {name: "Pendientes", value: 0.40}, | |
| {name: "Totales", value: 0.0667}, | |
| {name: "Parciales", value: 0.0667}, | |
| {name: "Rechazados", value: 0.0} | |
| ]; | |
| var margin = {top: 80, right: 180, bottom: 80, left: 180}, | |
| width = 960 - margin.left - margin.right, | |
| height = 500 - margin.top - margin.bottom; | |
| var x = d3.scaleBand().rangeRound([0, width], 0.1, 0.3); | |
| var y = d3.scaleLinear() | |
| .range([height, 0]); | |
| var xAxis = d3.axisBottom() | |
| .scale(x); | |
| var yAxis = d3.axisLeft() | |
| .scale(y) | |
| .ticks(8, "%"); | |
| var tooltip = d3.select("body").append("div") | |
| .attr("class", "tooltip"); | |
| var svg = d3.select("body").append("svg") | |
| .attr("width", width + margin.left + margin.right) | |
| .attr("height", height + margin.top + margin.bottom) | |
| .append("g") | |
| .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
| //EL GRÁFICO | |
| x.domain(puntos.map(function(d) { return d.name; })); | |
| y.domain([0, d3.max(puntos, function(d) { return d.value; })]); | |
| svg.append("text") | |
| .attr("class", "title") | |
| .attr("x", (150)) | |
| .attr("y", -30) | |
| .text("Porcentaje de las entregas según su estado"); | |
| svg.append("g") | |
| .attr("class", "x axis") | |
| .attr("transform", "translate(0," + height + ")") | |
| .call(xAxis) | |
| .selectAll(".tick text") | |
| .call(wrap, x.bandwidth()); | |
| svg.append("g") | |
| .attr("class", "y axis") | |
| .call(yAxis); | |
| svg.selectAll(".bar") | |
| .data(puntos) | |
| .enter().append("rect") | |
| .attr("class", function(d) { | |
| if(d.name == "Pendientes") { return "bar-pe";} | |
| else if(d.name == "Totales") { return "bar-to";} | |
| else if(d.name == "Parciales") { return "bar-pa";} | |
| else if(d.name == "Rechazados") { return "bar-re";} | |
| }) | |
| .attr("x", function(d) { return x(d.name); }) | |
| .attr("width", x.bandwidth()) | |
| .attr("y", function(d) { return y(d.value); }) | |
| .attr("height", function(d) { return height - y(d.value); }) | |
| .on('mouseover', function(d){ | |
| d3.select("#major").text(d.key); | |
| tooltip.transition() | |
| .duration(500) | |
| .style("opacity", 1); | |
| tooltip.html((d.value * 100) + "%") | |
| .style("left", (d3.event.pageX - 25) + "px") | |
| .style("top", (d3.event.pageY - 50) + "px"); | |
| }) | |
| .on('mousemove', function (d) { | |
| tooltip.style("top", (d3.event.pageY - 50) + 'px'); | |
| tooltip.style("left", (d3.event.pageX - 25) + 'px'); | |
| }) | |
| .on('mouseout', function(d){ | |
| d3.select("#major").text("Mouse over"); | |
| tooltip.transition() | |
| .duration(500) | |
| .style("opacity", 0); | |
| }) | |
| var downloader = createDownloader(); | |
| var selector = d3.selectAll("#chart") | |
| .datum(puntos) | |
| .call(yAxis) | |
| .call(xAxis) | |
| .call(downloader); | |
| d3.select("#downloadSVG").on("click", selector.downloadSVG ) | |
| d3.select("#downloadPNG").on("click", selector.downloadPNG ) | |
| function wrap(text, width) { | |
| text.each(function() { | |
| var text = d3.select(this), | |
| words = text.text().split(/\s+/).reverse(), | |
| word, | |
| line = [], | |
| lineNumber = 0, | |
| lineHeight = 1.1, // ems | |
| y = text.attr("y"), | |
| dy = parseFloat(text.attr("dy")), | |
| tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em"); | |
| while (word = words.pop()) { | |
| line.push(word); | |
| tspan.text(line.join(" ")); | |
| if (tspan.node().getComputedTextLength() > width) { | |
| line.pop(); | |
| tspan.text(line.join(" ")); | |
| line = [word]; | |
| tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word); | |
| } | |
| } | |
| }); | |
| } | |
| function type(d) { | |
| d.value = +d.value; | |
| return d; | |
| } | |
| // 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 | |
| } | |
| }); | |
| </script> | |
| <div> | |
| <button id='saveButton'>Export my D3 visualization to PNG</button> | |
| </div> | |
| </body> |