@fieldnotes/core 0.42.0 → 0.43.0

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.
package/dist/index.cjs CHANGED
@@ -4360,6 +4360,135 @@ var ContextMenu = class {
4360
4360
  }
4361
4361
  };
4362
4362
 
4363
+ // src/canvas/minimap-transform.ts
4364
+ function unionBounds(a, b) {
4365
+ const minX = Math.min(a.x, b.x);
4366
+ const minY = Math.min(a.y, b.y);
4367
+ const maxX = Math.max(a.x + a.w, b.x + b.w);
4368
+ const maxY = Math.max(a.y + a.h, b.y + b.h);
4369
+ return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };
4370
+ }
4371
+ function computeMinimapTransform(mapping, miniW, miniH, padding) {
4372
+ const availW = Math.max(1, miniW - 2 * padding);
4373
+ const availH = Math.max(1, miniH - 2 * padding);
4374
+ const w = Math.max(mapping.w, 1);
4375
+ const h = Math.max(mapping.h, 1);
4376
+ const scale = Math.min(availW / w, availH / h);
4377
+ const offsetX = (miniW - mapping.w * scale) / 2 - mapping.x * scale;
4378
+ const offsetY = (miniH - mapping.h * scale) / 2 - mapping.y * scale;
4379
+ return { scale, offsetX, offsetY };
4380
+ }
4381
+ function worldToMini(t, p) {
4382
+ return { x: p.x * t.scale + t.offsetX, y: p.y * t.scale + t.offsetY };
4383
+ }
4384
+ function miniToWorld(t, p) {
4385
+ return { x: (p.x - t.offsetX) / t.scale, y: (p.y - t.offsetY) / t.scale };
4386
+ }
4387
+
4388
+ // src/canvas/minimap.ts
4389
+ var WIDTH = 200;
4390
+ var HEIGHT = 140;
4391
+ var MARGIN = 16;
4392
+ var PADDING = 8;
4393
+ var NEUTRAL = "rgba(100,116,139,0.6)";
4394
+ var VIEWPORT_STROKE = "#3b82f6";
4395
+ function elementColor(el) {
4396
+ return "color" in el && typeof el.color === "string" ? el.color : NEUTRAL;
4397
+ }
4398
+ var Minimap = class {
4399
+ constructor(deps) {
4400
+ this.deps = deps;
4401
+ const canvas = document.createElement("canvas");
4402
+ canvas.width = WIDTH;
4403
+ canvas.height = HEIGHT;
4404
+ Object.assign(canvas.style, {
4405
+ position: "absolute",
4406
+ right: `${MARGIN}px`,
4407
+ bottom: `${MARGIN}px`,
4408
+ width: `${WIDTH}px`,
4409
+ height: `${HEIGHT}px`,
4410
+ background: "rgba(255,255,255,0.85)",
4411
+ border: "1px solid rgba(0,0,0,0.15)",
4412
+ borderRadius: "4px",
4413
+ touchAction: "none",
4414
+ cursor: "pointer",
4415
+ zIndex: "10"
4416
+ });
4417
+ canvas.addEventListener("pointerdown", this.onPointerDown);
4418
+ canvas.addEventListener("pointermove", this.onPointerMove);
4419
+ canvas.addEventListener("pointerup", this.onPointerUp);
4420
+ this.deps.container.appendChild(canvas);
4421
+ this.canvas = canvas;
4422
+ }
4423
+ canvas;
4424
+ rafId = null;
4425
+ dragging = false;
4426
+ scheduleDraw() {
4427
+ if (this.rafId !== null) return;
4428
+ this.rafId = this.deps.requestFrame(this.draw);
4429
+ }
4430
+ destroy() {
4431
+ if (this.rafId !== null) {
4432
+ this.deps.cancelFrame(this.rafId);
4433
+ this.rafId = null;
4434
+ }
4435
+ this.canvas.removeEventListener("pointerdown", this.onPointerDown);
4436
+ this.canvas.removeEventListener("pointermove", this.onPointerMove);
4437
+ this.canvas.removeEventListener("pointerup", this.onPointerUp);
4438
+ this.canvas.remove();
4439
+ }
4440
+ currentTransform() {
4441
+ const viewport = this.deps.getViewportRect();
4442
+ const content = this.deps.getContentBounds();
4443
+ const mapping = content ? unionBounds(content, viewport) : viewport;
4444
+ return computeMinimapTransform(mapping, WIDTH, HEIGHT, PADDING);
4445
+ }
4446
+ draw = () => {
4447
+ this.rafId = null;
4448
+ const ctx = this.canvas.getContext("2d");
4449
+ if (!ctx) return;
4450
+ const t = this.currentTransform();
4451
+ const viewport = this.deps.getViewportRect();
4452
+ ctx.clearRect(0, 0, WIDTH, HEIGHT);
4453
+ for (const el of this.deps.getElements()) {
4454
+ const b = getElementBounds(el);
4455
+ if (!b) continue;
4456
+ const tl = worldToMini(t, { x: b.x, y: b.y });
4457
+ ctx.fillStyle = elementColor(el);
4458
+ ctx.fillRect(tl.x, tl.y, Math.max(1, b.w * t.scale), Math.max(1, b.h * t.scale));
4459
+ }
4460
+ const vtl = worldToMini(t, { x: viewport.x, y: viewport.y });
4461
+ ctx.strokeStyle = VIEWPORT_STROKE;
4462
+ ctx.lineWidth = 1.5;
4463
+ ctx.strokeRect(vtl.x, vtl.y, viewport.w * t.scale, viewport.h * t.scale);
4464
+ };
4465
+ navigateFromEvent(e) {
4466
+ const rect = this.canvas.getBoundingClientRect();
4467
+ const point = { x: e.clientX - rect.left, y: e.clientY - rect.top };
4468
+ const world = miniToWorld(this.currentTransform(), point);
4469
+ this.deps.navigateTo(world);
4470
+ }
4471
+ onPointerDown = (e) => {
4472
+ e.stopPropagation();
4473
+ e.preventDefault();
4474
+ this.dragging = true;
4475
+ this.canvas.setPointerCapture?.(e.pointerId);
4476
+ this.navigateFromEvent(e);
4477
+ };
4478
+ onPointerMove = (e) => {
4479
+ if (!this.dragging) return;
4480
+ e.stopPropagation();
4481
+ this.navigateFromEvent(e);
4482
+ };
4483
+ onPointerUp = (e) => {
4484
+ this.dragging = false;
4485
+ try {
4486
+ this.canvas.releasePointerCapture(e.pointerId);
4487
+ } catch {
4488
+ }
4489
+ };
4490
+ };
4491
+
4363
4492
  // src/canvas/viewport-dom.ts
4364
4493
  function createWrapper() {
4365
4494
  const el = document.createElement("div");
@@ -6485,7 +6614,7 @@ function getElementStyle(element) {
6485
6614
  }
6486
6615
 
6487
6616
  // src/canvas/selection-ops.ts
6488
- function unionBounds(list) {
6617
+ function unionBounds2(list) {
6489
6618
  let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
6490
6619
  for (const b of list) {
6491
6620
  minX = Math.min(minX, b.x);
@@ -6580,7 +6709,7 @@ var SelectionOps = class {
6580
6709
  align(edge) {
6581
6710
  const bounded = this.boundedSelection();
6582
6711
  if (bounded.length < 2) return;
6583
- const B = unionBounds(bounded.map((e) => e.bounds));
6712
+ const B = unionBounds2(bounded.map((e) => e.bounds));
6584
6713
  this.deps.recorder.begin();
6585
6714
  const moved = [];
6586
6715
  for (const { id, el, bounds: b } of bounded) {
@@ -6987,6 +7116,27 @@ var Viewport = class {
6987
7116
  });
6988
7117
  }
6989
7118
  this.unsubToolChange = this.toolManager.onChange(() => this.contextMenu?.close());
7119
+ if (options.minimap) {
7120
+ const visibleEls = () => this.store.getAll().filter((el) => this.layerManager.isLayerVisible(el.layerId));
7121
+ this.minimap = new Minimap({
7122
+ container: this.wrapper,
7123
+ getElements: visibleEls,
7124
+ getContentBounds: () => getElementsBoundingBox(visibleEls()),
7125
+ getViewportRect: () => this.camera.getVisibleRect(this.canvasEl.clientWidth, this.canvasEl.clientHeight),
7126
+ navigateTo: (w) => {
7127
+ const z = this.camera.zoom;
7128
+ this.camera.moveTo(
7129
+ this.canvasEl.clientWidth / 2 - w.x * z,
7130
+ this.canvasEl.clientHeight / 2 - w.y * z
7131
+ );
7132
+ },
7133
+ requestFrame: (cb) => typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame(cb) : 0,
7134
+ cancelFrame: (id) => {
7135
+ if (typeof cancelAnimationFrame !== "undefined") cancelAnimationFrame(id);
7136
+ }
7137
+ });
7138
+ this.minimap.scheduleDraw();
7139
+ }
6990
7140
  this.domNodeManager = new DomNodeManager({
6991
7141
  domLayer: this.domLayer,
6992
7142
  onEditRequest: (id) => this.interactions.startEditingElement(id),
@@ -7019,6 +7169,7 @@ var Viewport = class {
7019
7169
  this.applyCameraTransform();
7020
7170
  this.noteEditor.updateToolbarPosition();
7021
7171
  this.contextMenu?.close();
7172
+ this.minimap?.scheduleDraw();
7022
7173
  this.requestRender();
7023
7174
  });
7024
7175
  this.gridController = new GridController({
@@ -7033,6 +7184,7 @@ var Viewport = class {
7033
7184
  this.store.on("add", (el) => {
7034
7185
  if (el.type === "grid") this.gridController.syncContext();
7035
7186
  this.renderLoop.markLayerDirty(el.layerId);
7187
+ this.minimap?.scheduleDraw();
7036
7188
  this.requestRender();
7037
7189
  }),
7038
7190
  this.store.on("remove", (el) => {
@@ -7040,6 +7192,7 @@ var Viewport = class {
7040
7192
  this.unbindArrowsFrom(el);
7041
7193
  this.domNodeManager.removeDomNode(el.id);
7042
7194
  this.renderLoop.markLayerDirty(el.layerId);
7195
+ this.minimap?.scheduleDraw();
7043
7196
  this.requestRender();
7044
7197
  }),
7045
7198
  this.store.on("update", ({ previous, current }) => {
@@ -7048,17 +7201,20 @@ var Viewport = class {
7048
7201
  if (previous.layerId !== current.layerId) {
7049
7202
  this.renderLoop.markLayerDirty(previous.layerId);
7050
7203
  }
7204
+ this.minimap?.scheduleDraw();
7051
7205
  this.requestRender();
7052
7206
  }),
7053
7207
  this.store.on("clear", () => {
7054
7208
  this.domNodeManager.clearDomNodes();
7055
7209
  this.renderLoop.markAllLayersDirty();
7056
7210
  this.gridController.syncContext();
7211
+ this.minimap?.scheduleDraw();
7057
7212
  this.requestRender();
7058
7213
  })
7059
7214
  ];
7060
7215
  this.layerManager.on("change", () => {
7061
7216
  this.toolContext.activeLayerId = this.layerManager.activeLayerId;
7217
+ this.minimap?.scheduleDraw();
7062
7218
  this.requestRender();
7063
7219
  });
7064
7220
  this.interactions = new ViewportInteractions({
@@ -7118,6 +7274,7 @@ var Viewport = class {
7118
7274
  gridController;
7119
7275
  interactions;
7120
7276
  contextMenu = null;
7277
+ minimap = null;
7121
7278
  htmlRenderers = /* @__PURE__ */ new Map();
7122
7279
  get ctx() {
7123
7280
  return this.canvasEl.getContext("2d");
@@ -7391,6 +7548,7 @@ var Viewport = class {
7391
7548
  this.arrowLabelEditor.cancel();
7392
7549
  this.historyRecorder.destroy();
7393
7550
  this.contextMenu?.dispose();
7551
+ this.minimap?.destroy();
7394
7552
  this.wrapper.removeEventListener("pointerdown", this.interactions.onTapDown);
7395
7553
  this.wrapper.removeEventListener("pointerup", this.interactions.onDoubleTap);
7396
7554
  this.wrapper.removeEventListener("dragover", this.interactions.onDragOver);
@@ -9893,7 +10051,7 @@ var LaserTool = class {
9893
10051
  };
9894
10052
 
9895
10053
  // src/index.ts
9896
- var VERSION = "0.42.0";
10054
+ var VERSION = "0.43.0";
9897
10055
  // Annotate the CommonJS export names for ESM import in node:
9898
10056
  0 && (module.exports = {
9899
10057
  ArrowTool,