javascript - 如何将鼠标移动距离转换为 SVG 坐标空间?

标签 javascript svg matrix

我在这里有一个 CSS4 颜色关键字在 HSL 空间中分布的 SVG 可视化:https://meyerweb.com/eric/css/colors/hsl-dist.html

我最近通过鼠标滚轮添加了缩放,并通过鼠标咔嗒声和拖动进行平移。我可以使用 matrixTransform 将一个点从屏幕空间转换为 SVG 坐标空间, .getScreenCTM() , 和 .inverse()感谢我在网上找到的示例代码,但是如何在拖动过程中转换鼠标移动?现在我只是转移 viewBox event 中的 X 和 Y 值坐标,这意味着放大时图像拖动比鼠标移动快。

例如,假设我放大了图像并拖动以平移,我将鼠标向左并略微向下猛拉。 event.movementX返回 -37event.movementY返回 6 .如何确定 SVG 坐标中的距离,以便 viewBox坐标是否正确移动?

( 注意: 我知道有这类库,但我有意编写 Vanilla JS 代码以了解有关 SVG 和 JS 的更多信息。所以请不要发布“大声笑,只需使用库 X”就可以了。谢谢!)

编辑添加:我被要求发布代码。发布整个 JS 似乎过长,但这是在 mousemove 上触发的函数事件:

function dragger(event) {
    var target = document.getElementById('color-wheel');
    var coords = parseViewBox(target);
    coords.x -= event.movementX;
    coords.y -= event.movementY;
    changeViewBox(target,coords);
}

如果需要更多,请在链接页面上查看源代码;所有的 JS 都在页面的顶部。除了只包含可视化的所有 HSL 值和颜色名称的文件之外,没有什么是外部的。

最佳答案

我的建议:
不用担心 movementX/Y事件的属性。
只需担心鼠标从哪里开始以及现在在哪里。

(这有一个额外的好处,即使你错过了一些事件,你也能得到相同的结果:可能是因为鼠标移出了窗口,或者可能是因为你想对事件进行分组,所以你只在每个动画帧运行一次代码。)

对于鼠标开始的位置,您可以在 mousedown 事件上进行测量。
使用您使用的方法将其转换为 SVG 坐标中的位置,
.getScreenCTM().inverse().matrixTransform() .
在此转换之后,您不必关心屏幕上的这个点在哪里。您只关心它在图片中的位置。这就是图片中的一点,您总是要移动到鼠标下方。

在 mousemove 事件上,您使用相同的转换方法来找出鼠标当前在当前 SVG 坐标系中的位置。然后,您可以计算出距离您想要在鼠标下方的点(同样,在 SVG 坐标中)有多远。这就是您用于转换图形的数量。我已经按照您的示例进行了转换,并通过移动 xy viewBox 的一部分:

function move(e) {
  var targetPoint = svgCoords(event, svg);
  shiftViewBox(anchorPoint.x - targetPoint.x,
               anchorPoint.y - targetPoint.y);
}

您也可以使用 transform 移动图形。在 SVG 中的组(<g> 元素)上;只需确保对 getScreenCTM() 使用相同的组元素从 clientX 转换的调用/Y事件坐标。

拖动平移的完整演示。我跳过了你所有的绘图代码和缩放效果。
但是缩放应该仍然有效,因为您保存在全局值中的唯一位置已经转换为 SVG 坐标。

var svg = document.querySelector("svg");
var anchorPoint;

function shiftViewBox(deltaX, deltaY) {
	svg.viewBox.baseVal.x += deltaX;
	svg.viewBox.baseVal.y += deltaY;
}

function svgCoords(event,elem) {
	var ctm = elem.getScreenCTM();
	var pt = svg.createSVGPoint();
    // Note: rest of method could work with another element,
    // if you don't want to listen to drags on the entire svg.
    // But createSVGPoint only exists on <svg> elements.
	pt.x = event.clientX;
	pt.y = event.clientY;
	return pt.matrixTransform(ctm.inverse());
}

svg.addEventListener("mousedown", function(e) {
  anchorPoint = svgCoords(event, svg);
  window.addEventListener("mousemove", move);
  window.addEventListener("mouseup", cancelMove);
});

function cancelMove(e) {
  window.removeEventListener("mousemove", move);
  window.removeEventListener("mouseup", cancelMove);
  anchorPoint = undefined;
}

function move(e) {
  var targetPoint = svgCoords(event, svg);
  shiftViewBox(anchorPoint.x - targetPoint.x,
               anchorPoint.y - targetPoint.y);
}
body {
  display: grid;
  margin: 0;
  min-height: 100vh;
}

svg {
  margin: auto;
  width: 70vmin;
  height: 70vmin;
  border: thin solid gray;
  cursor: move;
}
<svg viewBox="-40 -40 80 80">
  <polygon fill="skyBlue"
           points="0 -40, 40 0, 0 40 -40 0" />
</svg>

关于javascript - 如何将鼠标移动距离转换为 SVG 坐标空间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55564432/

相关文章:

javascript - 最大化打印宽度 CSS3

javascript - 从充当事件处理程序的多个方法中引用对象属性

javascript - 封装 Animate 回调的最佳方法?

ios - iOS浏览器中的SVG

java - Java中的矩阵运算

python - 此函数可以正确计算卷积吗?

javascript - 保存到Ajax服务器

javascript - 如何修复 FabricJS 中 Inkscape SVG 的缩放和旋转?

c - 距离使用出租车几何 : weird output

javascript - 如何更改选择的默认行为并仅显示所选元素?