Прослушивание события жеста изменения масштабирования на тачпаде в браузере
Тачпады некоторых современных ноутбуков поддерживают разные жесты. Один из таких жестов отвечает за изменение масштабирования. Недавно я заметил, что те же Google-карты успешно используют эти жесты при сёрфинге карт через любой популярный браузер. Я проверил Edge, Chrome, Firefox, Safari.
А карты Apple поддерживают не только жест масштабирования, но и жест вращения. При этом, все элементы страницы остаются на своих местах с неизменными габаритами. То есть, это не какое-нибудь растягивание HTML-странички, как по комбинации клавиш Ctrl++. Это именно прослушивание этих жестов.
Я хотел бы использовать эти жесты в своих приложениях. Например, масштабировать или вращать изображение. Чтобы не оставлять вопрос без кода, накидал демку с большой картинкой, оригинальный размер которой 4000x4000. Если кто знает как отслеживать эти жесты, поделитесь, пожалуйста, хотя бы ссылкой на материал.
document.querySelector('.canvas').onclick = (event) => event.target.classList.toggle('original');
window.onwheel = (event)=>{
let canvas = document.querySelector('.canvas');
let rect = canvas.getBoundingClientRect();
let { wheelDeltaX, wheelDeltaY } = event;
if(Math.round(rect.left) == window.innerWidth - 50 && wheelDeltaX > 0 ) wheelDeltaX = 0;
else if(rect.left > window.innerWidth - 50) { wheelDeltaX = - 50 - rect.left + window.innerWidth; }
if(Math.round(rect.top) == window.innerHeight - 50 && wheelDeltaY > 0 ) wheelDeltaY = 0;
else if(rect.top > window.innerHeight - 50) { wheelDeltaY = - 50 - rect.top + window.innerHeight; }
if(Math.round(rect.right) == 50 && wheelDeltaX < 0 ) wheelDeltaX = 0;
else if(rect.right < 50) { wheelDeltaX = 50 - rect.right; }
if(Math.round(rect.bottom) == 50 && wheelDeltaY < 0 ) wheelDeltaY = 0;
else if(rect.bottom < 50) { wheelDeltaY = 50 - rect.bottom; }
canvas.style.transform = `${getComputedStyle(canvas).transform} translate(${wheelDeltaX}px, ${wheelDeltaY}px)`;
//console.log(event.wheelDeltaX,event.wheelDeltaY);
};
body {
min-height: 100vh;
margin: 0;
}
.canvas {
position: fixed;
left: 50vw;
top: 50vh;
width: calc(100vw - 4rem);
height: calc(100vh - 4rem);
max-width: calc(100vh - 4rem);
max-height: calc(100vw - 4rem);
transform: translate(-50%, -50%);
}
.canvas.original{
transform: translate(0%, 0%);
left: calc(-2000px + 50vw);
top: calc(-2000px + 50vh);
width: 4000px;
height: 4000px;
max-width: 4000px;
max-height: 4000px;
}
img {
width: 100%;
height: 100%;
pointer-events:none;
}
.surface {
width: 100vw;
height: 100vh;
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="gray" stroke="none"><rect x="0" y="0" width="8" height="8"/><rect x="8" y="8" width="8" height="8"/></svg>') 16px/16px repeat;
}
.controls {
background: cyan;
position: fixed;
height: 3rem;
width: 5rem;
}
.top {
top: 0;
}
.bottom {
bottom: 0;
}
.left {
left: 0;
}
.right {
right: 0;
}
<div class="surface">
<div class="canvas">
<img src="https://images.unsplash.com/photo-1620421680906-275860f61e27?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=4000&q=80" />
</div>
</div>
<div class="controls top left"></div>
<div class="controls top right"></div>
<div class="controls bottom left"></div>
<div class="controls bottom right"></div>
Немного юмористического сарказма. На второй картинке страница с примерами карт Apple. На картинке виден горизонтальный скролл. Он остается при любом размере окна браузера, но проявляется только в Safari. Что-то подсказывает мне, что никто из web-мастеров Apple по картам не пользуется Safari по причинам скудного набора функционала панели разработчиков. В противном случае они бы давно заметили этот баг.
Ответы (1 шт):
Все оказалось вон оно как просто. Те события называются gesturestart, gestureend и gesturechange.
var node;
var rotation = 0;
var gestureStartRotation = 0;
var gestureStartScale = 0;
var scale = 1;
var posX = 0;
var posY = 0;
var startX;
var startY;
var node = document.querySelector('.canvas');
var render = () => {
window.requestAnimationFrame(() => {
var val = `translate3D(${posX}px, ${posY}px, 0px) rotate(${rotation}deg) scale(${scale})`;
node.style.transform = val;
});
};
window.addEventListener('wheel', (e) => {
e.preventDefault();
if (e.ctrlKey) {
scale -= e.deltaY * 0.01;
}
else {
posX -= e.deltaX * 2;
posY -= e.deltaY * 2;
}
render();
});
window.addEventListener("gesturestart", function (e) {
e.preventDefault();
startX = e.pageX - posX;
startY = e.pageY - posY;
gestureStartRotation = rotation;
gestureStartScale = scale;
});
window.addEventListener("gesturechange", function (e) {
e.preventDefault();
rotation = gestureStartRotation + e.rotation;
scale = gestureStartScale * e.scale;
posX = e.pageX - startX;
posY = e.pageY - startY;
render();
});
window.addEventListener("gestureend", function (e) {
e.preventDefault();
});
body {
min-height: 100vh;
margin: 0;
}
.canvas {
position: fixed;
left: calc(50vw - 50vmin + 2rem);
top: calc(50vh - 50vmin + 2rem);
width: calc(100vw - 4rem);
height: calc(100vh - 4rem);
max-width: calc(100vh - 4rem);
max-height: calc(100vw - 4rem);
/* transform: translate(-50%, -50%);*/
}
.canvas.original{
transform: translate(0%, 0%);
left: calc(-2000px + 50vw);
top: calc(-2000px + 50vh);
width: 4000px;
height: 4000px;
max-width: 4000px;
max-height: 4000px;
}
img {
width: 100%;
height: 100%;
pointer-events:none;
}
.surface {
width: 100vw;
height: 100vh;
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="gray" stroke="none"><rect x="0" y="0" width="8" height="8"/><rect x="8" y="8" width="8" height="8"/></svg>') 16px/16px repeat;
}
.controls {
background: cyan;
position: fixed;
height: 3rem;
width: 5rem;
}
.top {
top: 0;
}
.bottom {
bottom: 0;
}
.left {
left: 0;
}
.right {
right: 0;
}
<div class="surface">
<div class="canvas">
<img src="https://images.unsplash.com/photo-1620421680906-275860f61e27?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=4000&q=80" />
</div>
</div>
<div class="controls top left"></div>
<div class="controls top right"></div>
<div class="controls bottom left"></div>
<div class="controls bottom right"></div>

