From 0b85715c1e8f4e6cf66d92550b954702b31f212a Mon Sep 17 00:00:00 2001 From: Yaro Kasear Date: Fri, 12 Dec 2025 12:10:14 -0600 Subject: [PATCH] Better grid resizing behavior. --- inventory/templates/testing.html | 350 ++++++++++++++++++------------- 1 file changed, 202 insertions(+), 148 deletions(-) diff --git a/inventory/templates/testing.html b/inventory/templates/testing.html index f23ea05..f8f67a2 100644 --- a/inventory/templates/testing.html +++ b/inventory/templates/testing.html @@ -2,24 +2,21 @@ {% set dot_size = [grid_size * 1.25, 32]|max|int %} {% block style %} -:root { - --grid: {{ grid_size }}px; + +#gridWrap { + width: 100%; + height: 80vh; + position: relative; } #grid { + position: relative; cursor: crosshair; - height: 80vh; width: 100%; + height: 100%; touch-action: none; } -@supports (height: calc(round(nearest, 80vh, {{ grid_size }}px))) { - #grid { - height: calc(round(nearest, 80vh, var(--grid)) + 1px); - width: calc(round(nearest, 100%, var(--grid)) + 1px); - } -} - #toolBar { top: 10px; transform: translateX(-50%); @@ -46,143 +43,145 @@ {% block main %}
-
-
-
- Grid Size: - -
-
- -
-
- - +
+
+
+
+ Grid Size: + +
+
+ +
+
+ + - - + + - - + + - - + + - - -
-
-
- - - - - - - - -
-
-
- - - - + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+ + + + + +
+
- - - - - -
-
{% endblock %} @@ -199,6 +198,7 @@ const gridEl = document.getElementById('grid'); const importButtonEl = document.getElementById('importButton'); const importEl = document.getElementById('import'); const gridSizeEl = document.getElementById('gridSize'); +const gridWrapEl = document.getElementById('gridWrap'); let gridSize = Number(gridSizeEl.value) || {{ grid_size }}; let dotSize = Math.floor(Math.max(gridSize * 1.25, 32)); @@ -210,8 +210,11 @@ let selectedColor; let currentShape = null; let shapes = loadShapes(); -const ro = new ResizeObserver(() => resizeAndSetupCanvas()); -ro.observe(gridEl); +let sizingRAF = 0; +let lastApplied = { w: 0, h: 0 }; + +const ro = new ResizeObserver(scheduleSnappedGridSize); +ro.observe(gridWrapEl); const savedTool = localStorage.getItem('gridTool'); if (savedTool) { @@ -228,12 +231,43 @@ window.addEventListener('resize', resizeAndSetupCanvas); setGrid(); +function snapDown(n, step) { + return Math.floor(n / step) * step; +} + +function applySnappedGridSize() { + sizingRAF = 0; + + const grid = gridSize; + if (!Number.isFinite(grid) || grid < 1) return; + + const w = gridWrapEl.clientWidth; + const h = gridWrapEl.clientHeight; + + const snappedW = snapDown(w, grid); + const snappedH = snapDown(h, grid); + + if (snappedW === lastApplied.w && snappedH === lastApplied.h) return; + + lastApplied = { w: snappedW, h: snappedH }; + + gridEl.style.width = `${snappedW}px`; + gridEl.style.height = `${snappedH}px`; + + resizeAndSetupCanvas(); +} + +function scheduleSnappedGridSize() { + if (sizingRAF) return; + sizingRAF = requestAnimationFrame(applySnappedGridSize); +} + function applyGridSize(newSize) { const n = Number(newSize); if (!Number.isFinite(n) || n < 1) return; gridSize = n; - document.documentElement.style.setProperty('--grid', `${gridSize}px`); + snapSizeToGrid(); dotSize = Math.floor(Math.max(gridSize * 1.25, 32)); @@ -241,7 +275,7 @@ function applyGridSize(newSize) { dotSVGEl.setAttribute('height', dotSize); setGrid(); - resizeAndSetupCanvas(); + scheduleSnappedGridSize(); } function pxToGrid(v) { @@ -274,7 +308,29 @@ function setActiveType(typeId) { } } +function snapSizeToGrid() { + const grid = gridSize; + const rect = gridEl.getBoundingClientRect(); + + const targetW = rect.width; + const targetH = rect.height; + + const snappedW = Math.floor(targetW / grid) * grid + 1; + const snappedH = Math.floor(targetH / grid) * grid + 1; + + gridEl.style.width = `${snappedW}px`; + gridEl.style.height = `${snappedH}px`; +} + function snapToGrid(x, y) { + /* + For portability, we do not allow pixel coordinates in the data model + and only use pixels for rendering. We display both spaces on the screen + to ensure no matter the mode, the user is reasoning in the same two + coordinate spaces as they need. Thus, snapping will happen even if + the tool doesn't use it. + */ + const rect = gridEl.getBoundingClientRect(); const clampedX = Math.min(Math.max(x, rect.left), rect.right); const clampedY = Math.min(Math.max(y, rect.top), rect.bottom); @@ -344,6 +400,7 @@ function normalizeLine(shape) { } function resizeAndSetupCanvas() { + snapSizeToGrid(); dpr = window.devicePixelRatio || 1; const rect = canvasEl.getBoundingClientRect(); @@ -581,9 +638,6 @@ document.addEventListener('keydown', (e) => { }); gridEl.addEventListener('pointermove', (e) => { - // Note to certain minds that keep thinking we want to mix grid and pixel coordinates. - // No. No we do not. Pixels are not portable. Stop it. - if (!ctx) return; const { ix, iy, x: snapX, y: snapY } = snapToGrid(e.clientX, e.clientY);