Home > Enterprise >  SVG mouse position relative to transformed element
SVG mouse position relative to transformed element

Time:10-09

I have some SVG elements and I would like to add the ability to resize using mouse. It works great when element doesn't have any transforms (matrix, rotate, scale etc).

If I remove transform (transform="matrix(1.1,1.1,1,0,0,0)") from the rect element - it works great.

My understanding is that I should use matrix.inverse() function and transform it so I get mouse coordinates in the element space, but everything I tried didn't work for me.

I need to correctly calculate the x, y difference between start drag point and current point, but it doesn't work.

      var rect = document.getElementById('rect');
      var grip = document.getElementById('grip');
      function moveGrip() {
          var baseMatrix = rect.getCTM(),
            x = rect.width.baseVal.value   rect.x.baseVal.value,
              y = rect.height.baseVal.value   rect.y.baseVal.value;
          grip.cx.baseVal.value = x * baseMatrix.a   y * baseMatrix.c   baseMatrix.e;
          grip.cy.baseVal.value = x * baseMatrix.b   y * baseMatrix.d   baseMatrix.f;
      }
    
      grip.addEventListener('mousedown', onGripMouseDown);
      document.addEventListener('mousemove', onDocMouseMove);
    
      var startDragPoint, startDragSize;
      function onGripMouseDown(evt) {
          startDragSize = {w: rect.width.baseVal.value, h: rect.height.baseVal.value};
          startDragPoint = {x: evt.clientX, y: evt.clientY};
      }
    
      function onDocMouseMove(evt) {
          if (evt.buttons & 1) {
          //    dragging
              rect.width.baseVal.value = startDragSize.w   evt.clientX - startDragPoint.x;
              rect.height.baseVal.value = startDragSize.h   evt.clientY - startDragPoint.y;
              moveGrip();
          }
      }
    
      moveGrip();
  <svg width="500" height="400">
      <rect id="rect" x="20" y="20" width="200" height="100"
            transform="matrix(1.1,1.1,1,0,0,0)"
            style="fill:none;stroke: #3a2dd0; stroke-width: 2px;"></rect>
      <g>
          <circle id="grip" r="3" stroke-width="1" stroke="green"></circle>
      </g>
  </svg>

CodePudding user response:

Probably, you'd need to apply the inverse matrix to delta-x,y as follows;

function onDocMouseMove(evt) {
    if (evt.buttons & 1) {
        //    dragging
        var invMatrix = rect.getCTM().inverse(),
        x = evt.clientX - startDragPoint.x,
        y = evt.clientY - startDragPoint.y;

        rect.width.baseVal.value = startDragSize.w   x * invMatrix.a   y * invMatrix.c;
        rect.height.baseVal.value = startDragSize.h   x * invMatrix.b   y * invMatrix.d;
        moveGrip();
    }
}
  • Related