Add grid scaling.
This commit is contained in:
parent
0992cf97eb
commit
3f4aee73a3
1 changed files with 51 additions and 10 deletions
|
|
@ -24,6 +24,11 @@
|
||||||
top: 10px;
|
top: 10px;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
|
max-width: calc(100% - 20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#toolBar::-webkit-scrollbar {
|
||||||
|
height: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#coords {
|
#coords {
|
||||||
|
|
@ -43,7 +48,12 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div id="grid" class="position-relative overflow-hidden">
|
<div id="grid" class="position-relative overflow-hidden">
|
||||||
<div id="toolBar"
|
<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">
|
<input type="color" class="form-control form-control-sm form-control-color" id="color">
|
||||||
<div class="vr mx-1"></div>
|
<div class="vr mx-1"></div>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
|
|
@ -188,6 +198,10 @@ const exportEl = document.getElementById('export');
|
||||||
const gridEl = document.getElementById('grid');
|
const gridEl = document.getElementById('grid');
|
||||||
const importButtonEl = document.getElementById('importButton');
|
const importButtonEl = document.getElementById('importButton');
|
||||||
const importEl = document.getElementById('import');
|
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 ctx;
|
||||||
let dpr = 1;
|
let dpr = 1;
|
||||||
|
|
@ -214,8 +228,24 @@ window.addEventListener('resize', resizeAndSetupCanvas);
|
||||||
|
|
||||||
setGrid();
|
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) {
|
function pxToGrid(v) {
|
||||||
return v / {{ grid_size }};
|
return v / gridSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActiveTool() {
|
function getActiveTool() {
|
||||||
|
|
@ -252,7 +282,7 @@ function snapToGrid(x, y) {
|
||||||
const localX = clampedX - rect.left;
|
const localX = clampedX - rect.left;
|
||||||
const localY = clampedY - rect.top;
|
const localY = clampedY - rect.top;
|
||||||
|
|
||||||
const grid = {{ grid_size }};
|
const grid = gridSize;
|
||||||
const maxIx = Math.floor(rect.width / grid);
|
const maxIx = Math.floor(rect.width / grid);
|
||||||
const maxIy = Math.floor(rect.height / grid);
|
const maxIy = Math.floor(rect.height / grid);
|
||||||
|
|
||||||
|
|
@ -342,7 +372,7 @@ function redrawAll() {
|
||||||
function drawShape(shape) {
|
function drawShape(shape) {
|
||||||
if (!ctx) return;
|
if (!ctx) return;
|
||||||
|
|
||||||
const toPx = (v) => v * {{ grid_size }};
|
const toPx = (v) => v * gridSize;
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.strokeStyle = shape.color || '#000000';
|
ctx.strokeStyle = shape.color || '#000000';
|
||||||
|
|
@ -415,7 +445,6 @@ function saveShapes() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setGrid() {
|
function setGrid() {
|
||||||
const gridSize = {{ grid_size }};
|
|
||||||
const type = getActiveType();
|
const type = getActiveType();
|
||||||
|
|
||||||
gridEl.style.backgroundImage = "";
|
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());
|
importButtonEl.addEventListener('click', () => importEl.click());
|
||||||
|
|
||||||
importEl.addEventListener('change', (e) => {
|
importEl.addEventListener('change', (e) => {
|
||||||
|
|
@ -482,6 +514,12 @@ importEl.addEventListener('change', (e) => {
|
||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(reader.result);
|
const data = JSON.parse(reader.result);
|
||||||
|
|
||||||
|
if (data.gridSize) {
|
||||||
|
gridSizeEl.value = data.gridSize;
|
||||||
|
applyGridSize(data.gridSize);
|
||||||
|
}
|
||||||
|
|
||||||
const loadedShapes = Array.isArray(data) ? data : data.shapes;
|
const loadedShapes = Array.isArray(data) ? data : data.shapes;
|
||||||
if (!Array.isArray(loadedShapes)) return;
|
if (!Array.isArray(loadedShapes)) return;
|
||||||
|
|
||||||
|
|
@ -498,7 +536,7 @@ importEl.addEventListener('change', (e) => {
|
||||||
exportEl.addEventListener('click', () => {
|
exportEl.addEventListener('click', () => {
|
||||||
const payload = {
|
const payload = {
|
||||||
version: 1,
|
version: 1,
|
||||||
gridSize: {{ grid_size }},
|
gridSize: gridSize,
|
||||||
shapes
|
shapes
|
||||||
};
|
};
|
||||||
const blob = new Blob([JSON.stringify(payload, null, 2)], { type: 'application/json' });
|
const blob = new Blob([JSON.stringify(payload, null, 2)], { type: 'application/json' });
|
||||||
|
|
@ -543,13 +581,16 @@ document.addEventListener('keydown', (e) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
gridEl.addEventListener('pointermove', (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;
|
if (!ctx) return;
|
||||||
|
|
||||||
const { ix, iy, x: snapX, y: snapY } = snapToGrid(e.clientX, e.clientY);
|
const { ix, iy, x: snapX, y: snapY } = snapToGrid(e.clientX, e.clientY);
|
||||||
|
|
||||||
|
|
||||||
const renderX = snapX - {{ dot_size }} / 2;
|
const renderX = snapX - dotSize / 2;
|
||||||
const renderY = snapY - {{ dot_size }} / 2;
|
const renderY = snapY - dotSize / 2;
|
||||||
|
|
||||||
coordsEl.classList.remove('d-none');
|
coordsEl.classList.remove('d-none');
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue