У меня есть карта 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/