From 641ae1470df51ddd40a3fca728eda5fc13d0bfe8 Mon Sep 17 00:00:00 2001 From: Yaro Kasear Date: Tue, 16 Dec 2025 15:22:23 -0600 Subject: [PATCH] Opacity added. --- inventory/templates/testing.html | 107 ++++++++++++++++++------------- 1 file changed, 64 insertions(+), 43 deletions(-) diff --git a/inventory/templates/testing.html b/inventory/templates/testing.html index b4c9076..1a23a81 100644 --- a/inventory/templates/testing.html +++ b/inventory/templates/testing.html @@ -44,11 +44,11 @@
- Grid Size: - + Cell Size: + Fill Opacity: -
@@ -187,7 +187,7 @@ {% endblock %} {% block script %} -const DEFAULT_DOC = { version: 1, gridSize: 25, shapes: [] }; +const DEFAULT_DOC = { version: 1, cellSize: 25, shapes: [] }; const canvasEl = document.getElementById('overlay'); const clearEl = document.getElementById('clear'); @@ -199,18 +199,20 @@ const exportEl = document.getElementById('export'); const gridEl = document.getElementById('grid'); const importButtonEl = document.getElementById('importButton'); const importEl = document.getElementById('import'); -const gridSizeEl = document.getElementById('gridSize'); +const cellSizeEl = document.getElementById('cellSize'); const gridWrapEl = document.getElementById('gridWrap'); const toolBarEl = document.getElementById('toolBar'); +const fillOpacityEl = document.getElementById('fillOpacity'); let doc = loadDoc(); -let gridSize = Number(doc.gridSize) || 25; -gridSizeEl.value = gridSize; -let dotSize = Math.floor(Math.max(gridSize * 1.25, 32)); +let cellSize = Number(doc.cellSize) || 25; +cellSizeEl.value = cellSize; +let dotSize = Math.floor(Math.max(cellSize * 1.25, 32)); let ctx; let dpr = 1; let selectedColor; +let currentOpacity = clamp01(fillOpacity?.value ?? 0.15, 0.15); let currentShape = null; let shapes = Array.isArray(doc.shapes) ? doc.shapes : []; @@ -218,7 +220,7 @@ let shapes = Array.isArray(doc.shapes) ? doc.shapes : []; let sizingRAF = 0; let lastApplied = { w: 0, h: 0 }; -const ro = new ResizeObserver(scheduleSnappedGridSize); +const ro = new ResizeObserver(scheduleSnappedcellSize); ro.observe(gridWrapEl); const savedTool = localStorage.getItem('gridTool'); @@ -235,7 +237,12 @@ resizeAndSetupCanvas(); window.addEventListener('resize', resizeAndSetupCanvas); setGrid(); -scheduleSnappedGridSize(); +scheduleSnappedcellSize(); + +function clamp01(n, fallback = 0.15) { + const x = Number(n); + return Number.isFinite(x) ? Math.min(1, Math.max(0, x)) : fallback; +} function isFiniteNum(n) { return Number.isFinite(Number(n)); } @@ -248,6 +255,9 @@ function sanitizeShapes(list) { if (!s.color) s.color = '#000000'; + if (s.opacity == null) s.opacity = 0.15; + s.opacity = clamp01(s.opacity, 0.15); + if (s.type === 'line') { return ['x1','y1','x2','y2'].every(k => isFiniteNum(s[k])); } else { @@ -270,10 +280,10 @@ function snapDown(n, step) { return Math.floor(n / step) * step; } -function applySnappedGridSize() { +function applySnappedcellSize() { sizingRAF = 0; - const grid = gridSize; + const grid = cellSize; if (!Number.isFinite(grid) || grid < 1) return; const w = gridWrapEl.clientWidth; @@ -294,29 +304,29 @@ function applySnappedGridSize() { resizeAndSetupCanvas(); } -function scheduleSnappedGridSize() { +function scheduleSnappedcellSize() { if (sizingRAF) return; - sizingRAF = requestAnimationFrame(applySnappedGridSize); + sizingRAF = requestAnimationFrame(applySnappedcellSize); } -function applyGridSize(newSize) { +function applycellSize(newSize) { const n = Number(newSize); if (!Number.isFinite(n) || n < 1) return; - gridSize = n; - saveDoc({ ...doc, shapes, gridSize }); + cellSize = n; + saveDoc({ ...doc, shapes, cellSize }); - dotSize = Math.floor(Math.max(gridSize * 1.25, 32)); + dotSize = Math.floor(Math.max(cellSize * 1.25, 32)); dotSVGEl.setAttribute('width', dotSize); dotSVGEl.setAttribute('height', dotSize); setGrid(); - scheduleSnappedGridSize(); + scheduleSnappedcellSize(); } function pxToGrid(v) { - return v / gridSize; + return v / cellSize; } function getActiveTool() { @@ -348,7 +358,7 @@ function setActiveType(typeId) { function snapToGrid(x, y) { /* Shapes are stored in grid units (document units), not pixels. - 1 unit renders as gridSize pixels, so changing gridSize rescales (zooms) the whole drawing. + 1 unit renders as cellSize pixels, so changing cellSize rescales (zooms) the whole drawing. Grid modes only affect snapping/visuals; storage is always in document units for portability. */ @@ -359,7 +369,7 @@ function snapToGrid(x, y) { const localX = clampedX - rect.left; const localY = clampedY - rect.top; - const grid = gridSize; + const grid = cellSize; const maxIx = Math.floor(rect.width / grid); const maxIy = Math.floor(rect.height / grid); @@ -402,7 +412,8 @@ function normalizeRect(shape) { w: Math.abs(x2 - x1), h: Math.abs(y2 - y1), color: shape.color, - fill: shape.fill + fill: shape.fill, + opacity: clamp01(shape.opacity, 0.15) }; } @@ -456,7 +467,7 @@ function redrawAll() { function drawShape(shape) { if (!ctx) return; - const toPx = (v) => v * gridSize; + const toPx = (v) => v * cellSize; ctx.save(); ctx.strokeStyle = shape.color || '#000000'; @@ -478,7 +489,7 @@ function drawShape(shape) { } if (shape.fill) { - ctx.globalAlpha = 0.15; + ctx.globalAlpha = clamp01(shape.opacity, 0.15); ctx.fillStyle = shape.color; if (shape.type === 'rect') { ctx.fillRect(x, y, w, h); @@ -524,13 +535,13 @@ function setGrid() { gridEl.style.backgroundImage = "linear-gradient(to right, #ccc 1px, transparent 1px)," + "linear-gradient(to bottom, #ccc 1px, transparent 1px)"; - gridEl.style.backgroundSize = `${gridSize}px ${gridSize}px`; + gridEl.style.backgroundSize = `${cellSize}px ${cellSize}px`; gridEl.style.boxShadow = "inset 0 0 0 1px #ccc"; // full frame } else if (type === 'horizontalGrid') { gridEl.style.backgroundImage = "linear-gradient(to bottom, #ccc 1px, transparent 1px)"; - gridEl.style.backgroundSize = `100% ${gridSize}px`; + gridEl.style.backgroundSize = `100% ${cellSize}px`; // left + right borders only gridEl.style.boxShadow = @@ -539,7 +550,7 @@ function setGrid() { } else if (type === 'verticalGrid') { gridEl.style.backgroundImage = "linear-gradient(to right, #ccc 1px, transparent 1px)"; - gridEl.style.backgroundSize = `${gridSize}px 100%`; + gridEl.style.backgroundSize = `${cellSize}px 100%`; // top + bottom borders only gridEl.style.boxShadow = @@ -570,8 +581,8 @@ document.querySelectorAll('input[name="gridType"]').forEach(input => { }); }); -gridSizeEl.addEventListener('input', () => applyGridSize(gridSizeEl.value)); -gridSizeEl.addEventListener('change', () => applyGridSize(gridSizeEl.value)); +cellSizeEl.addEventListener('input', () => applycellSize(cellSizeEl.value)); +cellSizeEl.addEventListener('change', () => applycellSize(cellSizeEl.value)); importButtonEl.addEventListener('click', () => importEl.click()); @@ -584,9 +595,9 @@ importEl.addEventListener('change', (e) => { try { const data = JSON.parse(reader.result); - if (Number.isFinite(Number(data.gridSize)) && Number(data.gridSize) >= 1) { - gridSizeEl.value = data.gridSize; - applyGridSize(data.gridSize); + if (Number.isFinite(Number(data.cellSize)) && Number(data.cellSize) >= 1) { + cellSizeEl.value = data.cellSize; + applycellSize(data.cellSize); } const loadedShapes = Array.isArray(data) ? data : data.shapes; @@ -596,7 +607,7 @@ importEl.addEventListener('change', (e) => { doc = { version: Number(data?.version) || 1, - gridSize: Number(data?.gridSize) || gridSize, + cellSize: Number(data?.cellSize) || cellSize, shapes }; @@ -612,7 +623,7 @@ importEl.addEventListener('change', (e) => { exportEl.addEventListener('click', () => { const payload = { version: 1, - gridSize: gridSize, + cellSize: cellSize, shapes }; const blob = new Blob([JSON.stringify(payload, null, 2)], { type: 'application/json' }); @@ -625,11 +636,11 @@ exportEl.addEventListener('click', () => { }); clearEl.addEventListener('click', () => { - gridSize = 25; + cellSize = 25; shapes = []; - saveDoc({...doc, shapes, gridSize}); - gridSizeEl.value = 25; - applyGridSize(25); + saveDoc({...doc, shapes, cellSize}); + cellSizeEl.value = 25; + applycellSize(25); redrawAll(); }); @@ -648,7 +659,7 @@ document.addEventListener('keydown', (e) => { e.preventDefault(); if (shapes.length > 0) { shapes.pop(); - saveDoc({ ...doc, shapes, gridSize }); + saveDoc({ ...doc, shapes, cellSize }); redrawAll(); } } @@ -659,6 +670,14 @@ document.addEventListener('keydown', (e) => { } }); +fillOpacityEl?.addEventListener('input', () => { + currentOpacity = clamp01(fillOpacityEl.value, 0.15); +}); + +fillOpacityEl?.addEventListener('change', () => { + currentOpacity = clamp01(fillOpacityEl.value, 0.15); +}); + gridEl.addEventListener('pointercancel', () => { currentShape = null; redrawAll(); @@ -766,7 +785,8 @@ gridEl.addEventListener('pointerdown', (e) => { x2: snapX, y2: snapY, color: selectedColor, - fill: (tool === 'filled' || tool === 'filledEllipse') + fill: (tool === 'filled'), + opacity: currentOpacity }; } else if (tool === 'outlineEllipse' || tool === 'filledEllipse') { currentShape = { @@ -776,7 +796,8 @@ gridEl.addEventListener('pointerdown', (e) => { x2: snapX, y2: snapY, color: selectedColor, - fill: (tool === 'filledEllipse') + fill: (tool === 'filledEllipse'), + opacity: currentOpacity }; } }); @@ -814,7 +835,7 @@ window.addEventListener('pointerup', (e) => { if (finalShape) { shapes.push(finalShape); - saveDoc({...doc, shapes, gridSize}); + saveDoc({...doc, shapes, cellSize}); } clearCanvas();