Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Color transition in d3 using time elapsed

I've been having a hard time wrapping my head around some D3 concepts (it does not help that I am relatively new to javascript). What I am trying to do is have a status indicator that begins green, slowly turning yellow, and then slowly turning red. If some event occurs (button press, message received, whatever), I want the indicator to return to green, restarting the transition.

Here's a simple example (in jQuery) showing the basic visual effect (without the ability to reset) http://jsfiddle.net/N4APE/

In D3, my idea was to map the background color to the number of milliseconds passed. I tried to create a scale like this:

//10 sec is yellow, 30 sec is red
d3.scale.linear().domain([0, 10000, 30000]).range(["#00ff00", "#ffff00", "#ff0000"]);

But now I'm a bit lost. I have been playing with combinations of transitions, tweens, and interpolators, but I don't seem to be getting anywhere. Here's some pathetic attempts to get it working http://jsfiddle.net/Ebuwa/

My issues:

  • I don't know how to associate the elapsed millis of a transition to my scale, and then set the background color
  • My transition seems to run when I create it, instead of when I call it, and it operates on the wrong element.
  • I'm not positive how to reset the transition to keep it green once I've conquered my other problems.

One other note, I could be happy using an svg circle or something like that instead, but I have had just as poor luck manipulating an svg fill attribute as I have an html background attribute.

Thank you

like image 862
Denial Avatar asked Jul 03 '13 01:07

Denial


2 Answers

You don't really need to do any work with scales, .transition() will take care of the hard work behind the scenes:

function changeElementColor(d3Element){
    d3Element
    .transition().duration(0)
      .style("background", "green")
    .transition().duration(1000)
      .style("background", "yellow")
    .transition().delay(1000).duration(5000)
      .style("background", "red");
}
changeElementColor(d3.select("#d3Color"));

To reset the transition, just add an onclick event to the element:

d3.select("#d3Color")
  .on("click", function(){ changeElementColor(d3.select(this)) });

http://jsfiddle.net/N4APE/2/

I've also included a colored svg circle. I'm guessing you were trying to use .style("color", "red") to change its color; you need to use .attr("fill", "red") for non CSS properties.

like image 80
Adam Pearce Avatar answered Oct 08 '22 17:10

Adam Pearce


I had the same question but wanted to change the text colour as well to provide more contrast toward the end. Mine also updates the message with the elapsed seconds (to see how long slow queries take)

var duration = 30 * 1000;

// background color progression is smooth from lime to orange to red
var colorScale = d3.scale.linear().clamp(true)
    .domain([0, duration / 2, duration])
    .range(['lime', 'orange', 'red']);

// text color is mostly black but switches to yellow when there is good contrast
var textScale = d3.scale.quantile()
    .domain([0, 0.85 * duration, duration])
    .range(['black', 'yellow', 'yellow']);

var start = new Date();
var counterId = setInterval(function () {
    console.log("setInterval ID: " + counterId);
    var now = new Date();
    var elapsed = Math.round((now - start) / 1000);
    var message = "Querying... " + (elapsed) + " s";
    elapsed = 1000 * elapsed;
    d3.select('#progress')
    .style("color", textScale(elapsed))
        .style("background", colorScale(elapsed))
        .html(message)
    ;
}, 1000);

Working Example Here:

http://jsfiddle.net/SKLUn/5/

like image 37
zardoz Avatar answered Oct 08 '22 17:10

zardoz