commit c6dd1d4681637f9126ffd37c71619dab0392cfd1
parent 1a5f92f4702f1446558083b8f802d06cb7cc3539
Author: Jacob R. Edwards <jacob@jacobedwards.org>
Date: Sat, 17 Aug 2024 13:39:34 -0700
Add grid system
This grid generated from the editor measurement unit systems. Grid
measurements can be changed with useGrid(system), or the grid can
be hidden with useGrid(null).
Diffstat:
2 files changed, 80 insertions(+), 1 deletion(-)
diff --git a/files/floorplans/floorplan/editor.js b/files/floorplans/floorplan/editor.js
@@ -140,12 +140,36 @@ export class FloorplanEditor {
let editor = this
options.backend.callbacks.updateId = function(ids) { editor.updateId(ids) }
+
this.backend = new backend.FloorplanBackend(floorplan, options.backend)
this.updated = null // last time updated from backend
+ this.grids = {}
+ for (let system in this.units.systems) {
+ this.grids[system] = gridSystem(this, system)
+ }
+
+ this.draw.rect().attr({ id: "grid" })
+
let data = this.draw.group().attr({ id: "floorplan" })
data.group().attr({ id: "walls" }) // lines
data.group().attr({ id: "points" }) // circles
+
+ // Resize grid when appropriate
+ this.draw.on("zoom", function(event) {
+ editor.updateGrid(event.detail.box)
+ })
+ this.draw.on("panning", function(event) {
+ editor.updateGrid(event.detail.box)
+ })
+ let resize = new ResizeObserver(function(entries) {
+ if (entries[0].target != editor.draw.node) {
+ throw new Error("Expected draw node")
+ }
+ console.debug("Editor resized")
+ editor.updateGrid()
+ })
+ resize.observe(editor.draw.node)
}
addMode(name, mode) {
@@ -220,6 +244,34 @@ export class FloorplanEditor {
return this
}
+ useGrid(system) {
+ let grid = this.draw.findExactlyOne("#grid")
+ if (!system) {
+ grid.attr("visibility", "hidden")
+ } else {
+ grid.fill(this.grids[system].url()).attr("visibility", null)
+ }
+ }
+
+ updateGrid(box) {
+ let grid = this.draw.findExactlyOne("#grid")
+ if (!box) {
+ box = this.draw.viewbox()
+ }
+
+ const swap = { x: "y", y: "x", width: "height", height: "width" }
+ const map = { width: "x", height: "y" }
+
+ // Reads easy, right?
+ let real = this.draw.node.getBoundingClientRect()
+ let base = (real.width > real.height) ? "height" : "width"
+ let val = real[swap[base]] * (box[base] / real[base])
+ let diff = val - box[swap[base]]
+ box[map[swap[base]]] -= diff / 2
+ box[swap[base]] = val
+ grid.size(box.width, box.height).move(box.x, box.y)
+ }
+
// Should be called after each user "action"
finishAction() {
this.backend.newDiff()
@@ -374,7 +426,6 @@ export class FloorplanEditor {
}
}
-
function remove_mode_handlers(target, mode_handlers) {
for (let event in mode_handlers) {
for (let handler in mode_handlers[event]) {
@@ -393,6 +444,28 @@ function add_mode_handlers(target, mode_handlers) {
}
}
+function gridPattern(editor, unit, using) {
+ let n = editor.units.get(unit)
+ return editor.draw.pattern(n, n, function(on) {
+ if (using) {
+ on.rect(n, n).fill(using.url())
+ }
+ on.path(`M ${n} 0 L 0 0 0 ${n}`)
+ .fill("none")
+ .stroke({ width: n / 50, color: "grey" })
+ }).attr({ id: "grid_" + unit + "_pattern", patternUnits: "userSpaceOnUse" })
+}
+
+function gridSystem(editor, system) {
+ let unit = editor.units.systems[system]
+ let last
+
+ do {
+ last = gridPattern(editor, unit, last)
+ } while ((unit = editor.units.data[unit].next));
+ return last
+}
+
function byId(id) {
return "#" + id
}
diff --git a/files/floorplans/floorplan/main.js b/files/floorplans/floorplan/main.js
@@ -66,6 +66,7 @@ function init() {
editor.addMode(mode, modes[mode])
}
editor.useMode("testing")
+ editor.useGrid("imperial")
let toolbar = document.querySelector("header")
.appendChild(document.createElement("ul"))
@@ -77,6 +78,11 @@ function init() {
{ current: editor.mode, text: "Modes:" }
)
))
+ toolbar.append(item(
+ selector(editor, editor.grids, function(system) { editor.useGrid(system) },
+ { current: "imperial", text: "Grid systems:" }
+ )
+ ))
editor.backend.pull()
}