Масштабирование D3 V4 с помощью мыши и программного масштабирования происходит независимо друг от друга.

Я пытаюсь построить тренд с 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>

Как я могу решить эту проблему?

Надеюсь, вы поймете мою проблему и сможете помочь.

С уважением, ДВ.


person user7521838    schedule 06.02.2017    source источник


Ответы (1)


Изменив масштаб с svg на Canvas, я уже решил свою проблему.

See https://jsfiddle.net/DaWa/d5fdLwv0/4/
person user7521838    schedule 23.02.2017
comment
Что делать, если я настаиваю на использовании SVG? - person Haozhe Xie; 19.06.2017
comment
Я уже нашел другое решение, опубликованное здесь: github.com/d3/d3- масштаб/проблемы/48 - person user7521838; 19.06.2017