通过鼠标和程序的D3 V4变焦可以相互独立地进行变焦

时间:2017-02-06 07:23:56

标签: javascript d3.js zoom programmatically

我正在尝试用d3建立一个应该可缩放的趋势。这工作得非常好。它可以在趋势内放大(缩放所有轴),也可以通过鼠标滚轮在每个轴上放大。

现在我想通过按钮点击添加一些缩放。这些变焦也很好。

通过按钮放大X方向然后通过鼠标滚轮放大Y方向或趋势完美。

但是在X方向按下按钮并在X方向通过鼠标滚轮进行后木材变焦后,趋势会从默认开始变焦。

以下是我的示例:https://jsfiddle.net/DaWa/d5fdLwv0/

<label>X</label>
<button onclick="zoomXIn()">+</button>
<button onclick="zoomXOut()">-</button>
<br/>
<label>Y</label>
<button onclick="zoomYIn()">+</button>
<button onclick="zoomYOut()">-</button>
<br/>
<svg width="960" height="500"></svg>

<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
  var xyTransform;
  var xTransform;
  var yTransform;

  function zoomXIn() {
    xZoom.scaleBy(xGroup, 2);
  }

  function zoomXOut() {
    xZoom.scaleBy(xGroup, 0.5);
  }

  function zoomYIn() {
    yZoom.scaleBy(yGroup, 2);
  }

  function zoomYOut() {
    yZoom.scaleBy(yGroup, 0.5);
  }

  var svg = d3.select("svg"),
    margin = {top: 20, right: 20, bottom: 110, left: 40},
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom;

  var xScale = d3.scaleTime().range([0, width]),
    yScale = d3.scaleLinear().range([height, 0]),
    yOld, xOld;

  var xAxis = d3.axisBottom(xScale),
    yAxis = d3.axisLeft(yScale);

  var xZoom = d3.zoom()
    .on("zoom", function () {
      xTransform = d3.event.transform;
      zoomBoth("x")
    });
  var yZoom = d3.zoom()
    .on("zoom", function () {
      yTransform = d3.event.transform;
      zoomBoth("y")
    });
  var zoom = d3.zoom()
    .on("zoom", function () {
      xyTransform = d3.event.transform;
      setDefault();
      zoomBoth()
    });

  function setDefault() {
    if (!xTransform) {
      xTransform = d3.zoomTransform(overlayX.node());
    }
    if (!yTransform) {
      yTransform = d3.zoomTransform(overlayY.node());
    }

  }


  var line = d3.line()
    .curve(d3.curveMonotoneX)
    .x(function (d) {
      return xScale(d.date);
    })
    .y(function (d) {
      return yScale(d.price);
    });

  svg.append("defs").append("clipPath")
    .attr("id", "clip")
    .append("rect")
    .attr("width", width)
    .attr("height", height);

  var focus = svg.append("g")
    .attr("class", "focus")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


  var data = getData();
  xScale.domain(d3.extent(data, function (d) {
    return d.date;
  }));
  yScale.domain([0, d3.max(data, function (d) {
    return d.price;
  })]);

  var path = focus.append("path")
    .datum(data)
    .attr("class", "line")
    .attr("d", line);


  var xGroup = focus.append("g")
    .attr("transform", "translate(0," + height + ")").call(xAxis);

  var yGroup = focus.append("g")
    .call(yAxis);

  var overlayX = focus
    .append("rect")
    .attr("fill", "rgba(0,0,0,0.5)")
    .attr("width", width)
    .attr("height", 30)
    .attr("y", height)
    .call(xZoom);


  var overlayY = focus
    .append("rect")
    .attr("fill", "rgba(0,0,0,0.5)")
    .attr("width", 30)
    .attr("height", height)
    .attr("x", -30)
    .call(yZoom);

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

  function zoomBoth(axisType) {
    getZoomedScales(axisType);
    updateData();
    updateAxes();
  }


  function getZoomedScales(axisType) {
    if (!xOld) {
      xOld = xScale.copy();
    }

    if (!yOld) {
      yOld = yScale.copy();
    }


    var transformXY = d3.zoomTransform(overlayRect.node());
    if (axisType === 'x') {
      xScale = transformXY.rescaleX(xTransform.rescaleX(xOld));
    } else if (axisType === 'y') {
      yScale = transformXY.rescaleY(yTransform.rescaleY(yOld));
    } else {
      xScale = xyTransform.rescaleX(xTransform.rescaleX(xOld));
      yScale = xyTransform.rescaleY(yTransform.rescaleY(yOld));
    }
  }


  function updateAxes() {
    xGroup.call(xAxis.scale(xScale));
    yGroup.call(yAxis.scale(yScale));
  }


  function updateData() {
    focus.select(".line").attr("d", line);
  }

  function getData() {
    var data = [];
    var date = new Date('Jan 2000');
    for (var i = 0; i < 120; i++) {

      data.push({date: new Date(date), price: Math.random() * 100});
      date.setMonth(date.getMonth() + 1);
    }
    return data;
  }

</script>

我该如何解决这个问题?

我希望你能理解我的问题并提供帮助。

祝你好运,  DW

1 个答案:

答案 0 :(得分:1)

通过将我的缩放从svg更改为Canvas,我已经解决了我的问题。

See https://jsfiddle.net/DaWa/d5fdLwv0/4/