【问题标题】:Javascript and SVG - move element with offsetJavascript 和 SVG - 使用偏移量移动元素
【发布时间】:2021-06-01 14:31:16
【问题描述】:

在下面的代码中,我对画布进行了缩放和拖动。另外 - 当点击画布时,我可以添加蓝色圆圈。我也可以移动蓝色圆圈 - 但问题是圆圈中心移动到鼠标指针位置,而不考虑从鼠标指针到圆圈中心的偏移量。即使画布被缩放/重新定位,我如何才能在计算中包含这个偏移量?

var svgCanvas = document.getElementById("canvas");
var viewPort = document.getElementById("viewport");
var drag = false;
var dragged = false;
var offset = { x: 0, y: 0 };
var factor = .1;
var matrix = new DOMMatrix();
var whatToMove = function (event) { };
svgCanvas.addEventListener('pointerdown', function (event) {
    drag = true;
    whatToMove = moveViewPort;
    offset = { x: event.clientX, y: event.clientY };
});
document.addEventListener('pointermove', function (event) {
    if (event.buttons == 1) {
        whatToMove(event);
    }
});
var moveViewPort = function (event) {
    if (drag) {
        var tx = event.clientX - offset.x;
        var ty = event.clientY - offset.y;
        offset = {
            x: event.clientX,
            y: event.clientY
        };
        matrix.preMultiplySelf(new DOMMatrix()
            .translateSelf(tx, ty));
        viewPort.style.transform = matrix.toString();
        dragged = true;
    }
};
svgCanvas.addEventListener('pointerup', function (event) {
    if (!dragged) {
        var c = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
        var point = new DOMPoint(event.offsetX, event.offsetY);
        var tPoint = matrix.inverse().transformPoint(point);
        c.cx.baseVal.value = tPoint.x;
        c.cy.baseVal.value = tPoint.y;
        c.r.baseVal.value = 10;
        c.style.fill = "blue";
        var cdrag = false;
        c.addEventListener('pointerdown', function (event) {
            event.stopPropagation();
            cdrag = true;
            whatToMove = moveCircle;
        });
        var moveCircle = function (event) {
            if (cdrag) {
                var rect = svgCanvas.getBoundingClientRect();
                var x = event.clientX - rect.left;
                var y = event.clientY - rect.top;
                var point_1 = new DOMPoint(x, y);
                var tPoint_1 = matrix.inverse().transformPoint(point_1);
//!!!!!!! HERE NEEDS TO INCLUDE ADDITONAL OFFSET FROM POINTER TO CENTER OF CIRCLE
                c.cx.baseVal.value = tPoint_1.x;
                c.cy.baseVal.value = tPoint_1.y;
            }
        };
        c.addEventListener('pointerup', function (event) {
            event.stopPropagation();
            cdrag = false;
            whatToMove = function () { };
        });
        viewPort.appendChild(c);
    }
    drag = false;
    whatToMove = function () { };
    dragged = false;
});
document.addEventListener('wheel', function (event) {
    event.preventDefault();
    var zoom = event.deltaY > 0 ? -1 : 1;
    var scale = 1 + factor * zoom;
    offset = {
        x: event.offsetX,
        y: event.offsetY
    };
    matrix.preMultiplySelf(new DOMMatrix()
        .translateSelf(offset.x, offset.y)
        .scaleSelf(scale, scale)
        .translateSelf(-offset.x, -offset.y));
    viewPort.style.transform = matrix.toString();
}, { passive:false });
      #around{
          display: flex;
          width: 100%;
          height: 400px;
          padding: 20px;
          border: 1px dashed orange;
      }

      #canvas{
          flex: 1;
          height: auto;
      }
<div id="around">

<svg id="canvas" style="border: 1px solid blue;">
  <g id="viewport">
    <rect x="100" y="100" width="400" height="200" fill="red"/>
    <circle r="10" cx="600" cy="600" fill="blue"/>
  </g>
</svg>

</div>

【问题讨论】:

    标签: javascript html svg matrix linear-algebra


    【解决方案1】:

    您需要存储拖动事件开始时鼠标光标与圆心之间的偏移量。

    您已经设计了一种方法来获得正确的参考鼠标位置:

                    var rect = svgCanvas.getBoundingClientRect();
                    var x = event.clientX - rect.left;
                    var y = event.clientY - rect.top;
                    var point_1 = new DOMPoint(x, y);
                    var tPoint_1 = matrix.inverse().transformPoint(point_1);
    

    使用相同的代码计算初始偏移量并将其存储 (startDragOffset)onpointerdown

                    startDragOffset.x = c.cx.baseVal.value - tPoint_1.x;
                    startDragOffset.y = c.cy.baseVal.value - tPoint_1.y;
    

    最后将该偏移量添加到moveCircle中的鼠标位置:

                    c.cx.baseVal.value = startDragOffset.x + tPoint_1.x;
                    c.cy.baseVal.value = startDragOffset.y + tPoint_1.y;
    

    演示:

    var svgCanvas = document.getElementById("canvas");
    var viewPort = document.getElementById("viewport");
    var drag = false;
    var dragged = false;
    var offset = { x: 0, y: 0 };
    var factor = .1;
    var matrix = new DOMMatrix();
    var whatToMove = function (event) { };
    var startDragOffset = { x: 0, y: 0 };
    svgCanvas.addEventListener('pointerdown', function (event) {
        drag = true;
        whatToMove = moveViewPort;
        offset = { x: event.clientX, y: event.clientY };
    });
    document.addEventListener('pointermove', function (event) {
        if (event.buttons == 1) {
            whatToMove(event);
        }
    });
    var moveViewPort = function (event) {
        if (drag) {
            var tx = event.clientX - offset.x;
            var ty = event.clientY - offset.y;
            offset = {
                x: event.clientX,
                y: event.clientY
            };
            matrix.preMultiplySelf(new DOMMatrix()
                .translateSelf(tx, ty));
            viewPort.style.transform = matrix.toString();
            dragged = true;
        }
    };
    svgCanvas.addEventListener('pointerup', function (event) {
        if (!dragged) {
            var c = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
            var point = new DOMPoint(event.offsetX, event.offsetY);
            var tPoint = matrix.inverse().transformPoint(point);
            c.cx.baseVal.value = tPoint.x;
            c.cy.baseVal.value = tPoint.y;
            c.r.baseVal.value = 10;
            c.style.fill = "blue";
            var cdrag = false;
            c.addEventListener('pointerdown', function (event) {
                event.stopPropagation();
                cdrag = true;
                whatToMove = moveCircle;
                
                var rect = svgCanvas.getBoundingClientRect();
                var x = event.clientX - rect.left;
                var y = event.clientY - rect.top;
                var point_1 = new DOMPoint(x, y);
                var tPoint_1 = matrix.inverse().transformPoint(point_1);
    
                startDragOffset.x = c.cx.baseVal.value - tPoint_1.x;
                startDragOffset.y = c.cy.baseVal.value - tPoint_1.y;
            });
            var moveCircle = function (event) {
                if (cdrag) {
                    var rect = svgCanvas.getBoundingClientRect();
                    var x = event.clientX - rect.left;
                    var y = event.clientY - rect.top;
                    var point_1 = new DOMPoint(x, y);
                    var tPoint_1 = matrix.inverse().transformPoint(point_1);
    //!!!!!!! HERE NEEDS TO INCLUDE ADDITONAL OFFSET FROM POINTER TO CENTER OF CIRCLE
                    c.cx.baseVal.value = startDragOffset.x + tPoint_1.x;
                    c.cy.baseVal.value = startDragOffset.y + tPoint_1.y;
                }
            };
            c.addEventListener('pointerup', function (event) {
                event.stopPropagation();
                cdrag = false;
                whatToMove = function () { };
            });
            viewPort.appendChild(c);
        }
        drag = false;
        whatToMove = function () { };
        dragged = false;
    });
    document.addEventListener('wheel', function (event) {
        var zoom = event.deltaY > 0 ? -1 : 1;
        var scale = 1 + factor * zoom;
        offset = {
            x: event.offsetX,
            y: event.offsetY
        };
        matrix.preMultiplySelf(new DOMMatrix()
            .translateSelf(offset.x, offset.y)
            .scaleSelf(scale, scale)
            .translateSelf(-offset.x, -offset.y));
        viewPort.style.transform = matrix.toString();
    });
          #around{
              display: flex;
              width: 100%;
              height: 400px;
              padding: 20px;
              border: 1px dashed orange;
          }
    
          #canvas{
              flex: 1;
              height: auto;
          }
    <div id="around">
    
    <svg id="canvas" style="border: 1px solid blue;">
      <g id="viewport">
        <rect x="100" y="100" width="400" height="200" fill="red"/>
        <circle r="10" cx="600" cy="600" fill="blue"/>
      </g>
    </svg>
    
    </div>

    当然,您想进行一些调整,例如去除转换鼠标位置的重复代码。

    【讨论】:

    • 谢谢。就是这样。
    猜你喜欢
    • 2015-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-21
    • 2012-10-13
    • 2011-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多