floor-editor-ts 1.1.0 โ†’ 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -61678,27 +61678,32 @@ var persons = [];
61678
61678
  var lastSpawnTime = 0;
61679
61679
  var SPAWN_INTERVAL = 1e3;
61680
61680
  var MAX_PERSONS = 20;
61681
- var getHeatmapColor = (t, alpha = 1) => {
61681
+ function getHeatmapColor(t, alpha = 1) {
61682
61682
  t = Math.max(0, Math.min(t, 1));
61683
61683
  let r, g, b;
61684
- if (t < .35) {
61685
- const k = t / .35;
61684
+ if (t < .25) {
61685
+ const k = t / .25;
61686
61686
  r = 0;
61687
- g = Math.round(120 + 135 * k);
61688
- b = Math.round(255 - 180 * k);
61689
- } else if (t < .7) {
61690
- const k = (t - .35) / .35;
61687
+ g = Math.round(100 * k);
61688
+ b = 255;
61689
+ } else if (t < .5) {
61690
+ const k = (t - .25) / .25;
61691
+ r = 0;
61692
+ g = Math.round(100 + 155 * k);
61693
+ b = Math.round(255 * (1 - k));
61694
+ } else if (t < .75) {
61695
+ const k = (t - .5) / .25;
61691
61696
  r = Math.round(255 * k);
61692
61697
  g = 255;
61693
61698
  b = 0;
61694
61699
  } else {
61695
- const k = (t - .7) / .3;
61700
+ const k = (t - .75) / .25;
61696
61701
  r = 255;
61697
- g = Math.round(255 - 255 * k);
61702
+ g = Math.round(255 * (1 - k));
61698
61703
  b = 0;
61699
61704
  }
61700
61705
  return `rgba(${r}, ${g}, ${b}, ${alpha})`;
61701
- };
61706
+ }
61702
61707
  var drawCamera = (ctx, w, d, color, heatmapMatrix, hasPerson = false, showHeatmap = false) => {
61703
61708
  const bodyRadius = 4;
61704
61709
  const lensR = Math.min(w, d) * .25;
@@ -63867,15 +63872,15 @@ function drawAnnotations(cs, floor, selectedAnnotationId, dimSettings) {
63867
63872
  }
63868
63873
  var ROOM_FILLS_BY_TYPE = {
63869
63874
  "Living Room": "rgba(96, 165, 250, 0.08)",
63870
- "Bedroom": "rgba(167, 139, 250, 0.08)",
63871
- "Kitchen": "rgba(251, 191, 36, 0.08)",
63872
- "Bathroom": "rgba(45, 212, 191, 0.08)",
63875
+ Bedroom: "rgba(167, 139, 250, 0.08)",
63876
+ Kitchen: "rgba(251, 191, 36, 0.08)",
63877
+ Bathroom: "rgba(45, 212, 191, 0.08)",
63873
63878
  "Dining Room": "rgba(251, 146, 60, 0.08)",
63874
- "Office": "rgba(52, 211, 153, 0.08)",
63875
- "Hallway": "rgba(156, 163, 175, 0.06)",
63876
- "Closet": "rgba(244, 114, 182, 0.06)",
63877
- "Laundry": "rgba(129, 140, 248, 0.08)",
63878
- "Garage": "rgba(163, 163, 163, 0.08)"
63879
+ Office: "rgba(52, 211, 153, 0.08)",
63880
+ Hallway: "rgba(156, 163, 175, 0.06)",
63881
+ Closet: "rgba(244, 114, 182, 0.06)",
63882
+ Laundry: "rgba(129, 140, 248, 0.08)",
63883
+ Garage: "rgba(163, 163, 163, 0.08)"
63879
63884
  };
63880
63885
  var ROOM_FILLS_DEFAULT = [
63881
63886
  "rgba(167, 139, 250, 0.07)",
@@ -63897,15 +63902,15 @@ function getRoomFill(room, index) {
63897
63902
  }
63898
63903
  var ROOM_FLOOR_PATTERN = {
63899
63904
  "Living Room": "wood",
63900
- "Bedroom": "wood",
63901
- "Office": "wood",
63905
+ Bedroom: "wood",
63906
+ Office: "wood",
63902
63907
  "Dining Room": "wood",
63903
- "Hallway": "wood",
63904
- "Kitchen": "tile",
63905
- "Bathroom": "tile",
63906
- "Laundry": "tile",
63907
- "Garage": "stone",
63908
- "Closet": "none"
63908
+ Hallway: "wood",
63909
+ Kitchen: "tile",
63910
+ Bathroom: "tile",
63911
+ Laundry: "tile",
63912
+ Garage: "stone",
63913
+ Closet: "none"
63909
63914
  };
63910
63915
  function drawRoomFloorPattern(cs, room, screenPoly) {
63911
63916
  var _ROOM_FLOOR_PATTERN$r;
@@ -64175,13 +64180,19 @@ function drawMinimap(cs, minimapCanvas, floor, getWorldBBox) {
64175
64180
  mctx.lineWidth = 1;
64176
64181
  mctx.strokeRect(0, 0, mw, mh);
64177
64182
  }
64183
+ var heatmapCache = null;
64184
+ function getMatrixKey(matrix) {
64185
+ const flat = matrix.flat();
64186
+ const step = Math.max(1, Math.floor(flat.length / 20));
64187
+ return flat.filter((_, i) => i % step === 0).join(",");
64188
+ }
64178
64189
  function drawFloorHeatmap(cs, floor, heatmapMatrix, detectedRooms) {
64179
64190
  var _heatmapMatrix$;
64180
- const { ctx, zoom } = cs;
64191
+ const { ctx } = cs;
64181
64192
  const rows = heatmapMatrix.length;
64182
64193
  const cols = ((_heatmapMatrix$ = heatmapMatrix[0]) === null || _heatmapMatrix$ === void 0 ? void 0 : _heatmapMatrix$.length) || 0;
64183
64194
  if (rows === 0 || cols === 0) return;
64184
- const maxValue = Math.max(...heatmapMatrix.flat());
64195
+ const maxValue = heatmapMatrix.reduce((max, row) => row.reduce((m, v) => v > m ? v : m, max), 0);
64185
64196
  if (maxValue <= 0) return;
64186
64197
  const bounds = getFloorBounds(floor);
64187
64198
  if (!bounds) return;
@@ -64189,14 +64200,73 @@ function drawFloorHeatmap(cs, floor, heatmapMatrix, detectedRooms) {
64189
64200
  const boxW = bounds.width;
64190
64201
  const boxH = bounds.height;
64191
64202
  if (boxW <= 0 || boxH <= 0) return;
64192
- const cellW = boxW / cols;
64193
- const cellH = boxH / rows;
64203
+ const matrixKey = getMatrixKey(heatmapMatrix);
64204
+ const floorId = floor.id;
64205
+ const needsRedraw = !heatmapCache || heatmapCache.matrixKey !== matrixKey || heatmapCache.floorId !== floorId;
64206
+ const OFFSCREEN_W = 512;
64207
+ const OFFSCREEN_H = 512;
64208
+ if (needsRedraw) {
64209
+ const offCellW = OFFSCREEN_W / cols;
64210
+ const offCellH = OFFSCREEN_H / rows;
64211
+ const radius = Math.max(offCellW, offCellH) * 1.3;
64212
+ const blobCanvas = document.createElement("canvas");
64213
+ blobCanvas.width = OFFSCREEN_W;
64214
+ blobCanvas.height = OFFSCREEN_H;
64215
+ const blobCtx = blobCanvas.getContext("2d");
64216
+ blobCtx.filter = `blur(${Math.min(10, Math.max(2, radius * .2))}px)`;
64217
+ for (let y = 0; y < rows; y++) for (let x = 0; x < cols; x++) {
64218
+ const value = heatmapMatrix[y][x];
64219
+ if (!value || value <= 0) continue;
64220
+ const intensity = Math.min(value / maxValue, 1);
64221
+ const px = (x + .5) * offCellW;
64222
+ const py = (y + .5) * offCellH;
64223
+ const alpha = .5 + intensity * .45;
64224
+ const gradient = blobCtx.createRadialGradient(px, py, 0, px, py, radius);
64225
+ gradient.addColorStop(0, getHeatmapColor(intensity, alpha));
64226
+ gradient.addColorStop(.2, getHeatmapColor(intensity, alpha * .75));
64227
+ gradient.addColorStop(.5, getHeatmapColor(intensity, alpha * .25));
64228
+ gradient.addColorStop(1, getHeatmapColor(intensity, 0));
64229
+ blobCtx.fillStyle = gradient;
64230
+ blobCtx.beginPath();
64231
+ blobCtx.arc(px, py, radius, 0, Math.PI * 2);
64232
+ blobCtx.fill();
64233
+ }
64234
+ const finalCanvas = document.createElement("canvas");
64235
+ finalCanvas.width = OFFSCREEN_W;
64236
+ finalCanvas.height = OFFSCREEN_H;
64237
+ const finalCtx = finalCanvas.getContext("2d");
64238
+ finalCtx.drawImage(blobCanvas, 0, 0);
64239
+ finalCtx.filter = "none";
64240
+ finalCtx.strokeStyle = "rgba(255, 255, 255, 0.18)";
64241
+ finalCtx.lineWidth = .5;
64242
+ finalCtx.beginPath();
64243
+ for (let x = 0; x <= cols; x++) {
64244
+ const px = x * offCellW;
64245
+ finalCtx.moveTo(px, 0);
64246
+ finalCtx.lineTo(px, OFFSCREEN_H);
64247
+ }
64248
+ for (let y = 0; y <= rows; y++) {
64249
+ const py = y * offCellH;
64250
+ finalCtx.moveTo(0, py);
64251
+ finalCtx.lineTo(OFFSCREEN_W, py);
64252
+ }
64253
+ finalCtx.stroke();
64254
+ heatmapCache = {
64255
+ canvas: finalCanvas,
64256
+ matrixKey,
64257
+ floorId
64258
+ };
64259
+ }
64260
+ const p1 = wts(cs, minX, minY);
64261
+ const p2 = wts(cs, maxX, maxY);
64262
+ const destX = Math.min(p1.x, p2.x);
64263
+ const destY = Math.min(p1.y, p2.y);
64264
+ const destW = Math.abs(p2.x - p1.x);
64265
+ const destH = Math.abs(p2.y - p1.y);
64266
+ const canvasW = ctx.canvas.width;
64267
+ const canvasH = ctx.canvas.height;
64268
+ if (destX > canvasW || destY > canvasH || destX + destW < 0 || destY + destH < 0) return;
64194
64269
  ctx.save();
64195
- const boundP1 = wts(cs, minX, minY);
64196
- const boundP2 = wts(cs, maxX, maxY);
64197
- ctx.beginPath();
64198
- ctx.rect(Math.min(boundP1.x, boundP2.x), Math.min(boundP1.y, boundP2.y), Math.abs(boundP2.x - boundP1.x), Math.abs(boundP2.y - boundP1.y));
64199
- ctx.clip();
64200
64270
  let hasRoomClip = false;
64201
64271
  ctx.beginPath();
64202
64272
  for (const room of detectedRooms) {
@@ -64208,288 +64278,1345 @@ function drawFloorHeatmap(cs, floor, heatmapMatrix, detectedRooms) {
64208
64278
  ctx.closePath();
64209
64279
  hasRoomClip = true;
64210
64280
  }
64211
- if (hasRoomClip) ctx.clip();
64212
- ctx.globalCompositeOperation = "source-over";
64213
- ctx.filter = `blur(${Math.min(14, Math.max(3, 5 * zoom))}px)`;
64214
- const radius = Math.max(cellW, cellH) * zoom * 1.15;
64215
- for (let y = 0; y < rows; y++) for (let x = 0; x < cols; x++) {
64216
- const value = heatmapMatrix[y][x];
64217
- if (!value || value <= 0) continue;
64218
- const intensity = Math.min(value / maxValue, 1);
64219
- const s = wts(cs, minX + (x + .5) * cellW, minY + (y + .5) * cellH);
64220
- const gradient = ctx.createRadialGradient(s.x, s.y, 0, s.x, s.y, radius);
64221
- const alpha = .08 + intensity * .45;
64222
- gradient.addColorStop(0, getHeatmapColor(intensity, alpha));
64223
- gradient.addColorStop(.35, getHeatmapColor(intensity, alpha * .35));
64224
- gradient.addColorStop(1, getHeatmapColor(intensity, 0));
64225
- ctx.fillStyle = gradient;
64226
- ctx.beginPath();
64227
- ctx.arc(s.x, s.y, radius, 0, Math.PI * 2);
64228
- ctx.fill();
64229
- }
64230
- ctx.filter = "none";
64231
- ctx.globalCompositeOperation = "source-over";
64232
- ctx.strokeStyle = "rgba(255, 255, 255, 0.22)";
64233
- ctx.lineWidth = Math.max(.5, 1 / zoom);
64234
- ctx.beginPath();
64235
- for (let x = 0; x <= cols; x++) {
64236
- const wx = minX + x * cellW;
64237
- const p1 = wts(cs, wx, minY);
64238
- const p2 = wts(cs, wx, maxY);
64239
- ctx.moveTo(p1.x, p1.y);
64240
- ctx.lineTo(p2.x, p2.y);
64241
- }
64242
- for (let y = 0; y <= rows; y++) {
64243
- const wy = minY + y * cellH;
64244
- const p1 = wts(cs, minX, wy);
64245
- const p2 = wts(cs, maxX, wy);
64246
- ctx.moveTo(p1.x, p1.y);
64247
- ctx.lineTo(p2.x, p2.y);
64248
- }
64249
- ctx.stroke();
64281
+ if (hasRoomClip) ctx.clip("evenodd");
64282
+ ctx.globalAlpha = .92;
64283
+ ctx.drawImage(heatmapCache.canvas, destX, destY, destW, destH);
64284
+ ctx.globalAlpha = 1;
64250
64285
  ctx.restore();
64251
64286
  }
64252
64287
  //#endregion
64253
- //#region src/lib/utils/hitTesting.ts
64254
- function pointInPolygon(p, poly) {
64255
- let inside = false;
64256
- for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) if (poly[i].y > p.y !== poly[j].y > p.y && p.x < (poly[j].x - poly[i].x) * (p.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x) inside = !inside;
64257
- return inside;
64258
- }
64259
- function pointToSegmentDist(p, a, b) {
64260
- const dx = b.x - a.x, dy = b.y - a.y;
64261
- const len2 = dx * dx + dy * dy;
64262
- if (len2 === 0) return Math.hypot(p.x - a.x, p.y - a.y);
64263
- let t = ((p.x - a.x) * dx + (p.y - a.y) * dy) / len2;
64264
- t = Math.max(0, Math.min(1, t));
64265
- return Math.hypot(p.x - (a.x + t * dx), p.y - (a.y + t * dy));
64266
- }
64267
- function positionOnWall(p, w) {
64268
- if (w.curvePoint) {
64269
- let bestT = .5, bestDist = Infinity;
64270
- for (let i = 0; i <= 40; i++) {
64271
- const t = i / 40;
64272
- const pt = wallPointAt(w, t);
64273
- const d = Math.hypot(p.x - pt.x, p.y - pt.y);
64274
- if (d < bestDist) {
64275
- bestDist = d;
64276
- bestT = t;
64277
- }
64278
- }
64279
- return Math.max(.1, Math.min(.9, bestT));
64280
- }
64281
- const dx = w.end.x - w.start.x, dy = w.end.y - w.start.y;
64282
- const len2 = dx * dx + dy * dy;
64283
- if (len2 === 0) return .5;
64284
- return Math.max(.1, Math.min(.9, ((p.x - w.start.x) * dx + (p.y - w.start.y) * dy) / len2));
64285
- }
64286
- function findWallAt(p, walls, zoom) {
64287
- const threshold = 15 / zoom;
64288
- for (const w of walls) if (w.curvePoint) for (let i = 0; i <= 20; i++) {
64289
- const pt = wallPointAt(w, i / 20);
64290
- if (Math.hypot(p.x - pt.x, p.y - pt.y) < threshold + w.thickness / 2) return w;
64291
- }
64292
- else if (pointToSegmentDist(p, w.start, w.end) < threshold) return w;
64293
- return null;
64294
- }
64295
- function findHandleAt(p, selectedId, furniture, zoom) {
64296
- var _fi$scale$x, _fi$scale, _fi$scale$y, _fi$scale2;
64297
- if (!selectedId) return null;
64298
- const fi = furniture.find((f) => f.id === selectedId);
64299
- if (!fi) return null;
64300
- const cat = getCatalogItem(fi.catalogId);
64301
- if (!cat) return null;
64302
- const dx = p.x - fi.position.x;
64303
- const dy = p.y - fi.position.y;
64304
- const angle = -(fi.rotation * Math.PI) / 180;
64305
- const rx = dx * Math.cos(angle) - dy * Math.sin(angle);
64306
- const ry = dx * Math.sin(angle) + dy * Math.cos(angle);
64307
- const hw = cat.width * Math.abs((_fi$scale$x = (_fi$scale = fi.scale) === null || _fi$scale === void 0 ? void 0 : _fi$scale.x) !== null && _fi$scale$x !== void 0 ? _fi$scale$x : 1) / 2;
64308
- const hd = cat.depth * Math.abs((_fi$scale$y = (_fi$scale2 = fi.scale) === null || _fi$scale2 === void 0 ? void 0 : _fi$scale2.y) !== null && _fi$scale$y !== void 0 ? _fi$scale$y : 1) / 2;
64309
- const ht = 8 / zoom;
64310
- const rotHandleDist = 18 / zoom;
64311
- if (Math.abs(rx) < ht && Math.abs(ry - (-hd - rotHandleDist)) < ht) return "rotate";
64312
- if (Math.abs(rx - -hw) < ht && Math.abs(ry - -hd) < ht) return "resize-tl";
64313
- if (Math.abs(rx - hw) < ht && Math.abs(ry - -hd) < ht) return "resize-tr";
64314
- if (Math.abs(rx - -hw) < ht && Math.abs(ry - hd) < ht) return "resize-bl";
64315
- if (Math.abs(rx - hw) < ht && Math.abs(ry - hd) < ht) return "resize-br";
64316
- if (Math.abs(rx) < ht && Math.abs(ry - -hd) < ht) return "resize-t";
64317
- if (Math.abs(rx) < ht && Math.abs(ry - hd) < ht) return "resize-b";
64318
- if (Math.abs(rx - -hw) < ht && Math.abs(ry) < ht) return "resize-l";
64319
- if (Math.abs(rx - hw) < ht && Math.abs(ry) < ht) return "resize-r";
64320
- return null;
64321
- }
64322
- function findFurnitureAt(p, furniture) {
64323
- for (const fi of [...furniture].reverse()) {
64324
- var _fi$scale$x2, _fi$scale3, _fi$scale$y2, _fi$scale4;
64325
- const cat = getCatalogItem(fi.catalogId);
64326
- if (!cat) continue;
64327
- const dx = p.x - fi.position.x;
64328
- const dy = p.y - fi.position.y;
64329
- const angle = -(fi.rotation * Math.PI) / 180;
64330
- const rx = dx * Math.cos(angle) - dy * Math.sin(angle);
64331
- const ry = dx * Math.sin(angle) + dy * Math.cos(angle);
64332
- const hw = cat.width * Math.abs((_fi$scale$x2 = (_fi$scale3 = fi.scale) === null || _fi$scale3 === void 0 ? void 0 : _fi$scale3.x) !== null && _fi$scale$x2 !== void 0 ? _fi$scale$x2 : 1) / 2;
64333
- const hd = cat.depth * Math.abs((_fi$scale$y2 = (_fi$scale4 = fi.scale) === null || _fi$scale4 === void 0 ? void 0 : _fi$scale4.y) !== null && _fi$scale$y2 !== void 0 ? _fi$scale$y2 : 1) / 2;
64334
- if (Math.abs(rx) < hw && Math.abs(ry) < hd) return fi;
64335
- }
64336
- return null;
64337
- }
64338
- function findColumnAt(p, columns) {
64339
- if (!columns) return null;
64340
- for (const col of [...columns].reverse()) {
64341
- const dx = p.x - col.position.x;
64342
- const dy = p.y - col.position.y;
64343
- if (col.shape === "round") {
64344
- if (Math.hypot(dx, dy) < col.diameter / 2) return col;
64345
- } else {
64346
- const angle = -(col.rotation * Math.PI) / 180;
64347
- const rx = dx * Math.cos(angle) - dy * Math.sin(angle);
64348
- const ry = dx * Math.sin(angle) + dy * Math.cos(angle);
64349
- if (Math.abs(rx) < col.diameter / 2 && Math.abs(ry) < col.diameter / 2) return col;
64350
- }
64351
- }
64352
- return null;
64353
- }
64354
- function findStairAt(p, stairs) {
64355
- if (!stairs) return null;
64356
- for (const stair of [...stairs].reverse()) {
64357
- const dx = p.x - stair.position.x;
64358
- const dy = p.y - stair.position.y;
64359
- const angle = -(stair.rotation * Math.PI) / 180;
64360
- const rx = dx * Math.cos(angle) - dy * Math.sin(angle);
64361
- const ry = dx * Math.sin(angle) + dy * Math.cos(angle);
64362
- if (Math.abs(rx) < stair.width / 2 && Math.abs(ry) < stair.depth / 2) return stair;
64363
- }
64364
- return null;
64365
- }
64366
- function findDoorAt(p, doors, walls, zoom) {
64367
- for (const d of doors) {
64368
- const wall = walls.find((w) => w.id === d.wallId);
64369
- if (!wall) continue;
64370
- const cp = wallPointAt(wall, d.position);
64371
- if (Math.hypot(p.x - cp.x, p.y - cp.y) < (d.width / 2 + 5) / zoom) return d;
64372
- }
64373
- return null;
64374
- }
64375
- function findWindowAt(p, windows, walls, zoom) {
64376
- for (const w of windows) {
64377
- const wall = walls.find((wl) => wl.id === w.wallId);
64378
- if (!wall) continue;
64379
- const cp = wallPointAt(wall, w.position);
64380
- if (Math.hypot(p.x - cp.x, p.y - cp.y) < (w.width / 2 + 5) / zoom) return w;
64381
- }
64382
- return null;
64383
- }
64384
- function findRoomAt(p, rooms, walls) {
64385
- for (const room of rooms) if (pointInPolygon(p, getRoomPolygon(room, walls))) return room;
64386
- return null;
64387
- }
64388
- function hitTestMeasurement(wp, floor, zoom) {
64389
- if (!floor.measurements) return null;
64390
- const threshold = 8 / zoom;
64391
- for (const m of floor.measurements) {
64392
- const dx = m.x2 - m.x1, dy = m.y2 - m.y1;
64393
- const len2 = dx * dx + dy * dy;
64394
- if (len2 === 0) continue;
64395
- let t = ((wp.x - m.x1) * dx + (wp.y - m.y1) * dy) / len2;
64396
- t = Math.max(0, Math.min(1, t));
64397
- const px = m.x1 + t * dx, py = m.y1 + t * dy;
64398
- if (Math.hypot(wp.x - px, wp.y - py) < threshold) return m.id;
64399
- }
64400
- return null;
64401
- }
64402
- function hitTestAnnotation(wp, floor, zoom) {
64403
- if (!floor.annotations) return null;
64404
- const threshold = 10 / zoom;
64405
- for (const a of floor.annotations) {
64406
- const offset = a.offset || 40;
64407
- const dx = a.x2 - a.x1, dy = a.y2 - a.y1;
64408
- const len = Math.hypot(dx, dy);
64409
- if (len < 1) continue;
64410
- const ux = dx / len;
64411
- const nx = -(dy / len), ny = ux;
64412
- const d1x = a.x1 + nx * offset, d1y = a.y1 + ny * offset;
64413
- const d2x = a.x2 + nx * offset, d2y = a.y2 + ny * offset;
64414
- const ddx = d2x - d1x, ddy = d2y - d1y;
64415
- const len2 = ddx * ddx + ddy * ddy;
64416
- if (len2 === 0) continue;
64417
- let t = ((wp.x - d1x) * ddx + (wp.y - d1y) * ddy) / len2;
64418
- t = Math.max(0, Math.min(1, t));
64419
- const px = d1x + t * ddx, py = d1y + t * ddy;
64420
- if (Math.hypot(wp.x - px, wp.y - py) < threshold) return a.id;
64421
- for (const [lx1, ly1, lx2, ly2] of [[
64422
- a.x1,
64423
- a.y1,
64424
- d1x,
64425
- d1y
64426
- ], [
64427
- a.x2,
64428
- a.y2,
64429
- d2x,
64430
- d2y
64431
- ]]) {
64432
- const ldx = lx2 - lx1, ldy = ly2 - ly1;
64433
- const llen2 = ldx * ldx + ldy * ldy;
64434
- if (llen2 === 0) continue;
64435
- let lt = ((wp.x - lx1) * ldx + (wp.y - ly1) * ldy) / llen2;
64436
- lt = Math.max(0, Math.min(1, lt));
64437
- const lpx = lx1 + lt * ldx, lpy = ly1 + lt * ldy;
64438
- if (Math.hypot(wp.x - lpx, wp.y - lpy) < threshold) return a.id;
64439
- }
64440
- }
64441
- return null;
64442
- }
64443
- function hitTestTextAnnotation(wp, floor, ctx, zoom) {
64444
- if (!floor.textAnnotations) return null;
64445
- for (let i = floor.textAnnotations.length - 1; i >= 0; i--) {
64446
- const ta = floor.textAnnotations[i];
64447
- let dx = wp.x - ta.x;
64448
- let dy = wp.y - ta.y;
64449
- if (ta.rotation) {
64450
- const angle = -ta.rotation * Math.PI / 180;
64451
- const rx = dx * Math.cos(angle) - dy * Math.sin(angle);
64452
- const ry = dx * Math.sin(angle) + dy * Math.cos(angle);
64453
- dx = rx;
64454
- dy = ry;
64455
- }
64456
- ctx.font = `${ta.fontSize}px sans-serif`;
64457
- const lines = ta.text.split("\n");
64458
- const lineHeight = ta.fontSize * 1.2;
64459
- const totalHeight = lines.length * lineHeight;
64460
- let maxW = 0;
64461
- for (const line of lines) {
64462
- const w = ctx.measureText(line).width / zoom;
64463
- if (w > maxW) maxW = w;
64464
- }
64465
- const pad = 8 / zoom;
64466
- if (Math.abs(dx) < maxW / 2 + pad && Math.abs(dy) < totalHeight / 2 + pad) return ta.id;
64467
- }
64468
- return null;
64469
- }
64470
- //#endregion
64471
- //#region src/lib/components/editor/FloorPlanCanvas.svelte
64472
- init_client();
64473
- init_index_client();
64474
- var root_2$3 = /* @__PURE__ */ from_html(`<input type="text" class="absolute bg-white border-2 border-blue-500 rounded px-2 py-1 text-sm text-center shadow-lg outline-none"/>`);
64475
- var root_3$2 = /* @__PURE__ */ from_html(`<input type="text" class="absolute bg-white border-2 border-blue-500 rounded px-2 py-1 text-sm text-center shadow-lg outline-none"/>`);
64476
- var root_4$3 = /* @__PURE__ */ from_html(`<div class="absolute inset-0 flex items-center justify-center pointer-events-none"><div class="text-center opacity-60"><div class="text-5xl mb-3">๐Ÿ </div> <div class="text-sm font-medium text-gray-500">Start building your floor plan</div> <div class="text-xs text-gray-400 mt-1">Draw walls with <span class="font-mono bg-gray-100 px-1 rounded">W</span> or drag items from the sidebar</div></div></div>`);
64477
- var root_5 = /* @__PURE__ */ from_html(`<canvas width="180" height="120" class="absolute bottom-10 right-2 rounded-lg shadow-lg border border-gray-300 cursor-crosshair bg-white" style="z-index: 15;"></canvas>`);
64478
- var root_6 = /* @__PURE__ */ from_html(`<span> </span> <span> </span> <span class="text-gray-300">|</span>`, 1);
64479
- var root_8$1 = /* @__PURE__ */ from_html(`<span> </span>`);
64480
- var root_9 = /* @__PURE__ */ from_html(`<span> </span>`);
64481
- var root_10 = /* @__PURE__ */ from_html(`<span> </span>`);
64482
- var root_7$1 = /* @__PURE__ */ from_html(`<span> </span> <!> <!> <!> <span class="text-gray-300">|</span>`, 1);
64483
- var root_11 = /* @__PURE__ */ from_html(`<span class="text-blue-600 font-medium"> </span> <span class="text-gray-300">|</span>`, 1);
64484
- var root_13 = /* @__PURE__ */ from_html(`<label class="flex items-center gap-2 py-0.5 cursor-pointer hover:bg-gray-50 rounded px-1"><input type="checkbox" class="accent-blue-500"/> <span> </span></label>`);
64485
- var root_12 = /* @__PURE__ */ from_html(`<div class="absolute bottom-12 right-2 z-20 bg-white rounded-lg shadow-lg border border-gray-200 p-3 text-xs min-w-[160px]"><div class="font-semibold text-gray-700 mb-2">Layers</div> <!> <hr class="my-1 border-gray-100"/> <label class="flex items-center gap-2 py-0.5 cursor-pointer hover:bg-gray-50 rounded px-1"><input type="checkbox" class="accent-blue-500"/> <span>Room Labels</span></label> <label class="flex items-center gap-2 py-0.5 cursor-pointer hover:bg-gray-50 rounded px-1"><input type="checkbox" class="accent-blue-500"/> <span>Dimensions</span></label></div>`);
64486
- var root_16 = /* @__PURE__ */ from_html(`<button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500 hover:text-gray-700" title="Flip swing" aria-label="Flip swing"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M7 16V4m0 0L3 8m4-4l4 4M17 8v12m0 0l4-4m-4 4l-4-4"></path></svg></button>`);
64487
- var root_17 = /* @__PURE__ */ from_html(`<button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500 hover:text-gray-700" title="Split wall at midpoint" aria-label="Split wall at midpoint"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2v20M4 12h4M16 12h4"></path></svg></button>`);
64488
- var root_15 = /* @__PURE__ */ from_html(`<div class="absolute z-40 flex items-center gap-0.5 bg-white rounded-lg shadow-lg border border-gray-200 px-1 py-0.5"><button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500 hover:text-gray-700" title="Duplicate" aria-label="Duplicate"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"></rect><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"></path></svg></button> <!> <!> <div class="w-px h-5 bg-gray-200 mx-0.5"></div> <button class="w-7 h-7 flex items-center justify-center rounded hover:bg-red-50 text-gray-400 hover:text-red-600" title="Delete" aria-label="Delete"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2m3 0v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6h14"></path></svg></button></div>`);
64489
- var root_18 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-blue-600 text-white px-3 py-1 rounded-full text-xs shadow">Click to add wall segment ยท Double-click to finish ยท C to close loop ยท
64490
- Esc to cancel</div>`);
64491
- var root_19 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-purple-600 text-white px-3 py-1 rounded-full text-xs shadow"> </div>`);
64492
- var root_20 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-red-600 text-white px-3 py-1 rounded-full text-xs shadow">Right-click two points to measure ยท M to exit ยท Esc to cancel</div>`);
64288
+ //#region src/lib/utils/heatmapData.ts
64289
+ var SAMPLE_HEATMAP_32X32 = [
64290
+ [
64291
+ 0,
64292
+ 0,
64293
+ 0,
64294
+ 0,
64295
+ 0,
64296
+ 0,
64297
+ 0,
64298
+ 0,
64299
+ 0,
64300
+ 0,
64301
+ 0,
64302
+ 0,
64303
+ 0,
64304
+ 0,
64305
+ 0,
64306
+ 0,
64307
+ 0,
64308
+ 0,
64309
+ 0,
64310
+ 0,
64311
+ 0,
64312
+ 0,
64313
+ 0,
64314
+ 0,
64315
+ 0,
64316
+ 0,
64317
+ 0,
64318
+ 0,
64319
+ 0,
64320
+ 0,
64321
+ 0,
64322
+ 0
64323
+ ],
64324
+ [
64325
+ 0,
64326
+ 0,
64327
+ 0,
64328
+ 0,
64329
+ 0,
64330
+ 0,
64331
+ 0,
64332
+ 0,
64333
+ 0,
64334
+ 0,
64335
+ 0,
64336
+ 0,
64337
+ 0,
64338
+ 0,
64339
+ 0,
64340
+ 0,
64341
+ 0,
64342
+ 0,
64343
+ 0,
64344
+ 0,
64345
+ 0,
64346
+ 0,
64347
+ 0,
64348
+ 0,
64349
+ 0,
64350
+ 0,
64351
+ 0,
64352
+ 0,
64353
+ 0,
64354
+ 0,
64355
+ 0,
64356
+ 0
64357
+ ],
64358
+ [
64359
+ 0,
64360
+ 0,
64361
+ 0,
64362
+ 0,
64363
+ 0,
64364
+ 0,
64365
+ 0,
64366
+ 0,
64367
+ 0,
64368
+ 0,
64369
+ 0,
64370
+ 0,
64371
+ 0,
64372
+ 0,
64373
+ 0,
64374
+ 0,
64375
+ 0,
64376
+ 0,
64377
+ 0,
64378
+ 0,
64379
+ 0,
64380
+ 0,
64381
+ 0,
64382
+ 0,
64383
+ 0,
64384
+ 0,
64385
+ 0,
64386
+ 0,
64387
+ 0,
64388
+ 0,
64389
+ 0,
64390
+ 0
64391
+ ],
64392
+ [
64393
+ 0,
64394
+ 0,
64395
+ 0,
64396
+ 0,
64397
+ 0,
64398
+ 0,
64399
+ 0,
64400
+ 0,
64401
+ 0,
64402
+ 0,
64403
+ 0,
64404
+ 0,
64405
+ 0,
64406
+ 0,
64407
+ 0,
64408
+ 0,
64409
+ 0,
64410
+ 0,
64411
+ 0,
64412
+ 0,
64413
+ 0,
64414
+ 0,
64415
+ 0,
64416
+ 0,
64417
+ 0,
64418
+ 0,
64419
+ 0,
64420
+ 0,
64421
+ 0,
64422
+ 0,
64423
+ 0,
64424
+ 0
64425
+ ],
64426
+ [
64427
+ 0,
64428
+ 0,
64429
+ 0,
64430
+ 0,
64431
+ 0,
64432
+ 0,
64433
+ 0,
64434
+ 0,
64435
+ 0,
64436
+ 0,
64437
+ 0,
64438
+ 0,
64439
+ 0,
64440
+ 0,
64441
+ 0,
64442
+ 0,
64443
+ 0,
64444
+ 0,
64445
+ 0,
64446
+ 0,
64447
+ 0,
64448
+ 0,
64449
+ 0,
64450
+ 0,
64451
+ 0,
64452
+ 0,
64453
+ 0,
64454
+ 0,
64455
+ 0,
64456
+ 0,
64457
+ 0,
64458
+ 0
64459
+ ],
64460
+ [
64461
+ 0,
64462
+ 0,
64463
+ 0,
64464
+ 0,
64465
+ 0,
64466
+ 0,
64467
+ 0,
64468
+ 0,
64469
+ 0,
64470
+ 0,
64471
+ 0,
64472
+ 0,
64473
+ 0,
64474
+ 0,
64475
+ 0,
64476
+ 0,
64477
+ 0,
64478
+ 0,
64479
+ 0,
64480
+ 0,
64481
+ 0,
64482
+ 0,
64483
+ 0,
64484
+ 0,
64485
+ 0,
64486
+ 0,
64487
+ 0,
64488
+ 0,
64489
+ 0,
64490
+ 0,
64491
+ 0,
64492
+ 0
64493
+ ],
64494
+ [
64495
+ 0,
64496
+ 0,
64497
+ 0,
64498
+ 0,
64499
+ 0,
64500
+ 0,
64501
+ 0,
64502
+ 0,
64503
+ 0,
64504
+ 0,
64505
+ 0,
64506
+ 0,
64507
+ 0,
64508
+ 0,
64509
+ 0,
64510
+ 0,
64511
+ 0,
64512
+ 0,
64513
+ 0,
64514
+ 0,
64515
+ 0,
64516
+ 0,
64517
+ 0,
64518
+ 0,
64519
+ 0,
64520
+ 0,
64521
+ 0,
64522
+ 0,
64523
+ 0,
64524
+ 0,
64525
+ 0,
64526
+ 0
64527
+ ],
64528
+ [
64529
+ 0,
64530
+ 0,
64531
+ 0,
64532
+ 0,
64533
+ 0,
64534
+ 0,
64535
+ 0,
64536
+ 0,
64537
+ 0,
64538
+ 0,
64539
+ 0,
64540
+ 0,
64541
+ 0,
64542
+ 0,
64543
+ 0,
64544
+ 0,
64545
+ 0,
64546
+ 0,
64547
+ 0,
64548
+ 0,
64549
+ 0,
64550
+ 0,
64551
+ 0,
64552
+ 0,
64553
+ 0,
64554
+ 0,
64555
+ 0,
64556
+ 0,
64557
+ 0,
64558
+ 0,
64559
+ 0,
64560
+ 0
64561
+ ],
64562
+ [
64563
+ 0,
64564
+ 0,
64565
+ 0,
64566
+ 0,
64567
+ 0,
64568
+ 0,
64569
+ 0,
64570
+ 0,
64571
+ 0,
64572
+ 0,
64573
+ 0,
64574
+ 0,
64575
+ 0,
64576
+ 0,
64577
+ 0,
64578
+ 0,
64579
+ 0,
64580
+ 0,
64581
+ 0,
64582
+ 0,
64583
+ 0,
64584
+ 0,
64585
+ 0,
64586
+ 0,
64587
+ 0,
64588
+ 0,
64589
+ 0,
64590
+ 0,
64591
+ 0,
64592
+ 0,
64593
+ 0,
64594
+ 0
64595
+ ],
64596
+ [
64597
+ 0,
64598
+ 0,
64599
+ 0,
64600
+ 0,
64601
+ 0,
64602
+ 0,
64603
+ 0,
64604
+ 0,
64605
+ 0,
64606
+ 0,
64607
+ 0,
64608
+ 0,
64609
+ 0,
64610
+ 0,
64611
+ 0,
64612
+ 0,
64613
+ 0,
64614
+ 0,
64615
+ 0,
64616
+ 0,
64617
+ 0,
64618
+ 0,
64619
+ 0,
64620
+ 0,
64621
+ 0,
64622
+ 0,
64623
+ 0,
64624
+ 0,
64625
+ 0,
64626
+ 0,
64627
+ 0,
64628
+ 0
64629
+ ],
64630
+ [
64631
+ 0,
64632
+ 0,
64633
+ 0,
64634
+ 0,
64635
+ 0,
64636
+ 0,
64637
+ 0,
64638
+ 0,
64639
+ 0,
64640
+ 0,
64641
+ 0,
64642
+ 0,
64643
+ 0,
64644
+ 0,
64645
+ 0,
64646
+ 0,
64647
+ 0,
64648
+ 0,
64649
+ 0,
64650
+ 0,
64651
+ 0,
64652
+ 0,
64653
+ 0,
64654
+ 0,
64655
+ 0,
64656
+ 0,
64657
+ 0,
64658
+ 0,
64659
+ 0,
64660
+ 0,
64661
+ 0,
64662
+ 0
64663
+ ],
64664
+ [
64665
+ 0,
64666
+ 0,
64667
+ 0,
64668
+ 0,
64669
+ 0,
64670
+ 0,
64671
+ 0,
64672
+ 0,
64673
+ 0,
64674
+ 0,
64675
+ 0,
64676
+ 0,
64677
+ 0,
64678
+ 0,
64679
+ 0,
64680
+ 0,
64681
+ 0,
64682
+ 0,
64683
+ 0,
64684
+ 0,
64685
+ 0,
64686
+ 0,
64687
+ 0,
64688
+ 0,
64689
+ 0,
64690
+ 0,
64691
+ 0,
64692
+ 0,
64693
+ 0,
64694
+ 0,
64695
+ 0,
64696
+ 0
64697
+ ],
64698
+ [
64699
+ 0,
64700
+ 0,
64701
+ 0,
64702
+ 0,
64703
+ 0,
64704
+ 0,
64705
+ 0,
64706
+ 0,
64707
+ 0,
64708
+ 0,
64709
+ 0,
64710
+ 0,
64711
+ 0,
64712
+ 0,
64713
+ 0,
64714
+ 0,
64715
+ 0,
64716
+ 0,
64717
+ 0,
64718
+ 0,
64719
+ 0,
64720
+ 0,
64721
+ 0,
64722
+ 0,
64723
+ 0,
64724
+ 0,
64725
+ 0,
64726
+ 0,
64727
+ 0,
64728
+ 0,
64729
+ 0,
64730
+ 0
64731
+ ],
64732
+ [
64733
+ 0,
64734
+ 0,
64735
+ 0,
64736
+ 0,
64737
+ 0,
64738
+ 0,
64739
+ 0,
64740
+ 0,
64741
+ 0,
64742
+ 0,
64743
+ 0,
64744
+ 0,
64745
+ 0,
64746
+ 0,
64747
+ 0,
64748
+ 0,
64749
+ 0,
64750
+ 0,
64751
+ 0,
64752
+ 0,
64753
+ 0,
64754
+ 0,
64755
+ 0,
64756
+ 0,
64757
+ 0,
64758
+ 0,
64759
+ 0,
64760
+ 0,
64761
+ 0,
64762
+ 0,
64763
+ 0,
64764
+ 0
64765
+ ],
64766
+ [
64767
+ 0,
64768
+ 0,
64769
+ 0,
64770
+ 0,
64771
+ 0,
64772
+ 0,
64773
+ 0,
64774
+ 0,
64775
+ 0,
64776
+ 0,
64777
+ 0,
64778
+ 0,
64779
+ 0,
64780
+ 0,
64781
+ 0,
64782
+ 0,
64783
+ 0,
64784
+ 0,
64785
+ 0,
64786
+ 0,
64787
+ 0,
64788
+ 0,
64789
+ 0,
64790
+ 0,
64791
+ 0,
64792
+ 0,
64793
+ 0,
64794
+ 0,
64795
+ 0,
64796
+ 0,
64797
+ 0,
64798
+ 0
64799
+ ],
64800
+ [
64801
+ 0,
64802
+ 0,
64803
+ 0,
64804
+ 0,
64805
+ 0,
64806
+ 0,
64807
+ 0,
64808
+ 0,
64809
+ 12.748932716414688,
64810
+ 45.32230658043087,
64811
+ 68.04250459126601,
64812
+ 45.32230658043087,
64813
+ 12.748932716414688,
64814
+ 0,
64815
+ 0,
64816
+ 0,
64817
+ 0,
64818
+ 0,
64819
+ 0,
64820
+ 0,
64821
+ 0,
64822
+ 0,
64823
+ 0,
64824
+ 0,
64825
+ 0,
64826
+ 0,
64827
+ 0,
64828
+ 0,
64829
+ 0,
64830
+ 0,
64831
+ 0,
64832
+ 0
64833
+ ],
64834
+ [
64835
+ 0,
64836
+ 0,
64837
+ 0,
64838
+ 0,
64839
+ 0,
64840
+ 0,
64841
+ 0,
64842
+ 0,
64843
+ 45.4224478194094,
64844
+ 181.72045122075266,
64845
+ 275.3766843118068,
64846
+ 181.72045122075266,
64847
+ 45.4224478194094,
64848
+ 0,
64849
+ 0,
64850
+ 0,
64851
+ 0,
64852
+ 0,
64853
+ 0,
64854
+ 0,
64855
+ 0,
64856
+ 0,
64857
+ 0,
64858
+ 0,
64859
+ 0,
64860
+ 0,
64861
+ 0,
64862
+ 0,
64863
+ 0,
64864
+ 0,
64865
+ 0,
64866
+ 0
64867
+ ],
64868
+ [
64869
+ 0,
64870
+ 0,
64871
+ 0,
64872
+ 0,
64873
+ 0,
64874
+ 0,
64875
+ 0,
64876
+ 0,
64877
+ 68.31590812975966,
64878
+ 276.0871751974888,
64879
+ 412.63080261542115,
64880
+ 276.0567800219605,
64881
+ 68.28551295423132,
64882
+ 0,
64883
+ 0,
64884
+ 0,
64885
+ 0,
64886
+ 0,
64887
+ 0,
64888
+ 0,
64889
+ 0,
64890
+ 0,
64891
+ 0,
64892
+ 0,
64893
+ 0,
64894
+ 0,
64895
+ 0,
64896
+ 0,
64897
+ 0,
64898
+ 0,
64899
+ 0,
64900
+ 0
64901
+ ],
64902
+ [
64903
+ 0,
64904
+ 0,
64905
+ 0,
64906
+ 0,
64907
+ 0,
64908
+ 0,
64909
+ 0,
64910
+ .030395175528338574,
64911
+ 45.85002901047233,
64912
+ 183.2669337255748,
64913
+ 277.5660942229701,
64914
+ 183.11495784793308,
64915
+ 45.72844830835897,
64916
+ 0,
64917
+ 0,
64918
+ 0,
64919
+ 0,
64920
+ 0,
64921
+ 0,
64922
+ 0,
64923
+ 0,
64924
+ 0,
64925
+ 0,
64926
+ 0,
64927
+ 0,
64928
+ 0,
64929
+ 0,
64930
+ 0,
64931
+ 0,
64932
+ 0,
64933
+ 0,
64934
+ 0
64935
+ ],
64936
+ [
64937
+ 0,
64938
+ 0,
64939
+ 0,
64940
+ 0,
64941
+ 0,
64942
+ 0,
64943
+ 0,
64944
+ .04559276329250786,
64945
+ 13.231129308385174,
64946
+ 46.80863529396807,
64947
+ 70.01815269312522,
64948
+ 46.595869065269696,
64949
+ 13.063955842979313,
64950
+ 0,
64951
+ 0,
64952
+ 0,
64953
+ 0,
64954
+ 0,
64955
+ 0,
64956
+ .0883900124257005,
64957
+ .1184538668534887,
64958
+ .0883900124257005,
64959
+ 0,
64960
+ 0,
64961
+ 0,
64962
+ 0,
64963
+ 0,
64964
+ 0,
64965
+ 0,
64966
+ 0,
64967
+ 0,
64968
+ 0
64969
+ ],
64970
+ [
64971
+ 0,
64972
+ 0,
64973
+ 0,
64974
+ 0,
64975
+ 0,
64976
+ .3548876788672499,
64977
+ 1.5365008894852765,
64978
+ 2.311642755673626,
64979
+ 1.849545906847856,
64980
+ 1.0591053080371047,
64981
+ .8374628344858726,
64982
+ .48600196369050996,
64983
+ .12261466435560091,
64984
+ 0,
64985
+ 0,
64986
+ 0,
64987
+ 0,
64988
+ 0,
64989
+ .0883900124257005,
64990
+ .29523389170488973,
64991
+ .4437516129861666,
64992
+ .29523389170488973,
64993
+ .11706693153681717,
64994
+ .10683366069643516,
64995
+ .1641874989186685,
64996
+ .10683366069643516,
64997
+ .028676919111116663,
64998
+ 0,
64999
+ 0,
65000
+ 0,
65001
+ 0,
65002
+ 0
65003
+ ],
65004
+ [
65005
+ 0,
65006
+ 0,
65007
+ 0,
65008
+ 0,
65009
+ .05750012585497277,
65010
+ 1.6847750070526843,
65011
+ 6.3386099807859395,
65012
+ 9.604681011260025,
65013
+ 6.92418895556232,
65014
+ 2.368873542688024,
65015
+ .47238164060697785,
65016
+ .1889763779527559,
65017
+ .047244094488188976,
65018
+ 0,
65019
+ 0,
65020
+ 0,
65021
+ 0,
65022
+ 0,
65023
+ .1184538668534887,
65024
+ .4437516129861666,
65025
+ .6806593466931441,
65026
+ .4437516129861666,
65027
+ .24890957479401832,
65028
+ .5533188947542446,
65029
+ .8378523578793984,
65030
+ .5533188947542446,
65031
+ .13045570794052963,
65032
+ 0,
65033
+ 0,
65034
+ 0,
65035
+ 0,
65036
+ 0
65037
+ ],
65038
+ [
65039
+ 0,
65040
+ 0,
65041
+ 0,
65042
+ 0,
65043
+ .05750012585497277,
65044
+ 2.68681452030272,
65045
+ 10.263846862973189,
65046
+ 16.09777913600441,
65047
+ 12.361964591844814,
65048
+ 5.143188882061816,
65049
+ 1.4223676084533452,
65050
+ .312782108314394,
65051
+ .031496062992125984,
65052
+ 0,
65053
+ 0,
65054
+ 0,
65055
+ 0,
65056
+ 0,
65057
+ .0883900124257005,
65058
+ .29523389170488973,
65059
+ .4437516129861666,
65060
+ .3160367950679749,
65061
+ .4853954240093081,
65062
+ 1.3799926127035786,
65063
+ 1.9659744022399421,
65064
+ 1.2759780958881528,
65065
+ .3137937981312669,
65066
+ 0,
65067
+ 0,
65068
+ 0,
65069
+ 0,
65070
+ 0
65071
+ ],
65072
+ [
65073
+ 0,
65074
+ 0,
65075
+ 0,
65076
+ 0,
65077
+ .05750012585497277,
65078
+ 3.990289650564119,
65079
+ 20.695365814712115,
65080
+ 44.3522989543404,
65081
+ 49.69632864092277,
65082
+ 29.689044491512576,
65083
+ 9.033393108938617,
65084
+ 1.2347274821574294,
65085
+ .15202866764519157,
65086
+ .023622047244094488,
65087
+ .06937364893635427,
65088
+ .08512168043241726,
65089
+ .1312648874568188,
65090
+ .06921481053660235,
65091
+ .038269191276370074,
65092
+ .0883900124257005,
65093
+ .1184538668534887,
65094
+ .17160162587804118,
65095
+ .7552196059639998,
65096
+ 2.180300310840757,
65097
+ 2.82987585217934,
65098
+ 1.7231446814349316,
65099
+ .406046259121632,
65100
+ 0,
65101
+ 0,
65102
+ 0,
65103
+ 0,
65104
+ 0
65105
+ ],
65106
+ [
65107
+ 0,
65108
+ 0,
65109
+ 0,
65110
+ 0,
65111
+ 0,
65112
+ 8.344447730094426,
65113
+ 52.77867806990315,
65114
+ 128.79488712220683,
65115
+ 155.50781484945549,
65116
+ 94.8111770857038,
65117
+ 26.204290047405273,
65118
+ 2.6172004234133746,
65119
+ .5926756971464383,
65120
+ .17415822209335685,
65121
+ .2081209468090628,
65122
+ .41986725837226924,
65123
+ .4562363446228147,
65124
+ .3389093190666259,
65125
+ .13000516159327952,
65126
+ .030395175528338574,
65127
+ 0,
65128
+ .1619472165746013,
65129
+ .9301572259016863,
65130
+ 2.265879784982036,
65131
+ 2.6140297641904335,
65132
+ 1.4892533182159182,
65133
+ .3278895175363135,
65134
+ 0,
65135
+ 0,
65136
+ 0,
65137
+ 0,
65138
+ 0
65139
+ ],
65140
+ [
65141
+ 0,
65142
+ 0,
65143
+ 0,
65144
+ 0,
65145
+ 0,
65146
+ 11.569261098471213,
65147
+ 74.91244899006341,
65148
+ 185.41798253416076,
65149
+ 223.16964950617853,
65150
+ 134.47162508401345,
65151
+ 35.29886422851894,
65152
+ 2.9823101815276254,
65153
+ .8519113063812257,
65154
+ .239572716510202,
65155
+ .3186059411116472,
65156
+ .6464195523675033,
65157
+ .6905038159663283,
65158
+ .4700153681236928,
65159
+ .20654354414601966,
65160
+ .04559276329250786,
65161
+ 0,
65162
+ .1659149823226328,
65163
+ .7137277220177837,
65164
+ 1.4724250590707373,
65165
+ 1.4853812653248704,
65166
+ .7879622264171209,
65167
+ .14960629921259844,
65168
+ 0,
65169
+ 0,
65170
+ 0,
65171
+ 0,
65172
+ 0
65173
+ ],
65174
+ [
65175
+ 0,
65176
+ 0,
65177
+ 0,
65178
+ 0,
65179
+ 0,
65180
+ 7.659608408222048,
65181
+ 49.47160326026555,
65182
+ 122.0267564546405,
65183
+ 146.90471606648813,
65184
+ 87.12454645840202,
65185
+ 22.206612666760837,
65186
+ 1.6704856213622203,
65187
+ .5848016813984068,
65188
+ .17415822209335685,
65189
+ .2081209468090628,
65190
+ .41986725837226924,
65191
+ .4562363446228147,
65192
+ .3389093190666259,
65193
+ .13000516159327952,
65194
+ .030395175528338574,
65195
+ 0,
65196
+ .07873560312226063,
65197
+ .2801144141850509,
65198
+ .4950055287578913,
65199
+ .4297207133976494,
65200
+ .1968458393427331,
65201
+ .031496062992125984,
65202
+ 0,
65203
+ 0,
65204
+ 0,
65205
+ 0,
65206
+ 0
65207
+ ],
65208
+ [
65209
+ 0,
65210
+ 0,
65211
+ 0,
65212
+ 0,
65213
+ 0,
65214
+ 1.8758964163111886,
65215
+ 12.528184619475534,
65216
+ 30.384574544711377,
65217
+ 36.35399650870346,
65218
+ 21.427909044768864,
65219
+ 5.489463881244808,
65220
+ .38028740695142366,
65221
+ .12840662040109707,
65222
+ .023622047244094488,
65223
+ .06937364893635427,
65224
+ .08512168043241726,
65225
+ .1312648874568188,
65226
+ .06921481053660235,
65227
+ .038269191276370074,
65228
+ 0,
65229
+ 0,
65230
+ 0,
65231
+ .05793269975917546,
65232
+ .08270336887029212,
65233
+ .05793269975917546,
65234
+ 0,
65235
+ 0,
65236
+ 0,
65237
+ 0,
65238
+ 0,
65239
+ 0,
65240
+ 0
65241
+ ],
65242
+ [
65243
+ 0,
65244
+ 0,
65245
+ 0,
65246
+ 0,
65247
+ 0,
65248
+ 0,
65249
+ 0,
65250
+ 0,
65251
+ 0,
65252
+ 0,
65253
+ 0,
65254
+ 0,
65255
+ 0,
65256
+ 0,
65257
+ 0,
65258
+ 0,
65259
+ 0,
65260
+ 0,
65261
+ 0,
65262
+ 0,
65263
+ 0,
65264
+ 0,
65265
+ 0,
65266
+ 0,
65267
+ 0,
65268
+ 0,
65269
+ 0,
65270
+ 0,
65271
+ 0,
65272
+ 0,
65273
+ 0,
65274
+ 0
65275
+ ],
65276
+ [
65277
+ 0,
65278
+ 0,
65279
+ 0,
65280
+ 0,
65281
+ 0,
65282
+ 0,
65283
+ 0,
65284
+ 0,
65285
+ 0,
65286
+ 0,
65287
+ 0,
65288
+ 0,
65289
+ 0,
65290
+ 0,
65291
+ 0,
65292
+ 0,
65293
+ 0,
65294
+ 0,
65295
+ 0,
65296
+ 0,
65297
+ 0,
65298
+ 0,
65299
+ 0,
65300
+ 0,
65301
+ 0,
65302
+ 0,
65303
+ 0,
65304
+ 0,
65305
+ 0,
65306
+ 0,
65307
+ 0,
65308
+ 0
65309
+ ],
65310
+ [
65311
+ 0,
65312
+ 0,
65313
+ 0,
65314
+ 0,
65315
+ 0,
65316
+ 0,
65317
+ 0,
65318
+ 0,
65319
+ 0,
65320
+ 0,
65321
+ 0,
65322
+ 0,
65323
+ 0,
65324
+ 0,
65325
+ 0,
65326
+ 0,
65327
+ 0,
65328
+ 0,
65329
+ 0,
65330
+ 0,
65331
+ 0,
65332
+ 0,
65333
+ 0,
65334
+ 0,
65335
+ 0,
65336
+ 0,
65337
+ 0,
65338
+ 0,
65339
+ 0,
65340
+ 0,
65341
+ 0,
65342
+ 0
65343
+ ],
65344
+ [
65345
+ 0,
65346
+ 0,
65347
+ 0,
65348
+ 0,
65349
+ 0,
65350
+ 0,
65351
+ 0,
65352
+ 0,
65353
+ 0,
65354
+ 0,
65355
+ 0,
65356
+ 0,
65357
+ 0,
65358
+ 0,
65359
+ 0,
65360
+ 0,
65361
+ 0,
65362
+ 0,
65363
+ 0,
65364
+ 0,
65365
+ 0,
65366
+ 0,
65367
+ 0,
65368
+ 0,
65369
+ 0,
65370
+ 0,
65371
+ 0,
65372
+ 0,
65373
+ 0,
65374
+ 0,
65375
+ 0,
65376
+ 0
65377
+ ]
65378
+ ];
65379
+ //#endregion
65380
+ //#region src/lib/utils/hitTesting.ts
65381
+ function pointInPolygon(p, poly) {
65382
+ let inside = false;
65383
+ for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) if (poly[i].y > p.y !== poly[j].y > p.y && p.x < (poly[j].x - poly[i].x) * (p.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x) inside = !inside;
65384
+ return inside;
65385
+ }
65386
+ function pointToSegmentDist(p, a, b) {
65387
+ const dx = b.x - a.x, dy = b.y - a.y;
65388
+ const len2 = dx * dx + dy * dy;
65389
+ if (len2 === 0) return Math.hypot(p.x - a.x, p.y - a.y);
65390
+ let t = ((p.x - a.x) * dx + (p.y - a.y) * dy) / len2;
65391
+ t = Math.max(0, Math.min(1, t));
65392
+ return Math.hypot(p.x - (a.x + t * dx), p.y - (a.y + t * dy));
65393
+ }
65394
+ function positionOnWall(p, w) {
65395
+ if (w.curvePoint) {
65396
+ let bestT = .5, bestDist = Infinity;
65397
+ for (let i = 0; i <= 40; i++) {
65398
+ const t = i / 40;
65399
+ const pt = wallPointAt(w, t);
65400
+ const d = Math.hypot(p.x - pt.x, p.y - pt.y);
65401
+ if (d < bestDist) {
65402
+ bestDist = d;
65403
+ bestT = t;
65404
+ }
65405
+ }
65406
+ return Math.max(.1, Math.min(.9, bestT));
65407
+ }
65408
+ const dx = w.end.x - w.start.x, dy = w.end.y - w.start.y;
65409
+ const len2 = dx * dx + dy * dy;
65410
+ if (len2 === 0) return .5;
65411
+ return Math.max(.1, Math.min(.9, ((p.x - w.start.x) * dx + (p.y - w.start.y) * dy) / len2));
65412
+ }
65413
+ function findWallAt(p, walls, zoom) {
65414
+ const threshold = 15 / zoom;
65415
+ for (const w of walls) if (w.curvePoint) for (let i = 0; i <= 20; i++) {
65416
+ const pt = wallPointAt(w, i / 20);
65417
+ if (Math.hypot(p.x - pt.x, p.y - pt.y) < threshold + w.thickness / 2) return w;
65418
+ }
65419
+ else if (pointToSegmentDist(p, w.start, w.end) < threshold) return w;
65420
+ return null;
65421
+ }
65422
+ function findHandleAt(p, selectedId, furniture, zoom) {
65423
+ var _fi$scale$x, _fi$scale, _fi$scale$y, _fi$scale2;
65424
+ if (!selectedId) return null;
65425
+ const fi = furniture.find((f) => f.id === selectedId);
65426
+ if (!fi) return null;
65427
+ const cat = getCatalogItem(fi.catalogId);
65428
+ if (!cat) return null;
65429
+ const dx = p.x - fi.position.x;
65430
+ const dy = p.y - fi.position.y;
65431
+ const angle = -(fi.rotation * Math.PI) / 180;
65432
+ const rx = dx * Math.cos(angle) - dy * Math.sin(angle);
65433
+ const ry = dx * Math.sin(angle) + dy * Math.cos(angle);
65434
+ const hw = cat.width * Math.abs((_fi$scale$x = (_fi$scale = fi.scale) === null || _fi$scale === void 0 ? void 0 : _fi$scale.x) !== null && _fi$scale$x !== void 0 ? _fi$scale$x : 1) / 2;
65435
+ const hd = cat.depth * Math.abs((_fi$scale$y = (_fi$scale2 = fi.scale) === null || _fi$scale2 === void 0 ? void 0 : _fi$scale2.y) !== null && _fi$scale$y !== void 0 ? _fi$scale$y : 1) / 2;
65436
+ const ht = 8 / zoom;
65437
+ const rotHandleDist = 18 / zoom;
65438
+ if (Math.abs(rx) < ht && Math.abs(ry - (-hd - rotHandleDist)) < ht) return "rotate";
65439
+ if (Math.abs(rx - -hw) < ht && Math.abs(ry - -hd) < ht) return "resize-tl";
65440
+ if (Math.abs(rx - hw) < ht && Math.abs(ry - -hd) < ht) return "resize-tr";
65441
+ if (Math.abs(rx - -hw) < ht && Math.abs(ry - hd) < ht) return "resize-bl";
65442
+ if (Math.abs(rx - hw) < ht && Math.abs(ry - hd) < ht) return "resize-br";
65443
+ if (Math.abs(rx) < ht && Math.abs(ry - -hd) < ht) return "resize-t";
65444
+ if (Math.abs(rx) < ht && Math.abs(ry - hd) < ht) return "resize-b";
65445
+ if (Math.abs(rx - -hw) < ht && Math.abs(ry) < ht) return "resize-l";
65446
+ if (Math.abs(rx - hw) < ht && Math.abs(ry) < ht) return "resize-r";
65447
+ return null;
65448
+ }
65449
+ function findFurnitureAt(p, furniture) {
65450
+ for (const fi of [...furniture].reverse()) {
65451
+ var _fi$scale$x2, _fi$scale3, _fi$scale$y2, _fi$scale4;
65452
+ const cat = getCatalogItem(fi.catalogId);
65453
+ if (!cat) continue;
65454
+ const dx = p.x - fi.position.x;
65455
+ const dy = p.y - fi.position.y;
65456
+ const angle = -(fi.rotation * Math.PI) / 180;
65457
+ const rx = dx * Math.cos(angle) - dy * Math.sin(angle);
65458
+ const ry = dx * Math.sin(angle) + dy * Math.cos(angle);
65459
+ const hw = cat.width * Math.abs((_fi$scale$x2 = (_fi$scale3 = fi.scale) === null || _fi$scale3 === void 0 ? void 0 : _fi$scale3.x) !== null && _fi$scale$x2 !== void 0 ? _fi$scale$x2 : 1) / 2;
65460
+ const hd = cat.depth * Math.abs((_fi$scale$y2 = (_fi$scale4 = fi.scale) === null || _fi$scale4 === void 0 ? void 0 : _fi$scale4.y) !== null && _fi$scale$y2 !== void 0 ? _fi$scale$y2 : 1) / 2;
65461
+ if (Math.abs(rx) < hw && Math.abs(ry) < hd) return fi;
65462
+ }
65463
+ return null;
65464
+ }
65465
+ function findColumnAt(p, columns) {
65466
+ if (!columns) return null;
65467
+ for (const col of [...columns].reverse()) {
65468
+ const dx = p.x - col.position.x;
65469
+ const dy = p.y - col.position.y;
65470
+ if (col.shape === "round") {
65471
+ if (Math.hypot(dx, dy) < col.diameter / 2) return col;
65472
+ } else {
65473
+ const angle = -(col.rotation * Math.PI) / 180;
65474
+ const rx = dx * Math.cos(angle) - dy * Math.sin(angle);
65475
+ const ry = dx * Math.sin(angle) + dy * Math.cos(angle);
65476
+ if (Math.abs(rx) < col.diameter / 2 && Math.abs(ry) < col.diameter / 2) return col;
65477
+ }
65478
+ }
65479
+ return null;
65480
+ }
65481
+ function findStairAt(p, stairs) {
65482
+ if (!stairs) return null;
65483
+ for (const stair of [...stairs].reverse()) {
65484
+ const dx = p.x - stair.position.x;
65485
+ const dy = p.y - stair.position.y;
65486
+ const angle = -(stair.rotation * Math.PI) / 180;
65487
+ const rx = dx * Math.cos(angle) - dy * Math.sin(angle);
65488
+ const ry = dx * Math.sin(angle) + dy * Math.cos(angle);
65489
+ if (Math.abs(rx) < stair.width / 2 && Math.abs(ry) < stair.depth / 2) return stair;
65490
+ }
65491
+ return null;
65492
+ }
65493
+ function findDoorAt(p, doors, walls, zoom) {
65494
+ for (const d of doors) {
65495
+ const wall = walls.find((w) => w.id === d.wallId);
65496
+ if (!wall) continue;
65497
+ const cp = wallPointAt(wall, d.position);
65498
+ if (Math.hypot(p.x - cp.x, p.y - cp.y) < (d.width / 2 + 5) / zoom) return d;
65499
+ }
65500
+ return null;
65501
+ }
65502
+ function findWindowAt(p, windows, walls, zoom) {
65503
+ for (const w of windows) {
65504
+ const wall = walls.find((wl) => wl.id === w.wallId);
65505
+ if (!wall) continue;
65506
+ const cp = wallPointAt(wall, w.position);
65507
+ if (Math.hypot(p.x - cp.x, p.y - cp.y) < (w.width / 2 + 5) / zoom) return w;
65508
+ }
65509
+ return null;
65510
+ }
65511
+ function findRoomAt(p, rooms, walls) {
65512
+ for (const room of rooms) if (pointInPolygon(p, getRoomPolygon(room, walls))) return room;
65513
+ return null;
65514
+ }
65515
+ function hitTestMeasurement(wp, floor, zoom) {
65516
+ if (!floor.measurements) return null;
65517
+ const threshold = 8 / zoom;
65518
+ for (const m of floor.measurements) {
65519
+ const dx = m.x2 - m.x1, dy = m.y2 - m.y1;
65520
+ const len2 = dx * dx + dy * dy;
65521
+ if (len2 === 0) continue;
65522
+ let t = ((wp.x - m.x1) * dx + (wp.y - m.y1) * dy) / len2;
65523
+ t = Math.max(0, Math.min(1, t));
65524
+ const px = m.x1 + t * dx, py = m.y1 + t * dy;
65525
+ if (Math.hypot(wp.x - px, wp.y - py) < threshold) return m.id;
65526
+ }
65527
+ return null;
65528
+ }
65529
+ function hitTestAnnotation(wp, floor, zoom) {
65530
+ if (!floor.annotations) return null;
65531
+ const threshold = 10 / zoom;
65532
+ for (const a of floor.annotations) {
65533
+ const offset = a.offset || 40;
65534
+ const dx = a.x2 - a.x1, dy = a.y2 - a.y1;
65535
+ const len = Math.hypot(dx, dy);
65536
+ if (len < 1) continue;
65537
+ const ux = dx / len;
65538
+ const nx = -(dy / len), ny = ux;
65539
+ const d1x = a.x1 + nx * offset, d1y = a.y1 + ny * offset;
65540
+ const d2x = a.x2 + nx * offset, d2y = a.y2 + ny * offset;
65541
+ const ddx = d2x - d1x, ddy = d2y - d1y;
65542
+ const len2 = ddx * ddx + ddy * ddy;
65543
+ if (len2 === 0) continue;
65544
+ let t = ((wp.x - d1x) * ddx + (wp.y - d1y) * ddy) / len2;
65545
+ t = Math.max(0, Math.min(1, t));
65546
+ const px = d1x + t * ddx, py = d1y + t * ddy;
65547
+ if (Math.hypot(wp.x - px, wp.y - py) < threshold) return a.id;
65548
+ for (const [lx1, ly1, lx2, ly2] of [[
65549
+ a.x1,
65550
+ a.y1,
65551
+ d1x,
65552
+ d1y
65553
+ ], [
65554
+ a.x2,
65555
+ a.y2,
65556
+ d2x,
65557
+ d2y
65558
+ ]]) {
65559
+ const ldx = lx2 - lx1, ldy = ly2 - ly1;
65560
+ const llen2 = ldx * ldx + ldy * ldy;
65561
+ if (llen2 === 0) continue;
65562
+ let lt = ((wp.x - lx1) * ldx + (wp.y - ly1) * ldy) / llen2;
65563
+ lt = Math.max(0, Math.min(1, lt));
65564
+ const lpx = lx1 + lt * ldx, lpy = ly1 + lt * ldy;
65565
+ if (Math.hypot(wp.x - lpx, wp.y - lpy) < threshold) return a.id;
65566
+ }
65567
+ }
65568
+ return null;
65569
+ }
65570
+ function hitTestTextAnnotation(wp, floor, ctx, zoom) {
65571
+ if (!floor.textAnnotations) return null;
65572
+ for (let i = floor.textAnnotations.length - 1; i >= 0; i--) {
65573
+ const ta = floor.textAnnotations[i];
65574
+ let dx = wp.x - ta.x;
65575
+ let dy = wp.y - ta.y;
65576
+ if (ta.rotation) {
65577
+ const angle = -ta.rotation * Math.PI / 180;
65578
+ const rx = dx * Math.cos(angle) - dy * Math.sin(angle);
65579
+ const ry = dx * Math.sin(angle) + dy * Math.cos(angle);
65580
+ dx = rx;
65581
+ dy = ry;
65582
+ }
65583
+ ctx.font = `${ta.fontSize}px sans-serif`;
65584
+ const lines = ta.text.split("\n");
65585
+ const lineHeight = ta.fontSize * 1.2;
65586
+ const totalHeight = lines.length * lineHeight;
65587
+ let maxW = 0;
65588
+ for (const line of lines) {
65589
+ const w = ctx.measureText(line).width / zoom;
65590
+ if (w > maxW) maxW = w;
65591
+ }
65592
+ const pad = 8 / zoom;
65593
+ if (Math.abs(dx) < maxW / 2 + pad && Math.abs(dy) < totalHeight / 2 + pad) return ta.id;
65594
+ }
65595
+ return null;
65596
+ }
65597
+ //#endregion
65598
+ //#region src/lib/components/editor/FloorPlanCanvas.svelte
65599
+ init_client();
65600
+ init_index_client();
65601
+ var root_2$3 = /* @__PURE__ */ from_html(`<input type="text" class="absolute bg-white border-2 border-blue-500 rounded px-2 py-1 text-sm text-center shadow-lg outline-none"/>`);
65602
+ var root_3$2 = /* @__PURE__ */ from_html(`<input type="text" class="absolute bg-white border-2 border-blue-500 rounded px-2 py-1 text-sm text-center shadow-lg outline-none"/>`);
65603
+ var root_4$3 = /* @__PURE__ */ from_html(`<div class="absolute inset-0 flex items-center justify-center pointer-events-none"><div class="text-center opacity-60"><div class="text-5xl mb-3">๐Ÿ </div> <div class="text-sm font-medium text-gray-500">Start building your floor plan</div> <div class="text-xs text-gray-400 mt-1">Draw walls with <span class="font-mono bg-gray-100 px-1 rounded">W</span> or drag items from the sidebar</div></div></div>`);
65604
+ var root_5 = /* @__PURE__ */ from_html(`<canvas width="180" height="120" class="absolute bottom-10 right-2 rounded-lg shadow-lg border border-gray-300 cursor-crosshair bg-white" style="z-index: 15;"></canvas>`);
65605
+ var root_6 = /* @__PURE__ */ from_html(`<span> </span> <span> </span> <span class="text-gray-300">|</span>`, 1);
65606
+ var root_8$1 = /* @__PURE__ */ from_html(`<span> </span>`);
65607
+ var root_9 = /* @__PURE__ */ from_html(`<span> </span>`);
65608
+ var root_10 = /* @__PURE__ */ from_html(`<span> </span>`);
65609
+ var root_7$1 = /* @__PURE__ */ from_html(`<span> </span> <!> <!> <!> <span class="text-gray-300">|</span>`, 1);
65610
+ var root_11 = /* @__PURE__ */ from_html(`<span class="text-blue-600 font-medium"> </span> <span class="text-gray-300">|</span>`, 1);
65611
+ var root_13 = /* @__PURE__ */ from_html(`<label class="flex items-center gap-2 py-0.5 cursor-pointer hover:bg-gray-50 rounded px-1"><input type="checkbox" class="accent-blue-500"/> <span> </span></label>`);
65612
+ var root_12 = /* @__PURE__ */ from_html(`<div class="absolute bottom-12 right-2 z-20 bg-white rounded-lg shadow-lg border border-gray-200 p-3 text-xs min-w-[160px]"><div class="font-semibold text-gray-700 mb-2">Layers</div> <!> <hr class="my-1 border-gray-100"/> <label class="flex items-center gap-2 py-0.5 cursor-pointer hover:bg-gray-50 rounded px-1"><input type="checkbox" class="accent-blue-500"/> <span>Room Labels</span></label> <label class="flex items-center gap-2 py-0.5 cursor-pointer hover:bg-gray-50 rounded px-1"><input type="checkbox" class="accent-blue-500"/> <span>Dimensions</span></label></div>`);
65613
+ var root_16 = /* @__PURE__ */ from_html(`<button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500 hover:text-gray-700" title="Flip swing" aria-label="Flip swing"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M7 16V4m0 0L3 8m4-4l4 4M17 8v12m0 0l4-4m-4 4l-4-4"></path></svg></button>`);
65614
+ var root_17 = /* @__PURE__ */ from_html(`<button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500 hover:text-gray-700" title="Split wall at midpoint" aria-label="Split wall at midpoint"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2v20M4 12h4M16 12h4"></path></svg></button>`);
65615
+ var root_15 = /* @__PURE__ */ from_html(`<div class="absolute z-40 flex items-center gap-0.5 bg-white rounded-lg shadow-lg border border-gray-200 px-1 py-0.5"><button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500 hover:text-gray-700" title="Duplicate" aria-label="Duplicate"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"></rect><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"></path></svg></button> <!> <!> <div class="w-px h-5 bg-gray-200 mx-0.5"></div> <button class="w-7 h-7 flex items-center justify-center rounded hover:bg-red-50 text-gray-400 hover:text-red-600" title="Delete" aria-label="Delete"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2m3 0v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6h14"></path></svg></button></div>`);
65616
+ var root_18 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-blue-600 text-white px-3 py-1 rounded-full text-xs shadow">Click to add wall segment ยท Double-click to finish ยท C to close loop ยท
65617
+ Esc to cancel</div>`);
65618
+ var root_19 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-purple-600 text-white px-3 py-1 rounded-full text-xs shadow"> </div>`);
65619
+ var root_20 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-red-600 text-white px-3 py-1 rounded-full text-xs shadow">Right-click two points to measure ยท M to exit ยท Esc to cancel</div>`);
64493
65620
  var root_21 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-emerald-600 text-white px-3 py-1 rounded-full text-xs shadow">Click to place text label ยท Esc to cancel</div>`);
64494
65621
  var root_22 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-indigo-600 text-white px-3 py-1 rounded-full text-xs shadow"> </div>`);
64495
65622
  var root_1$5 = /* @__PURE__ */ from_html(`<!> <!> <!> <!> <div class="absolute bottom-2 right-2 bg-white/80 rounded px-2 py-1 text-xs text-gray-500 flex gap-3"><!> <!> <!> <span> </span> <button class="hover:text-gray-700" title="Zoom to Fit (F)">โŠž Fit</button> <button class="hover:text-gray-700" title="Toggle Grid (G)"> </button> <button class="hover:text-gray-700" title="Toggle Snap to Grid (S)"> </button> <button class="hover:text-gray-700" title="Toggle Furniture"> </button> <button class="hover:text-gray-700" title="Layer Visibility">๐Ÿ—‚ Layers</button> <button class="hover:text-gray-700" title="Toggle Rulers"> </button> <button class="hover:text-gray-700" title="Toggle Mini-map"> </button></div> <!> <!> <!> <!> <!> <!> <!> <div class="absolute bottom-3 left-3 z-20 flex items-center gap-1 bg-white rounded-lg shadow-lg border border-gray-200 px-1 py-0.5"><button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-600 hover:text-gray-800 font-bold text-lg" title="Zoom Out (โˆ’)" aria-label="Zoom out">โˆ’</button> <button class="min-w-[3.5rem] h-7 flex items-center justify-center rounded hover:bg-gray-100 text-xs font-medium text-gray-600 hover:text-gray-800 tabular-nums" title="Reset to 100%" aria-label="Zoom to 100%"> </button> <button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-600 hover:text-gray-800 font-bold text-lg" title="Zoom In (+)" aria-label="Zoom in">+</button> <div class="w-px h-5 bg-gray-200"></div> <button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500 hover:text-gray-700 text-sm" title="Zoom to Fit (F)" aria-label="Zoom to fit">โŠž</button></div> <!>`, 1);
@@ -65412,7 +66539,7 @@ function FloorPlanCanvas($$anchor, $$props) {
65412
66539
  canvasDirty = false;
65413
66540
  ctx.clearRect(0, 0, get(width), get(height));
65414
66541
  ctx.fillStyle = "#f8f9fa";
65415
- ctx.fillRect(0, 0, $$props.floorMaxWidth, $$props.floorMaxHeight);
66542
+ ctx.fillRect(0, 0, $$props.viewOnly ? $$props.floorMaxWidth : get(width), $$props.viewOnly ? $$props.floorMaxHeight : get(height));
65416
66543
  drawGrid();
65417
66544
  if (!$$props.viewOnly && get(layerVis).guides) drawGuides$1();
65418
66545
  drawBackgroundImage();
@@ -65433,7 +66560,12 @@ function FloorPlanCanvas($$anchor, $$props) {
65433
66560
  return id === selId || multiIds.has(id);
65434
66561
  }
65435
66562
  drawRooms$1();
65436
- if (floor && $$props.heatmapEnabled) drawFloorHeatmap(getCS(), floor, $$props.heatmapMatrix || [], get(detectedRooms));
66563
+ console.log("๐Ÿš€ ~ draw ~ heatmapEnabled:", $$props.heatmapEnabled);
66564
+ console.log("๐Ÿš€ ~ draw ~ heatmapMatrix:", $$props.heatmapMatrix);
66565
+ if (floor) {
66566
+ var _$$props$heatmapMatri;
66567
+ drawFloorHeatmap(getCS(), floor, $$props.heatmapMatrix ? ((_$$props$heatmapMatri = $$props.heatmapMatrix) === null || _$$props$heatmapMatri === void 0 ? void 0 : _$$props$heatmapMatri.length) > 0 ? $$props.heatmapMatrix : SAMPLE_HEATMAP_32X32 : SAMPLE_HEATMAP_32X32, get(detectedRooms));
66568
+ }
65437
66569
  if (!$$props.viewOnly) drawSnapPoints$1();
65438
66570
  if (get(layerVis).walls) {
65439
66571
  for (const w of floor.walls) drawWall$1(w, isSelected(w.id));