@fieldnotes/core 0.6.0 → 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/README.md +61 -11
- package/dist/index.cjs +217 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -3
- package/dist/index.d.ts +37 -3
- package/dist/index.js +216 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,12 +7,15 @@ A lightweight, framework-agnostic infinite canvas SDK for the web — with first
|
|
|
7
7
|
- **Infinite canvas** — pan, zoom, pinch-to-zoom
|
|
8
8
|
- **Freehand drawing** — pencil tool with stroke smoothing and pressure-sensitive width
|
|
9
9
|
- **Sticky notes** — editable text notes with customizable colors
|
|
10
|
-
- **Arrows** — curved bezier arrows with
|
|
11
|
-
- **
|
|
10
|
+
- **Arrows** — curved bezier arrows with element binding
|
|
11
|
+
- **Shapes** — rectangles, ellipses with fill and stroke
|
|
12
|
+
- **Text** — standalone text elements with font size and alignment
|
|
13
|
+
- **Images** — drag & drop or programmatic placement (canvas-rendered for proper layer ordering)
|
|
12
14
|
- **HTML embedding** — add any DOM element as a fully interactive canvas citizen
|
|
13
|
-
- **
|
|
15
|
+
- **Layers** — named layers with visibility, locking, and absolute ordering
|
|
16
|
+
- **Select & multi-select** — click, drag box, move, resize (layer-aware)
|
|
14
17
|
- **Undo / redo** — full history stack with configurable depth
|
|
15
|
-
- **State serialization** — export/import JSON snapshots
|
|
18
|
+
- **State serialization** — export/import JSON snapshots with automatic migration
|
|
16
19
|
- **Touch & tablet** — Pointer Events API, pinch-to-zoom, two-finger pan, stylus pressure
|
|
17
20
|
- **Zero dependencies** — vanilla TypeScript, no framework required
|
|
18
21
|
- **Tree-shakeable** — ESM + CJS output
|
|
@@ -91,10 +94,13 @@ viewport.stopInteracting();
|
|
|
91
94
|
```typescript
|
|
92
95
|
// Programmatic
|
|
93
96
|
viewport.addImage('https://example.com/photo.jpg', { x: 0, y: 0 });
|
|
97
|
+
viewport.addImage('/assets/map.png', { x: 0, y: 0 }, { w: 800, h: 600 });
|
|
94
98
|
|
|
95
99
|
// Drag & drop is handled automatically — drop images onto the canvas
|
|
96
100
|
```
|
|
97
101
|
|
|
102
|
+
> **Important: Use URLs, not base64 data URLs.** Images are stored inline in the serialized state. A single base64-encoded photo can be 2-5MB, which will blow past the `localStorage` ~5MB quota and make JSON exports impractical. Upload images to your server or CDN and use the URL. For offline/local-first apps, store blobs in IndexedDB and reference them by URL.
|
|
103
|
+
|
|
98
104
|
## Camera Control
|
|
99
105
|
|
|
100
106
|
```typescript
|
|
@@ -147,6 +153,45 @@ viewport.history.onChange(() => {
|
|
|
147
153
|
});
|
|
148
154
|
```
|
|
149
155
|
|
|
156
|
+
## Layers
|
|
157
|
+
|
|
158
|
+
Organize elements into named layers with visibility, lock, and ordering controls. All elements on a higher layer render above all elements on a lower layer, regardless of individual z-index.
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
const { layerManager } = viewport;
|
|
162
|
+
|
|
163
|
+
// Create layers
|
|
164
|
+
const background = layerManager.activeLayer; // "Layer 1" exists by default
|
|
165
|
+
layerManager.renameLayer(background.id, 'Map');
|
|
166
|
+
const tokens = layerManager.createLayer('Tokens');
|
|
167
|
+
const notes = layerManager.createLayer('Notes');
|
|
168
|
+
|
|
169
|
+
// Set active layer — new elements are created on the active layer
|
|
170
|
+
layerManager.setActiveLayer(tokens.id);
|
|
171
|
+
|
|
172
|
+
// Visibility and locking
|
|
173
|
+
layerManager.setLayerVisible(background.id, false); // hide
|
|
174
|
+
layerManager.setLayerLocked(background.id, true); // prevent selection/editing
|
|
175
|
+
|
|
176
|
+
// Move elements between layers
|
|
177
|
+
layerManager.moveElementToLayer(elementId, notes.id);
|
|
178
|
+
|
|
179
|
+
// Reorder layers
|
|
180
|
+
layerManager.reorderLayer(tokens.id, 5); // higher order = renders on top
|
|
181
|
+
|
|
182
|
+
// Query
|
|
183
|
+
layerManager.getLayers(); // sorted by order
|
|
184
|
+
layerManager.isLayerVisible(id);
|
|
185
|
+
layerManager.isLayerLocked(id);
|
|
186
|
+
|
|
187
|
+
// Listen for changes
|
|
188
|
+
layerManager.on('change', () => {
|
|
189
|
+
/* update UI */
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Locked layers prevent selection, erasing, and arrow binding on their elements. Hidden layers are invisible and non-interactive. The active layer cannot be hidden or locked — if you try, it automatically switches to the next available layer.
|
|
194
|
+
|
|
150
195
|
## State Serialization
|
|
151
196
|
|
|
152
197
|
```typescript
|
|
@@ -158,6 +203,8 @@ localStorage.setItem('canvas', json);
|
|
|
158
203
|
viewport.loadJSON(localStorage.getItem('canvas'));
|
|
159
204
|
```
|
|
160
205
|
|
|
206
|
+
> **Note:** Serialized state includes all layers and element `layerId` assignments. States saved before layers were introduced are automatically migrated — elements are placed on a default "Layer 1".
|
|
207
|
+
|
|
161
208
|
## Tool Switching
|
|
162
209
|
|
|
163
210
|
```typescript
|
|
@@ -296,16 +343,19 @@ interface BaseElement {
|
|
|
296
343
|
position: { x: number; y: number };
|
|
297
344
|
zIndex: number;
|
|
298
345
|
locked: boolean;
|
|
346
|
+
layerId: string;
|
|
299
347
|
}
|
|
300
348
|
```
|
|
301
349
|
|
|
302
|
-
| Type | Key Fields
|
|
303
|
-
| -------- |
|
|
304
|
-
| `stroke` | `points: StrokePoint[]`, `color`, `width`, `opacity`
|
|
305
|
-
| `note` | `size`, `text`, `backgroundColor`
|
|
306
|
-
| `arrow` | `from`, `to`, `bend`, `color`, `width`
|
|
307
|
-
| `image` | `size`, `src`
|
|
308
|
-
| `
|
|
350
|
+
| Type | Key Fields |
|
|
351
|
+
| -------- | ---------------------------------------------------------------------- |
|
|
352
|
+
| `stroke` | `points: StrokePoint[]`, `color`, `width`, `opacity` |
|
|
353
|
+
| `note` | `size`, `text`, `backgroundColor`, `textColor` |
|
|
354
|
+
| `arrow` | `from`, `to`, `bend`, `color`, `width`, `fromBinding`, `toBinding` |
|
|
355
|
+
| `image` | `size`, `src` |
|
|
356
|
+
| `shape` | `size`, `shape` (`rectangle` \| `ellipse`), `strokeColor`, `fillColor` |
|
|
357
|
+
| `text` | `size`, `text`, `fontSize`, `color`, `textAlign` |
|
|
358
|
+
| `html` | `size` |
|
|
309
359
|
|
|
310
360
|
## Built-in Interactions
|
|
311
361
|
|
package/dist/index.cjs
CHANGED
|
@@ -52,6 +52,7 @@ __export(index_exports, {
|
|
|
52
52
|
Viewport: () => Viewport,
|
|
53
53
|
clearStaleBindings: () => clearStaleBindings,
|
|
54
54
|
createArrow: () => createArrow,
|
|
55
|
+
createGrid: () => createGrid,
|
|
55
56
|
createHtmlElement: () => createHtmlElement,
|
|
56
57
|
createId: () => createId,
|
|
57
58
|
createImage: () => createImage,
|
|
@@ -165,7 +166,7 @@ function validateState(data) {
|
|
|
165
166
|
];
|
|
166
167
|
}
|
|
167
168
|
}
|
|
168
|
-
var VALID_TYPES = /* @__PURE__ */ new Set(["stroke", "note", "arrow", "image", "html", "text", "shape"]);
|
|
169
|
+
var VALID_TYPES = /* @__PURE__ */ new Set(["stroke", "note", "arrow", "image", "html", "text", "shape", "grid"]);
|
|
169
170
|
function validateElement(el) {
|
|
170
171
|
if (!el || typeof el !== "object") {
|
|
171
172
|
throw new Error("Invalid element: expected an object");
|
|
@@ -286,7 +287,11 @@ var AutoSave = class {
|
|
|
286
287
|
if (typeof localStorage === "undefined") return;
|
|
287
288
|
const layers = this.layerManager?.snapshot() ?? [];
|
|
288
289
|
const state = exportState(this.store.snapshot(), this.camera, layers);
|
|
289
|
-
|
|
290
|
+
try {
|
|
291
|
+
localStorage.setItem(this.key, JSON.stringify(state));
|
|
292
|
+
} catch {
|
|
293
|
+
console.warn("Auto-save failed: storage quota exceeded. State too large for localStorage.");
|
|
294
|
+
}
|
|
290
295
|
}
|
|
291
296
|
};
|
|
292
297
|
|
|
@@ -1022,6 +1027,118 @@ function smoothToSegments(points) {
|
|
|
1022
1027
|
return segments;
|
|
1023
1028
|
}
|
|
1024
1029
|
|
|
1030
|
+
// src/elements/grid-renderer.ts
|
|
1031
|
+
function getSquareGridLines(bounds, cellSize) {
|
|
1032
|
+
if (cellSize <= 0) return { verticals: [], horizontals: [] };
|
|
1033
|
+
const verticals = [];
|
|
1034
|
+
const startX = Math.floor(bounds.minX / cellSize) * cellSize;
|
|
1035
|
+
const endX = Math.ceil(bounds.maxX / cellSize) * cellSize;
|
|
1036
|
+
for (let x = startX; x <= endX; x += cellSize) {
|
|
1037
|
+
verticals.push(x);
|
|
1038
|
+
}
|
|
1039
|
+
const horizontals = [];
|
|
1040
|
+
const startY = Math.floor(bounds.minY / cellSize) * cellSize;
|
|
1041
|
+
const endY = Math.ceil(bounds.maxY / cellSize) * cellSize;
|
|
1042
|
+
for (let y = startY; y <= endY; y += cellSize) {
|
|
1043
|
+
horizontals.push(y);
|
|
1044
|
+
}
|
|
1045
|
+
return { verticals, horizontals };
|
|
1046
|
+
}
|
|
1047
|
+
function getHexVertices(cx, cy, circumradius, orientation) {
|
|
1048
|
+
const vertices = [];
|
|
1049
|
+
const angleOffset = orientation === "pointy" ? -Math.PI / 2 : 0;
|
|
1050
|
+
for (let i = 0; i < 6; i++) {
|
|
1051
|
+
const angle = Math.PI / 3 * i + angleOffset;
|
|
1052
|
+
vertices.push({
|
|
1053
|
+
x: cx + circumradius * Math.cos(angle),
|
|
1054
|
+
y: cy + circumradius * Math.sin(angle)
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
return vertices;
|
|
1058
|
+
}
|
|
1059
|
+
function getHexCenters(bounds, circumradius, orientation) {
|
|
1060
|
+
if (circumradius <= 0) return [];
|
|
1061
|
+
const centers = [];
|
|
1062
|
+
if (orientation === "pointy") {
|
|
1063
|
+
const hexW = Math.sqrt(3) * circumradius;
|
|
1064
|
+
const hexH = 2 * circumradius;
|
|
1065
|
+
const rowH = hexH * 0.75;
|
|
1066
|
+
const startRow = Math.floor((bounds.minY - circumradius) / rowH);
|
|
1067
|
+
const endRow = Math.ceil((bounds.maxY + circumradius) / rowH);
|
|
1068
|
+
const startCol = Math.floor((bounds.minX - hexW) / hexW);
|
|
1069
|
+
const endCol = Math.ceil((bounds.maxX + hexW) / hexW);
|
|
1070
|
+
for (let row = startRow; row <= endRow; row++) {
|
|
1071
|
+
const offsetX = row % 2 !== 0 ? hexW / 2 : 0;
|
|
1072
|
+
for (let col = startCol; col <= endCol; col++) {
|
|
1073
|
+
centers.push({
|
|
1074
|
+
x: col * hexW + offsetX,
|
|
1075
|
+
y: row * rowH
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
} else {
|
|
1080
|
+
const hexW = 2 * circumradius;
|
|
1081
|
+
const hexH = Math.sqrt(3) * circumradius;
|
|
1082
|
+
const colW = hexW * 0.75;
|
|
1083
|
+
const startCol = Math.floor((bounds.minX - circumradius) / colW);
|
|
1084
|
+
const endCol = Math.ceil((bounds.maxX + circumradius) / colW);
|
|
1085
|
+
const startRow = Math.floor((bounds.minY - hexH) / hexH);
|
|
1086
|
+
const endRow = Math.ceil((bounds.maxY + hexH) / hexH);
|
|
1087
|
+
for (let col = startCol; col <= endCol; col++) {
|
|
1088
|
+
const offsetY = col % 2 !== 0 ? hexH / 2 : 0;
|
|
1089
|
+
for (let row = startRow; row <= endRow; row++) {
|
|
1090
|
+
centers.push({
|
|
1091
|
+
x: col * colW,
|
|
1092
|
+
y: row * hexH + offsetY
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
return centers;
|
|
1098
|
+
}
|
|
1099
|
+
function renderSquareGrid(ctx, bounds, cellSize, strokeColor, strokeWidth, opacity) {
|
|
1100
|
+
if (cellSize <= 0) return;
|
|
1101
|
+
const { verticals, horizontals } = getSquareGridLines(bounds, cellSize);
|
|
1102
|
+
ctx.save();
|
|
1103
|
+
ctx.strokeStyle = strokeColor;
|
|
1104
|
+
ctx.lineWidth = strokeWidth;
|
|
1105
|
+
ctx.globalAlpha = opacity;
|
|
1106
|
+
ctx.beginPath();
|
|
1107
|
+
for (const x of verticals) {
|
|
1108
|
+
ctx.moveTo(x, bounds.minY);
|
|
1109
|
+
ctx.lineTo(x, bounds.maxY);
|
|
1110
|
+
}
|
|
1111
|
+
for (const y of horizontals) {
|
|
1112
|
+
ctx.moveTo(bounds.minX, y);
|
|
1113
|
+
ctx.lineTo(bounds.maxX, y);
|
|
1114
|
+
}
|
|
1115
|
+
ctx.stroke();
|
|
1116
|
+
ctx.restore();
|
|
1117
|
+
}
|
|
1118
|
+
function renderHexGrid(ctx, bounds, cellSize, orientation, strokeColor, strokeWidth, opacity) {
|
|
1119
|
+
if (cellSize <= 0) return;
|
|
1120
|
+
const centers = getHexCenters(bounds, cellSize, orientation);
|
|
1121
|
+
ctx.save();
|
|
1122
|
+
ctx.strokeStyle = strokeColor;
|
|
1123
|
+
ctx.lineWidth = strokeWidth;
|
|
1124
|
+
ctx.globalAlpha = opacity;
|
|
1125
|
+
ctx.beginPath();
|
|
1126
|
+
for (const center of centers) {
|
|
1127
|
+
const verts = getHexVertices(center.x, center.y, cellSize, orientation);
|
|
1128
|
+
const first = verts[0];
|
|
1129
|
+
if (!first) continue;
|
|
1130
|
+
ctx.moveTo(first.x, first.y);
|
|
1131
|
+
for (let i = 1; i < verts.length; i++) {
|
|
1132
|
+
const v = verts[i];
|
|
1133
|
+
if (!v) continue;
|
|
1134
|
+
ctx.lineTo(v.x, v.y);
|
|
1135
|
+
}
|
|
1136
|
+
ctx.closePath();
|
|
1137
|
+
}
|
|
1138
|
+
ctx.stroke();
|
|
1139
|
+
ctx.restore();
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1025
1142
|
// src/elements/element-renderer.ts
|
|
1026
1143
|
var DOM_ELEMENT_TYPES = /* @__PURE__ */ new Set(["note", "html", "text"]);
|
|
1027
1144
|
var ARROWHEAD_LENGTH = 12;
|
|
@@ -1030,12 +1147,20 @@ var ElementRenderer = class {
|
|
|
1030
1147
|
store = null;
|
|
1031
1148
|
imageCache = /* @__PURE__ */ new Map();
|
|
1032
1149
|
onImageLoad = null;
|
|
1150
|
+
camera = null;
|
|
1151
|
+
canvasSize = null;
|
|
1033
1152
|
setStore(store) {
|
|
1034
1153
|
this.store = store;
|
|
1035
1154
|
}
|
|
1036
1155
|
setOnImageLoad(callback) {
|
|
1037
1156
|
this.onImageLoad = callback;
|
|
1038
1157
|
}
|
|
1158
|
+
setCamera(camera) {
|
|
1159
|
+
this.camera = camera;
|
|
1160
|
+
}
|
|
1161
|
+
setCanvasSize(w, h) {
|
|
1162
|
+
this.canvasSize = { w, h };
|
|
1163
|
+
}
|
|
1039
1164
|
isDomElement(element) {
|
|
1040
1165
|
return DOM_ELEMENT_TYPES.has(element.type);
|
|
1041
1166
|
}
|
|
@@ -1053,6 +1178,9 @@ var ElementRenderer = class {
|
|
|
1053
1178
|
case "image":
|
|
1054
1179
|
this.renderImage(ctx, element);
|
|
1055
1180
|
break;
|
|
1181
|
+
case "grid":
|
|
1182
|
+
this.renderGrid(ctx, element);
|
|
1183
|
+
break;
|
|
1056
1184
|
}
|
|
1057
1185
|
}
|
|
1058
1186
|
renderStroke(ctx, stroke) {
|
|
@@ -1188,6 +1316,42 @@ var ElementRenderer = class {
|
|
|
1188
1316
|
}
|
|
1189
1317
|
}
|
|
1190
1318
|
}
|
|
1319
|
+
renderGrid(ctx, grid) {
|
|
1320
|
+
if (!this.canvasSize) return;
|
|
1321
|
+
const cam = this.camera;
|
|
1322
|
+
if (!cam) return;
|
|
1323
|
+
const topLeft = cam.screenToWorld({ x: 0, y: 0 });
|
|
1324
|
+
const bottomRight = cam.screenToWorld({
|
|
1325
|
+
x: this.canvasSize.w,
|
|
1326
|
+
y: this.canvasSize.h
|
|
1327
|
+
});
|
|
1328
|
+
const bounds = {
|
|
1329
|
+
minX: topLeft.x,
|
|
1330
|
+
minY: topLeft.y,
|
|
1331
|
+
maxX: bottomRight.x,
|
|
1332
|
+
maxY: bottomRight.y
|
|
1333
|
+
};
|
|
1334
|
+
if (grid.gridType === "hex") {
|
|
1335
|
+
renderHexGrid(
|
|
1336
|
+
ctx,
|
|
1337
|
+
bounds,
|
|
1338
|
+
grid.cellSize,
|
|
1339
|
+
grid.hexOrientation,
|
|
1340
|
+
grid.strokeColor,
|
|
1341
|
+
grid.strokeWidth,
|
|
1342
|
+
grid.opacity
|
|
1343
|
+
);
|
|
1344
|
+
} else {
|
|
1345
|
+
renderSquareGrid(
|
|
1346
|
+
ctx,
|
|
1347
|
+
bounds,
|
|
1348
|
+
grid.cellSize,
|
|
1349
|
+
grid.strokeColor,
|
|
1350
|
+
grid.strokeWidth,
|
|
1351
|
+
grid.opacity
|
|
1352
|
+
);
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1191
1355
|
renderImage(ctx, image) {
|
|
1192
1356
|
const img = this.getImage(image.src);
|
|
1193
1357
|
if (!img) return;
|
|
@@ -1630,6 +1794,22 @@ function createShape(input) {
|
|
|
1630
1794
|
fillColor: input.fillColor ?? "none"
|
|
1631
1795
|
};
|
|
1632
1796
|
}
|
|
1797
|
+
function createGrid(input) {
|
|
1798
|
+
return {
|
|
1799
|
+
id: createId("grid"),
|
|
1800
|
+
type: "grid",
|
|
1801
|
+
position: input.position ?? { x: 0, y: 0 },
|
|
1802
|
+
zIndex: input.zIndex ?? 0,
|
|
1803
|
+
locked: input.locked ?? false,
|
|
1804
|
+
layerId: input.layerId ?? "",
|
|
1805
|
+
gridType: input.gridType ?? "square",
|
|
1806
|
+
hexOrientation: input.hexOrientation ?? "pointy",
|
|
1807
|
+
cellSize: input.cellSize ?? 40,
|
|
1808
|
+
strokeColor: input.strokeColor ?? "#000000",
|
|
1809
|
+
strokeWidth: input.strokeWidth ?? 1,
|
|
1810
|
+
opacity: input.opacity ?? 1
|
|
1811
|
+
};
|
|
1812
|
+
}
|
|
1633
1813
|
function createText(input) {
|
|
1634
1814
|
return {
|
|
1635
1815
|
id: createId("text"),
|
|
@@ -1807,6 +1987,7 @@ var Viewport = class {
|
|
|
1807
1987
|
this.toolManager = new ToolManager();
|
|
1808
1988
|
this.renderer = new ElementRenderer();
|
|
1809
1989
|
this.renderer.setStore(this.store);
|
|
1990
|
+
this.renderer.setCamera(this.camera);
|
|
1810
1991
|
this.renderer.setOnImageLoad(() => this.requestRender());
|
|
1811
1992
|
this.noteEditor = new NoteEditor();
|
|
1812
1993
|
this.noteEditor.setOnStop((id) => this.onTextEditStop(id));
|
|
@@ -1953,6 +2134,34 @@ var Viewport = class {
|
|
|
1953
2134
|
this.requestRender();
|
|
1954
2135
|
return el.id;
|
|
1955
2136
|
}
|
|
2137
|
+
addGrid(input) {
|
|
2138
|
+
const existing = this.store.getElementsByType("grid")[0];
|
|
2139
|
+
this.historyRecorder.begin();
|
|
2140
|
+
if (existing) {
|
|
2141
|
+
this.store.remove(existing.id);
|
|
2142
|
+
}
|
|
2143
|
+
const grid = createGrid({ ...input, layerId: this.layerManager.activeLayerId });
|
|
2144
|
+
this.store.add(grid);
|
|
2145
|
+
this.historyRecorder.commit();
|
|
2146
|
+
this.requestRender();
|
|
2147
|
+
return grid.id;
|
|
2148
|
+
}
|
|
2149
|
+
updateGrid(updates) {
|
|
2150
|
+
const grid = this.store.getElementsByType("grid")[0];
|
|
2151
|
+
if (!grid) return;
|
|
2152
|
+
this.historyRecorder.begin();
|
|
2153
|
+
this.store.update(grid.id, updates);
|
|
2154
|
+
this.historyRecorder.commit();
|
|
2155
|
+
this.requestRender();
|
|
2156
|
+
}
|
|
2157
|
+
removeGrid() {
|
|
2158
|
+
const grid = this.store.getElementsByType("grid")[0];
|
|
2159
|
+
if (!grid) return;
|
|
2160
|
+
this.historyRecorder.begin();
|
|
2161
|
+
this.store.remove(grid.id);
|
|
2162
|
+
this.historyRecorder.commit();
|
|
2163
|
+
this.requestRender();
|
|
2164
|
+
}
|
|
1956
2165
|
destroy() {
|
|
1957
2166
|
cancelAnimationFrame(this.animFrameId);
|
|
1958
2167
|
this.stopInteracting();
|
|
@@ -1984,6 +2193,7 @@ var Viewport = class {
|
|
|
1984
2193
|
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
1985
2194
|
ctx.save();
|
|
1986
2195
|
ctx.scale(dpr, dpr);
|
|
2196
|
+
this.renderer.setCanvasSize(this.canvasEl.clientWidth, this.canvasEl.clientHeight);
|
|
1987
2197
|
this.background.render(ctx, this.camera);
|
|
1988
2198
|
ctx.save();
|
|
1989
2199
|
ctx.translate(this.camera.position.x, this.camera.position.y);
|
|
@@ -2970,6 +3180,7 @@ var SelectTool = class {
|
|
|
2970
3180
|
for (const el of ctx.store.getAll()) {
|
|
2971
3181
|
if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;
|
|
2972
3182
|
if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;
|
|
3183
|
+
if (el.type === "grid") continue;
|
|
2973
3184
|
const bounds = this.getElementBounds(el);
|
|
2974
3185
|
if (bounds && this.rectsOverlap(marquee, bounds)) {
|
|
2975
3186
|
ids.push(el.id);
|
|
@@ -3006,11 +3217,13 @@ var SelectTool = class {
|
|
|
3006
3217
|
for (const el of elements) {
|
|
3007
3218
|
if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;
|
|
3008
3219
|
if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;
|
|
3220
|
+
if (el.type === "grid") continue;
|
|
3009
3221
|
if (this.isInsideBounds(world, el)) return el;
|
|
3010
3222
|
}
|
|
3011
3223
|
return null;
|
|
3012
3224
|
}
|
|
3013
3225
|
isInsideBounds(point, el) {
|
|
3226
|
+
if (el.type === "grid") return false;
|
|
3014
3227
|
if ("size" in el) {
|
|
3015
3228
|
const s = el.size;
|
|
3016
3229
|
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;
|
|
@@ -3436,7 +3649,7 @@ var UpdateLayerCommand = class {
|
|
|
3436
3649
|
};
|
|
3437
3650
|
|
|
3438
3651
|
// src/index.ts
|
|
3439
|
-
var VERSION = "0.6.
|
|
3652
|
+
var VERSION = "0.6.1";
|
|
3440
3653
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3441
3654
|
0 && (module.exports = {
|
|
3442
3655
|
AddElementCommand,
|
|
@@ -3471,6 +3684,7 @@ var VERSION = "0.6.0";
|
|
|
3471
3684
|
Viewport,
|
|
3472
3685
|
clearStaleBindings,
|
|
3473
3686
|
createArrow,
|
|
3687
|
+
createGrid,
|
|
3474
3688
|
createHtmlElement,
|
|
3475
3689
|
createId,
|
|
3476
3690
|
createImage,
|