Moving elements along a path while maintaining orientation. For each arrow, the translate is determined by interpolating a point along the length of the path and the rotation is determined by calculating the approximate tangent of the path using two nearby points.
Last active
February 3, 2018 19:17
-
-
Save veltman/1d6da36a626dd265f700d5a583e74e94 to your computer and use it in GitHub Desktop.
Animating along a path
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8" /> | |
<style> | |
path { | |
fill: dodgerblue; | |
stroke: none; | |
} | |
.track { | |
fill: none; | |
stroke: dodgerblue; | |
stroke-width: 3px; | |
} | |
</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"> | |
<defs> | |
<path id="arrow" d="M-5,0 L-15,15 L15,0 L-15,-15 Z"/> | |
</defs> | |
<path class="track" d="M636.5,315c-0.4-18.7,1.9-27.9-5.3-35.9 | |
c-22.7-25-107.3-2.8-118.3,35.9c-7,24.4,20.6,37.2,16,71c-4,29.6-30.8,60.7-56.5,61.1c-30.8,0.4-32.9-43.8-81.7-70.2 | |
c-50.9-27.6-110.1-12.9-125.2-9.2c-66.1,16.4-82.2,56.9-109.2,47.3c-38-13.6-55.9-112.1-19.8-143.5c39-34,121.2,27.7,148.1-3.8 | |
c18-21.1,3.1-74.3-25.2-105.3c-31.1-34.1-70.1-32.4-105.3-76.3c-8.2-10.2-16.9-23.8-15.3-39.7c1.2-11.4,7.5-23.3,15.3-29 | |
c33.8-25,101.6,62.6,193.1,59.5c40.1-1.3,38.7-18.5,99.2-38.9c126.2-42.6,242.4-4.9,297.7,13c54.7,17.7,105.4,35,129.8,82.4 | |
c13,25.3,22.9,67.7,4.6,87c-11.6,12.3-25.1,5.1-46.6,20.6c-2.8,2-28.9,21.4-32.1,49.6c-3.1,27.4,18.7,35,29,70.2 | |
c8.8,30.1,8.5,77.8-18.3,99.2c-32.3,25.8-87,0.6-100-5.3c-69.6-32-67.2-88.4-73.3-109.2z"/> | |
</svg> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script> | |
var path = document.querySelector(".track"), | |
totalLength = path.getTotalLength(); | |
var markers = d3.select("svg").selectAll("g") | |
.data(d3.range(0, 1, 0.1)) | |
.enter() | |
.append("g") | |
.attr("transform",function(d){ | |
var p = pointAtLength(totalLength * d); | |
return "translate(" + p + ") rotate( " + angleAtLength(totalLength * d) + ")"; | |
}); | |
markers.append("use") | |
.attr("xlink:href", "#arrow"); | |
d3.timer(function(t){ | |
markers.attr("transform",function(d){ | |
var pos = (d + t / 15000) * totalLength % totalLength; | |
return "translate(" + pointAtLength(pos) + ") rotate( " + angleAtLength(pos) + ")"; | |
}); | |
}); | |
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> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment