D3 добавить зум и панорамирование - PullRequest
0 голосов
/ 03 марта 2019

Мне нужно увеличить и панорамировать группу элементов SVG, как в этом примере:

https://embed.plnkr.co/kVw0rWMo728dmbm8EjuG/

Я сделал масштабирование, но не могу переместить изображениекогда я перетаскиваю мышку (панорамирование).Я пробовал с:

var zoom = d3.zoom()
  .scaleExtent([1, 100])
  .translateExtent([[150, 150],[150, 150]])
  .on('zoom', zoomFn);

  d3.select('svg')
  .select('g')
  .style("transform-origin", "50% 50% 0");

function zoomFn() {
  d3.select('svg').select('g')
    .style('transform', 'translate(' + d3.event.translate + ')' + ' scale(' + d3.event.transform.k + ')');
}

d3.select('svg')
  .select('rect')
  .call(zoom);

Как добавить поведение панорамирования в этом примере?

1 Ответ

0 голосов
/ 03 марта 2019

Есть несколько вещей:

Первый

d3.event.translate не содержит значений x и y преобразования, используйте d3.event.transform для полученияэти значения.Объект преобразования имеет свойства x, y и k.

Секунда

Если вы используете .style() для размещения преобразования, вам нужно указать, что единица измеренияпикселей для смещения:

var t = d3.event.transform;
d3.select("zoomedElement")
  .style('transform', 'translate('+t.x+"px,"+t.y + 'px)scale(' + t.k + ')');

В качестве альтернативы, вы можете использовать .attr() без px:

var t = d3.event.transform;
d3.select("zoomedElement")
  .style('transform', 'translate('+[t.x,t.y]+')scale(' + t.k + ')');

Давайте посмотрим на ваш поршень с этими изменениями (и без степени перевода):

var zoom = d3.zoom()
  .scaleExtent([1, 100])
  .on('zoom', zoomFn);

  d3.select('svg')
  .select('g')
  .style("transform-origin", "50% 50% 0");

function zoomFn() {
   var t = d3.event.transform;
  d3.select('svg').select('g')
    .style('transform', 'translate('+t.x+"px,"+t.y + 'px)scale(' + t.k + ')');


}

d3.select('svg')
  .select('rect')
  .call(zoom);
    .zoom-layer {
      fill: #EEE;
      fill-opacity: 0.25;
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.0.0/d3.min.js"></script>
<svg width="300" height="300">
    <g>
      <circle cx=150 cy=150 r=20 style="fill:#F22"></circle>
      <rect x=0 y=0 width=300 height=300 class="zoom-layer"></rect>
    </g>
  </svg>

Вы, вероятно, хотите сделать выделение, которое не включает прямоугольник, - оно должно остаться таким же, чтобы вся поверхность SVGостается интерактивным

Третий

Выглядит так, как будто вы хотите перевести экстент, иногда это немного сложно установить. Этот ответ углубляется в степень увеличения / степени масштабирования, но я расскажу, как ограничить ваш круг на экране:

С переводом [0,0] вашегокруг сидит в середине SVG.Если мы переведем [-150, -150], ваш круг будет в верхнем левом углу svg.Если круг центрируется на cx = 150 cy = 150, то верхний левый угол видимой области теперь равен [150,150].Следовательно, справа внизу - [450,450].Видимый экстент: [[150,150],[450,450]].

С переводом [150,150] ваш круг находится в правом нижнем углу SVG.Поскольку круг все еще находится в [150,150], нижний правый угол находится в [150,150] (не помогает ясность, что перевод и положение круга имеют одинаковое значение здесь) .Верхний левый угол на [-150,-150].В этом случае видимый экстент должен быть: [[-150,-150],[150,150]].

. Мы берем экстремумы из пределов видимого экстента, так как это экстент перевода, который сохраняет круг:

var translateExtent = [[-150,-150],[450,450]]

Естественно, если бы у вас были вещи во всех углах, а не в середине, вы бы имели больший экстент.

И мы можем применить к фрагменту все:

var zoom = d3.zoom()
  .scaleExtent([1, 100])
  .translateExtent([[-150,-150],[450, 450]])
  .on('zoom', zoomFn);

  d3.select('svg')
  .select('g')
  .style("transform-origin", "50% 50% 0");

function zoomFn() {
   var t = d3.event.transform;
  d3.select('svg').select('g')
    .style('transform', 'translate('+t.x+"px,"+t.y + 'px)scale(' + t.k + ')');

  console.log(t.x,t.y)

}

d3.select('svg')
  .select('rect')
  .call(zoom);
    
    .zoom-layer {
      fill: #aaa;
      fill-opacity: 0.25;
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="300" height="300">
    <g>
      <circle cx=150 cy=150 r=20 style="fill:#F22"></circle>
    </g>
    <rect x=0 y=0 width=300 height=300 class="zoom-layer"></rect>
  </svg>
...