Skip to content

Instantly share code, notes, and snippets.

@steltenpower
Last active January 18, 2016 02:45
Show Gist options
  • Save steltenpower/0cfe97cda6ed02d49591 to your computer and use it in GitHub Desktop.
Save steltenpower/0cfe97cda6ed02d49591 to your computer and use it in GitHub Desktop.
morph a composite path
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
svg { width:100%; height: 100% }
</style>
</head>
<body>
<script>
function myFunction(){
var sq2=Math.sqrt(2), pi=Math.PI;
// actually want to do this for many i,j combinations at the same time, for which D3 should be particularly handy
var i=10, j=30; // 0<n<40,i<>j
// defining the 4 control points to start with
var P0={start:{x:i-0.5, y:0}};
var P1={start:{x:P0.start.x, y:j-1}};
var P2={start:{x:P1.start.x-0.5, y:P1.start.y+0.5}};
var P3={start:{x:0, y:P2.start.y}};
// calculating different parameters to describe the same path
function av(a,b){
return {x:(a.x+b.x)/2,
y:(a.y+b.y)/2};}
var Pmid={start:av(P1.start,P2.start)};
Pmid.end={x: sq2/4*(i+j-1)};
Pmid.end.y = Pmid.end.x;
var r={start:0.5,
end : Math.abs(i-j)*sq2/2};
var angle={start: -pi/4};
angle.end = angle.start+pi/2*Math.sign(j-i);
var L0={start:(P1.start.y-P0.start.y),
end:0},
L1={start:(P2.start.x-P3.start.x),
end:0};
return function(d, i, a) {
return function(t){
function interpolate_scalar(ip,t){
ip.move = ip.start * (1-t)+ip.end * t;
return ip;}
function interpolate(ip,t){
ip.move={x:ip.start.x*(1-t)+ip.end.x*t,
y:ip.start.y*(1-t)+ip.end.y*t};
return ip;}
Pmid=interpolate(Pmid,t);
angle=interpolate_scalar(angle,t);
L0=interpolate_scalar(L0,t);
L1=interpolate_scalar(L1,t);
r=interpolate_scalar(r,t);
// just some trigonometry
var c=Math.cos(angle.move), s=Math.sin(angle.move);
var Pc={move:{x:Pmid.move.x-r.move/sq2*c,
y:Pmid.move.y+r.move/sq2*s}};
var a=angle.move-pi/4;
var sa=Math.sin(a), ca=Math.cos(a);
var rs=r.move*sa, rc=r.move*ca;
P1.move={x:Pc.move.x-rs,
y:Pc.move.y-rc};
P2.move={x:Pc.move.x+rc,
y:Pc.move.y-rs};
P0.move={x:P1.move.x-L0.move*ca,
y:P1.move.y+L0.move*sa};
P3.move={x:P2.move.x+L1.move*sa,
y:P2.move.y+L1.move*ca};
return ("M"+P0.move.x+","+P0.move.y+
" L"+P1.move.x+","+P1.move.y+
" A"+r.move+","+r.move+" 0 0,1 "+P2.move.x+","+P2.move.y+
" L"+P3.move.x+","+P3.move.y);
};
};
}
// generating some SVG
var svg = d3.select("body").append("svg");
svg.append("rect")
.attr({x: 0, y: 0, width: 400, height: 400})
.style({ fill: "#a72d1a"});
var g=svg.append("g").attr("transform","scale(10)");
g.append("path")
.style({ stroke: "yellow",fill:"none", "stroke-width":0.2})
.transition()
.duration(5000)
.attrTween("d",myFunction());
// also see http://bl.ocks.org/cloudshapes/5662135
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment