Skip to content

Instantly share code, notes, and snippets.

@syntagmatic
Forked from armollica/README.md
Last active September 11, 2016 11:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save syntagmatic/1dd1acd35f77c1fc64863e42f4a405bb to your computer and use it in GitHub Desktop.
Save syntagmatic/1dd1acd35f77c1fc64863e42f4a405bb to your computer and use it in GitHub Desktop.
Convert SVG to Retina Canvas

Convert SVG to canvas on-the-fly. Updated to support higher pixel densities, like Retina displays. Compare to Andrew Mollica's example which looks slightly fuzzy on high-density displays.

This article from MDN explains the process: Drawing DOM object into a canvas. This works for any DOM object, not just SVG. Not sure if this is well supported by older browsers. Works on Chrome, Firefox and IE 10 for me. The bar chart is a fork of this block by Mike Bostock: Canvas Bar Chart.

letter frequency
A .08167
B .01492
C .02782
D .04253
E .12702
F .02288
G .02015
H .06094
I .06966
J .00153
K .00772
L .04025
M .02406
N .06749
O .07507
P .01929
Q .00095
R .05987
S .06327
T .09056
U .02758
V .00978
W .02360
X .00150
Y .01974
Z .00074
<html>
<head>
<style>
/* Any styling on the SVG won't transfer to the Canvas */
/* Styling must be done inline */
</style>
</head>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var margin = { top: 20, right: 20, bottom: 30, left: 40 },
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scaleBand()
.rangeRound([0, width])
.padding(0.1);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var svg = d3.select("body").append("svg")
.attr("xmlns", "http://www.w3.org/2000/svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var devicePixelRatio = window.devicePixelRatio || 1;
var canvas = d3.select("body").append("canvas")
.attr("width", (width + margin.left + margin.right) * devicePixelRatio)
.attr("height", (height + margin.top + margin.bottom) * devicePixelRatio)
.style("width", width + "px")
.style("height", height + "px")
.style("margin-top", margin.top + "px")
.style("margin-left", margin.left + "px");
var context = canvas.node().getContext("2d");
context.scale(devicePixelRatio, devicePixelRatio);
d3.tsv("data.tsv", processRow, function(error, data) {
if (error) throw error;
// Update scales
x.domain(data.map(function(d) { return d.letter; }));
y.domain([0, d3.max(data, function(d) { return d.frequency; })]);
// Draw axes
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.select("path")
.style("stroke", "none");
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y).tickFormat(d3.format(".0%")))
.append("text")
.attr("transform", "rotate(-90)")
.attr("dx", "-1em")
.attr("dy", "1.66em")
.style("fill", "#000")
.text("Frequency");
// Draw bars
g.append("g")
.attr("class", "bars")
.selectAll(".bar").data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.letter); })
.attr("y", function(d) { return y(d.frequency); })
.attr("width", x.bandwidth())
.attr("height", function(d) { return height - y(d.frequency); })
.style("fill", "steelblue");
// Convert SVG to Canvas
// see: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Drawing_DOM_objects_into_a_canvas
var DOMURL = window.URL || window.webkitURL || window;
var svgString = domNodeToString(svg.node());
var image = new Image();
var svgBlob = new Blob([svgString], { type: "image/svg+xml;charset=utf-8" });
var url = DOMURL.createObjectURL(svgBlob);
image.onload = function() {
context.drawImage(image, 0, 0);
DOMURL.revokeObjectURL(url);
}
image.src = url;
});
function processRow(d) {
d.frequency = +d.frequency;
return d;
}
// Get the string representation of a DOM node (removes the node)
function domNodeToString(domNode) {
var element = document.createElement("div");
element.appendChild(domNode);
return element.innerHTML;
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment