交互 JS,在 viewboxed svg 中拖动 svg 元素?
Interact JS, Drag svg elements inside viewboxed svg?
我的问题,当我拖动元素时,元素在光标后面很远,所以看起来可能是比例问题?
代码:
interact('.element', {
context: '.lipstick__plane'
})
.draggable({
snap: {
targets: [
interact.createSnapGrid({x: 10, y: 10})
],
range: Infinity
},
inertia: true,
restrict: {
restriction: '#lipstick__plane__main',
elementRect: {top: 0, left: 0, bottom: 1, right: 1},
endOnly: true
}
})
.on('dragmove', function (event) {
$scope.$apply(function () {
var target = event.target,
x = (parseFloat(target.getAttribute('x')) || 0) + ((1020 / window.outerWidth) * event.dx),
y = (parseFloat(target.getAttribute('y')) || 0) + ((1020 / window.outerHeight) * event.dy);
var indx = event.target.getAttribute('data-index');
_.set($scope.stage.elements[indx], 'meta.XCord', x);
_.set($scope.stage.elements[indx], 'meta.YCord', y);
});
});
我正在那里潜水,这让它离光标更近了,但我可能整天都在尝试数字...
我的 svg 初始化块:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1024 1024" width="1024px" height="1024px" xml:space="preserve" id="lipstick__plane__main">
有一件事我确实认为可能是个问题,但我对此表示怀疑,Angular 摘要是在重新查询以获取新的 x
和 y
属性之后发生的吗?
这个问题的发生是因为 SVG 的内部设置在宽度和高度上设置为 1024 像素,但是以不同的尺寸显示,在这种情况下更小,所以从拖动应用的平移被缩小并且该元素似乎比光标慢。
为了解决这个问题,您需要相应地缩放平移向量。获得比例因子 sx
和 sy
的一种方法可能是:
- 通过
getClientBoudingRect
查询svg的结果边界框bb
sx = bb.width / 1024 // (original size), same for sy
或者,如果您可以访问 svg
元素,则可以使用 .getScreenCTM()
获取转换矩阵。应该是这样的:
| a c e |
| b d f |
| 0 0 1 |
a
应该代表 sx
和 d
sy
.
编辑
我稍微设置了一下fiddlehere which shows the basic approach. All in all, the solution is a matrix transformation of a vector and the puzzle to solve is to find the right matrix. Since any svg element may have its own transform, or as child of a group, may gain transform from its parents, it is not sufficient to use the root <svg>
's Current Transformation Matrix. That is why each SVGElement
implements the the SVGLocatable Interface, what enables you to gain the transform from the root <svg>
to the SVGElement
(getCTM), or, the document to the SVGElement
(getScreenCTM()). The opposite direction is described by the inverse of those matrices. (explanation on SO)
let svg = document.querySelector('svg'),
e = svg.querySelector('.myelement'),
ctm = e.getScreenCTM(),
point = svg.createSVGPoint(),
point2;
point.x = …;
point.y = …;
point2 = point.matrixTransform(ctm);
总结:使用变换矩阵应该是首选方式,因为它将(至少应该)考虑所有变换,这可以通过 css 应用于 svg,如旋转,3d变换等等。你越具体,意味着你越了解你想要转换的元素,精度就会越高。
因为您的 SVG 是缩放的,所以您的鼠标坐标与您的 SVG 坐标不 1:1。所以你需要将 mouse/screen 坐标转换为 SVG 坐标,以便获得拖动对象的正确位置。
请参阅此问题了解如何进行转换。
How do you convert screen coordinates to document space in a scaled SVG?
我的问题,当我拖动元素时,元素在光标后面很远,所以看起来可能是比例问题?
代码:
interact('.element', {
context: '.lipstick__plane'
})
.draggable({
snap: {
targets: [
interact.createSnapGrid({x: 10, y: 10})
],
range: Infinity
},
inertia: true,
restrict: {
restriction: '#lipstick__plane__main',
elementRect: {top: 0, left: 0, bottom: 1, right: 1},
endOnly: true
}
})
.on('dragmove', function (event) {
$scope.$apply(function () {
var target = event.target,
x = (parseFloat(target.getAttribute('x')) || 0) + ((1020 / window.outerWidth) * event.dx),
y = (parseFloat(target.getAttribute('y')) || 0) + ((1020 / window.outerHeight) * event.dy);
var indx = event.target.getAttribute('data-index');
_.set($scope.stage.elements[indx], 'meta.XCord', x);
_.set($scope.stage.elements[indx], 'meta.YCord', y);
});
});
我正在那里潜水,这让它离光标更近了,但我可能整天都在尝试数字...
我的 svg 初始化块:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1024 1024" width="1024px" height="1024px" xml:space="preserve" id="lipstick__plane__main">
有一件事我确实认为可能是个问题,但我对此表示怀疑,Angular 摘要是在重新查询以获取新的 x
和 y
属性之后发生的吗?
这个问题的发生是因为 SVG 的内部设置在宽度和高度上设置为 1024 像素,但是以不同的尺寸显示,在这种情况下更小,所以从拖动应用的平移被缩小并且该元素似乎比光标慢。
为了解决这个问题,您需要相应地缩放平移向量。获得比例因子 sx
和 sy
的一种方法可能是:
- 通过
getClientBoudingRect
查询svg的结果边界框 sx = bb.width / 1024 // (original size), same for sy
bb
或者,如果您可以访问 svg
元素,则可以使用 .getScreenCTM()
获取转换矩阵。应该是这样的:
| a c e |
| b d f |
| 0 0 1 |
a
应该代表 sx
和 d
sy
.
编辑
我稍微设置了一下fiddlehere which shows the basic approach. All in all, the solution is a matrix transformation of a vector and the puzzle to solve is to find the right matrix. Since any svg element may have its own transform, or as child of a group, may gain transform from its parents, it is not sufficient to use the root <svg>
's Current Transformation Matrix. That is why each SVGElement
implements the the SVGLocatable Interface, what enables you to gain the transform from the root <svg>
to the SVGElement
(getCTM), or, the document to the SVGElement
(getScreenCTM()). The opposite direction is described by the inverse of those matrices. (explanation on SO)
let svg = document.querySelector('svg'),
e = svg.querySelector('.myelement'),
ctm = e.getScreenCTM(),
point = svg.createSVGPoint(),
point2;
point.x = …;
point.y = …;
point2 = point.matrixTransform(ctm);
总结:使用变换矩阵应该是首选方式,因为它将(至少应该)考虑所有变换,这可以通过 css 应用于 svg,如旋转,3d变换等等。你越具体,意味着你越了解你想要转换的元素,精度就会越高。
因为您的 SVG 是缩放的,所以您的鼠标坐标与您的 SVG 坐标不 1:1。所以你需要将 mouse/screen 坐标转换为 SVG 坐标,以便获得拖动对象的正确位置。
请参阅此问题了解如何进行转换。
How do you convert screen coordinates to document space in a scaled SVG?