Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

d3-transition attrTween, styleTween methods are not getting triggered in d3 version 4

I'm trying to upgrade the following donut chart from d3.js v3 to d3.js v4.

http://bl.ocks.org/dbuezas/9306799

I have replaced all the old version method names with the equivalant methods in new version.

d3.scale.ordinal() to d3.scaleOrdinal()

d3.layout.pie() to d3.pie()

d3.svg.arc() to d3.arc()

The "d" attribute of path tag not getting generated.

And the methods "attrTween and styleTween" not even getting triggered in v4.

I have created a plunker for this.

<!DOCTYPE html>
<meta charset="utf-8">
<style>

body {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  width: 960px;
  height: 500px;
  position: relative;
}

svg {
    width: 100%;
    height: 100%;
}

path.slice{
    stroke-width:2px;
}

polyline{
    opacity: .3;
    stroke: black;
    stroke-width: 2px;
    fill: none;
}

</style>
<body>
<button class="randomize">randomize</button>

<script src="http://d3js.org/d3.v4.min.js"></script>
<script>

var svg = d3.select("body")
    .append("svg")
    .append("g")

svg.append("g")
    .attr("class", "slices");
svg.append("g")
    .attr("class", "labels");
svg.append("g")
    .attr("class", "lines");

var width = 960,
    height = 450,
    radius = Math.min(width, height) / 2;

var pie = d3.pie()
    .sort(null)
    .value(function(d) {
        return d.value;
    });

var arc = d3.arc()
    .outerRadius(radius * 0.8)
    .innerRadius(radius * 0.4);

var outerArc = d3.arc()
    .innerRadius(radius * 0.9)
    .outerRadius(radius * 0.9);

svg.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

var key = function(d){ return d.data.label; };

var color = d3.scaleOrdinal()
    .domain(["Lorem ipsum", "dolor sit", "amet", "consectetur", "adipisicing", "elit", "sed", "do", "eiusmod", "tempor", "incididunt"])
    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);

function randomData (){
    var labels = color.domain();
    return labels.map(function(label){
        return { label: label, value: Math.random() }
    });
}

change(randomData());

d3.select(".randomize")
    .on("click", function(){
        change(randomData());
    });


function change(data) {

    /* ------- PIE SLICES -------*/
    var slice = svg.select(".slices").selectAll("path.slice")
        .data(pie(data), key);

    slice.enter()
        .insert("path")
        .style("fill", function(d) { return color(d.data.label); })
        .attr("class", "slice");

    slice       
        .transition().duration(1000)
        .attrTween("d", function(d) {
            this._current = this._current || d;
            var interpolate = d3.interpolate(this._current, d);
            this._current = interpolate(0);
            return function(t) {
                return arc(interpolate(t));
            };
        })

    slice.exit()
        .remove();

    /* ------- TEXT LABELS -------*/

    var text = svg.select(".labels").selectAll("text")
        .data(pie(data), key);

    text.enter()
        .append("text")
        .attr("dy", ".35em")
        .text(function(d) {
            return d.data.label;
        });

    function midAngle(d){
        return d.startAngle + (d.endAngle - d.startAngle)/2;
    }

    text.transition().duration(1000)
        .attrTween("transform", function(d) {
            this._current = this._current || d;
            var interpolate = d3.interpolate(this._current, d);
            this._current = interpolate(0);
            return function(t) {
                var d2 = interpolate(t);
                var pos = outerArc.centroid(d2);
                pos[0] = radius * (midAngle(d2) < Math.PI ? 1 : -1);
                return "translate("+ pos +")";
            };
        })
        .styleTween("text-anchor", function(d){
            this._current = this._current || d;
            var interpolate = d3.interpolate(this._current, d);
            this._current = interpolate(0);
            return function(t) {
                var d2 = interpolate(t);
                return midAngle(d2) < Math.PI ? "start":"end";
            };
        });

    text.exit()
        .remove();

    /* ------- SLICE TO TEXT POLYLINES -------*/

    var polyline = svg.select(".lines").selectAll("polyline")
        .data(pie(data), key);

    polyline.enter()
        .append("polyline");

    polyline.transition().duration(1000)
        .attrTween("points", function(d){
            this._current = this._current || d;
            var interpolate = d3.interpolate(this._current, d);
            this._current = interpolate(0);
            return function(t) {
                var d2 = interpolate(t);
                var pos = outerArc.centroid(d2);
                pos[0] = radius * 0.95 * (midAngle(d2) < Math.PI ? 1 : -1);
                return [arc.centroid(d2), outerArc.centroid(d2), pos];
            };          
        });

    polyline.exit()
        .remove();
};

</script>
</body>

Thanks in advance.

like image 654
Anand Kumar Avatar asked Oct 13 '16 10:10

Anand Kumar


1 Answers

The enter, update, and exit pattern changed slightly in d3.js v4. You now need to incorporate the .merge statement.

var slice = svg.select(".slices").selectAll("path.slice")
    .data(pie(data), key);

slice.enter()
    .insert("path")
    .style("fill", function(d) { return color(d.data.label); })
    .attr("class", "slice") //<-- enter selection
    .merge(slice) //<-- merge back in update selection
    .transition().duration(1000)
    .attrTween("d", function(d) {
        this._current = this._current || d;
        var interpolate = d3.interpolate(this._current, d);
        this._current = interpolate(0);
        return function(t) {
            return arc(interpolate(t));
        };
    });

Updated plunker.

like image 97
Mark Avatar answered Oct 25 '22 07:10

Mark