d3.js area graph with initial zoom

夙愿已清 提交于 2020-02-03 10:39:10

问题


I am trying ti implement a zoom and brush chart with D3.js with an initial zoom. The initial zoom covers only about 10% of the brushable extent - this works correctly. When I zoom on the chart the first time, the zoom does not take into account the initial state.

Here's the graph initially:

And after the first zoom:

Here's a plunkr, and the relevant code:

 svg.append("rect")
      .attr("class", "zoom")
      .attr("width", width)
      .attr("height", height)
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
      .call(zoom);

    //To set initial zoom level in graph
      var d0 = data[0].date,
      d1 = data[data.length-1].date;
     svg.call(zoom).transition()
    .duration(1500)
    .call(zoom.transform, d3.zoomIdentity
          .scale(width / (x(d1) - x(d0)))
          .translate(-x(d0), 0)); 

  function brushed() {
    if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom
    var s = d3.event.selection || x2.range();
    x.domain(s.map(x2.invert, x2));
    focus.select(".area").attr("d", area);
    focus.select(".axis--x").call(xAxis);
    svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
        .scale(width / (s[1] - s[0]))
        .translate(-s[0], 0));
  }

  function zoomed() {
    if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush
    var t = d3.event.transform;
    x.domain(t.rescaleX(x2).domain());
    focus.select(".area").attr("d", area);
    focus.select(".axis--x").call(xAxis);
    context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
  }

Why are zoom events not relative to the initial zoom state?


回答1:


Your code works fine if, you don't zoom over the chart plot area: you can zoom on the axes or margins for example. This is a hint as to what is happening:

The zoom is applied to two elements:

svg.append("rect")
   ...
   .call(zoom);

And:

svg.call(zoom)

This means we are keeping track of two zoom states - but you only apply an initial state to one:

svg.call(zoom).transition()
  .duration(1500)
  .call(zoom.transform, d3.zoomIdentity
      .scale(width / (x(d1) - x(d0)))
      .translate(-x(d0), 0)); 

This is why you can zoom in the margins and the chart works as intended, but doesn't work if you zoom over the rect that covers the plot area. Let's just apply the zoom once on one element:

  var rect = svg.append("rect")
    ...
    .call(zoom);

  rect.transition()
   .duration(1500)
   .call(zoom.transform, d3.zoomIdentity
      .scale(width / (x(d1) - x(d0)))
      .translate(-x(d0), 0));      

Here's an updated plunkr

I've removed the script.js file as it duplicated script in the index.html file.

I had issues with your original plunkr in Firefox, I have not addressed those, I used Chrome to view



来源:https://stackoverflow.com/questions/57164113/d3-js-area-graph-with-initial-zoom

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!