Применение масштабирования на основе предыдущего перевода - PullRequest
0 голосов
/ 25 октября 2019

Мне нужно расположить несколько SVG-фигур на основе регулярной двумерной сетки, которая определяется следующим образом:

data = [[0, 0], [0, 1], [0, 2], ...]

Существует одна фигура на элемент data. Его фактическое положение является функцией соответствующей координаты сетки. Кроме того, я должен разместить несколько текстовых меток на каждой сетке и применить масштабирование и панорамирование на основе D3.js.

Часть кода JS выглядит следующим образом, а работает как ожидалось .

gap = 10;
size = 40;
data = [[0, 0], [0, 1], [0, 2]];

var gs = d3.select("svg").selectAll("g").data(data).enter().append("g");

var boxes = d3.selectAll("g").append("rect")
  .attr("width", size)
  .attr("height", size)
  .attr("x", d => d[0]*(size+gap))
  .attr("y", d => d[1]*(size+gap));

var text = d3.selectAll("g").append("text")
  .attr("x", d => d[0]*(size+gap)+2)
  .attr("y", d => d[1]*(size+gap)+size/2)
  .text((d, i) => i);

var zoom = d3.zoom()
  .extent([[0, 0], [300, 400]])
  .scaleExtent([1, 20])
  .on("zoom", zoomBoxes);

d3.select("svg").call(zoom)

function zoomBoxes() {
    d3.selectAll("g").attr("transform", d3.event.transform);
}

Также вы можете видеть, мне нужно пересчитать атрибуты x и y для каждой текстовой метки (только один в этом примере для простоты) и фактически записать вычисление. Определение функции для вычисления упростит дело, так как это сохранит только несколько символов оператора. Итак, я пришел к следующей идее: не устанавливайте положение ящиков, а используйте перевод, чтобы поместить родительские элементы g в правильные места. Таким образом, мне нужно было бы написать код для позиционирования только один раз, и позиции текста были легко вычислены из нового источника:

gap = 10;
size = 40;
data = [[0, 0], [0, 1], [0, 2]];

var gs = d3.select("svg").selectAll("g").data(data).enter().append("g")
    .attr("transform", d => "translate("+ d[0]*(size+gap) + ","
                                        + d[1]*(size+gap) + ")");

var boxes = d3.selectAll("g").append("rect")
  .attr("width", size)
  .attr("height", size)

var text = d3.selectAll("g").append("text")
    .attr("x", 2)
    .attr("y", size/2)
    .text((d, i) => i);

var zoom = d3.zoom()
  .extent([[0, 0], [300, 400]])
  .scaleExtent([1, 20])
  .on("zoom", zoomBoxes);

d3.select("svg").call(zoom)

function zoomBoxes() {
    d3.selectAll("g").attr("transform", d3.event.transform);
}

Однако D3.js-zoom, кажется, полагается на форму x и y атрибутов, так что каждая фигура в предыдущем примере сбрасывается в исходную точку SVG, когда вызывается функция масштабирования. Проверьте скрипку .

Короче говоря, есть ли способ основать D3.js-zoom на относительных позициях, на которых фигуры располагаются после первоначального перевода?

...