Search code examples
javascriptd3.jstimeline

D3 zoomable timeline, how to get actual extreme values?


I have a zoomable timeline in d3:

var zoom = d3.behavior.zoom().on("zoom", draw);

With a default domain of 1 year, it will be rendered like this:

20 Jan 2015 ...........2 feb..... 10 feb 2016

When i zoom in or zoom out i would like to get actual viewable limit date. e.g. when i zoom in i have

10 aug 2015 ....30 aug....09 sep 2015

I would catch first and last value of the scale (10 aug and 09 sep) My code:

svg.append("rect")
                .attr("class", "pane")
                .attr("width", width)
                .attr("height", height)
                .call(zoom)
                .on("mouseup", function(){
                     //...here i need to catch 10 aug and 09 sep
                 });

How can I do?


Solution

  • If you link your zoom to your domains:

    var zoom = d3.behavior.zoom()
      .x(x)
      .y(y)
      .on("zoom", zoomed);
    

    Then the x.domain() is auto-magically set after zoom:

    var svg = d3.select("body").append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
      .call(zoom)
      .on("mouseup", function(d){
        console.log(x.domain());
      });
    

    Example:

    <!DOCTYPE html>
    <meta charset="utf-8">
    <title>Zoom + Pan</title>
    <style>
    
    body {
      position: relative;
      width: 960px;
    }
    
    svg {
      font: 10px sans-serif;
      shape-rendering: crispEdges;
    }
    
    rect {
      fill: #ddd;
    }
    
    .axis path,
    .axis line {
      fill: none;
      stroke: #fff;
    }
    
    
    </style>
    <body>
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script>
    
    var margin = {top: 20, right: 20, bottom: 30, left: 40},
        width = 960 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom;
    
    var x = d3.time.scale()
        .domain([new Date(2012, 0, 1), new Date(2013, 0, 1)])
        .range([0, width]);
    
    var y = d3.scale.linear()
        .domain([-height / 2, height / 2])
        .range([height, 0]);
    
    var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom")
        .tickSize(-height);
    
    var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left")
        .ticks(5)
        .tickSize(-width);
    
    var zoom = d3.behavior.zoom()
        .x(x)
        .y(y)
        .on("zoom", zoomed);
    
    var svg = d3.select("body").append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
      .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
        .call(zoom)
        .on("mouseup", function(d){
          console.log(x.domain());
        })
    
    svg.append("rect")
        .attr("width", width)
        .attr("height", height);
    
    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);
    
    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis);
    
    function zoomed() {
      svg.select(".x.axis").call(xAxis);
      svg.select(".y.axis").call(yAxis);
    }
    
    </script>
    </body>