Interact JS, Drag svg elements inside viewboxed svg?

陌路散爱 提交于 2019-12-21 20:24:30

问题


My problem, when I drag elements, the element is far behind the cursor, so it looks like it's a ratio issue potentially?

The code:

    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);
            });
        });

I am diving there, which got it closer to the cursor, but i could be trying numbers all day long...

My svg init block:

<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">

One thing I do think could be a problem, but i doubt it, is that the Angular digest happens after a requery to get the new x and y attribute?


回答1:


This problem comes to happen since the inner setup of the SVG is set to 1024 Pixel in width and Height, but displayed in a different Size, smaller in this case, so the applied translation from the drag is scaled down and the element appears to be slower than the cursor.

To address this, you need to scale the translation vector accordingly. One way to gain the scaling factors sx and sy could be:

  1. query the resulting bounding box bb of the svg by getClientBoudingRect
  2. sx = bb.width / 1024 // (original size), same for sy

Or, if you can access the svg element you can use .getScreenCTM() to get the transformation matrix. Which should look like this:

| a  c  e |
| b  d  f |
| 0  0  1 |

a should represent sx and d sy.

Edit

I have setup a little fiddle here 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);

To conclude: Using the transformation matrix should be the preferred way, since it will (at least should) take all transformations into account, which could be applied to the svg by css, like rotations, 3d transforms and so on. The more specific you are, meaning the more you know the element you would like to transform, the higher the precision will be.




回答2:


Because your SVG is scaled, your mouse coordinates are not 1:1 with your SVG coordinates. So you need to convert the mouse/screen coordinates to SVG coordinates in order to get the correct position for the dragged object.

See this question for how to do the conversion.

How do you convert screen coordinates to document space in a scaled SVG?



来源:https://stackoverflow.com/questions/38420786/interact-js-drag-svg-elements-inside-viewboxed-svg

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!