Marais Rossouw Marais Rossouw - 4 months ago 64
Javascript Question

Interact JS, Drag svg elements inside viewboxed svg?

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

screen grab of the weird movement

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?

Answer

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. On way way to gain the 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.

So:

var ctm = svgElement.getScreenCTM();
x = x + ev.dx / ctm.a;
y = y + ev.dy / ctm.d;