javascriptd3.jsconsole.logeasingeasing-functions

D3 Elastic easing transition of circle radius causes negative radius to be set


I have a very weird problem whilst using the ease("elastic", a, p) function in d3js. I am transitioning the radius of circles and I'm getting a flood of errors in the console, which are significantly slowing down my webpage. The errors state that I'm setting a negative radius — after some debugging (from console logging everything to diffs with previous code) I found out that's caused by the elastic easing. Here's my code:

function redraw() {
    var day = d3.select('input[name="day"]:checked').node().value;
    var time = d3.select('input[type="range"]').node().value.toString();
    var direction = d3.select('input[name="direction"]:checked').node().value;

    // fix bug in which data for single digit hours is not displayed
    if (time.length == 1) {time = "0" + time;}

    if (circles !== undefined) {
        circles.transition().duration(900).ease('elastic', 1, 0.75).attr({
            fill: function(d) {
                return shadeColor("#ff0000", (-1 * getCircleSize(d.data, day, time, direction)));
            },
            r: function(d) {
                var size = getCircleSize(d.data, day, time, direction);

                if (size <= 0) {
                    return 0;
                } else if (size > 0 && size < 2) {
                    return size + 2;
                } else if (size > 50) {
                    return size*0.1 + 50;
                } else {
                    return size;
                }
            }
        });
    }
}

And here is an example of the error I'm getting:

Error: Invalid negative value for <circle> attribute r="-0.04404809159933931"
(anonymous function)
@ d3.v3.min.js:5l
@ d3.v3.min.js:3Lt
@ d3.v3.min.js:1qt
@ d3.v3.min.js:1

If I change the line:

circles.transition().duration(900).ease('elastic', 1, 0.75).attr({...});

to:

circles.transition().duration(900).ease('quad').attr({...});

...it doesn't spit out any errors in the console.

Here's a screenshot as well: d3-elastic-bug

It would be great if you can give me some guidance on how to solve this problem. Thanks in advance!


Solution

  • Check the spec on d3.ease():

    • elastic(a, p) - simulates an elastic band; may extend slightly beyond 0 and 1.

    Because the elastic easing overshoots the range [0,1] a little, it is not useful for lengths which must not be negative like radius, width etc. As you already noticed there are other easing functions which are guaranteed to yield positive values only. Have a look at this overview on easing function to find a function which will stay within the range of [0,1].