Объект SVG - как правильно масштабировать и перетаскивать его? - PullRequest
0 голосов
/ 01 апреля 2019

У меня есть карта SVG и простой плагин, который добавляет функции масштабирования и перетаскивания.

<svg>
    <g class="main-container draggable" transform="matrix(1 0 0 1 0 0)">
      <path id="AT-1" title="Burgenland" class="land" d=".../>
  </g>
</svg>

const maxScale = 5,
        minScale = 0.15;

    var selected,
        scale = 1,
        svg = document.querySelector('svg');

    function beginDrag(e) {
        e.stopPropagation();
        let target = e.target;

        if (target.classList.contains('draggable')) {
            selected = target;
        } else {
            selected = document.querySelector('.main-container');
        }

        selected.dataset.startMouseX = e.clientX;
        selected.dataset.startMouseY = e.clientY;
    }

    function drag(e) {
        if (!selected) return;
        e.stopPropagation();

        let startX = parseFloat(selected.dataset.startMouseX),
            startY = parseFloat(selected.dataset.startMouseY),
            dx = (e.clientX - startX),
            dy = (e.clientY - startY);

        if (selected.classList.contains('draggable')) {
            let selectedBox = selected.getBoundingClientRect(),
                boundaryBox = selected.parentElement.getBoundingClientRect();

            if (selectedBox.right + dx > boundaryBox.right) {
                dx = (boundaryBox.right - selectedBox.right);
            } else if (selectedBox.left + dx < boundaryBox.left) {
                dx = (boundaryBox.left - selectedBox.left);
            }

            if (selectedBox.bottom + dy > boundaryBox.bottom) {
                dy = (boundaryBox.bottom - selectedBox.bottom);
            }
            else if (selectedBox.top + dy < boundaryBox.top) {
                dy = (boundaryBox.top - selectedBox.top);
            }
        }

        let currentMatrix = selected.transform.baseVal.consolidate().matrix,
            newMatrix = currentMatrix.translate(dx / scale, dy / scale),
            transform = svg.createSVGTransformFromMatrix(newMatrix);

        selected.transform.baseVal.initialize(transform);
        selected.dataset.startMouseX = dx + startX;
        selected.dataset.startMouseY = dy + startY;
    }

    function endDrag(e) {
        e.stopPropagation();

        if (selected) {
            selected = undefined;
        }
    }


    function zoom(e) {
        e.stopPropagation();
        e.preventDefault();

        let delta = e.wheelDelta,
            container = document.querySelector('svg .main-container'),
            scaleStep = delta > 0 ? 1.25 : 0.8;

        if (scale * scaleStep > maxScale) {
            scaleStep = maxScale / scale;
        }

        if (scale * scaleStep < minScale) {
            scaleStep = minScale / scale;
        }

        scale *= scaleStep;

        let box = svg.getBoundingClientRect();
        let point = svg.createSVGPoint();
        point.x = e.clientX - box.left;
        point.y = e.clientY - box.top;

        let currentZoomMatrix = container.getCTM();

        point = point.matrixTransform(currentZoomMatrix.inverse());

        let matrix = svg.createSVGMatrix()
            .translate(point.x, point.y)
            .scale(scaleStep)
            .translate(-point.x, -point.y);


        let newZoomMatrix = currentZoomMatrix.multiply(matrix);
        container.transform.baseVal.initialize(svg.createSVGTransformFromMatrix(newZoomMatrix));

        console.log("scale", scale);
        let t = newZoomMatrix;
        console.log("zoomMatrix", t.a, t.b, t.c, t.d, t.e, t.f);
    }

    document.querySelector('svg').addEventListener('mousedown', beginDrag);
    document.querySelector('svg').addEventListener('mousewheel', zoom);
    svg.addEventListener('mousemove', drag);
    window.addEventListener('mouseup', endDrag);

На первый взгляд, он работает нормально, однако в некоторых ситуациях он ведет себя странно.

Например, если вы уменьшаете масштаб, я могу свободно перетаскивать его в любом направлении без каких-либо проблем.

Но если увеличить масштаб до той части карты, которая превышает родительский элемент, любойпопытка его перемещения вызывает скачок всей карты и блокирует эту функциональность.

Второе: сейчас я могу перемещать карту только в границах элемента SVG и хочу иметь возможность перетаскиватьэто вне его так же, как это работает здесь: https://www.amcharts.com/svg-maps/?map=austria

Вот фрагмент с моим кодом: https://jsfiddle.net/marektchas/qo1eynag/3/

1 Ответ

0 голосов
/ 01 апреля 2019

Кажется, я нашел решение, но я не совсем уверен, как оно работает.

Это работает как положено, если я удаляю .draggable класс из g элемента

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...