document.addEventListener("DOMContentLoaded", function() {
let img = document.querySelector('.bg_map'),
el = document.querySelector('.block_map'),
wrapper = document.querySelector('.wrapper_map'),
plus = document.querySelector('.button_plus'),
minus = document.querySelector('.button_minus'),
source = document.querySelector('.button_source'),
fullscreen = document.querySelector('.button_screen');
let imgRect = img.getBoundingClientRect(),
elRect = el.getBoundingClientRect();
let pos = {
x: 0,
y: 0
}
const sizeImg = {
w: img.offsetWidth,
h: img.offsetHeight
};
let sizeEl = {
w: el.offsetWidth,
h: el.offsetHeight
};
let scale = 1;
const mat = new DOMMatrix();
const maxScale = 4;
const stepScale = 0.1;
const stepScaleTouch = 0.1;
function filterPos(a, b, t) {
if (a > 0) return 0;
else if (a < b) return b;
else return a;
}
function filterScale(a) {
let minScale = Math.max(sizeEl.w/sizeImg.w,sizeEl.h/sizeImg.h);
scale = Math.min(Math.max(minScale, a), maxScale);
mat.a = scale;
mat.d = scale;
(maxScale == scale ? plus.classList.add("not_active") : plus.classList.remove('not_active'));
(minScale == scale ? minus.classList.add("not_active") : minus.classList.remove('not_active'));
}
function zoomAt(d, x, y) {
let target = { // коорд курсора отн исходного img
x: x / scale,
y: y / scale
}
scale += d; // В±0.05
filterScale(scale);
let offset = { // разница м/у коорд курсора текущие/будущие + текущие смещение
x: x - target.x * scale + mat.e,
y: y - target.y * scale + mat.f
}
mat.e = filterPos(offset.x, (sizeEl.w - sizeImg.w*scale));
mat.f = filterPos(offset.y, (sizeEl.h - sizeImg.h*scale));
img.style.transform = mat.toString();
}
let start = { x: 0, y: 0 };
let scroll = { x: 0, y: 0 };
const pan = (event) => {
imgRect = img.getBoundingClientRect();
elRect = el.getBoundingClientRect();
if (event.type === "pointerdown") {
document.addEventListener("pointermove", pan);
document.addEventListener("pointerup", pan);
// коорд курсора отн окна браузера
start.x = event.clientX;
start.y = event.clientY;
// смещение img отн el
scroll.x = imgRect.left - elRect.left;
scroll.y = imgRect.top - elRect.top;
}
if (event.type === "pointerup") {
document.removeEventListener("pointermove", pan);
document.removeEventListener("pointerup", pan);
}
if (event.type === "pointermove") {
if (evCache.length == 1) { // если в кэше 1 указатель
pos.x = scroll.x + (event.clientX - start.x);
pos.y = scroll.y + (event.clientY - start.y);
mat.e = filterPos(pos.x, (elRect.width - imgRect.width));
mat.f = filterPos(pos.y, (elRect.height - imgRect.height));
if (!document.fullscreenElement) {
((mat.f == pos.y) ? wrapper.classList.add("touch_action") : wrapper.classList.remove("touch_action"))
}
img.style.transform = mat.toString();
}
}
event.preventDefault();
}
el.addEventListener("pointerdown", pan);
const wheelAt = (event) => {
event.preventDefault();
imgRect = img.getBoundingClientRect();
elRect = el.getBoundingClientRect();
let offset = { // коорд курсора отн img
x: event.clientX - imgRect.left,
y: event.clientY - imgRect.top
}
let delta = Math.max(-1,Math.min(1,event.deltaY)) * -stepScale; // ±0.05
zoomAt(delta, offset.x, offset.y);
// document.getElementsByTagName('pre')[0].innerHTML += event.clientX + " и " + imgRect.left+"
";
}
el.addEventListener("wheel", wheelAt);
let evCache = new Array();
let prevDiff = -1;
function zoomTouchDown(ev) { // добавление в конец кэша
evCache.push(ev);
}
function zoomTouchMove(ev) {
// обновление в кэше события
for (var i = 0; i < evCache.length; i++) {
if (ev.pointerId == evCache[i].pointerId) {
evCache[i] = ev;
break;
}
}
if (evCache.length == 2) { // если в кэше 2 указателя
// расстояние между двумя указателями
let curDiff = Math.sqrt(Math.pow(evCache[1].clientX - evCache[0].clientX, 2) + Math.pow(evCache[1].clientY - evCache[0].clientY, 2));
imgRect = img.getBoundingClientRect();
elRect = el.getBoundingClientRect();
let delta = 0;
let offset = { // коорд курсора отн img
x: (evCache[1].clientX + evCache[0].clientX)/2 - imgRect.left,
y: (evCache[1].clientY + evCache[0].clientY)/2 - imgRect.top
}
if (prevDiff > 0) {
if (curDiff > prevDiff) { // если расстояние увеличилось
delta += stepScaleTouch; // ±0.05
}
if (curDiff < prevDiff) { // если расстояние уменьшилось
delta -= stepScaleTouch; // ±0.05
}
}
prevDiff = curDiff;
// document.getElementsByTagName('pre')[0].innerHTML += (evCache[1].clientX + evCache[0].clientX)/2 + " и " + imgRect.left+"
";
zoomAt(delta, offset.x, offset.y);
}
}
function zoomTouchRem(ev) { // удаляем указатели из кэша и сбрасываем
remove_event(ev);
if (evCache.length < 2) prevDiff = -1; // если в кэше меньше 2 указателей
}
function remove_event(ev) { // удалить событие из кэша
for (var i = 0; i < evCache.length; i++) {
if (evCache[i].pointerId == ev.pointerId) {
evCache.splice(i, 1);
break;
}
}
}
// обработчики события
el.onpointerdown = zoomTouchDown;
el.onpointermove = zoomTouchMove;
// pointer{up,cancel,out,leave} те же
el.onpointerup = zoomTouchRem;
el.onpointercancel = zoomTouchRem;
el.onpointerout = zoomTouchRem;
el.onpointerleave = zoomTouchRem;
});