block by eesur c2e3e7aa916038da8995e0c388b2949b

d3 | path animation

Full Screen

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

script.js

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))

}
 

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <!-- //www.basscss.com/ -->
    <link href="//npmcdn.com/basscss@8.0.2/css/basscss.min.css" rel="stylesheet">
    <!-- //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>


d3-interpolate-path.min.js

!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})});