|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="utf-8" /> |
|
<style> |
|
|
|
path { |
|
fill: none; |
|
stroke: black; |
|
stroke-width: 2px; |
|
display: none; |
|
} |
|
|
|
.arrow { |
|
fill: black; |
|
stroke: none; |
|
} |
|
|
|
</style> |
|
</head> |
|
<body> |
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="960" height="500"> |
|
<path class="swoop" d="M36.2,268.1C70.2,153.8,108.1,58,140.8,61.2 |
|
c63.1,6.1,69,376.4,103.1,376.2c33-0.2,47.6-346.4,83.8-346.9c32.4-0.4,54.9,275.7,85.4,274.6c27.7-1,34.1-230,62.3-230.8 |
|
c26.2-0.7,48.4,195.5,70,193.8c19.1-1.4,20.7-162.2,43.8-158.5c13.8,2.2,19.3,29.9,24,40.2c17.2,37.4,55.8,58.7,97,54.6 |
|
c13.1-1.3,28.6-6.8,38.9-15c9.4-7.5,15.6-20.4,11.6-31.7c-2.8-7.8-9.8-13.5-17.4-16.9c-9.7-4.4-21.1-5.7-31.2-2 |
|
c-16.6,6.1-25.2,26.6-14.8,41.8c10.9,16.1,31,17.1,48,21.7c55,14.6,112,3.9,165.4-12.2"/> |
|
<path class="arrow" d="M-5,0 L-15,15 L15,0 L-15,-15 Z"/> |
|
</svg> |
|
|
|
<script src="https://d3js.org/d3.v4.min.js"></script> |
|
<script> |
|
|
|
var swoop = d3.select(".swoop"), |
|
arrow = d3.select(".arrow"), |
|
path = swoop.node(), |
|
totalLength = path.getTotalLength(); |
|
|
|
draw(true); |
|
|
|
function draw(immediate) { |
|
|
|
var t = d3.transition() |
|
.duration(4000) |
|
.delay(immediate ? 0 : 1000) |
|
.on("start",function(){ |
|
d3.selectAll("path").style("display", "block"); |
|
}) |
|
.on("end",draw); |
|
|
|
arrow.transition(t) |
|
.attrTween("transform",function(){ |
|
return function(t){ |
|
var pos = t * totalLength; |
|
return "translate(" + pointAtLength(pos) + ") rotate( " + angleAtLength(pos) + ")"; |
|
}; |
|
}); |
|
|
|
swoop.transition(t) |
|
.attrTween("stroke-dasharray",function(){ |
|
return d3.interpolateString("0," + totalLength,totalLength + "," + totalLength); |
|
}); |
|
|
|
} |
|
|
|
|
|
function pointAtLength(l) { |
|
|
|
var xy = path.getPointAtLength(l); |
|
return [xy.x, xy.y]; |
|
|
|
} |
|
|
|
// Approximate tangent |
|
function angleAtLength(l) { |
|
|
|
var a = pointAtLength(Math.max(l - 0.01,0)), // this could be slightly negative |
|
b = pointAtLength(l + 0.01); // browsers cap at total length |
|
|
|
return Math.atan2(b[1] - a[1], b[0] - a[0]) * 180 / Math.PI; |
|
|
|
} |
|
|
|
</script> |