@fieldnotes/core 0.6.1 → 0.7.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.d.cts CHANGED
@@ -85,7 +85,17 @@ interface ShapeElement extends BaseElement {
85
85
  strokeWidth: number;
86
86
  fillColor: string;
87
87
  }
88
- type CanvasElement = StrokeElement | NoteElement | ArrowElement | ImageElement | HtmlElement | TextElement | ShapeElement;
88
+ type HexOrientation = 'pointy' | 'flat';
89
+ interface GridElement extends BaseElement {
90
+ type: 'grid';
91
+ gridType: 'square' | 'hex';
92
+ hexOrientation: HexOrientation;
93
+ cellSize: number;
94
+ strokeColor: string;
95
+ strokeWidth: number;
96
+ opacity: number;
97
+ }
98
+ type CanvasElement = StrokeElement | NoteElement | ArrowElement | ImageElement | HtmlElement | TextElement | ShapeElement | GridElement;
89
99
  type ElementType = CanvasElement['type'];
90
100
 
91
101
  interface Layer {
@@ -437,6 +447,16 @@ declare class Viewport {
437
447
  w: number;
438
448
  h: number;
439
449
  }): string;
450
+ addGrid(input: {
451
+ gridType?: 'square' | 'hex';
452
+ hexOrientation?: 'pointy' | 'flat';
453
+ cellSize?: number;
454
+ strokeColor?: string;
455
+ strokeWidth?: number;
456
+ opacity?: number;
457
+ }): string;
458
+ updateGrid(updates: Partial<Pick<GridElement, 'gridType' | 'hexOrientation' | 'cellSize' | 'strokeColor' | 'strokeWidth' | 'opacity'>>): void;
459
+ removeGrid(): void;
440
460
  destroy(): void;
441
461
  private startRenderLoop;
442
462
  private render;
@@ -469,8 +489,12 @@ declare class ElementRenderer {
469
489
  private store;
470
490
  private imageCache;
471
491
  private onImageLoad;
492
+ private camera;
493
+ private canvasSize;
472
494
  setStore(store: ElementStore): void;
473
495
  setOnImageLoad(callback: () => void): void;
496
+ setCamera(camera: Camera): void;
497
+ setCanvasSize(w: number, h: number): void;
474
498
  isDomElement(element: CanvasElement): boolean;
475
499
  renderCanvasElement(ctx: CanvasRenderingContext2D, element: CanvasElement): void;
476
500
  private renderStroke;
@@ -480,6 +504,7 @@ declare class ElementRenderer {
480
504
  private renderShape;
481
505
  private fillShapePath;
482
506
  private strokeShapePath;
507
+ private renderGrid;
483
508
  private renderImage;
484
509
  private getImage;
485
510
  }
@@ -562,6 +587,15 @@ interface ShapeInput extends BaseDefaults {
562
587
  fillColor?: string;
563
588
  }
564
589
  declare function createShape(input: ShapeInput): ShapeElement;
590
+ interface GridInput extends BaseDefaults {
591
+ gridType?: 'square' | 'hex';
592
+ hexOrientation?: HexOrientation;
593
+ cellSize?: number;
594
+ strokeColor?: string;
595
+ strokeWidth?: number;
596
+ opacity?: number;
597
+ }
598
+ declare function createGrid(input: GridInput): GridElement;
565
599
  declare function createText(input: TextInput): TextElement;
566
600
 
567
601
  interface Rect {
@@ -826,4 +860,4 @@ declare class UpdateLayerCommand implements Command {
826
860
 
827
861
  declare const VERSION = "0.6.1";
828
862
 
829
- export { AddElementCommand, type ArrowElement, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, Background, type BackgroundOptions, type BackgroundPattern, BatchCommand, type Binding, type Bounds, Camera, type CameraOptions, type CanvasElement, type CanvasState, type Command, CreateLayerCommand, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, HandTool, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputHandler, type Layer, LayerManager, NoteEditor, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, RemoveElementCommand, RemoveLayerCommand, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type Size, type StrokeElement, type StrokePoint, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, UpdateElementCommand, UpdateLayerCommand, VERSION, Viewport, type ViewportOptions, clearStaleBindings, createArrow, createHtmlElement, createId, createImage, createNote, createShape, createStroke, createText, exportState, findBindTarget, findBoundArrows, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getEdgeIntersection, getElementBounds, getElementCenter, isBindable, isNearBezier, parseState, snapPoint, unbindArrow, updateBoundArrow };
863
+ export { AddElementCommand, type ArrowElement, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, Background, type BackgroundOptions, type BackgroundPattern, BatchCommand, type Binding, type Bounds, Camera, type CameraOptions, type CanvasElement, type CanvasState, type Command, CreateLayerCommand, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, type GridElement, HandTool, type HexOrientation, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputHandler, type Layer, LayerManager, NoteEditor, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, RemoveElementCommand, RemoveLayerCommand, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type Size, type StrokeElement, type StrokePoint, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, UpdateElementCommand, UpdateLayerCommand, VERSION, Viewport, type ViewportOptions, clearStaleBindings, createArrow, createGrid, createHtmlElement, createId, createImage, createNote, createShape, createStroke, createText, exportState, findBindTarget, findBoundArrows, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getEdgeIntersection, getElementBounds, getElementCenter, isBindable, isNearBezier, parseState, snapPoint, unbindArrow, updateBoundArrow };
package/dist/index.d.ts CHANGED
@@ -85,7 +85,17 @@ interface ShapeElement extends BaseElement {
85
85
  strokeWidth: number;
86
86
  fillColor: string;
87
87
  }
88
- type CanvasElement = StrokeElement | NoteElement | ArrowElement | ImageElement | HtmlElement | TextElement | ShapeElement;
88
+ type HexOrientation = 'pointy' | 'flat';
89
+ interface GridElement extends BaseElement {
90
+ type: 'grid';
91
+ gridType: 'square' | 'hex';
92
+ hexOrientation: HexOrientation;
93
+ cellSize: number;
94
+ strokeColor: string;
95
+ strokeWidth: number;
96
+ opacity: number;
97
+ }
98
+ type CanvasElement = StrokeElement | NoteElement | ArrowElement | ImageElement | HtmlElement | TextElement | ShapeElement | GridElement;
89
99
  type ElementType = CanvasElement['type'];
90
100
 
91
101
  interface Layer {
@@ -437,6 +447,16 @@ declare class Viewport {
437
447
  w: number;
438
448
  h: number;
439
449
  }): string;
450
+ addGrid(input: {
451
+ gridType?: 'square' | 'hex';
452
+ hexOrientation?: 'pointy' | 'flat';
453
+ cellSize?: number;
454
+ strokeColor?: string;
455
+ strokeWidth?: number;
456
+ opacity?: number;
457
+ }): string;
458
+ updateGrid(updates: Partial<Pick<GridElement, 'gridType' | 'hexOrientation' | 'cellSize' | 'strokeColor' | 'strokeWidth' | 'opacity'>>): void;
459
+ removeGrid(): void;
440
460
  destroy(): void;
441
461
  private startRenderLoop;
442
462
  private render;
@@ -469,8 +489,12 @@ declare class ElementRenderer {
469
489
  private store;
470
490
  private imageCache;
471
491
  private onImageLoad;
492
+ private camera;
493
+ private canvasSize;
472
494
  setStore(store: ElementStore): void;
473
495
  setOnImageLoad(callback: () => void): void;
496
+ setCamera(camera: Camera): void;
497
+ setCanvasSize(w: number, h: number): void;
474
498
  isDomElement(element: CanvasElement): boolean;
475
499
  renderCanvasElement(ctx: CanvasRenderingContext2D, element: CanvasElement): void;
476
500
  private renderStroke;
@@ -480,6 +504,7 @@ declare class ElementRenderer {
480
504
  private renderShape;
481
505
  private fillShapePath;
482
506
  private strokeShapePath;
507
+ private renderGrid;
483
508
  private renderImage;
484
509
  private getImage;
485
510
  }
@@ -562,6 +587,15 @@ interface ShapeInput extends BaseDefaults {
562
587
  fillColor?: string;
563
588
  }
564
589
  declare function createShape(input: ShapeInput): ShapeElement;
590
+ interface GridInput extends BaseDefaults {
591
+ gridType?: 'square' | 'hex';
592
+ hexOrientation?: HexOrientation;
593
+ cellSize?: number;
594
+ strokeColor?: string;
595
+ strokeWidth?: number;
596
+ opacity?: number;
597
+ }
598
+ declare function createGrid(input: GridInput): GridElement;
565
599
  declare function createText(input: TextInput): TextElement;
566
600
 
567
601
  interface Rect {
@@ -826,4 +860,4 @@ declare class UpdateLayerCommand implements Command {
826
860
 
827
861
  declare const VERSION = "0.6.1";
828
862
 
829
- export { AddElementCommand, type ArrowElement, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, Background, type BackgroundOptions, type BackgroundPattern, BatchCommand, type Binding, type Bounds, Camera, type CameraOptions, type CanvasElement, type CanvasState, type Command, CreateLayerCommand, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, HandTool, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputHandler, type Layer, LayerManager, NoteEditor, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, RemoveElementCommand, RemoveLayerCommand, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type Size, type StrokeElement, type StrokePoint, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, UpdateElementCommand, UpdateLayerCommand, VERSION, Viewport, type ViewportOptions, clearStaleBindings, createArrow, createHtmlElement, createId, createImage, createNote, createShape, createStroke, createText, exportState, findBindTarget, findBoundArrows, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getEdgeIntersection, getElementBounds, getElementCenter, isBindable, isNearBezier, parseState, snapPoint, unbindArrow, updateBoundArrow };
863
+ export { AddElementCommand, type ArrowElement, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, Background, type BackgroundOptions, type BackgroundPattern, BatchCommand, type Binding, type Bounds, Camera, type CameraOptions, type CanvasElement, type CanvasState, type Command, CreateLayerCommand, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, type GridElement, HandTool, type HexOrientation, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputHandler, type Layer, LayerManager, NoteEditor, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, RemoveElementCommand, RemoveLayerCommand, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type Size, type StrokeElement, type StrokePoint, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, UpdateElementCommand, UpdateLayerCommand, VERSION, Viewport, type ViewportOptions, clearStaleBindings, createArrow, createGrid, createHtmlElement, createId, createImage, createNote, createShape, createStroke, createText, exportState, findBindTarget, findBoundArrows, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getEdgeIntersection, getElementBounds, getElementCenter, isBindable, isNearBezier, parseState, snapPoint, unbindArrow, updateBoundArrow };
package/dist/index.js CHANGED
@@ -84,7 +84,7 @@ function validateState(data) {
84
84
  ];
85
85
  }
86
86
  }
87
- var VALID_TYPES = /* @__PURE__ */ new Set(["stroke", "note", "arrow", "image", "html", "text", "shape"]);
87
+ var VALID_TYPES = /* @__PURE__ */ new Set(["stroke", "note", "arrow", "image", "html", "text", "shape", "grid"]);
88
88
  function validateElement(el) {
89
89
  if (!el || typeof el !== "object") {
90
90
  throw new Error("Invalid element: expected an object");
@@ -945,6 +945,118 @@ function smoothToSegments(points) {
945
945
  return segments;
946
946
  }
947
947
 
948
+ // src/elements/grid-renderer.ts
949
+ function getSquareGridLines(bounds, cellSize) {
950
+ if (cellSize <= 0) return { verticals: [], horizontals: [] };
951
+ const verticals = [];
952
+ const startX = Math.floor(bounds.minX / cellSize) * cellSize;
953
+ const endX = Math.ceil(bounds.maxX / cellSize) * cellSize;
954
+ for (let x = startX; x <= endX; x += cellSize) {
955
+ verticals.push(x);
956
+ }
957
+ const horizontals = [];
958
+ const startY = Math.floor(bounds.minY / cellSize) * cellSize;
959
+ const endY = Math.ceil(bounds.maxY / cellSize) * cellSize;
960
+ for (let y = startY; y <= endY; y += cellSize) {
961
+ horizontals.push(y);
962
+ }
963
+ return { verticals, horizontals };
964
+ }
965
+ function getHexVertices(cx, cy, circumradius, orientation) {
966
+ const vertices = [];
967
+ const angleOffset = orientation === "pointy" ? -Math.PI / 2 : 0;
968
+ for (let i = 0; i < 6; i++) {
969
+ const angle = Math.PI / 3 * i + angleOffset;
970
+ vertices.push({
971
+ x: cx + circumradius * Math.cos(angle),
972
+ y: cy + circumradius * Math.sin(angle)
973
+ });
974
+ }
975
+ return vertices;
976
+ }
977
+ function getHexCenters(bounds, circumradius, orientation) {
978
+ if (circumradius <= 0) return [];
979
+ const centers = [];
980
+ if (orientation === "pointy") {
981
+ const hexW = Math.sqrt(3) * circumradius;
982
+ const hexH = 2 * circumradius;
983
+ const rowH = hexH * 0.75;
984
+ const startRow = Math.floor((bounds.minY - circumradius) / rowH);
985
+ const endRow = Math.ceil((bounds.maxY + circumradius) / rowH);
986
+ const startCol = Math.floor((bounds.minX - hexW) / hexW);
987
+ const endCol = Math.ceil((bounds.maxX + hexW) / hexW);
988
+ for (let row = startRow; row <= endRow; row++) {
989
+ const offsetX = row % 2 !== 0 ? hexW / 2 : 0;
990
+ for (let col = startCol; col <= endCol; col++) {
991
+ centers.push({
992
+ x: col * hexW + offsetX,
993
+ y: row * rowH
994
+ });
995
+ }
996
+ }
997
+ } else {
998
+ const hexW = 2 * circumradius;
999
+ const hexH = Math.sqrt(3) * circumradius;
1000
+ const colW = hexW * 0.75;
1001
+ const startCol = Math.floor((bounds.minX - circumradius) / colW);
1002
+ const endCol = Math.ceil((bounds.maxX + circumradius) / colW);
1003
+ const startRow = Math.floor((bounds.minY - hexH) / hexH);
1004
+ const endRow = Math.ceil((bounds.maxY + hexH) / hexH);
1005
+ for (let col = startCol; col <= endCol; col++) {
1006
+ const offsetY = col % 2 !== 0 ? hexH / 2 : 0;
1007
+ for (let row = startRow; row <= endRow; row++) {
1008
+ centers.push({
1009
+ x: col * colW,
1010
+ y: row * hexH + offsetY
1011
+ });
1012
+ }
1013
+ }
1014
+ }
1015
+ return centers;
1016
+ }
1017
+ function renderSquareGrid(ctx, bounds, cellSize, strokeColor, strokeWidth, opacity) {
1018
+ if (cellSize <= 0) return;
1019
+ const { verticals, horizontals } = getSquareGridLines(bounds, cellSize);
1020
+ ctx.save();
1021
+ ctx.strokeStyle = strokeColor;
1022
+ ctx.lineWidth = strokeWidth;
1023
+ ctx.globalAlpha = opacity;
1024
+ ctx.beginPath();
1025
+ for (const x of verticals) {
1026
+ ctx.moveTo(x, bounds.minY);
1027
+ ctx.lineTo(x, bounds.maxY);
1028
+ }
1029
+ for (const y of horizontals) {
1030
+ ctx.moveTo(bounds.minX, y);
1031
+ ctx.lineTo(bounds.maxX, y);
1032
+ }
1033
+ ctx.stroke();
1034
+ ctx.restore();
1035
+ }
1036
+ function renderHexGrid(ctx, bounds, cellSize, orientation, strokeColor, strokeWidth, opacity) {
1037
+ if (cellSize <= 0) return;
1038
+ const centers = getHexCenters(bounds, cellSize, orientation);
1039
+ ctx.save();
1040
+ ctx.strokeStyle = strokeColor;
1041
+ ctx.lineWidth = strokeWidth;
1042
+ ctx.globalAlpha = opacity;
1043
+ ctx.beginPath();
1044
+ for (const center of centers) {
1045
+ const verts = getHexVertices(center.x, center.y, cellSize, orientation);
1046
+ const first = verts[0];
1047
+ if (!first) continue;
1048
+ ctx.moveTo(first.x, first.y);
1049
+ for (let i = 1; i < verts.length; i++) {
1050
+ const v = verts[i];
1051
+ if (!v) continue;
1052
+ ctx.lineTo(v.x, v.y);
1053
+ }
1054
+ ctx.closePath();
1055
+ }
1056
+ ctx.stroke();
1057
+ ctx.restore();
1058
+ }
1059
+
948
1060
  // src/elements/element-renderer.ts
949
1061
  var DOM_ELEMENT_TYPES = /* @__PURE__ */ new Set(["note", "html", "text"]);
950
1062
  var ARROWHEAD_LENGTH = 12;
@@ -953,12 +1065,20 @@ var ElementRenderer = class {
953
1065
  store = null;
954
1066
  imageCache = /* @__PURE__ */ new Map();
955
1067
  onImageLoad = null;
1068
+ camera = null;
1069
+ canvasSize = null;
956
1070
  setStore(store) {
957
1071
  this.store = store;
958
1072
  }
959
1073
  setOnImageLoad(callback) {
960
1074
  this.onImageLoad = callback;
961
1075
  }
1076
+ setCamera(camera) {
1077
+ this.camera = camera;
1078
+ }
1079
+ setCanvasSize(w, h) {
1080
+ this.canvasSize = { w, h };
1081
+ }
962
1082
  isDomElement(element) {
963
1083
  return DOM_ELEMENT_TYPES.has(element.type);
964
1084
  }
@@ -976,6 +1096,9 @@ var ElementRenderer = class {
976
1096
  case "image":
977
1097
  this.renderImage(ctx, element);
978
1098
  break;
1099
+ case "grid":
1100
+ this.renderGrid(ctx, element);
1101
+ break;
979
1102
  }
980
1103
  }
981
1104
  renderStroke(ctx, stroke) {
@@ -1111,6 +1234,42 @@ var ElementRenderer = class {
1111
1234
  }
1112
1235
  }
1113
1236
  }
1237
+ renderGrid(ctx, grid) {
1238
+ if (!this.canvasSize) return;
1239
+ const cam = this.camera;
1240
+ if (!cam) return;
1241
+ const topLeft = cam.screenToWorld({ x: 0, y: 0 });
1242
+ const bottomRight = cam.screenToWorld({
1243
+ x: this.canvasSize.w,
1244
+ y: this.canvasSize.h
1245
+ });
1246
+ const bounds = {
1247
+ minX: topLeft.x,
1248
+ minY: topLeft.y,
1249
+ maxX: bottomRight.x,
1250
+ maxY: bottomRight.y
1251
+ };
1252
+ if (grid.gridType === "hex") {
1253
+ renderHexGrid(
1254
+ ctx,
1255
+ bounds,
1256
+ grid.cellSize,
1257
+ grid.hexOrientation,
1258
+ grid.strokeColor,
1259
+ grid.strokeWidth,
1260
+ grid.opacity
1261
+ );
1262
+ } else {
1263
+ renderSquareGrid(
1264
+ ctx,
1265
+ bounds,
1266
+ grid.cellSize,
1267
+ grid.strokeColor,
1268
+ grid.strokeWidth,
1269
+ grid.opacity
1270
+ );
1271
+ }
1272
+ }
1114
1273
  renderImage(ctx, image) {
1115
1274
  const img = this.getImage(image.src);
1116
1275
  if (!img) return;
@@ -1553,6 +1712,22 @@ function createShape(input) {
1553
1712
  fillColor: input.fillColor ?? "none"
1554
1713
  };
1555
1714
  }
1715
+ function createGrid(input) {
1716
+ return {
1717
+ id: createId("grid"),
1718
+ type: "grid",
1719
+ position: input.position ?? { x: 0, y: 0 },
1720
+ zIndex: input.zIndex ?? 0,
1721
+ locked: input.locked ?? false,
1722
+ layerId: input.layerId ?? "",
1723
+ gridType: input.gridType ?? "square",
1724
+ hexOrientation: input.hexOrientation ?? "pointy",
1725
+ cellSize: input.cellSize ?? 40,
1726
+ strokeColor: input.strokeColor ?? "#000000",
1727
+ strokeWidth: input.strokeWidth ?? 1,
1728
+ opacity: input.opacity ?? 1
1729
+ };
1730
+ }
1556
1731
  function createText(input) {
1557
1732
  return {
1558
1733
  id: createId("text"),
@@ -1730,6 +1905,7 @@ var Viewport = class {
1730
1905
  this.toolManager = new ToolManager();
1731
1906
  this.renderer = new ElementRenderer();
1732
1907
  this.renderer.setStore(this.store);
1908
+ this.renderer.setCamera(this.camera);
1733
1909
  this.renderer.setOnImageLoad(() => this.requestRender());
1734
1910
  this.noteEditor = new NoteEditor();
1735
1911
  this.noteEditor.setOnStop((id) => this.onTextEditStop(id));
@@ -1876,6 +2052,34 @@ var Viewport = class {
1876
2052
  this.requestRender();
1877
2053
  return el.id;
1878
2054
  }
2055
+ addGrid(input) {
2056
+ const existing = this.store.getElementsByType("grid")[0];
2057
+ this.historyRecorder.begin();
2058
+ if (existing) {
2059
+ this.store.remove(existing.id);
2060
+ }
2061
+ const grid = createGrid({ ...input, layerId: this.layerManager.activeLayerId });
2062
+ this.store.add(grid);
2063
+ this.historyRecorder.commit();
2064
+ this.requestRender();
2065
+ return grid.id;
2066
+ }
2067
+ updateGrid(updates) {
2068
+ const grid = this.store.getElementsByType("grid")[0];
2069
+ if (!grid) return;
2070
+ this.historyRecorder.begin();
2071
+ this.store.update(grid.id, updates);
2072
+ this.historyRecorder.commit();
2073
+ this.requestRender();
2074
+ }
2075
+ removeGrid() {
2076
+ const grid = this.store.getElementsByType("grid")[0];
2077
+ if (!grid) return;
2078
+ this.historyRecorder.begin();
2079
+ this.store.remove(grid.id);
2080
+ this.historyRecorder.commit();
2081
+ this.requestRender();
2082
+ }
1879
2083
  destroy() {
1880
2084
  cancelAnimationFrame(this.animFrameId);
1881
2085
  this.stopInteracting();
@@ -1907,6 +2111,7 @@ var Viewport = class {
1907
2111
  const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
1908
2112
  ctx.save();
1909
2113
  ctx.scale(dpr, dpr);
2114
+ this.renderer.setCanvasSize(this.canvasEl.clientWidth, this.canvasEl.clientHeight);
1910
2115
  this.background.render(ctx, this.camera);
1911
2116
  ctx.save();
1912
2117
  ctx.translate(this.camera.position.x, this.camera.position.y);
@@ -2893,6 +3098,7 @@ var SelectTool = class {
2893
3098
  for (const el of ctx.store.getAll()) {
2894
3099
  if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;
2895
3100
  if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;
3101
+ if (el.type === "grid") continue;
2896
3102
  const bounds = this.getElementBounds(el);
2897
3103
  if (bounds && this.rectsOverlap(marquee, bounds)) {
2898
3104
  ids.push(el.id);
@@ -2929,11 +3135,13 @@ var SelectTool = class {
2929
3135
  for (const el of elements) {
2930
3136
  if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;
2931
3137
  if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;
3138
+ if (el.type === "grid") continue;
2932
3139
  if (this.isInsideBounds(world, el)) return el;
2933
3140
  }
2934
3141
  return null;
2935
3142
  }
2936
3143
  isInsideBounds(point, el) {
3144
+ if (el.type === "grid") return false;
2937
3145
  if ("size" in el) {
2938
3146
  const s = el.size;
2939
3147
  return point.x >= el.position.x && point.x <= el.position.x + s.w && point.y >= el.position.y && point.y <= el.position.y + s.h;
@@ -3393,6 +3601,7 @@ export {
3393
3601
  Viewport,
3394
3602
  clearStaleBindings,
3395
3603
  createArrow,
3604
+ createGrid,
3396
3605
  createHtmlElement,
3397
3606
  createId,
3398
3607
  createImage,