D3.js: fetch x-axis information during transition

I am trying to create a timeline using D3.js v4. I have successfully created a scatter plot with its axis and brush so that users can define a specific time period.

I want users to be able to "play" the timeline just like an audio / video player with an indicator that will move from left to right with a configurable duration. For this I have placed a vertical line with a transition as an indicator.

My problem is that I cannot get the x-axis coordinates during the transition. I want to achieve this because the x-axis values ​​have to interact with another part of the code.

I've tried everything including the twin and feature game, but I couldn't get it to work. Ideally, I would like the indicator to start and stop within the brush.

svg.append("g")
    .attr("class", "brush")
    .call(brush)
    .call(brush.move, x.range());

svg.append('line')
    .attr("class", "timeline-indicator")
    .attr("stroke-width", 2)
    .attr("stroke", "black")
    .attr("x1", 0)
    .attr("y1", 0)
    .attr("x2", 0)
    .attr("y2", height)
    .transition()
        .duration(9000)
        .attr("x1", 500)
        .attr("y1", 0)
        .attr("x2", 500)
        .attr("y2", height);

      

+3


source to share


2 answers


You will be able to accomplish this by using the tween function in your transition. The tween function will run on every tick of the transition and is one of the ways to call the function on every tick.

The tween method needs an attribute name (as it is meant to provide custom interpolation for the attribute), but it could be an attribute of a dummy type or one that hasn't been changed (as in my example below). The documentation for the method is here .

In my example, I'm pulling the x property (well, the cx property) of the circle as it moves across the screen using the twin function:

 .tween("attr.fill", function() {
        var node = this;
        return function(t) { 
         console.log(node.getAttribute("cx"));
        }
      })

      



Here is a snippet of his work:

var svg = d3.select("body").append("svg")
  .attr("width",400)
  .attr("height",400);
  
var circle = svg.append("circle")
  .attr("cx",20)
  .attr("cy",20)
  .attr("r",10);
 
circle.transition()
  .attr("cx",380)
  .attr("cy",20)
  .tween("attr.fill", function() {
    var node = this;
    return function(t) { 
     console.log(node.getAttribute("cx"));
    }
  })
  .duration(1000);
      

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.min.js"></script>
      

Run codeHide result


+2


source


Andrew's answer is a good and probably traditional way of doing this.

However, just for the sake of curiosity, here's an alternate answer using d3.timer .

The math is, of course, a little more complicated. Also, keep in mind that the past tense is obvious:

The exact values ​​can vary depending on the JavaScript runtime and what else your computer is doing. Note that the first elapsed time is 3ms: this is the elapsed time since the timer started, not since the timer started.



Check out the demo:

var svg = d3.select("body")
  .append("svg")
  .attr("width", 500)
  .attr("height", 100);

var circle = svg.append("circle")
  .attr("cx", 30)
  .attr("cy", 50)
  .attr("r", 20)
  .attr("fill", "tan")
  .attr("stroke", "dimgray");

var timer = d3.timer(move);

function move(t) {
  if (t > 2000) timer.stop();
  console.log("position now is: " + ~~(30 + (t / 2000) * 440))
  circle.attr("cx", 30 + (t / 2000) * 440)
}
      

.as-console-wrapper { max-height: 30% !important;}
      

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

Run codeHide result


+2


source







All Articles