Почему d3.event в перетаскивании обратного вызова так или иначе связан с координатой данных - PullRequest
2 голосов
/ 21 июня 2019

Я играю с d3.js и заметил странное поведение при перетаскивании. Если я добавлю круг с использованием данных и scaleX / scaleY, то при перетаскивании его значение d3.event.y будет относиться к координатам xy внутри массива «data», а не к верхнему левому углу ...

Вот код и jsFiddle : если вы открываете консоль, если вы перетаскиваете первый круг, ссылка находится в верхнем левом углу, если вы перетаскиваете второй круг, ссылка является чем-то связанным с { х: 3, у: 2}

var circle2 = svgGraph
  .selectAll('.circle2')
  .data([{ x: 3, y: 2 }])
  .enter()
  .append('circle') // Uses the enter().append() method
  .attr('cx', scaleX(100))
  .attr('cy', scaleY(100))
  .attr('r', 15)
  .call(d3.drag()
    .on('start', (d) => { })
    .on('drag', onHandlerDrag())
    .on('end', (d) => { }));

function onHandlerDrag() {
  return (d) => {
    console.log(d3.event.y);
  }
}

Предназначено ли поведение? Есть ли у вас какие-либо упоминания об этом?

Спасибо

1 Ответ

1 голос
/ 21 июня 2019

Да, это предполагаемое поведение.Фактически, мы обычно используем эти свойства x и y в событии перетаскивания, чтобы элемент не прыгал вокруг контейнера (когда один достаточно ленив, чтобы указать правильный объект).

Поскольку вы просили ссылку, взгляните на drag.subject:

Предметом жеста перетаскивания является перетаскиваемая вещь.Он вычисляется при получении исходного события ввода, такого как mousedown или touchstart, непосредственно перед началом жеста перетаскивания.

Затем в следующем абзаце наиболее важная информация для вас:

Субъектом по умолчанию является элемент данных элемента в исходном выделении (см. Перетаскивание), получившего исходное событие ввода;если этот элемент данных не определен, создается объект, представляющий координаты указателя.Таким образом, при перетаскивании элементов круга в SVG предметом по умолчанию является элемент перетаскиваемого круга.(выделение мое)

И наконец:

Возвращаемый объект должен быть объектом, который обладает свойствами x и y, так что относительное положение объектапредмет и указатель может быть сохранена во время жеста перетаскивания.

Итак, если вы не хотите x и y в данное время используется drag, просто установитьдругой объект в теме:

.subject(function() {
    return {
        foo: d3.event.x,
        bar: d3.event.y
    };
})

Вот ваш код с этим изменением:

function onHandlerDrag() {
  return (d) => {
    console.log(d3.event.y);
  }
}

var scaleX = d3
  .scaleLinear()
  .domain([0, 500])
  .range([0, 500]);

var scaleY = d3
  .scaleLinear()
  .domain([0, 500])
  .range([0, 500]);

var svgGraph = d3
  .select('.area')
  .attr('width', 500)
  .attr('height', 500);

var circle1 = svgGraph
  .append('circle')
  .attr('cx', scaleX(20))
  .attr('cy', scaleY(20))
  .attr('r', 15)
  .call(d3.drag()
    .on('start', (d) => {})
    .on('drag', onHandlerDrag())
    .on('end', (d) => {}));

var circle2 = svgGraph
  .selectAll('.circle2')
  .data([{
    x: 3,
    y: 2
  }])
  .enter()
  .append('circle') // Uses the enter().append() method
  .attr('cx', scaleX(100))
  .attr('cy', scaleY(100))
  .attr('r', 15)
  .call(d3.drag()
    .subject(function() {
      return {
        foo: d3.event.x,
        bar: d3.event.y
      };
    })
    .on('start', (d) => {})
    .on('drag', onHandlerDrag())
    .on('end', (d) => {}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg class='area'></svg>
...