D3 добавить зум и панорамирование

Здесь есть две вещи:

1. class attributes and instance attributes
2. difference between the operators + and += for lists

+ оператор вызывает метод __add__ в списке. Он берет все элементы из своих операндов и создает новый список, содержащий эти элементы, поддерживающие их порядок.

+= оператор вызывает метод __iadd__ в списке. Он требует итерации и добавляет все элементы итерабельности в список на месте. Он не создает новый объект списка.

В классе foo оператор self.bar += [x] не является оператором присваивания, но фактически переводит на

self.bar.__iadd__([x])  # modifies the class attribute  

, который изменяет список на месте и действует как метод списка extend.

В классе foo2, наоборот, оператор присваивания в методе init

self.bar = self.bar + [x]  

может быть деконструирован как: экземпляр не имеет атрибута bar (есть атрибут класса с тем же именем), поэтому он обращается к атрибуту class bar и создает новый список, добавляя к нему x. Оператор преобразуется в:

self.bar = self.bar.__add__([x]) # bar on the lhs is the class attribute 

Затем он создает атрибут экземпляра bar и присваивает ему вновь созданный список. Обратите внимание, что bar на rhs присваивания отличается от bar на lhs.

Для экземпляров класса foo, bar является атрибутом класса, а не атрибутом экземпляра. Следовательно, любое изменение атрибута class bar будет отражено для всех экземпляров.

Напротив, каждый экземпляр класса foo2 имеет свой собственный атрибут экземпляра bar, который отличается от атрибута класса с тем же именем bar.

f = foo2(4)
print f.bar # accessing the instance attribute. prints [4]  
print f.__class__.bar # accessing the class attribute. prints []  

Надеюсь, это очистит.

1
задан csotelo 3 March 2019 в 19:15
поделиться

1 ответ

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

Первый

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 оставалась интерактивной [ 1121]

Третий

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

С переводом [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>

0
ответ дан Andrew Reid 3 March 2019 в 19:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: