mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-02 04:38:55 +00:00
zoom: editor zoom is a working tool — leaving any editor restores the view-mode viewport
Entering an editor snapshots the view-mode zoom+center (per space); leaving back to view brings it back and re-saves it to LS_ZOOM, so wheel zoom done inside the editors no longer leaks into the viewing zoom. Editor-to-editor switches and the per-space view zoom keep working as before. Smoke: smoke_zoom_out.mjs grows the 1.6 -> editor 2.5 -> 1.6 scenario (zoom, center, LS), the no-touch no-jump case and the space-switch persistence guard.
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -48,6 +48,66 @@ out.floorIsHalf = await page.evaluate(() => { window.__card._resetZoom(); const
|
|||||||
c._applyView(0.1); return c._zoom; }) === 0.4; // clamped at the floor
|
c._applyView(0.1); return c._zoom; }) === 0.4; // clamped at the floor
|
||||||
await page.evaluate(() => window.__card._resetZoom());
|
await page.evaluate(() => window.__card._resetZoom());
|
||||||
|
|
||||||
|
// -- editor zoom is a working tool, not the viewing intent ----------------
|
||||||
|
// view 1.6 → devices editor 2.5 → back to view: the pre-editor viewport
|
||||||
|
// (zoom AND center) comes back; the editor keeps its own zoom while open.
|
||||||
|
out.editorZoomNotSaved = await page.evaluate(async () => {
|
||||||
|
const c = window.__card;
|
||||||
|
const raf2 = () => new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));
|
||||||
|
const center = () => { const v = c._view; return [v.x + v.w / 2, v.y + v.h / 2]; };
|
||||||
|
c._setMode('view');
|
||||||
|
c._resetZoom();
|
||||||
|
c._zoomAt(10, 10, 1.6); c._saveZoom(); // off-center on purpose
|
||||||
|
const want = { zoom: c._zoom, c: center() };
|
||||||
|
c._setMode('devices'); await raf2();
|
||||||
|
c._zoomAt(10, 10, 2.5); c._saveZoom(); // off-center too: the center must not leak either
|
||||||
|
const editorZoomFree = Math.abs(c._zoom - 2.5) < 0.01; // zooming inside stays
|
||||||
|
c._setMode('view'); await raf2();
|
||||||
|
const got = { zoom: c._zoom, c: center() };
|
||||||
|
const ls = JSON.parse(localStorage.getItem('houseplan_card_zoom_v1') || '{}');
|
||||||
|
return {
|
||||||
|
editorZoomFree,
|
||||||
|
zoomRestored: Math.abs(got.zoom - want.zoom) < 0.01,
|
||||||
|
centerRestored: Math.hypot(got.c[0] - want.c[0], got.c[1] - want.c[1]) < 0.02,
|
||||||
|
lsRestored: Math.abs((ls[c._space] || 1) - want.zoom) < 0.01,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
out.editorZoomFree = out.editorZoomNotSaved.editorZoomFree;
|
||||||
|
out.viewZoomRestored = out.editorZoomNotSaved.zoomRestored;
|
||||||
|
out.viewCenterRestored = out.editorZoomNotSaved.centerRestored;
|
||||||
|
out.viewZoomBackInLs = out.editorZoomNotSaved.lsRestored;
|
||||||
|
delete out.editorZoomNotSaved;
|
||||||
|
|
||||||
|
// -- editor entered and left without touching zoom: no jump ---------------
|
||||||
|
out.untouchedEditorNoJump = await page.evaluate(async () => {
|
||||||
|
const c = window.__card;
|
||||||
|
const raf2 = () => new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));
|
||||||
|
c._setMode('view');
|
||||||
|
c._resetZoom();
|
||||||
|
c._zoomAt(30, 30, 1.6); c._saveZoom();
|
||||||
|
const before = { ...c._view };
|
||||||
|
c._setMode('plan'); await raf2();
|
||||||
|
c._setMode('view'); await raf2();
|
||||||
|
const v = c._view;
|
||||||
|
return Math.abs(c._zoom - 1.6) < 0.01
|
||||||
|
&& Math.abs(v.x - before.x) < 0.005 && Math.abs(v.y - before.y) < 0.005
|
||||||
|
&& Math.abs(v.w - before.w) < 0.005 && Math.abs(v.h - before.h) < 0.005;
|
||||||
|
});
|
||||||
|
|
||||||
|
// -- the view zoom still survives a space switch, per space ---------------
|
||||||
|
out.viewZoomSurvivesSpaceSwitch = await page.evaluate(async () => {
|
||||||
|
const c = window.__card;
|
||||||
|
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||||
|
c._setMode('view');
|
||||||
|
c._resetZoom(); c._applyView(1.7); c._saveZoom();
|
||||||
|
c._slideTo('garden', 'left'); await wait(350);
|
||||||
|
const gardenGotOwnZoom = Math.abs(c._zoom - (JSON.parse(
|
||||||
|
localStorage.getItem('houseplan_card_zoom_v1') || '{}').garden || 1)) < 0.01;
|
||||||
|
c._slideTo('f1', 'right'); await wait(350);
|
||||||
|
return gardenGotOwnZoom && Math.abs(c._zoom - 1.7) < 0.01;
|
||||||
|
});
|
||||||
|
await page.evaluate(() => window.__card._resetZoom());
|
||||||
|
|
||||||
// -- devices outside rooms stretch the default frame ---------------------
|
// -- devices outside rooms stretch the default frame ---------------------
|
||||||
out.devicesStretchFrame = await page.evaluate(() => {
|
out.devicesStretchFrame = await page.evaluate(() => {
|
||||||
const c = window.__card;
|
const c = window.__card;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -246,6 +246,12 @@ class HouseplanCard extends LitElement {
|
|||||||
private _zoom = 1;
|
private _zoom = 1;
|
||||||
private _view: { x: number; y: number; w: number; h: number } | null = null; // current SVG viewBox (vb coordinates)
|
private _view: { x: number; y: number; w: number; h: number } | null = null; // current SVG viewBox (vb coordinates)
|
||||||
private _zoomBySpace: Record<string, number> = {};
|
private _zoomBySpace: Record<string, number> = {};
|
||||||
|
/**
|
||||||
|
* View-mode viewport remembered on entering an editor. Editor zoom is a
|
||||||
|
* working tool (zoom in to grab a vertex), not the user's intention for
|
||||||
|
* viewing — leaving any editor brings the view-mode viewport back.
|
||||||
|
*/
|
||||||
|
private _viewModeSnap: { space: string; zoom: number; cx?: number; cy?: number } | null = null;
|
||||||
private _pointers = new Map<number, { x: number; y: number }>();
|
private _pointers = new Map<number, { x: number; y: number }>();
|
||||||
private _panStart: { sx: number; sy: number; vx: number; vy: number } | null = null;
|
private _panStart: { sx: number; sy: number; vx: number; vy: number } | null = null;
|
||||||
private _pinchStart: { dist: number; zoom: number } | null = null;
|
private _pinchStart: { dist: number; zoom: number } | null = null;
|
||||||
@@ -1857,6 +1863,17 @@ class HouseplanCard extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const baseChanges = !this._spaceModel().bg && (mode === 'view') !== (this._mode === 'view');
|
const baseChanges = !this._spaceModel().bg && (mode === 'view') !== (this._mode === 'view');
|
||||||
|
if (this._mode === 'view' && mode !== 'view') {
|
||||||
|
// remember the view-mode viewport: whatever zooming happens inside the
|
||||||
|
// editors is a working tool, not what the user wants to see afterwards
|
||||||
|
const v = this._view;
|
||||||
|
this._viewModeSnap = {
|
||||||
|
space: this._space,
|
||||||
|
zoom: this._zoom,
|
||||||
|
cx: v ? v.x + v.w / 2 : undefined,
|
||||||
|
cy: v ? v.y + v.h / 2 : undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
this._mode = mode;
|
this._mode = mode;
|
||||||
if (baseChanges) {
|
if (baseChanges) {
|
||||||
// refit against the new base: the editors measure from the full square,
|
// refit against the new base: the editors measure from the full square,
|
||||||
@@ -1865,6 +1882,22 @@ class HouseplanCard extends LitElement {
|
|||||||
this._zoom = 1;
|
this._zoom = 1;
|
||||||
this._view = null; // updated() refits on the next frame
|
this._view = null; // updated() refits on the next frame
|
||||||
}
|
}
|
||||||
|
if (mode === 'view') {
|
||||||
|
const snap = this._viewModeSnap;
|
||||||
|
this._viewModeSnap = null;
|
||||||
|
// restore only for the space the snapshot was taken in — after a space
|
||||||
|
// switch inside the editor the saved per-space zoom already applies
|
||||||
|
if (snap && snap.space === this._space) {
|
||||||
|
this._zoom = snap.zoom;
|
||||||
|
this._view = null;
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
if (!this._stageEl || this._mode !== 'view' || this._space !== snap.space) return;
|
||||||
|
this._applyView(snap.zoom, snap.cx, snap.cy);
|
||||||
|
this._saveZoom(); // editor wheel zoom wrote itself to LS_ZOOM — put the view zoom back
|
||||||
|
this.requestUpdate();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
this._path = [];
|
this._path = [];
|
||||||
this._cursorPt = null;
|
this._cursorPt = null;
|
||||||
this._tool = 'draw';
|
this._tool = 'draw';
|
||||||
|
|||||||
Reference in New Issue
Block a user