Как центрировать масштабирование вокруг курсора в приложении с бесконечной доской и панорамированиемCSS

Разбираемся в CSS
Ответить Пред. темаСлед. тема
Anonymous
 Как центрировать масштабирование вокруг курсора в приложении с бесконечной доской и панорамированием

Сообщение Anonymous »


Я пытаюсь создать Javascript-приложение с бесконечной доской, похожее на Miro или Figma, где пользователи могут увеличивать и уменьшать масштаб с помощью события колеса, панорамировать влево/вправо/вверх/вниз путем перетаскивания из пустого места в рабочей области. и перемещайте отдельные элементы в любое место рабочей области, перетаскивая их. Я использую React без JSX. Нет HTML-холста.

У меня работают все эти функции, за исключением масштабирования при наведении на курсор. (Вместо масштабирования относительно статической (0,0) исходной точки элемента рабочей области.)

Самый близкий к этому вариант — преобразование начала масштабируемого элемента (#workspace) в текущую позицию мыши при срабатывании события колеса. В основном это работает, но когда вы используете любой масштаб масштабирования, отличный от 1,0, если вы переместите курсор в другое положение, а затем снова масштабируете, все рабочее пространство подпрыгнет, и то, что находится под вашим курсором, изменится (оно должно остаться прежним, просто появиться при другом масштабе масштабирования). Затем, когда вы снова увеличиваете масштаб, не перемещая мышь, он ведет себя так, как хотелось: то, что находится под курсором, остается на месте и просто увеличивается или уменьшается.

Поведение «прыжков» тем более выражено, чем дальше текущий масштаб масштабирования от 1,0. (Простой способ увидеть это — достаточно сильно увеличить или уменьшить масштаб, переместить курсор, затем снова увеличить масштаб и наблюдать, как содержимое рабочей области уходит из-под вас.) Это заставляет меня думать, что, возможно, мне нужно составить уравнение для нового Значения transformOrigin, которые каким-то образом включают значение zoom. Но я не уверен, как написать это уравнение. Ничего из того, что я пробовал, не помогло.

Текущий код находится здесь: https://codepen.io/swelmel/pen/zYeNpPO

Вытаскивание ключевых функций:

Вот моя функция makeZoomable(), определяющая такое поведение:

/* * Сделайте рабочую область масштабируемой, фиксируя события колеса для всего документа. * Передайте appState.workspace для состояния. Изменится реквизит «зум». * ИСПРАВЛЕНИЕ: попытка отцентрировать масштаб вокруг текущего положения мыши, * но это не работает. */ функция makeZoomable(state, el) { console.log(`Сделаем элемент масштабируемым:`,el); функциональное колесо (событие) { событие.preventDefault(); событие.stopPropagation(); // Перемещаем начало координат масштабируемого элемента в текущую позицию курсора // Не работает - когда вы перемещаете курсор, а затем переходите от другого масштаба // чем Zoom=1.0, он будет прыгать. Не знаю почему. state.transformOrigin.x = event.clientX; state.transformOrigin.y = event.clientY; // Увеличение или уменьшение масштаба в зависимости от направления прокрутки const currentZoom = state.zoom; let newZoom = currentZoom + ( event.deltaY * -(state.zoomRate) ); // Ограничить масштаб newZoom =strictRange(newZoom,0.1,10); state.zoom = новыйZoom; рендерUI(); }; document.addEventListener('колесо', колесо, {пассив: false }); } Я передаю элемент #workspace в makeZoomable() вместе с моим объектом состояния приложения React, в котором хранятся transformOrigin и Значения zoom, которые затем передаются в качестве реквизита функции рендеринга для компонента Workspace React (ниже). Рабочая область перерисовывается каждый раз, когда мы запускаем renderUI(), что мы делаем при изменении состояния.

Обратите внимание, что событие wheel должно быть во всем документе, а не только в масштабируемом элементе, поскольку размер масштабируемого элемента рабочей области равен 0x0 и поэтому не может фиксировать никакие события колеса. Я установил для него значение 0x0, потому что мы пытаемся имитировать бесконечное рабочее пространство, поэтому мы не можем указать для него размер. Это означает, что значения event.pageX/Y относятся к документу, а не к масштабируемому элементу. Это может быть источником проблемы или почему подобные ответы мне не помогают, но когда я попытался это компенсировать, это не сработало.

Компонент Workspace React:

function Workspace(props) { const workspace = document.getElementById("workspace"); const {масштаб, перевод, мышь, TransformOrigin} = props.workspace; return e('div', {id: 'workspace', style: { // Чтобы изменить начало координат только при увеличении/уменьшении масштаба: TransformOrigin: `${transformOrigin.x}px ${transformOrigin.y}px`, // Чтобы изменить начало координат при каждом движении мыши: //transformOrigin: `${mouse.x}px ${mouse.y}px`, Transform: `scale(${zoom}) Translate(${translate.x}px, ${translate.y}px)` }}, e(Перекрестье, {x: mouse.x - Translate.x, y: mouse.y - Translate.y }), //e(Перекрестие, {x: TransformOrigin.x, y: TransformOrigin.y }), props.scraps.map((лом) => e(Лом, {ключ: Scrap.id, металлолом})) ); } Значения translate в свойстве CSS transform используются для функции панорамирования.

Будем очень признательны за любые подсказки! Я уже давно над этим ломаю голову.
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «CSS»