block by pjsier 6c049cceb35b37f5562d2d34f0469482

Map Arc Transition

Full Screen

index.html

<!DOCTYPE html>
<html>
<head>
    <title>Map Arc Transition</title>
    <style>
        .states {
            fill: #ccc;
            stroke: #fff;
            stroke-width: 0.5px;
            stroke-linejoin: round;
            stroke-linecap: round;
        }

        .arc {
            fill: none;
            stroke: red;
            stroke-width: 2px;
        }
    </style>
    <script src="https://d3js.org/d3.v4.min.js"></script>
</head>

<body>
    <svg width="500" height="500"></svg>
    <script>
        var width = 500,
            height = 500;
        var svg = d3.select("svg");

        var projection = d3.geoMercator()
            .scale(2800)
            .rotate([86, 0])
            .center([0, 43.2])
            .translate([width / 2, height / 2]);
        var path = d3.geoPath().projection(projection);

        var clipPath = svg.append("defs")
            .append("clipPath").attr("id", "circle-clip")
            .append("circle")
            .attr("cy", "50%")
            .attr("cx", "50%")
            .attr("r", "50%")
            .attr("fill", "transparent");

        var g = svg.append("g")
            .attr("clip-path", "url(#circle-clip)");

        var aa = [-83.7377, 42.2733];
        var chi = [-87.732, 41.8338];
        function link(p1, p2) {
            var start = projection(p1);
            var end = projection(p2);
            return "M" + start[0] + "," + start[1]
                + "C" + (start[0] + end[0]) / 2 + "," + start[1]
                + " " + (start[0] + end[0]) / 2 + "," + start[1]
                + " " + end[0] + "," + end[1];
        }

        // From https://bl.ocks.org/mbostock/5649592
        function transition(path) {
            path.transition()
                .duration(1000)
                .attrTween("stroke-dasharray", tweenDash);
        }

        function tweenDash() {
            var l = this.getTotalLength(),
                i = d3.interpolateString("0," + l, l + "," + l);
            return function (t) { return i(t); };
        }

        // https://bl.ocks.org/mbostock/1705868
        function translateAlong(path, attr) {
            var l = path.getTotalLength();
            return function (d, i, a) {
                return function (t) {
                    var p = path.getPointAtLength(t * l);
                    return p[attr];
                };
            };
        }

        // ann arbor 42.2733, -83.7377
        // chicago 41.8338, -87.7320
        d3.json("us-states.json", function (error, us) {
            if (error) throw error;

            g.selectAll("path")
                .data(us.features)
                .enter().append("path")
                    .attr("class", "states")
                    .attr("d", path);

            g.append("path")
                .attr("class", "arc")
                .attr("d", link(aa, chi))
                .call(transition);

            var pAA = projection(aa);
            var circle = g.append("circle")
                .attr("width", 0)
                .attr("height", 0)
                .attr("fill", "blue")
                .attr("cx", pAA[0])
                .attr("cy", pAA[1])
                .attr("r", 15);

            circle.transition()
                .duration(1000)
                .attrTween("cx", translateAlong(d3.select("path.arc").node(), "x"))
                .attrTween("cy", translateAlong(d3.select("path.arc").node(), "y"));

        });
    </script>
</body>
</html>