Configurable grid + snap-to-grid in the layout system (#45)
Build image / build-and-push (push) Successful in 7s

Closes #44. Two independent grids (garden + per-bed), each with a size and a snap toggle; snapping defaults off. See PR #45 for details.

Co-authored-by: Steve Dudenhoeffer <[email protected]>
This commit was merged in pull request #45.
This commit is contained in:
2026-07-19 07:07:14 +00:00
committed by steve
parent 9968c06243
commit e74fb308c1
23 changed files with 581 additions and 88 deletions
+37
View File
@@ -3,6 +3,9 @@ import {
clampScale,
localToWorld,
screenToWorld,
snapLocalToBedGrid,
snapPoint,
snapValue,
worldToLocal,
worldToScreen,
zoomToFitRect,
@@ -91,3 +94,37 @@ describe('zoomToFitRect', () => {
expect(fit.scale).toBe(20)
})
})
describe('grid snapping', () => {
it('snaps a scalar to the nearest multiple of the step', () => {
expect(snapValue(37, 30)).toBe(30)
expect(snapValue(46, 30)).toBe(60)
expect(snapValue(-46, 30)).toBe(-60)
expect(snapValue(15, 30)).toBe(30) // .5 rounds up
})
it('leaves a scalar unchanged for a non-positive step', () => {
expect(snapValue(37, 0)).toBe(37)
expect(snapValue(37, -5)).toBe(37)
expect(snapValue(37, NaN)).toBe(37)
})
it('snaps a world point to the origin-anchored garden grid', () => {
expect(snapPoint({ x: 37, y: -46 }, 30)).toEqual({ x: 30, y: -60 })
})
it('snaps a local point to the bed grid anchored at the top-left corner', () => {
// A 120×80 bed (halfW=60, halfH=40), 30cm grid: lines at x=-60,-30,0,30,60
// and y=-40,-10,20 (from the corner, then +30 while ≤ halfH).
expect(snapLocalToBedGrid({ x: 5, y: 2 }, 30, 60, 40)).toEqual({ x: 0, y: -10 })
expect(snapLocalToBedGrid({ x: 22, y: 18 }, 30, 60, 40)).toEqual({ x: 30, y: 20 })
})
it('clamps a snapped bed point back inside the bed bounds', () => {
// Near the far corner, rounding would land at x=90 (> halfW=60); clamp to 60.
const p = snapLocalToBedGrid({ x: 100, y: 100 }, 30, 60, 40)
expect(p.x).toBeLessThanOrEqual(60)
expect(p.y).toBeLessThanOrEqual(40)
expect(p.x).toBeGreaterThanOrEqual(-60)
})
})