www.spaceplanner.app

Web client to the spaceplanner API
git clone git://jacobedwards.org/www.spaceplanner.app
Log | Files | Refs

commit 703b2b6fd2e69e997647fe358a36308d653f42c0
parent 36f939973f6c38d4476da30448abef2f73cbcd37
Author: Jacob R. Edwards <jacob@jacobedwards.org>
Date:   Thu, 10 Oct 2024 11:42:02 -0700

Update backend mapPoints method

It now takes a parameters argument along with the ID of the map to
update like furniture maps. It uses a new method updatedObject to
validate parameters and build to new object. In the future I want
all these functions function the same way using this updatedObject
method.

While it should have been a separate commit, the precisePointHandler
function was also updated so fix some issues with the snapmap stuff,
which led to the changes described above.

Diffstat:
Mfiles/floorplans/floorplan/backend.js | 85++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Mfiles/floorplans/floorplan/editor.js | 12+++++++++---
Mfiles/floorplans/floorplan/main.js | 94++++++++++++++++++++++++++++++++-----------------------------------------------
3 files changed, 110 insertions(+), 81 deletions(-)

diff --git a/files/floorplans/floorplan/backend.js b/files/floorplans/floorplan/backend.js @@ -489,31 +489,40 @@ export class FloorplanBackend { } } - // Returns map id - mapPoints(type, a, b, options) { - options = options ?? {} - if (type != "wall" && type != "door") { - throw new Error("Only walls and doors allowed in pointmap so far") - } - if (!this.cache.points[a] || !this.cache.points[b]) { - throw new Error(`${a}, ${b}: Pointmap must reference existing points`) + mapPoints(params, id) { + const backend = this + const validPoint = function(id) { + return idType(id) === "pnt" && backend.obj(id) } - let d = { - type: type, - a: a, - b: b - } - if (options.door_swing != null) { - switch (options.door_swing) { - case "a+": case "a-": case "b+": case "b-": - break; - default: - throw new Error(options.door_swing + ": Invalid door swing") + const m = this.updatedObject(params, id, { + type: { + required: true, + validate: function(type) { + return type === "wall" || type === "door" + } + }, + a: { + required: true, + validate: validPoint + }, + b: { + required: true, + validate: validPoint + }, + door_swing: { + validate: function(swing) { + switch (swing) { + case "a+": case "a-": case "b+": case "b-": + return true + default: + return false + } + } } - d.door_swing = options.door_swing - } - return this.addData(this.whichPointMap(a, b) ?? "pointmaps", d, options) + }) + + this.addData(this.whichPointMap(m.a, m.b) ?? "pointmaps", m) } unmapPoints(id, options) { @@ -639,6 +648,38 @@ export class FloorplanBackend { return this.mapFurniture(params, id) } + updatedObject(params, id, vd) { + let obj = id ? structuredClone(this.reqObj(id)) : {} + + for (let k in vd) { + let vdk = vd[k] + if (vdk.required && params[k] === null) { + throw new Error(`Cannot delete required parameter ("${k}")`) + } + if (params[k] === undefined) { + continue + } + if (typeof vdk.parse === "function") { + obj[k] = vdk.parse(params[k]) + } else if (typeof vdk.validate === "function") { + if (!vdk.validate(params[k])) { + throw new Error(`Invalid value for "${k}" parameter ("${params[k]}")`) + } + obj[k] = params[k] + } else { + throw new Error(`"${k}" parameter missing validate or parse function`) + } + } + + for (let k in vd) { + if (vd[k].required && obj[k] == null) { + throw new Error(`Cannot omit required parameter ("${k}")`) + } + } + + return obj + } + reqObj(id) { let obj = this.obj(id) if (obj == null) { diff --git a/files/floorplans/floorplan/editor.js b/files/floorplans/floorplan/editor.js @@ -585,11 +585,17 @@ export class FloorplanEditor { mapSelected(type) { let points = this.selectedPoints() - return this.mapPoints(type, points.a, points.b) + return this.mapPoints({ type, a: points.a, b: points.b }) } - mapPoints(type, p1, p2) { - return this.backend.mapPoints(type, getID(p1, "points"), getID(p2, "points")) + mapPoints(params, id) { + if (params.a) { + params.a = getID(params.a, "points") + } + if (params.b) { + params.b = getID(params.b, "points") + } + return this.backend.mapPoints(params, id) } addFurniture(params, id) { diff --git a/files/floorplans/floorplan/main.js b/files/floorplans/floorplan/main.js @@ -275,29 +275,30 @@ function selectHandler(event, editor, state) { userLength(editor, editor.pointmapLength(groups.pntmap[0])))) } - let maps = [] if (groups.pntmap !== undefined) { + let maps = {} for (let i = 0; i < groups.pntmap.length; ++i) { - maps.push(editor.backend.cache.pointmaps[groups.pntmap[i]]) + maps[groups.pntmap[i]] = editor.backend.cache.pointmaps[groups.pntmap[i]] } - } - - if (maps.length > 0) { - const changeTypes = function(newvalue) { - for (let i in maps) { - editor.mapPoints(newvalue, maps[i].a, maps[i].b) + if (groups.pntmap.length > 0) { + const changeTypes = function(newvalue) { + for (let id in maps) { + editor.mapPoints({ type: newvalue }, id) + } } - } - let current = maps[0].type - for (let i = 0; i < maps.length; ++i) { - if (current !== maps[i].type) { - current = null - break; + let current + for (let id in maps) { + if (current === undefined) { + current = maps[id].type + } else if (current !== maps[i].type) { + current = null + break; + } } + c.appendChild( + selector({ wall: true, door: true }, changeTypes, { current, text: "Type:" }) + ) } - c.appendChild( - selector({ wall: true, door: true }, changeTypes, { current, text: "Type:" }) - ) } let fmaps = ids.filter(function(item) { return backend.idType(item) === "furmap" }) @@ -537,6 +538,7 @@ function precisePointHandler(event, editor, state) { } }) } + const cleanup = function() { if (state.moveTimeout != null) { clearTimeout(state.moveTimeout) @@ -548,58 +550,30 @@ function precisePointHandler(event, editor, state) { delete state[i] } } + const updatePoint = function(p, options) { options = options ?? {} - if (state.snapmap == null) { - editor.movePoint(state.to, p) - } - let points = editor.thingsAt(p, "#points") let fid = lib.getID(state.from) - let tid - if (state.snapmap == null) { - tid = lib.getID(state.to) - } - let instead + let tid = lib.getID(state.to) + delete state.onPoint for (let i in points) { let id = lib.getID(points[i]) if (id !== tid && id !== fid) { - instead = id + state.onPoint = id + p = editor.backend.obj(id) } } - if (instead != undefined) { - if (instead !== state.to) { - if (state.snapmap == null) { - editor.remove(state.to) - } else { - editor.remove(state.snapmap) - } - state.to = editor.findObj(instead) - if (state.removeSnapmap == undefined) { - state.removeSnapmap = editor.backend.whichPointMap( - lib.getID(state.from), lib.getID(state.to) - ) == null - } - state.snapmap = editor.mapPoints("wall", state.from, state.to) - } - } else if (state.snapmap != null) { - if (state.removeSnapmap) { - editor.remove(state.snapmap) - delete state.removeSnapmap - } - state.snapmap = null - state.to = editor.addPoint(p, true) - editor.mapPoints("wall", state.from, state.to) - state.to = editor.findObj(state.to) - } + editor.movePoint(state.to, p) if (!options.leave_input) { unitInput(editor, state.len, editor.units.snapTo(state.origin.distanceTo(p), editor.unit)) } } + const doMove = function() { const ad = function(a, b) { return Math.abs(a - b) @@ -639,6 +613,7 @@ function precisePointHandler(event, editor, state) { } updatePoint(snapped) } + const revert = function() { /* * NOTE: WARNING: If allowing asyncronous edits this would be bad @@ -651,7 +626,14 @@ function precisePointHandler(event, editor, state) { editor.undo() cleanup() } + const commit = function() { + if (state.onPoint) { + for (let oth in editor.backend.mappedPoints[state.to]) { + editor.mapPoints({ a: state.onPoint, b: oth }, editor.backend.mappedPoints[state.to][oth]) + } + editor.remove(state.to) + } editor.finishAction() cleanup() } @@ -705,7 +687,7 @@ function precisePointHandler(event, editor, state) { } else if (event.type === "pointermove" && state.origin != undefined && state.origin.distanceTo(cursor) > 200) { state.to = editor.addPoint(cursor, true) - editor.mapPoints("wall", state.from, state.to) + editor.mapPoints({ type: "wall", a: state.from, b: state.to}) state.to = editor.findObj(state.to) init() } else { @@ -782,7 +764,7 @@ function precisePointMapHandler(event, editor, state) { } let s = (o > 0 ? "+" : "-") - editor.backend.mapPoints(state.door.type, state.door.a, state.door.b, { door_swing: state.hinge + s }) + editor.backend.mapPoints({ door_swing: state.hinge + s }, state.doorID) editor.finishAction() cleanup() return @@ -807,8 +789,8 @@ function precisePointMapHandler(event, editor, state) { } sub = editor.addPoint(sub) - editor.mapPoints("wall", data.a, sub) - editor.mapPoints("wall", sub, data.b) + editor.mapPoints({ type: "wall", a: data.a, b: sub }) + editor.mapPoints({ type: "wall", a: sub, b: data.b }) editor.remove(map) return }