Move the dot outside the grid.

This commit is contained in:
Conrad Nelson 2025-12-17 10:36:42 -06:00
parent e8d9d1a330
commit c5cc368ef9

View file

@ -37,6 +37,11 @@
margin: 0 auto; margin: 0 auto;
} }
#dot {
transform: translate(-50%, -50%);
z-index: 10000;
pointer-events: none;
}
{% endblock %} {% endblock %}
{% block main %} {% block main %}
@ -48,7 +53,7 @@
<input type="number" min="1" value="25" name="cellSize" id="cellSize" class="form-control form-control-sm"> <input type="number" min="1" value="25" name="cellSize" id="cellSize" class="form-control form-control-sm">
<span class="input-group-text">Fill Opacity:</span> <span class="input-group-text">Fill Opacity:</span>
<input type="number" min="0" max="1" step=".01" value="0.15" name="fillOpacity" id="fillOpacity" <input type="number" min="0" max="1" step=".01" value="1" name="fillOpacity" id="fillOpacity"
class="form-control form-control-sm"> class="form-control form-control-sm">
</div> </div>
<div class="vr mx-1"></div> <div class="vr mx-1"></div>
@ -171,13 +176,12 @@
</div> </div>
</div> </div>
<div id="gridWrap"> <div id="gridWrap">
<div id="grid" class="position-relative overflow-hidden">
<span id="dot" class="position-absolute p-0 m-0 d-none"> <span id="dot" class="position-absolute p-0 m-0 d-none">
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" id="dotSVG"> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" id="dotSVG">
<circle cx="16" cy="16" r="4" fill="black" /> <circle cx="16" cy="16" r="4" fill="black" />
</svg> </svg>
</span> </span>
<div id="grid" class="position-relative overflow-hidden">
<div id="coords" <div id="coords"
class="border border-black position-absolute d-none bg-warning-subtle px-1 py-0 user-select-none"></div> class="border border-black position-absolute d-none bg-warning-subtle px-1 py-0 user-select-none"></div>
<canvas id="overlay" class="position-absolute w-100 h-100"></canvas> <canvas id="overlay" class="position-absolute w-100 h-100"></canvas>
@ -215,7 +219,7 @@ let dotSize = Math.floor(Math.max(cellSize * 1.25, 32));
let ctx; let ctx;
let dpr = 1; let dpr = 1;
let selectedColor; let selectedColor;
let currentOpacity = clamp01(fillOpacityEl?.value ?? 0.15, 0.15); let currentOpacity = clamp01(fillOpacityEl?.value ?? 1, 1);
let currentShape = null; let currentShape = null;
const history = [structuredClone(shapes)]; const history = [structuredClone(shapes)];
@ -268,7 +272,7 @@ function commit(nextShapes) {
redrawAll(); redrawAll();
} }
function clamp01(n, fallback = 0.15) { function clamp01(n, fallback = 1) {
const x = Number(n); const x = Number(n);
return Number.isFinite(x) ? Math.min(1, Math.max(0, x)) : fallback; return Number.isFinite(x) ? Math.min(1, Math.max(0, x)) : fallback;
} }
@ -281,7 +285,7 @@ function sanitizeShapes(list) {
return list.flatMap((s) => { return list.flatMap((s) => {
if (!s || typeof s !== 'object' || !allowed.has(s.type)) return []; if (!s || typeof s !== 'object' || !allowed.has(s.type)) return [];
const color = typeof s.color === 'string' ? s.color : '#000000'; const color = typeof s.color === 'string' ? s.color : '#000000';
const opacity = clamp01(s.opacity, 0.15); const opacity = clamp01(s.opacity, 1);
if (s.type === 'line') { if (s.type === 'line') {
if (!['x1','y1','x2','y2'].every(k => isFiniteNum(s[k]))) return []; if (!['x1','y1','x2','y2'].every(k => isFiniteNum(s[k]))) return [];
@ -446,7 +450,7 @@ function normalizeRect(shape) {
h: Math.abs(y2 - y1), h: Math.abs(y2 - y1),
color: shape.color, color: shape.color,
fill: shape.fill, fill: shape.fill,
opacity: clamp01(shape.opacity, 0.15) opacity: clamp01(shape.opacity, 1)
}; };
} }
@ -522,7 +526,7 @@ function drawShape(shape) {
} }
if (shape.fill) { if (shape.fill) {
ctx.globalAlpha = clamp01(shape.opacity, 0.15); ctx.globalAlpha = clamp01(shape.opacity, 1);
ctx.fillStyle = shape.color; ctx.fillStyle = shape.color;
if (shape.type === 'rect') { if (shape.type === 'rect') {
ctx.fillRect(x, y, w, h); ctx.fillRect(x, y, w, h);
@ -702,11 +706,11 @@ document.addEventListener('keydown', (e) => {
}); });
fillOpacityEl?.addEventListener('input', () => { fillOpacityEl?.addEventListener('input', () => {
currentOpacity = clamp01(fillOpacityEl.value, 0.15); currentOpacity = clamp01(fillOpacityEl.value, 0);
}); });
fillOpacityEl?.addEventListener('change', () => { fillOpacityEl?.addEventListener('change', () => {
currentOpacity = clamp01(fillOpacityEl.value, 0.15); currentOpacity = clamp01(fillOpacityEl.value, 0);
}); });
gridEl.addEventListener('pointercancel', () => { gridEl.addEventListener('pointercancel', () => {
@ -724,16 +728,19 @@ gridEl.addEventListener('pointermove', (e) => {
const { ix, iy, x: snapX, y: snapY, localX, localY } = snapToGrid(e.clientX, e.clientY); const { ix, iy, x: snapX, y: snapY, localX, localY } = snapToGrid(e.clientX, e.clientY);
const renderX = snapX - dotSize / 2;
const renderY = snapY - dotSize / 2;
coordsEl.classList.remove('d-none'); coordsEl.classList.remove('d-none');
if (getActiveType() !== 'noGrid') { if (getActiveType() !== 'noGrid') {
dotEl.classList.remove('d-none'); dotEl.classList.remove('d-none');
dotEl.style.top = `${renderY}px`;
dotEl.style.left = `${renderX}px`; const gridRect = gridEl.getBoundingClientRect();
const wrapRect = gridWrapEl.getBoundingClientRect();
const offsetX = gridRect.left - wrapRect.left;
const offsetY = gridRect.top - wrapRect.top;
dotEl.style.left = `${offsetX + snapX}px`;
dotEl.style.top = `${offsetY + snapY}px`;
} }
if (getActiveType() == 'noGrid') { if (getActiveType() == 'noGrid') {