Fix "impossible d'aller plus loin vers la droite" — défilement automatique du canevas
Cause confirmée (tous les objets bloquaient au même endroit, pas spécifique à un widget) : une scène à taille fixe (960×540 par ex.) peut être plus LARGE que la zone visible de .canvasFrame (overflow:auto) selon la largeur de fenêtre — sa partie droite/basse défile alors HORS de vue, et le curseur atteignait le bord de cette zone VISIBLE bien avant celui de la scène elle-même : la souris ne pouvait tout simplement plus bouger physiquement plus loin, sans aucun rapport avec la limite réelle (960px) de la scène. onSceneObjectMouseDown/onSceneObjectResizeMouseDown font maintenant défiler .canvasFrame automatiquement quand le curseur approche un bord pendant un glisser/redimensionnement — et continuent de déplacer l'objet même si la souris reste immobile près du bord (mirror du comportement standard d'un glisser-déposer dans une zone scrollable), grâce à une position ACCUMULÉE plutôt que recalculée depuis le point de départ fixe. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
046c38b4dc
commit
7c9b2c9b25
@@ -36,16 +36,53 @@ function updateScenePosFields(x, y, w, h) {
|
||||
if (hEl) hEl.value = Math.round(h);
|
||||
}
|
||||
|
||||
// Défilement automatique de .canvasFrame (overflow:auto, voir static/
|
||||
// style.css) pendant un glisser/redimensionnement — bug corrigé : une
|
||||
// scène à taille FIXE (960×540 par ex.) peut être plus LARGE que la zone
|
||||
// visible de .canvasFrame (fenêtre pas assez large, panneaux ouverts...),
|
||||
// auquel cas sa partie droite/basse défile HORS de vue. Sans défilement
|
||||
// automatique, le curseur atteignait le bord de la zone visible (donc de
|
||||
// .canvasFrame) bien avant celui de la scène elle-même — "impossible
|
||||
// d'aller plus loin vers la droite" alors qu'il restait pourtant de la
|
||||
// place dans la scène. `onNudge(dx, dy)` est rappelé à chaque tick tant
|
||||
// que le curseur reste dans la marge d'un bord, MÊME SI la souris ne
|
||||
// bouge plus (immobile près du bord) — mirror du comportement standard
|
||||
// d'un glisser-déposer proche d'un bord de zone scrollable.
|
||||
function forgeStartCanvasAutoScroll(getMouse, onNudge) {
|
||||
var MARGIN = 40, SPEED = 14;
|
||||
var timer = setInterval(function () {
|
||||
var frame = document.querySelector('.canvasFrame');
|
||||
if (!frame) return;
|
||||
var rect = frame.getBoundingClientRect();
|
||||
var mouse = getMouse();
|
||||
var dx = 0, dy = 0;
|
||||
if (mouse.x > rect.right - MARGIN) dx = SPEED;
|
||||
else if (mouse.x < rect.left + MARGIN) dx = -SPEED;
|
||||
if (mouse.y > rect.bottom - MARGIN) dy = SPEED;
|
||||
else if (mouse.y < rect.top + MARGIN) dy = -SPEED;
|
||||
if (!dx && !dy) return;
|
||||
frame.scrollLeft = Math.max(0, frame.scrollLeft + dx);
|
||||
frame.scrollTop = Math.max(0, frame.scrollTop + dy);
|
||||
onNudge(dx, dy);
|
||||
}, 30);
|
||||
return function stop() { clearInterval(timer); };
|
||||
}
|
||||
|
||||
// Glisser-déposer en pixels, clampé à la taille FIXE de la scène
|
||||
// (SCENE_WIDTH/SCENE_HEIGHT, voir templates/scene_edit.html) — mirror
|
||||
// d'onElementMouseDown() (tree-panels.js), mais sans conversion en % :
|
||||
// une scène a des coordonnées pixel absolues, pas fluides.
|
||||
// une scène a des coordonnées pixel absolues, pas fluides. Position
|
||||
// ACCUMULÉE (curLeft/curTop, jamais recalculée depuis le point de départ
|
||||
// fixe) : c'est ce qui permet à forgeStartCanvasAutoScroll ci-dessus de
|
||||
// continuer à la déplacer même quand la souris ne bouge plus (immobile
|
||||
// près d'un bord).
|
||||
function onSceneObjectMouseDown(e, id) {
|
||||
if (e.target.classList.contains('resizeHandle')) return;
|
||||
e.preventDefault();
|
||||
var el = document.getElementById('el-' + id);
|
||||
var startX = e.clientX, startY = e.clientY;
|
||||
var startLeft = parseFloat(el.style.left) || 0, startTop = parseFloat(el.style.top) || 0;
|
||||
var lastClientX = e.clientX, lastClientY = e.clientY;
|
||||
var curLeft = parseFloat(el.style.left) || 0, curTop = parseFloat(el.style.top) || 0;
|
||||
var width = parseFloat(el.style.width) || 0, height = parseFloat(el.style.height) || 0;
|
||||
var moved = false;
|
||||
// Les panneaux flottants "🧩 Objets"/"⚙️ Propriétés" (voir static/style.css
|
||||
@@ -59,25 +96,32 @@ function onSceneObjectMouseDown(e, id) {
|
||||
// à sa valeur d'origine à la fin.
|
||||
var previousZIndex = el.style.zIndex;
|
||||
|
||||
function applyDelta(dx, dy) {
|
||||
curLeft = Math.max(0, Math.min(SCENE_WIDTH - width, curLeft + dx));
|
||||
curTop = Math.max(0, Math.min(SCENE_HEIGHT - height, curTop + dy));
|
||||
el.style.left = curLeft + 'px';
|
||||
el.style.top = curTop + 'px';
|
||||
}
|
||||
function onMove(ev) {
|
||||
var dx = ev.clientX - startX, dy = ev.clientY - startY;
|
||||
if (Math.abs(dx) > 3 || Math.abs(dy) > 3) {
|
||||
var dx = ev.clientX - lastClientX, dy = ev.clientY - lastClientY;
|
||||
lastClientX = ev.clientX; lastClientY = ev.clientY;
|
||||
if (Math.abs(ev.clientX - startX) > 3 || Math.abs(ev.clientY - startY) > 3) {
|
||||
if (!moved) el.style.zIndex = 9999;
|
||||
moved = true;
|
||||
}
|
||||
var newLeft = Math.max(0, Math.min(SCENE_WIDTH - width, startLeft + dx));
|
||||
var newTop = Math.max(0, Math.min(SCENE_HEIGHT - height, startTop + dy));
|
||||
el.style.left = newLeft + 'px';
|
||||
el.style.top = newTop + 'px';
|
||||
applyDelta(dx, dy);
|
||||
}
|
||||
var stopAutoScroll = forgeStartCanvasAutoScroll(
|
||||
function () { return { x: lastClientX, y: lastClientY }; }, applyDelta
|
||||
);
|
||||
function onUp() {
|
||||
document.removeEventListener('mousemove', onMove);
|
||||
document.removeEventListener('mouseup', onUp);
|
||||
stopAutoScroll();
|
||||
if (moved) {
|
||||
el.style.zIndex = previousZIndex;
|
||||
var newLeft = parseFloat(el.style.left), newTop = parseFloat(el.style.top);
|
||||
updateScenePosFields(newLeft, newTop, width, height);
|
||||
saveSceneObjectGeometry(id, newLeft, newTop, width, height);
|
||||
updateScenePosFields(curLeft, curTop, width, height);
|
||||
saveSceneObjectGeometry(id, curLeft, curTop, width, height);
|
||||
} else {
|
||||
window.location.href = SCREEN_EDIT_URL + '?selected=' + id;
|
||||
}
|
||||
@@ -90,8 +134,8 @@ function onSceneObjectResizeMouseDown(e, id) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
var el = document.getElementById('el-' + id);
|
||||
var startX = e.clientX, startY = e.clientY;
|
||||
var startWidth = parseFloat(el.style.width) || 0, startHeight = parseFloat(el.style.height) || 0;
|
||||
var lastClientX = e.clientX, lastClientY = e.clientY;
|
||||
var curWidth = parseFloat(el.style.width) || 0, curHeight = parseFloat(el.style.height) || 0;
|
||||
var left = parseFloat(el.style.left) || 0, top = parseFloat(el.style.top) || 0;
|
||||
// Voir la même note dans onSceneObjectMouseDown ci-dessus : au-dessus
|
||||
// des panneaux flottants le temps du geste, pour rester visible même
|
||||
@@ -99,18 +143,26 @@ function onSceneObjectResizeMouseDown(e, id) {
|
||||
var previousZIndex = el.style.zIndex;
|
||||
el.style.zIndex = 9999;
|
||||
|
||||
function onMove(ev) {
|
||||
var dx = ev.clientX - startX, dy = ev.clientY - startY;
|
||||
var newWidth = Math.max(8, Math.min(SCENE_WIDTH - left, startWidth + dx));
|
||||
var newHeight = Math.max(8, Math.min(SCENE_HEIGHT - top, startHeight + dy));
|
||||
el.style.width = newWidth + 'px';
|
||||
el.style.height = newHeight + 'px';
|
||||
function applyDelta(dx, dy) {
|
||||
curWidth = Math.max(8, Math.min(SCENE_WIDTH - left, curWidth + dx));
|
||||
curHeight = Math.max(8, Math.min(SCENE_HEIGHT - top, curHeight + dy));
|
||||
el.style.width = curWidth + 'px';
|
||||
el.style.height = curHeight + 'px';
|
||||
}
|
||||
function onMove(ev) {
|
||||
var dx = ev.clientX - lastClientX, dy = ev.clientY - lastClientY;
|
||||
lastClientX = ev.clientX; lastClientY = ev.clientY;
|
||||
applyDelta(dx, dy);
|
||||
}
|
||||
var stopAutoScroll = forgeStartCanvasAutoScroll(
|
||||
function () { return { x: lastClientX, y: lastClientY }; }, applyDelta
|
||||
);
|
||||
function onUp() {
|
||||
document.removeEventListener('mousemove', onMove);
|
||||
document.removeEventListener('mouseup', onUp);
|
||||
stopAutoScroll();
|
||||
el.style.zIndex = previousZIndex;
|
||||
var newWidth = parseFloat(el.style.width), newHeight = parseFloat(el.style.height);
|
||||
var newWidth = curWidth, newHeight = curHeight;
|
||||
updateScenePosFields(left, top, newWidth, newHeight);
|
||||
saveSceneObjectGeometry(id, left, top, newWidth, newHeight);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user