Add grid scaling.

This commit is contained in:
Yaro Kasear 2025-12-12 11:21:18 -06:00
parent 0992cf97eb
commit 3f4aee73a3

View file

@ -24,6 +24,11 @@
top: 10px;
transform: translateX(-50%);
z-index: 10000;
max-width: calc(100% - 20px);
}
#toolBar::-webkit-scrollbar {
height: 8px;
}
#coords {
@ -43,7 +48,12 @@
<div class="container">
<div id="grid" class="position-relative overflow-hidden">
<div id="toolBar"
class="btn-toolbar bg-light position-absolute border border-secondary-subtle rounded start-50 p-1">
class="btn-toolbar bg-light position-absolute border border-secondary-subtle rounded start-50 p-1 align-items-center flex-nowrap overflow-auto">
<div class="input-group input-group-sm w-auto">
<span class="input-group-text">Grid Size:</span>
<input type="number" min="1" value="{{ grid_size }}" name="gridSize" id="gridSize" class="form-control form-control-sm">
</div>
<div class="vr mx-1"></div>
<input type="color" class="form-control form-control-sm form-control-color" id="color">
<div class="vr mx-1"></div>
<div class="btn-group">
@ -188,6 +198,10 @@ 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');
let gridSize = Number(gridSizeEl.value) || {{ grid_size }};
let dotSize = Math.floor(Math.max(gridSize * 1.25, 32));
let ctx;
let dpr = 1;
@ -214,8 +228,24 @@ window.addEventListener('resize', resizeAndSetupCanvas);
setGrid();
function applyGridSize(newSize) {
const n = Number(newSize);
if (!Number.isFinite(n) || n < 1) return;
gridSize = n;
document.documentElement.style.setProperty('--grid', `${gridSize}px`);
dotSize = Math.floor(Math.max(gridSize * 1.25, 32));
dotSVGEl.setAttribute('width', dotSize);
dotSVGEl.setAttribute('height', dotSize);
setGrid();
resizeAndSetupCanvas();
}
function pxToGrid(v) {
return v / {{ grid_size }};
return v / gridSize;
}
function getActiveTool() {
@ -252,7 +282,7 @@ function snapToGrid(x, y) {
const localX = clampedX - rect.left;
const localY = clampedY - rect.top;
const grid = {{ grid_size }};
const grid = gridSize;
const maxIx = Math.floor(rect.width / grid);
const maxIy = Math.floor(rect.height / grid);
@ -342,7 +372,7 @@ function redrawAll() {
function drawShape(shape) {
if (!ctx) return;
const toPx = (v) => v * {{ grid_size }};
const toPx = (v) => v * gridSize;
ctx.save();
ctx.strokeStyle = shape.color || '#000000';
@ -415,7 +445,6 @@ function saveShapes() {
}
function setGrid() {
const gridSize = {{ grid_size }};
const type = getActiveType();
gridEl.style.backgroundImage = "";
@ -472,6 +501,9 @@ document.querySelectorAll('input[name="gridType"]').forEach(input => {
});
});
gridSizeEl.addEventListener('input', () => applyGridSize(gridSizeEl.value));
gridSizeEl.addEventListener('change', () => applyGridSize(gridSizeEl.value));
importButtonEl.addEventListener('click', () => importEl.click());
importEl.addEventListener('change', (e) => {
@ -482,6 +514,12 @@ importEl.addEventListener('change', (e) => {
reader.onload = () => {
try {
const data = JSON.parse(reader.result);
if (data.gridSize) {
gridSizeEl.value = data.gridSize;
applyGridSize(data.gridSize);
}
const loadedShapes = Array.isArray(data) ? data : data.shapes;
if (!Array.isArray(loadedShapes)) return;
@ -498,7 +536,7 @@ importEl.addEventListener('change', (e) => {
exportEl.addEventListener('click', () => {
const payload = {
version: 1,
gridSize: {{ grid_size }},
gridSize: gridSize,
shapes
};
const blob = new Blob([JSON.stringify(payload, null, 2)], { type: 'application/json' });
@ -543,13 +581,16 @@ 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);
const renderX = snapX - {{ dot_size }} / 2;
const renderY = snapY - {{ dot_size }} / 2;
const renderX = snapX - dotSize / 2;
const renderY = snapY - dotSize / 2;
coordsEl.classList.remove('d-none');