@fieldnotes/core 0.6.1 → 0.7.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.
- package/dist/index.cjs +236 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -3
- package/dist/index.d.ts +40 -3
- package/dist/index.js +235 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -67,6 +67,7 @@ interface ImageElement extends BaseElement {
|
|
|
67
67
|
interface HtmlElement extends BaseElement {
|
|
68
68
|
type: 'html';
|
|
69
69
|
size: Size;
|
|
70
|
+
domId?: string;
|
|
70
71
|
}
|
|
71
72
|
interface TextElement extends BaseElement {
|
|
72
73
|
type: 'text';
|
|
@@ -85,7 +86,17 @@ interface ShapeElement extends BaseElement {
|
|
|
85
86
|
strokeWidth: number;
|
|
86
87
|
fillColor: string;
|
|
87
88
|
}
|
|
88
|
-
type
|
|
89
|
+
type HexOrientation = 'pointy' | 'flat';
|
|
90
|
+
interface GridElement extends BaseElement {
|
|
91
|
+
type: 'grid';
|
|
92
|
+
gridType: 'square' | 'hex';
|
|
93
|
+
hexOrientation: HexOrientation;
|
|
94
|
+
cellSize: number;
|
|
95
|
+
strokeColor: string;
|
|
96
|
+
strokeWidth: number;
|
|
97
|
+
opacity: number;
|
|
98
|
+
}
|
|
99
|
+
type CanvasElement = StrokeElement | NoteElement | ArrowElement | ImageElement | HtmlElement | TextElement | ShapeElement | GridElement;
|
|
89
100
|
type ElementType = CanvasElement['type'];
|
|
90
101
|
|
|
91
102
|
interface Layer {
|
|
@@ -437,6 +448,16 @@ declare class Viewport {
|
|
|
437
448
|
w: number;
|
|
438
449
|
h: number;
|
|
439
450
|
}): string;
|
|
451
|
+
addGrid(input: {
|
|
452
|
+
gridType?: 'square' | 'hex';
|
|
453
|
+
hexOrientation?: 'pointy' | 'flat';
|
|
454
|
+
cellSize?: number;
|
|
455
|
+
strokeColor?: string;
|
|
456
|
+
strokeWidth?: number;
|
|
457
|
+
opacity?: number;
|
|
458
|
+
}): string;
|
|
459
|
+
updateGrid(updates: Partial<Pick<GridElement, 'gridType' | 'hexOrientation' | 'cellSize' | 'strokeColor' | 'strokeWidth' | 'opacity'>>): void;
|
|
460
|
+
removeGrid(): void;
|
|
440
461
|
destroy(): void;
|
|
441
462
|
private startRenderLoop;
|
|
442
463
|
private render;
|
|
@@ -457,6 +478,7 @@ declare class Viewport {
|
|
|
457
478
|
private hideDomNode;
|
|
458
479
|
private removeDomNode;
|
|
459
480
|
private clearDomNodes;
|
|
481
|
+
private reattachHtmlContent;
|
|
460
482
|
private createWrapper;
|
|
461
483
|
private createCanvas;
|
|
462
484
|
private createDomLayer;
|
|
@@ -469,8 +491,12 @@ declare class ElementRenderer {
|
|
|
469
491
|
private store;
|
|
470
492
|
private imageCache;
|
|
471
493
|
private onImageLoad;
|
|
494
|
+
private camera;
|
|
495
|
+
private canvasSize;
|
|
472
496
|
setStore(store: ElementStore): void;
|
|
473
497
|
setOnImageLoad(callback: () => void): void;
|
|
498
|
+
setCamera(camera: Camera): void;
|
|
499
|
+
setCanvasSize(w: number, h: number): void;
|
|
474
500
|
isDomElement(element: CanvasElement): boolean;
|
|
475
501
|
renderCanvasElement(ctx: CanvasRenderingContext2D, element: CanvasElement): void;
|
|
476
502
|
private renderStroke;
|
|
@@ -480,6 +506,7 @@ declare class ElementRenderer {
|
|
|
480
506
|
private renderShape;
|
|
481
507
|
private fillShapePath;
|
|
482
508
|
private strokeShapePath;
|
|
509
|
+
private renderGrid;
|
|
483
510
|
private renderImage;
|
|
484
511
|
private getImage;
|
|
485
512
|
}
|
|
@@ -539,6 +566,7 @@ interface ImageInput extends BaseDefaults {
|
|
|
539
566
|
interface HtmlInput extends BaseDefaults {
|
|
540
567
|
position: Point;
|
|
541
568
|
size: Size;
|
|
569
|
+
domId?: string;
|
|
542
570
|
}
|
|
543
571
|
interface TextInput extends BaseDefaults {
|
|
544
572
|
position: Point;
|
|
@@ -562,6 +590,15 @@ interface ShapeInput extends BaseDefaults {
|
|
|
562
590
|
fillColor?: string;
|
|
563
591
|
}
|
|
564
592
|
declare function createShape(input: ShapeInput): ShapeElement;
|
|
593
|
+
interface GridInput extends BaseDefaults {
|
|
594
|
+
gridType?: 'square' | 'hex';
|
|
595
|
+
hexOrientation?: HexOrientation;
|
|
596
|
+
cellSize?: number;
|
|
597
|
+
strokeColor?: string;
|
|
598
|
+
strokeWidth?: number;
|
|
599
|
+
opacity?: number;
|
|
600
|
+
}
|
|
601
|
+
declare function createGrid(input: GridInput): GridElement;
|
|
565
602
|
declare function createText(input: TextInput): TextElement;
|
|
566
603
|
|
|
567
604
|
interface Rect {
|
|
@@ -824,6 +861,6 @@ declare class UpdateLayerCommand implements Command {
|
|
|
824
861
|
undo(_store: ElementStore): void;
|
|
825
862
|
}
|
|
826
863
|
|
|
827
|
-
declare const VERSION = "0.
|
|
864
|
+
declare const VERSION = "0.7.0";
|
|
828
865
|
|
|
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 };
|
|
866
|
+
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
|
@@ -67,6 +67,7 @@ interface ImageElement extends BaseElement {
|
|
|
67
67
|
interface HtmlElement extends BaseElement {
|
|
68
68
|
type: 'html';
|
|
69
69
|
size: Size;
|
|
70
|
+
domId?: string;
|
|
70
71
|
}
|
|
71
72
|
interface TextElement extends BaseElement {
|
|
72
73
|
type: 'text';
|
|
@@ -85,7 +86,17 @@ interface ShapeElement extends BaseElement {
|
|
|
85
86
|
strokeWidth: number;
|
|
86
87
|
fillColor: string;
|
|
87
88
|
}
|
|
88
|
-
type
|
|
89
|
+
type HexOrientation = 'pointy' | 'flat';
|
|
90
|
+
interface GridElement extends BaseElement {
|
|
91
|
+
type: 'grid';
|
|
92
|
+
gridType: 'square' | 'hex';
|
|
93
|
+
hexOrientation: HexOrientation;
|
|
94
|
+
cellSize: number;
|
|
95
|
+
strokeColor: string;
|
|
96
|
+
strokeWidth: number;
|
|
97
|
+
opacity: number;
|
|
98
|
+
}
|
|
99
|
+
type CanvasElement = StrokeElement | NoteElement | ArrowElement | ImageElement | HtmlElement | TextElement | ShapeElement | GridElement;
|
|
89
100
|
type ElementType = CanvasElement['type'];
|
|
90
101
|
|
|
91
102
|
interface Layer {
|
|
@@ -437,6 +448,16 @@ declare class Viewport {
|
|
|
437
448
|
w: number;
|
|
438
449
|
h: number;
|
|
439
450
|
}): string;
|
|
451
|
+
addGrid(input: {
|
|
452
|
+
gridType?: 'square' | 'hex';
|
|
453
|
+
hexOrientation?: 'pointy' | 'flat';
|
|
454
|
+
cellSize?: number;
|
|
455
|
+
strokeColor?: string;
|
|
456
|
+
strokeWidth?: number;
|
|
457
|
+
opacity?: number;
|
|
458
|
+
}): string;
|
|
459
|
+
updateGrid(updates: Partial<Pick<GridElement, 'gridType' | 'hexOrientation' | 'cellSize' | 'strokeColor' | 'strokeWidth' | 'opacity'>>): void;
|
|
460
|
+
removeGrid(): void;
|
|
440
461
|
destroy(): void;
|
|
441
462
|
private startRenderLoop;
|
|
442
463
|
private render;
|
|
@@ -457,6 +478,7 @@ declare class Viewport {
|
|
|
457
478
|
private hideDomNode;
|
|
458
479
|
private removeDomNode;
|
|
459
480
|
private clearDomNodes;
|
|
481
|
+
private reattachHtmlContent;
|
|
460
482
|
private createWrapper;
|
|
461
483
|
private createCanvas;
|
|
462
484
|
private createDomLayer;
|
|
@@ -469,8 +491,12 @@ declare class ElementRenderer {
|
|
|
469
491
|
private store;
|
|
470
492
|
private imageCache;
|
|
471
493
|
private onImageLoad;
|
|
494
|
+
private camera;
|
|
495
|
+
private canvasSize;
|
|
472
496
|
setStore(store: ElementStore): void;
|
|
473
497
|
setOnImageLoad(callback: () => void): void;
|
|
498
|
+
setCamera(camera: Camera): void;
|
|
499
|
+
setCanvasSize(w: number, h: number): void;
|
|
474
500
|
isDomElement(element: CanvasElement): boolean;
|
|
475
501
|
renderCanvasElement(ctx: CanvasRenderingContext2D, element: CanvasElement): void;
|
|
476
502
|
private renderStroke;
|
|
@@ -480,6 +506,7 @@ declare class ElementRenderer {
|
|
|
480
506
|
private renderShape;
|
|
481
507
|
private fillShapePath;
|
|
482
508
|
private strokeShapePath;
|
|
509
|
+
private renderGrid;
|
|
483
510
|
private renderImage;
|
|
484
511
|
private getImage;
|
|
485
512
|
}
|
|
@@ -539,6 +566,7 @@ interface ImageInput extends BaseDefaults {
|
|
|
539
566
|
interface HtmlInput extends BaseDefaults {
|
|
540
567
|
position: Point;
|
|
541
568
|
size: Size;
|
|
569
|
+
domId?: string;
|
|
542
570
|
}
|
|
543
571
|
interface TextInput extends BaseDefaults {
|
|
544
572
|
position: Point;
|
|
@@ -562,6 +590,15 @@ interface ShapeInput extends BaseDefaults {
|
|
|
562
590
|
fillColor?: string;
|
|
563
591
|
}
|
|
564
592
|
declare function createShape(input: ShapeInput): ShapeElement;
|
|
593
|
+
interface GridInput extends BaseDefaults {
|
|
594
|
+
gridType?: 'square' | 'hex';
|
|
595
|
+
hexOrientation?: HexOrientation;
|
|
596
|
+
cellSize?: number;
|
|
597
|
+
strokeColor?: string;
|
|
598
|
+
strokeWidth?: number;
|
|
599
|
+
opacity?: number;
|
|
600
|
+
}
|
|
601
|
+
declare function createGrid(input: GridInput): GridElement;
|
|
565
602
|
declare function createText(input: TextInput): TextElement;
|
|
566
603
|
|
|
567
604
|
interface Rect {
|
|
@@ -824,6 +861,6 @@ declare class UpdateLayerCommand implements Command {
|
|
|
824
861
|
undo(_store: ElementStore): void;
|
|
825
862
|
}
|
|
826
863
|
|
|
827
|
-
declare const VERSION = "0.
|
|
864
|
+
declare const VERSION = "0.7.0";
|
|
828
865
|
|
|
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 };
|
|
866
|
+
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;
|
|
@@ -1528,7 +1687,7 @@ function createImage(input) {
|
|
|
1528
1687
|
};
|
|
1529
1688
|
}
|
|
1530
1689
|
function createHtmlElement(input) {
|
|
1531
|
-
|
|
1690
|
+
const el = {
|
|
1532
1691
|
id: createId("html"),
|
|
1533
1692
|
type: "html",
|
|
1534
1693
|
position: input.position,
|
|
@@ -1537,6 +1696,8 @@ function createHtmlElement(input) {
|
|
|
1537
1696
|
layerId: input.layerId ?? "",
|
|
1538
1697
|
size: input.size
|
|
1539
1698
|
};
|
|
1699
|
+
if (input.domId) el.domId = input.domId;
|
|
1700
|
+
return el;
|
|
1540
1701
|
}
|
|
1541
1702
|
function createShape(input) {
|
|
1542
1703
|
return {
|
|
@@ -1553,6 +1714,22 @@ function createShape(input) {
|
|
|
1553
1714
|
fillColor: input.fillColor ?? "none"
|
|
1554
1715
|
};
|
|
1555
1716
|
}
|
|
1717
|
+
function createGrid(input) {
|
|
1718
|
+
return {
|
|
1719
|
+
id: createId("grid"),
|
|
1720
|
+
type: "grid",
|
|
1721
|
+
position: input.position ?? { x: 0, y: 0 },
|
|
1722
|
+
zIndex: input.zIndex ?? 0,
|
|
1723
|
+
locked: input.locked ?? false,
|
|
1724
|
+
layerId: input.layerId ?? "",
|
|
1725
|
+
gridType: input.gridType ?? "square",
|
|
1726
|
+
hexOrientation: input.hexOrientation ?? "pointy",
|
|
1727
|
+
cellSize: input.cellSize ?? 40,
|
|
1728
|
+
strokeColor: input.strokeColor ?? "#000000",
|
|
1729
|
+
strokeWidth: input.strokeWidth ?? 1,
|
|
1730
|
+
opacity: input.opacity ?? 1
|
|
1731
|
+
};
|
|
1732
|
+
}
|
|
1556
1733
|
function createText(input) {
|
|
1557
1734
|
return {
|
|
1558
1735
|
id: createId("text"),
|
|
@@ -1730,6 +1907,7 @@ var Viewport = class {
|
|
|
1730
1907
|
this.toolManager = new ToolManager();
|
|
1731
1908
|
this.renderer = new ElementRenderer();
|
|
1732
1909
|
this.renderer.setStore(this.store);
|
|
1910
|
+
this.renderer.setCamera(this.camera);
|
|
1733
1911
|
this.renderer.setOnImageLoad(() => this.requestRender());
|
|
1734
1912
|
this.noteEditor = new NoteEditor();
|
|
1735
1913
|
this.noteEditor.setOnStop((id) => this.onTextEditStop(id));
|
|
@@ -1837,6 +2015,7 @@ var Viewport = class {
|
|
|
1837
2015
|
if (state.layers && state.layers.length > 0) {
|
|
1838
2016
|
this.layerManager.loadSnapshot(state.layers);
|
|
1839
2017
|
}
|
|
2018
|
+
this.reattachHtmlContent();
|
|
1840
2019
|
this.history.clear();
|
|
1841
2020
|
this.historyRecorder.resume();
|
|
1842
2021
|
this.camera.moveTo(state.camera.position.x, state.camera.position.y);
|
|
@@ -1868,7 +2047,8 @@ var Viewport = class {
|
|
|
1868
2047
|
return image.id;
|
|
1869
2048
|
}
|
|
1870
2049
|
addHtmlElement(dom, position, size = { w: 200, h: 150 }) {
|
|
1871
|
-
const
|
|
2050
|
+
const domId = dom.id || void 0;
|
|
2051
|
+
const el = createHtmlElement({ position, size, domId, layerId: this.layerManager.activeLayerId });
|
|
1872
2052
|
this.htmlContent.set(el.id, dom);
|
|
1873
2053
|
this.historyRecorder.begin();
|
|
1874
2054
|
this.store.add(el);
|
|
@@ -1876,6 +2056,34 @@ var Viewport = class {
|
|
|
1876
2056
|
this.requestRender();
|
|
1877
2057
|
return el.id;
|
|
1878
2058
|
}
|
|
2059
|
+
addGrid(input) {
|
|
2060
|
+
const existing = this.store.getElementsByType("grid")[0];
|
|
2061
|
+
this.historyRecorder.begin();
|
|
2062
|
+
if (existing) {
|
|
2063
|
+
this.store.remove(existing.id);
|
|
2064
|
+
}
|
|
2065
|
+
const grid = createGrid({ ...input, layerId: this.layerManager.activeLayerId });
|
|
2066
|
+
this.store.add(grid);
|
|
2067
|
+
this.historyRecorder.commit();
|
|
2068
|
+
this.requestRender();
|
|
2069
|
+
return grid.id;
|
|
2070
|
+
}
|
|
2071
|
+
updateGrid(updates) {
|
|
2072
|
+
const grid = this.store.getElementsByType("grid")[0];
|
|
2073
|
+
if (!grid) return;
|
|
2074
|
+
this.historyRecorder.begin();
|
|
2075
|
+
this.store.update(grid.id, updates);
|
|
2076
|
+
this.historyRecorder.commit();
|
|
2077
|
+
this.requestRender();
|
|
2078
|
+
}
|
|
2079
|
+
removeGrid() {
|
|
2080
|
+
const grid = this.store.getElementsByType("grid")[0];
|
|
2081
|
+
if (!grid) return;
|
|
2082
|
+
this.historyRecorder.begin();
|
|
2083
|
+
this.store.remove(grid.id);
|
|
2084
|
+
this.historyRecorder.commit();
|
|
2085
|
+
this.requestRender();
|
|
2086
|
+
}
|
|
1879
2087
|
destroy() {
|
|
1880
2088
|
cancelAnimationFrame(this.animFrameId);
|
|
1881
2089
|
this.stopInteracting();
|
|
@@ -1907,6 +2115,7 @@ var Viewport = class {
|
|
|
1907
2115
|
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
1908
2116
|
ctx.save();
|
|
1909
2117
|
ctx.scale(dpr, dpr);
|
|
2118
|
+
this.renderer.setCanvasSize(this.canvasEl.clientWidth, this.canvasEl.clientHeight);
|
|
1910
2119
|
this.background.render(ctx, this.camera);
|
|
1911
2120
|
ctx.save();
|
|
1912
2121
|
ctx.translate(this.camera.position.x, this.camera.position.y);
|
|
@@ -2208,6 +2417,16 @@ var Viewport = class {
|
|
|
2208
2417
|
this.htmlContent.clear();
|
|
2209
2418
|
this.requestRender();
|
|
2210
2419
|
}
|
|
2420
|
+
reattachHtmlContent() {
|
|
2421
|
+
for (const el of this.store.getElementsByType("html")) {
|
|
2422
|
+
if (el.domId) {
|
|
2423
|
+
const dom = document.getElementById(el.domId);
|
|
2424
|
+
if (dom) {
|
|
2425
|
+
this.htmlContent.set(el.id, dom);
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2211
2430
|
createWrapper() {
|
|
2212
2431
|
const el = document.createElement("div");
|
|
2213
2432
|
Object.assign(el.style, {
|
|
@@ -2466,10 +2685,11 @@ function applyArrowHandleDrag(handle, elementId, world, ctx) {
|
|
|
2466
2685
|
const el = ctx.store.getById(elementId);
|
|
2467
2686
|
if (!el || el.type !== "arrow") return;
|
|
2468
2687
|
const threshold = BIND_THRESHOLD / ctx.camera.zoom;
|
|
2688
|
+
const layerFilter = (candidate) => candidate.layerId === el.layerId;
|
|
2469
2689
|
switch (handle) {
|
|
2470
2690
|
case "start": {
|
|
2471
2691
|
const excludeId = el.toBinding?.elementId;
|
|
2472
|
-
const target = findBindTarget(world, ctx.store, threshold, excludeId);
|
|
2692
|
+
const target = findBindTarget(world, ctx.store, threshold, excludeId, layerFilter);
|
|
2473
2693
|
if (target) {
|
|
2474
2694
|
const center = getElementCenter(target);
|
|
2475
2695
|
ctx.store.update(elementId, {
|
|
@@ -2488,7 +2708,7 @@ function applyArrowHandleDrag(handle, elementId, world, ctx) {
|
|
|
2488
2708
|
}
|
|
2489
2709
|
case "end": {
|
|
2490
2710
|
const excludeId = el.fromBinding?.elementId;
|
|
2491
|
-
const target = findBindTarget(world, ctx.store, threshold, excludeId);
|
|
2711
|
+
const target = findBindTarget(world, ctx.store, threshold, excludeId, layerFilter);
|
|
2492
2712
|
if (target) {
|
|
2493
2713
|
const center = getElementCenter(target);
|
|
2494
2714
|
ctx.store.update(elementId, {
|
|
@@ -2517,7 +2737,8 @@ function getArrowHandleDragTarget(handle, elementId, world, ctx) {
|
|
|
2517
2737
|
if (!el || el.type !== "arrow") return null;
|
|
2518
2738
|
const threshold = BIND_THRESHOLD / ctx.camera.zoom;
|
|
2519
2739
|
const excludeId = handle === "start" ? el.toBinding?.elementId : el.fromBinding?.elementId;
|
|
2520
|
-
const
|
|
2740
|
+
const layerFilter = (candidate) => candidate.layerId === el.layerId;
|
|
2741
|
+
const target = findBindTarget(world, ctx.store, threshold, excludeId, layerFilter);
|
|
2521
2742
|
if (!target) return null;
|
|
2522
2743
|
return getElementBounds(target);
|
|
2523
2744
|
}
|
|
@@ -2893,6 +3114,7 @@ var SelectTool = class {
|
|
|
2893
3114
|
for (const el of ctx.store.getAll()) {
|
|
2894
3115
|
if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;
|
|
2895
3116
|
if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;
|
|
3117
|
+
if (el.type === "grid") continue;
|
|
2896
3118
|
const bounds = this.getElementBounds(el);
|
|
2897
3119
|
if (bounds && this.rectsOverlap(marquee, bounds)) {
|
|
2898
3120
|
ids.push(el.id);
|
|
@@ -2929,11 +3151,13 @@ var SelectTool = class {
|
|
|
2929
3151
|
for (const el of elements) {
|
|
2930
3152
|
if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;
|
|
2931
3153
|
if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;
|
|
3154
|
+
if (el.type === "grid") continue;
|
|
2932
3155
|
if (this.isInsideBounds(world, el)) return el;
|
|
2933
3156
|
}
|
|
2934
3157
|
return null;
|
|
2935
3158
|
}
|
|
2936
3159
|
isInsideBounds(point, el) {
|
|
3160
|
+
if (el.type === "grid") return false;
|
|
2937
3161
|
if ("size" in el) {
|
|
2938
3162
|
const s = el.size;
|
|
2939
3163
|
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;
|
|
@@ -2974,8 +3198,10 @@ var ArrowTool = class {
|
|
|
2974
3198
|
if (options.width !== void 0) this.width = options.width;
|
|
2975
3199
|
}
|
|
2976
3200
|
layerFilter(ctx) {
|
|
2977
|
-
|
|
3201
|
+
const activeLayerId = ctx.activeLayerId;
|
|
3202
|
+
if (!activeLayerId && !ctx.isLayerVisible && !ctx.isLayerLocked) return void 0;
|
|
2978
3203
|
return (el) => {
|
|
3204
|
+
if (activeLayerId && el.layerId !== activeLayerId) return false;
|
|
2979
3205
|
if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) return false;
|
|
2980
3206
|
if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) return false;
|
|
2981
3207
|
return true;
|
|
@@ -3359,7 +3585,7 @@ var UpdateLayerCommand = class {
|
|
|
3359
3585
|
};
|
|
3360
3586
|
|
|
3361
3587
|
// src/index.ts
|
|
3362
|
-
var VERSION = "0.
|
|
3588
|
+
var VERSION = "0.7.0";
|
|
3363
3589
|
export {
|
|
3364
3590
|
AddElementCommand,
|
|
3365
3591
|
ArrowTool,
|
|
@@ -3393,6 +3619,7 @@ export {
|
|
|
3393
3619
|
Viewport,
|
|
3394
3620
|
clearStaleBindings,
|
|
3395
3621
|
createArrow,
|
|
3622
|
+
createGrid,
|
|
3396
3623
|
createHtmlElement,
|
|
3397
3624
|
createId,
|
|
3398
3625
|
createImage,
|