Skip to content

Instantly share code, notes, and snippets.

@osoken
Last active March 20, 2016 07:15
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 osoken/ff0a4ab77ec34c34b0b9 to your computer and use it in GitHub Desktop.
Save osoken/ff0a4ab77ec34c34b0b9 to your computer and use it in GitHub Desktop.
Download as PNG

svg 要素を canvas でレンダリングするサンプル。 マウスオーバーで出現するアイコンをクリックすると svg 要素を canvas でレンダリングし、png としてダウンロードする。

<!DOCTYPE html>
<meta charset="utf-8">
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="renderer.js"></script>
<body>
<script>
var width = 960;
var height = 500;
var rt3 = 1.7320508075688772935274463415059;
var svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height);
var layer = svg.append('g').attr('transform', 'translate('+width/2+',0)');
var points = [{x:-height/rt3, y:height, seed:true},{x:height/rt3, y:height, seed:false}];
var step = function(a)
{
var ret = [];
d3.range(a.length).forEach(function(i)
{
var seed = a[i].seed;
a[i].seed = false;
ret.push(a[i]);
if (seed)
{
var dx = (a[i+1].x - a[i].x)/2;
var dy = (a[i+1].y - a[i].y)/2;
ret.push({x: a[i].x+dx, y: a[i].y+dy, seed:true});
ret.push({x: a[i].x+dx/2+rt3*dy/2, y: a[i].y+dy/2-rt3*dx/2, seed:true});
ret.push({x: a[i].x+3*dx/2+rt3*dy/2, y: a[i].y+3*dy/2-rt3*dx/2, seed:true});
ret.push({x: a[i].x+dx, y: a[i].y+dy, seed:false});
}
});
return ret;
}
var gasket = function(a) { return 'M0,0 ' + a.map(function(d){return 'L'+d.x+','+d.y;}).join(' ') + ' z'; }
var triangle = layer.append('path').attr('fill', '#CCC').attr('d', gasket(points));
var tick = function(depth)
{
if (depth > 5)
{
return;
}
points = step(points);
var dummy = [];
var p = null;
points.forEach(function(d)
{
if (d.seed)
{
if (p==null)
{
p = d;
}
dummy.push(p);
}
else
{
dummy.push(d);
p = null;
}
});
triangle.attr('d', gasket(dummy))
.transition().duration(10000)
.attr('d', gasket(points))
.each('end', function(){tick(depth+1)});
}
tick(0);
var r = renderer()
.source(svg.node())
.target(d3.select('body').node())
.cb(function(err,canvas)
{
if (err != null)
{
console.log(err);
return;
}
var tag = d3.select('body').append('a')
.attr('type','application/octet-stream')
.attr('href', canvas.toDataURL('image/png'))
.attr('download','image.png');
tag.node().click();
tag.remove();
canvas.remove();
});
var icon = svg.append('image')
.attr('width', 256)
.attr('height', 256)
.attr('x',width/2-128)
.attr('y', height/2-128)
.attr('opacity', 0.8)
.attr('xlink:href','downloadbtn.png')
.on('click', r);
icon.transition().duration(2000).attr('opacity', 0.0);
svg.on('mouseover', function()
{
icon.transition().attr('opacity', 0.8);
})
.on('mouseout', function()
{
icon.transition().attr('opacity', 0.0);
})
</script>
!(function()
{
var constant = function(d)
{
return function()
{
return d;
}
}
var renderer = function()
{
var _source = function(d){return this;}
var _target = function(d){return this.parentNode;}
var _cb = function(e,d){}
function _renderer()
{
var source = _source.apply(this, arguments);
var target = _target.apply(this, arguments);
var cb = _cb;
var canvas = document.createElement('canvas');
try
{
var ns = source.getAttribute('xmlns');
source.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
target.appendChild(canvas);
canvas.setAttribute('width', source.clientWidth);
canvas.setAttribute('height', source.clientHeight);
var ctx = canvas.getContext('2d');
var data = new Blob([source.outerHTML],
{type: 'image/svg+xml; charset=utf-8'});
var img = new Image();
var blobReader = new FileReader();
blobReader.onload = function()
{
img.onload = function()
{
ctx.drawImage(img, 0, 0);
if (ns == null)
{
source.removeAttribute('xmlns');
}
else
{
source.setAttribute('xmlns', ns)
}
cb(null, canvas);
}
img.src = this.result;
}
blobReader.readAsDataURL(data);
}
catch (e)
{
canvas.remove();
cb(e, null);
}
}
_renderer.source = function(_)
{
return arguments.length ? (_source = typeof _ === 'function' ? _ : constant(_), _renderer): _source;
}
_renderer.target = function(_)
{
return arguments.length ? (_target = typeof _ === 'function' ? _ : constant(_), _renderer): _target;
}
_renderer.cb = function(_)
{
return arguments.length ? (_cb = typeof _ === 'function' ? _ : constant(_), _renderer): _cb;
}
return _renderer;
}
if (typeof define === "function" && define.amd) define(renderer);
else if (typeof module === "object" && module.exports) module.exports = renderer;
this.renderer = renderer;
}());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment