Как сделан zoom в редакторе блок-схем dgrm.net.
Zoom-ить можно:
-
колесиком мышки,
-
touchpad-ом
-
и двумя пальцами на телефонах и планшетах.
Готовая функция zoom-а SVG для ваших проектов прилагается. Для HTML можно переделать.
Алгоритм zoom-а
В SVG и HTML есть масштабирование. Масштабирование в HTML.
Только менять масштаб не достаточно. Изображение будет уезжать.
При увеличении круг в центре экрана съезжает вниз вправо.
Черный прямоугольник это экран. Синий это увеличенное изображение. Увеличенный круг находится в центре увеличенного изображения, но съехал относительно экрана.
Нужно увеличивать и сдвигать, тогда центр изображения не уедет.
На рисунке 4 центр изображения не съезжает. Но карты работают не так. Карты зумятся не в центр. Карты зумятся относительно курсора. Место, куда указывает курсор, не сдвигается относительно экрана.
Здание в центре карты уезжает вниз. Оно выделено красным. Здание под курсором остается на месте. Выделено синим.
Значит функция зума должна сдвигать изображение так, чтобы точка под курсором оставалась на месте.
/** * @param {SVGGraphicsElement} svgEl * @param {Point} fixedPoint this point will not change position while scale * @param {number} scale * @param {number} nextScale */ export function svgScale(svgEl, fixedPoint, scale, nextScale) { const position = svgPositionGet(svgEl); svgPositionSet(svgEl, { x: nextScale / scale * (position.x - fixedPoint.x) + fixedPoint.x, y: nextScale / scale * (position.y - fixedPoint.y) + fixedPoint.y }); ensureTransform(svgEl, SVGTransform.SVG_TRANSFORM_SCALE) .setScale(nextScale, nextScale); }
Листинг 1. Функция зума. Сдвигает изображение так, что fixedPoint остается на месте.
Вспомогательные функции svgPositionGet, svgPositionSet, ensureTransform смотрите на GitHub.
Zoom колесиком мышки и touchpad-ом
Подписываемся на событие колесика мышки “wheel”. Для щипка двумя пальцами на touchpad отдельного события нет. Щипок использует это же событие “wheel”.
Для колесика масштаб изменяется с шагом 0.25, а для touchpad 0.05. Значения подобраны так чтобы:
-
колесико мышки не нужно было долго крутить,
-
а на touchpad изображение не скакало.
// 'svg' is type of {SVGSVGElement} // mouse wheel, trackpad pitch svg.addEventListener('wheel', /** @param {WheelEvent} evt */ evt => { evt.preventDefault(); // calc nextScale const delta = evt.deltaY || evt.deltaX; const scaleStep = Math.abs(delta) < 50 ? 0.05 // touchpad pitch : 0.25; // mouse wheel const scaleDelta = delta < 0 ? scaleStep : -scaleStep; const nextScale = scale + scaleDelta; // 'scale' is previous scale // calc fixedPoint const fixedPoint = { x: evt.clientX, y: evt.clientY }; // scale // 'svgEl' is element to scale svgScale(svgEl, fixedPoint, scale, nextScale); });
Листинг 2. Подписываемся на событие колесика мышки. Щипок touchpad запускает это же событие. Полный код смотрите на GitHub.
Zoom двумя пальцам на телефонах и планшетах
Для zoom-а пальцами фиксированная точка — это точка посередине между пальцами. Изменение масштаба зависит от изменения расстояния между пальцами.
Еще нужно учитывать что изображение можно одновременно зумить и двигать.
// calc nextScale // distance between fingers const distanceNew = Math.hypot( firstFinger.x - secondFinger.x, firstFinger.y - secondFinger.y); // 'distance' variable is previous distance between fingers const scaleDelta = (distanceNew - distance) * 0.01; const nextScale = scale + scaleDelta; // 'scale' is previous scale // calc fixedPoint const fixedPoint = { x: (firstFinger.x + secondFinger.x) / 2, y: (firstFinger.y + secondFinger.y) / 2 }; // scale // 'svgEl' is element to scale svgScale(svgEl, fixedPoint, scale, nextScale); // don't forget to also move the canvas behind your fingers
Листинг 3. При zoom-е пальцами фиксированная точка это точка посередине между пальцами. Изменение масштаба зависит от изменения расстояния между пальцами. Полный код смотрите на GitHub.
Другие статьи про dgrm.net
Как поддержать проект
ссылка на оригинал статьи https://habr.com/ru/post/696266/
Добавить комментарий