Testing out animating d3 paths with varying numbers of points. Top one is standard and other using d3-interpolate-path plugin. More information in this awesome blog post: Improving D3 Path Animation
forked from eesur's block: d3 | path animation
license: mit |
function drawLine(data, path1, path2) { | |
// the line accessor function | |
var line = d3.line() | |
.x(function (d) { return d.x; }) | |
.y(function (d) { return d.y; }) | |
.curve(d3.curveLinear) | |
d3.select(path1) | |
.datum(data) | |
.transition() | |
.duration(2000) | |
.attr('d', line) | |
d3.select(path2) | |
.datum(data) | |
.transition() | |
.duration(2000) | |
.attrTween('d', function (d) { | |
// console.log(d) | |
var previous = d3.select(this).attr('d') | |
var current = line(d) | |
// console.log(current) | |
// d3.select('#path-data').text(current) | |
return d3.interpolatePath(previous, current) | |
}) | |
d3.select('#path-data').text(line(data)) | |
} | |
Testing out animating d3 paths with varying numbers of points. Top one is standard and other using d3-interpolate-path plugin. More information in this awesome blog post: Improving D3 Path Animation
forked from eesur's block: d3 | path animation
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("d3-interpolate")):"function"==typeof define&&define.amd?define(["exports","d3-interpolate"],t):t(e.d3=e.d3||{},e.d3)}(this,function(e,t){"use strict";function n(e){e=e.trim().replace(/ /g,",");var t=e[0],n=e.substring(1).split(",");return l[t.toUpperCase()].reduce(function(e,t,r){return e[t]="x"===t?parseFloat(n[r]):n[r],e},{type:t})}function r(e){var t=e.type,n=l[t.toUpperCase()];return""+t+n.map(function(t){return e[t]}).join(",")}function a(e,t){var n={x1:"x",y1:"y",x2:"x",y2:"y"},r=["xAxisRotation","largeArcFlag","sweepFlag"];return e.type!==t.type&&"M"!==t.type.toUpperCase()&&!function(){var a={};Object.keys(t).forEach(function(i){var o=t[i],p=e[i];void 0===p&&(r.includes(i)?p=o:(void 0===p&&n[i]&&(p=e[n[i]]),void 0===p&&(p=0))),a[i]=p}),a.type=t.type,e=a}(),e}function i(e,t,n){var r=void 0;r=e.length>1&&"M"===e[0].type?1:0;for(var a=t.reduce(function(t,n,a){if(0===a&&"M"===n.type)return t[0]=1,t;for(var i=Math.abs(e[r].x-n.x),o=r,p=r+1;p<e.length;p++){var l=Math.abs(e[p].x-n.x);if(!(l<i))break;i=l,o=p}return t[o]=(t[o]||0)+1,t},{}),i=[],o=0,l=0;l<e.length;l++){i.push(e[l]);for(var u=1;u<a[l]&&o<n;u++){var y=p({},e[l]);"M"===y.type?y.type="L":(void 0!==y.x1&&(y.x1=y.x,y.y1=y.y),void 0!==y.x2&&(y.x2=y.x,y.y2=y.y)),i.push(y),o+=1}}return i}function o(e,o){var p=null==e?"":e.replace(/[Z]/gi,"").replace(/([MLCSTQAHV])\s*/gi,"$1"),l=null==o?"":o.replace(/[Z]/gi,"").replace(/([MLCSTQAHV])\s*/gi,"$1"),u=""===p?[]:p.split(/(?=[MLCSTQAHV])/gi),y=""===l?[]:l.split(/(?=[MLCSTQAHV])/gi);if(!u.length&&!y.length)return function(){return""};u.length?y.length||y.push(u[0]):u.push(y[0]);var c=u.map(n),x=y.map(n),f=Math.abs(y.length-u.length);0!==f&&(x.length>c.length?c=i(c,x,f):x.length<c.length&&(x=i(x,c,f))),c=c.map(function(e,t){return a(e,x[t])});var s=c.map(r).join(""),g=x.map(r).join("");null!=e&&"Z"!==e[e.length-1]||null!=o&&"Z"!==o[o.length-1]||(s+="Z",g+="Z");var h=t.interpolateString(s,g);return function(e){return 1===e?null==o?"":o:h(e)}}var p=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},l={M:["x","y"],L:["x","y"],H:["x"],V:["y"],C:["x1","y1","x2","y2","x","y"],S:["x2","y2","x","y"],Q:["x1","y1","x","y"],T:["x","y"],A:["rx","ry","xAxisRotation","largeArcFlag","sweepFlag","x","y"]};e.interpolatePath=o,Object.defineProperty(e,"__esModule",{value:!0})}); |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<!-- http://www.basscss.com/ --> | |
<link href="//npmcdn.com/[email protected]/css/basscss.min.css" rel="stylesheet"> | |
<!-- http://clrs.cc/ --> | |
<link href="//s3-us-west-2.amazonaws.com/colors-css/2.2.0/colors.min.css" rel="stylesheet"> | |
<style> | |
body { | |
font-family: Consolas, monaco, monospace; | |
background: #dfe0e2; | |
color: #2f292b; | |
} | |
path { | |
fill: none; | |
stroke: #f45844; | |
stroke-width: 2; | |
} | |
</style> | |
</head> | |
<body> | |
<section> | |
<h1 class="h5 caps">standard</h1> | |
<svg width="960" height="200"> | |
<g translate="transform(10, 10)"> | |
<path id="path-normal"></path> | |
</g> | |
</svg> | |
</section> | |
<hr> | |
<section> | |
<h1 class="h5 caps">using interpolate</h1> | |
<svg width="960" height="200"> | |
<g translate="transform(10, 10)"> | |
<path id="path-interpolate"></path> | |
</g> | |
</svg> | |
</section> | |
<hr> | |
<footer> | |
<h1 class="h5 caps">svg path: (same for both)</h1> | |
<p id="path-data"></p> | |
</footer> | |
<script src="//d3js.org/d3.v4.min.js" charset="utf-8"></script> | |
<script src="d3-interpolate-path.min.js" charset="utf-8"></script> | |
<!-- d3 code --> | |
<script src=".script-compiled.js" charset="utf-8"></script> | |
<!-- render code --> | |
<script> | |
// create array of random objects for line data | |
function data() { | |
let _data = d3.range(Math.floor(d3.randomUniform(10, 90)())) | |
.map(function(n, i) { | |
return { | |
'x': i *10, // constrain x | |
'y': Math.floor(d3.randomUniform(200)()) } | |
}) | |
// console.info(_data) | |
return _data | |
} | |
drawLine('#path', data()) | |
d3.interval(function() { | |
return drawLine(data(), '#path-normal', '#path-interpolate') | |
}, 3000) | |
d3.select(self.frameElement).style('height', '670px'); | |
</script> | |
</body> | |
</html> | |
function drawLine(data, path1, path2) { | |
// the line accessor function | |
const line = d3.line() | |
.x(d => d.x) | |
.y(d => d.y) | |
.curve(d3.curveLinear) | |
d3.select(path1) | |
.datum(data) | |
.transition() | |
.duration(2000) | |
.attr('d', line) | |
d3.select(path2) | |
.datum(data) | |
.transition() | |
.duration(2000) | |
.attrTween('d', function (d) { | |
// console.log(d) | |
let previous = d3.select(this).attr('d') | |
let current = line(d) | |
// console.log(current) | |
// d3.select('#path-data').text(current) | |
return d3.interpolatePath(previous, current) | |
}) | |
d3.select('#path-data').text(line(data)) | |
} | |