Получить положение мыши в координатах SVG после увеличения - PullRequest
0 голосов
/ 09 мая 2018

Используя D3 v4, SVG и режим масштабирования, при перемещении мыши я хочу отобразить координаты мыши в системе координат SVG.

Событие mousemove появляется только для предоставления координат клиент / экран.

Как мне преобразовать эти координаты в координаты SVG, которые отражают текущее преобразование zooom / pan / etc?

Я могу видеть примеры этого с использованием оси / масштабов / и т. Д., Но я не создаю график и не использую ось / и т. Д. Я использую D3.js для интерактивной диаграммы.

Я попробовал подход crateSVGPoint / getScreenCTM, но (а) не совсем понял его и поэтому не уверен, как применить его к моему коду, и (б) он не работает, когда я масштабирую / панорамирую - Я просто получаю координаты клиент / экран. EG: вот код в моем событии mousemove для преобразования в SVG-коды:

var theSvg = document.getElementById('svgItem');
var pt = theSvg.createSVGPoint();
var cursorPoint = function(evt){
  pt.x = evt.clientX; pt.y = evt.clientY;
  return pt.matrixTransform(theSvg.getScreenCTM().inverse());
}
var loc = cursorPoint(d3.event);

//the pair of co-ordinates should be different on zoom, but aren't
d3.select(".statusBarText").text("move (" + d3.event.x + "," + d3.event.y + ") (" + loc.x + "," + loc.y + ")");

Для чего бы то ни было, поведение масштабирования применяется к элементу группы SVG элемента SVG. Масштабирование работает отлично; Я вижу, как перевод / шкала применяются к группе.

Я пытался изменить вышеупомянутое, чтобы вызвать createSVGPoint () для элемента группы, который был преобразован, но получил ошибки о том, что createSVGPoint () не является функцией; Я думаю, это работает только с элементом SVG из DOM ...

Также есть элемент viewBox для элемента SVG, который я использую, если это имеет значение.

Неужели должен быть простой способ сделать преобразование?

1 Ответ

0 голосов
/ 09 мая 2018

Чтобы преобразовать координату, возвращенную d3.mouse, в систему координат, используемую d3.zoom, вам необходимо получить преобразование масштабирования в дополнение к координатам, возвращенным d3.mouse. Я выделю здесь один метод.

Текущее преобразование масштаба можно получить с помощью:

d3.zoomTransform(selection.node());

Там, где выбрано значение d3, вызывается увеличение. В то время как d3.mouse () дает нам экранные координаты мыши относительно контейнера, мы можем использовать это и преобразование, чтобы дать нам масштабированные и переведенные координаты с transform.invert(), который берет точку и возвращает увеличенные координаты:

  var xy = d3.mouse(this);         // relative to specified container
  var transform = d3.zoomTransform(selection.node());
  var xy1 = transform.invert(xy);  // relative to zoom

Вот быстрый пример, показывающий извлечение увеличенных координат по сравнению с координатами мыши. Оси просто дают приблизительное представление о том, что такое система координат масштабирования (они показывают координаты масштабирования), но функциональность остается без них:

var svg = d3.select("body")
  .append("svg")
  .attr("width", 500)
  .attr("height", 300)
  .attr("fill","#eee");
  
var g = svg.append("g")
  .attr("transform","translate(50,50)");
  
var rect = g.append("rect")
  .attr("width",400)
  .attr("height",200)
  .attr("fill","#eee");

var x = d3.scaleLinear().domain([0,400]).range([0,400]);
var y = d3.scaleLinear().domain([0,200]).range([0,200]);

var axisX = d3.axisTop().scale(x).tickSize(-200)
var axisY = d3.axisLeft().scale(y).tickSize(-400);

var gX = g.append("g").call(axisX)
var gY = g.append("g").call(axisY)

var zoom = d3.zoom()
  .scaleExtent([1, 8])
  .on("zoom",zoomed);
  
rect.call(zoom);

rect.on("click", function() {
  var xy = d3.mouse(this);
  
  var transform = d3.zoomTransform(rect.node());
  var xy1 = transform.invert(xy);

  console.log("Mouse:[", xy[0], xy[1], "] Zoomed:[",xy1[0],xy1[1],"]")
})
  
function zoomed() {
  gX.call(axisX.scale(d3.event.transform.rescaleX(x)));
  gY.call(axisY.scale(d3.event.transform.rescaleY(y)));
}
rect {
  cursor: pointer;
}
.tick line {
  stroke: #ccc;
  pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

Конечно, вы должны убедиться, что d3.mouse и d3.zoom ссылаются на одно и то же, в данном случае это прямоугольник.

...