@fieldnotes/core 0.7.0 → 0.8.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 +285 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +284 -7
- 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';
|
|
@@ -392,6 +393,14 @@ declare class InputHandler {
|
|
|
392
393
|
private cancelToolIfActive;
|
|
393
394
|
}
|
|
394
395
|
|
|
396
|
+
interface ExportImageOptions {
|
|
397
|
+
scale?: number;
|
|
398
|
+
padding?: number;
|
|
399
|
+
background?: string;
|
|
400
|
+
filter?: (element: CanvasElement) => boolean;
|
|
401
|
+
}
|
|
402
|
+
declare function exportImage(store: ElementStore, options?: ExportImageOptions, layerManager?: LayerManager): Promise<Blob | null>;
|
|
403
|
+
|
|
395
404
|
interface ViewportOptions {
|
|
396
405
|
camera?: CameraOptions;
|
|
397
406
|
background?: BackgroundOptions;
|
|
@@ -429,6 +438,7 @@ declare class Viewport {
|
|
|
429
438
|
requestRender(): void;
|
|
430
439
|
exportState(): CanvasState;
|
|
431
440
|
exportJSON(): string;
|
|
441
|
+
exportImage(options?: ExportImageOptions): Promise<Blob | null>;
|
|
432
442
|
loadState(state: CanvasState): void;
|
|
433
443
|
loadJSON(json: string): void;
|
|
434
444
|
undo(): boolean;
|
|
@@ -477,6 +487,7 @@ declare class Viewport {
|
|
|
477
487
|
private hideDomNode;
|
|
478
488
|
private removeDomNode;
|
|
479
489
|
private clearDomNodes;
|
|
490
|
+
private reattachHtmlContent;
|
|
480
491
|
private createWrapper;
|
|
481
492
|
private createCanvas;
|
|
482
493
|
private createDomLayer;
|
|
@@ -564,6 +575,7 @@ interface ImageInput extends BaseDefaults {
|
|
|
564
575
|
interface HtmlInput extends BaseDefaults {
|
|
565
576
|
position: Point;
|
|
566
577
|
size: Size;
|
|
578
|
+
domId?: string;
|
|
567
579
|
}
|
|
568
580
|
interface TextInput extends BaseDefaults {
|
|
569
581
|
position: Point;
|
|
@@ -858,6 +870,6 @@ declare class UpdateLayerCommand implements Command {
|
|
|
858
870
|
undo(_store: ElementStore): void;
|
|
859
871
|
}
|
|
860
872
|
|
|
861
|
-
declare const VERSION = "0.
|
|
873
|
+
declare const VERSION = "0.8.0";
|
|
862
874
|
|
|
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 };
|
|
875
|
+
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 ExportImageOptions, 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, exportImage, 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';
|
|
@@ -392,6 +393,14 @@ declare class InputHandler {
|
|
|
392
393
|
private cancelToolIfActive;
|
|
393
394
|
}
|
|
394
395
|
|
|
396
|
+
interface ExportImageOptions {
|
|
397
|
+
scale?: number;
|
|
398
|
+
padding?: number;
|
|
399
|
+
background?: string;
|
|
400
|
+
filter?: (element: CanvasElement) => boolean;
|
|
401
|
+
}
|
|
402
|
+
declare function exportImage(store: ElementStore, options?: ExportImageOptions, layerManager?: LayerManager): Promise<Blob | null>;
|
|
403
|
+
|
|
395
404
|
interface ViewportOptions {
|
|
396
405
|
camera?: CameraOptions;
|
|
397
406
|
background?: BackgroundOptions;
|
|
@@ -429,6 +438,7 @@ declare class Viewport {
|
|
|
429
438
|
requestRender(): void;
|
|
430
439
|
exportState(): CanvasState;
|
|
431
440
|
exportJSON(): string;
|
|
441
|
+
exportImage(options?: ExportImageOptions): Promise<Blob | null>;
|
|
432
442
|
loadState(state: CanvasState): void;
|
|
433
443
|
loadJSON(json: string): void;
|
|
434
444
|
undo(): boolean;
|
|
@@ -477,6 +487,7 @@ declare class Viewport {
|
|
|
477
487
|
private hideDomNode;
|
|
478
488
|
private removeDomNode;
|
|
479
489
|
private clearDomNodes;
|
|
490
|
+
private reattachHtmlContent;
|
|
480
491
|
private createWrapper;
|
|
481
492
|
private createCanvas;
|
|
482
493
|
private createDomLayer;
|
|
@@ -564,6 +575,7 @@ interface ImageInput extends BaseDefaults {
|
|
|
564
575
|
interface HtmlInput extends BaseDefaults {
|
|
565
576
|
position: Point;
|
|
566
577
|
size: Size;
|
|
578
|
+
domId?: string;
|
|
567
579
|
}
|
|
568
580
|
interface TextInput extends BaseDefaults {
|
|
569
581
|
position: Point;
|
|
@@ -858,6 +870,6 @@ declare class UpdateLayerCommand implements Command {
|
|
|
858
870
|
undo(_store: ElementStore): void;
|
|
859
871
|
}
|
|
860
872
|
|
|
861
|
-
declare const VERSION = "0.
|
|
873
|
+
declare const VERSION = "0.8.0";
|
|
862
874
|
|
|
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 };
|
|
875
|
+
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 ExportImageOptions, 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, exportImage, exportState, findBindTarget, findBoundArrows, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getEdgeIntersection, getElementBounds, getElementCenter, isBindable, isNearBezier, parseState, snapPoint, unbindArrow, updateBoundArrow };
|
package/dist/index.js
CHANGED
|
@@ -1687,7 +1687,7 @@ function createImage(input) {
|
|
|
1687
1687
|
};
|
|
1688
1688
|
}
|
|
1689
1689
|
function createHtmlElement(input) {
|
|
1690
|
-
|
|
1690
|
+
const el = {
|
|
1691
1691
|
id: createId("html"),
|
|
1692
1692
|
type: "html",
|
|
1693
1693
|
position: input.position,
|
|
@@ -1696,6 +1696,8 @@ function createHtmlElement(input) {
|
|
|
1696
1696
|
layerId: input.layerId ?? "",
|
|
1697
1697
|
size: input.size
|
|
1698
1698
|
};
|
|
1699
|
+
if (input.domId) el.domId = input.domId;
|
|
1700
|
+
return el;
|
|
1699
1701
|
}
|
|
1700
1702
|
function createShape(input) {
|
|
1701
1703
|
return {
|
|
@@ -1744,6 +1746,256 @@ function createText(input) {
|
|
|
1744
1746
|
};
|
|
1745
1747
|
}
|
|
1746
1748
|
|
|
1749
|
+
// src/canvas/export-image.ts
|
|
1750
|
+
function getStrokeBounds(el) {
|
|
1751
|
+
if (el.type !== "stroke") return null;
|
|
1752
|
+
if (el.points.length === 0) return null;
|
|
1753
|
+
let minX = Infinity;
|
|
1754
|
+
let minY = Infinity;
|
|
1755
|
+
let maxX = -Infinity;
|
|
1756
|
+
let maxY = -Infinity;
|
|
1757
|
+
for (const p of el.points) {
|
|
1758
|
+
const px = el.position.x + p.x;
|
|
1759
|
+
const py = el.position.y + p.y;
|
|
1760
|
+
minX = Math.min(minX, px);
|
|
1761
|
+
minY = Math.min(minY, py);
|
|
1762
|
+
maxX = Math.max(maxX, px);
|
|
1763
|
+
maxY = Math.max(maxY, py);
|
|
1764
|
+
}
|
|
1765
|
+
const pad = el.width / 2;
|
|
1766
|
+
return {
|
|
1767
|
+
x: minX - pad,
|
|
1768
|
+
y: minY - pad,
|
|
1769
|
+
w: maxX - minX + el.width,
|
|
1770
|
+
h: maxY - minY + el.width
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
1773
|
+
function getElementRect(el) {
|
|
1774
|
+
switch (el.type) {
|
|
1775
|
+
case "stroke":
|
|
1776
|
+
return getStrokeBounds(el);
|
|
1777
|
+
case "arrow": {
|
|
1778
|
+
const b = getArrowBounds(el.from, el.to, el.bend);
|
|
1779
|
+
const pad = el.width / 2 + 14;
|
|
1780
|
+
return { x: b.x - pad, y: b.y - pad, w: b.w + pad * 2, h: b.h + pad * 2 };
|
|
1781
|
+
}
|
|
1782
|
+
case "grid":
|
|
1783
|
+
return null;
|
|
1784
|
+
case "note":
|
|
1785
|
+
case "image":
|
|
1786
|
+
case "html":
|
|
1787
|
+
case "text":
|
|
1788
|
+
case "shape":
|
|
1789
|
+
if ("size" in el) {
|
|
1790
|
+
return { x: el.position.x, y: el.position.y, w: el.size.w, h: el.size.h };
|
|
1791
|
+
}
|
|
1792
|
+
return null;
|
|
1793
|
+
default:
|
|
1794
|
+
return null;
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
function computeBounds(elements, padding) {
|
|
1798
|
+
let minX = Infinity;
|
|
1799
|
+
let minY = Infinity;
|
|
1800
|
+
let maxX = -Infinity;
|
|
1801
|
+
let maxY = -Infinity;
|
|
1802
|
+
let found = false;
|
|
1803
|
+
for (const el of elements) {
|
|
1804
|
+
const rect = getElementRect(el);
|
|
1805
|
+
if (!rect) continue;
|
|
1806
|
+
found = true;
|
|
1807
|
+
minX = Math.min(minX, rect.x);
|
|
1808
|
+
minY = Math.min(minY, rect.y);
|
|
1809
|
+
maxX = Math.max(maxX, rect.x + rect.w);
|
|
1810
|
+
maxY = Math.max(maxY, rect.y + rect.h);
|
|
1811
|
+
}
|
|
1812
|
+
if (!found) return null;
|
|
1813
|
+
return {
|
|
1814
|
+
x: minX - padding,
|
|
1815
|
+
y: minY - padding,
|
|
1816
|
+
w: maxX - minX + padding * 2,
|
|
1817
|
+
h: maxY - minY + padding * 2
|
|
1818
|
+
};
|
|
1819
|
+
}
|
|
1820
|
+
function renderNoteOnCanvas(ctx, note) {
|
|
1821
|
+
const { x, y } = note.position;
|
|
1822
|
+
const { w, h } = note.size;
|
|
1823
|
+
const r = 4;
|
|
1824
|
+
const pad = 8;
|
|
1825
|
+
ctx.save();
|
|
1826
|
+
ctx.fillStyle = note.backgroundColor;
|
|
1827
|
+
ctx.beginPath();
|
|
1828
|
+
ctx.moveTo(x + r, y);
|
|
1829
|
+
ctx.lineTo(x + w - r, y);
|
|
1830
|
+
ctx.arcTo(x + w, y, x + w, y + r, r);
|
|
1831
|
+
ctx.lineTo(x + w, y + h - r);
|
|
1832
|
+
ctx.arcTo(x + w, y + h, x + w - r, y + h, r);
|
|
1833
|
+
ctx.lineTo(x + r, y + h);
|
|
1834
|
+
ctx.arcTo(x, y + h, x, y + h - r, r);
|
|
1835
|
+
ctx.lineTo(x, y + r);
|
|
1836
|
+
ctx.arcTo(x, y, x + r, y, r);
|
|
1837
|
+
ctx.closePath();
|
|
1838
|
+
ctx.fill();
|
|
1839
|
+
if (note.text) {
|
|
1840
|
+
ctx.fillStyle = note.textColor;
|
|
1841
|
+
ctx.font = "14px system-ui, sans-serif";
|
|
1842
|
+
ctx.textBaseline = "top";
|
|
1843
|
+
wrapText(ctx, note.text, x + pad, y + pad, w - pad * 2, 18);
|
|
1844
|
+
}
|
|
1845
|
+
ctx.restore();
|
|
1846
|
+
}
|
|
1847
|
+
function renderTextOnCanvas(ctx, text) {
|
|
1848
|
+
if (!text.text) return;
|
|
1849
|
+
ctx.save();
|
|
1850
|
+
ctx.fillStyle = text.color;
|
|
1851
|
+
ctx.font = `${text.fontSize}px system-ui, sans-serif`;
|
|
1852
|
+
ctx.textBaseline = "top";
|
|
1853
|
+
ctx.textAlign = text.textAlign;
|
|
1854
|
+
const pad = 2;
|
|
1855
|
+
let textX = text.position.x + pad;
|
|
1856
|
+
if (text.textAlign === "center") {
|
|
1857
|
+
textX = text.position.x + text.size.w / 2;
|
|
1858
|
+
} else if (text.textAlign === "right") {
|
|
1859
|
+
textX = text.position.x + text.size.w - pad;
|
|
1860
|
+
}
|
|
1861
|
+
const lineHeight = text.fontSize * 1.4;
|
|
1862
|
+
const lines = text.text.split("\n");
|
|
1863
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1864
|
+
const line = lines[i];
|
|
1865
|
+
if (line !== void 0) {
|
|
1866
|
+
ctx.fillText(line, textX, text.position.y + pad + i * lineHeight);
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
ctx.restore();
|
|
1870
|
+
}
|
|
1871
|
+
function wrapText(ctx, text, x, y, maxWidth, lineHeight) {
|
|
1872
|
+
const words = text.split(" ");
|
|
1873
|
+
let line = "";
|
|
1874
|
+
let offsetY = 0;
|
|
1875
|
+
for (const word of words) {
|
|
1876
|
+
const testLine = line ? `${line} ${word}` : word;
|
|
1877
|
+
const metrics = ctx.measureText(testLine);
|
|
1878
|
+
if (metrics.width > maxWidth && line) {
|
|
1879
|
+
ctx.fillText(line, x, y + offsetY);
|
|
1880
|
+
line = word;
|
|
1881
|
+
offsetY += lineHeight;
|
|
1882
|
+
} else {
|
|
1883
|
+
line = testLine;
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
if (line) {
|
|
1887
|
+
ctx.fillText(line, x, y + offsetY);
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
function renderGridForBounds(ctx, grid, bounds) {
|
|
1891
|
+
const visibleBounds = {
|
|
1892
|
+
minX: bounds.x,
|
|
1893
|
+
minY: bounds.y,
|
|
1894
|
+
maxX: bounds.x + bounds.w,
|
|
1895
|
+
maxY: bounds.y + bounds.h
|
|
1896
|
+
};
|
|
1897
|
+
if (grid.gridType === "hex") {
|
|
1898
|
+
renderHexGrid(
|
|
1899
|
+
ctx,
|
|
1900
|
+
visibleBounds,
|
|
1901
|
+
grid.cellSize,
|
|
1902
|
+
grid.hexOrientation,
|
|
1903
|
+
grid.strokeColor,
|
|
1904
|
+
grid.strokeWidth,
|
|
1905
|
+
grid.opacity
|
|
1906
|
+
);
|
|
1907
|
+
} else {
|
|
1908
|
+
renderSquareGrid(
|
|
1909
|
+
ctx,
|
|
1910
|
+
visibleBounds,
|
|
1911
|
+
grid.cellSize,
|
|
1912
|
+
grid.strokeColor,
|
|
1913
|
+
grid.strokeWidth,
|
|
1914
|
+
grid.opacity
|
|
1915
|
+
);
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
function loadImages(elements) {
|
|
1919
|
+
const imageElements = elements.filter(
|
|
1920
|
+
(el) => el.type === "image" && "src" in el
|
|
1921
|
+
);
|
|
1922
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1923
|
+
if (imageElements.length === 0) return Promise.resolve(cache);
|
|
1924
|
+
return new Promise((resolve) => {
|
|
1925
|
+
let remaining = imageElements.length;
|
|
1926
|
+
const done = () => {
|
|
1927
|
+
remaining--;
|
|
1928
|
+
if (remaining <= 0) resolve(cache);
|
|
1929
|
+
};
|
|
1930
|
+
for (const el of imageElements) {
|
|
1931
|
+
const img = new Image();
|
|
1932
|
+
img.onload = () => {
|
|
1933
|
+
cache.set(el.id, img);
|
|
1934
|
+
done();
|
|
1935
|
+
};
|
|
1936
|
+
img.onerror = done;
|
|
1937
|
+
img.src = el.src;
|
|
1938
|
+
}
|
|
1939
|
+
});
|
|
1940
|
+
}
|
|
1941
|
+
async function exportImage(store, options = {}, layerManager) {
|
|
1942
|
+
const scale = options.scale ?? 2;
|
|
1943
|
+
const padding = options.padding ?? 0;
|
|
1944
|
+
const background = options.background ?? "#ffffff";
|
|
1945
|
+
const filter = options.filter;
|
|
1946
|
+
const allElements = store.getAll();
|
|
1947
|
+
let visibleElements = layerManager ? allElements.filter((el) => layerManager.isLayerVisible(el.layerId)) : allElements;
|
|
1948
|
+
if (filter) {
|
|
1949
|
+
visibleElements = visibleElements.filter(filter);
|
|
1950
|
+
}
|
|
1951
|
+
const bounds = computeBounds(visibleElements, padding);
|
|
1952
|
+
if (!bounds) return null;
|
|
1953
|
+
const imageCache = await loadImages(visibleElements);
|
|
1954
|
+
const canvas = document.createElement("canvas");
|
|
1955
|
+
canvas.width = Math.ceil(bounds.w * scale);
|
|
1956
|
+
canvas.height = Math.ceil(bounds.h * scale);
|
|
1957
|
+
const ctx = canvas.getContext("2d");
|
|
1958
|
+
if (!ctx) return null;
|
|
1959
|
+
ctx.scale(scale, scale);
|
|
1960
|
+
ctx.translate(-bounds.x, -bounds.y);
|
|
1961
|
+
ctx.fillStyle = background;
|
|
1962
|
+
ctx.fillRect(bounds.x, bounds.y, bounds.w, bounds.h);
|
|
1963
|
+
const renderer = new ElementRenderer();
|
|
1964
|
+
renderer.setStore(store);
|
|
1965
|
+
const grids = [];
|
|
1966
|
+
for (const el of visibleElements) {
|
|
1967
|
+
if (el.type === "grid") {
|
|
1968
|
+
grids.push(el);
|
|
1969
|
+
continue;
|
|
1970
|
+
}
|
|
1971
|
+
if (el.type === "note") {
|
|
1972
|
+
renderNoteOnCanvas(ctx, el);
|
|
1973
|
+
continue;
|
|
1974
|
+
}
|
|
1975
|
+
if (el.type === "text") {
|
|
1976
|
+
renderTextOnCanvas(ctx, el);
|
|
1977
|
+
continue;
|
|
1978
|
+
}
|
|
1979
|
+
if (el.type === "html") {
|
|
1980
|
+
continue;
|
|
1981
|
+
}
|
|
1982
|
+
if (el.type === "image") {
|
|
1983
|
+
const img = imageCache.get(el.id);
|
|
1984
|
+
if (img) {
|
|
1985
|
+
ctx.drawImage(img, el.position.x, el.position.y, el.size.w, el.size.h);
|
|
1986
|
+
}
|
|
1987
|
+
continue;
|
|
1988
|
+
}
|
|
1989
|
+
renderer.renderCanvasElement(ctx, el);
|
|
1990
|
+
}
|
|
1991
|
+
for (const grid of grids) {
|
|
1992
|
+
renderGridForBounds(ctx, grid, bounds);
|
|
1993
|
+
}
|
|
1994
|
+
return new Promise((resolve) => {
|
|
1995
|
+
canvas.toBlob((blob) => resolve(blob), "image/png");
|
|
1996
|
+
});
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1747
1999
|
// src/layers/layer-manager.ts
|
|
1748
2000
|
var LayerManager = class {
|
|
1749
2001
|
constructor(store) {
|
|
@@ -2005,6 +2257,9 @@ var Viewport = class {
|
|
|
2005
2257
|
exportJSON() {
|
|
2006
2258
|
return JSON.stringify(this.exportState());
|
|
2007
2259
|
}
|
|
2260
|
+
async exportImage(options) {
|
|
2261
|
+
return exportImage(this.store, options, this.layerManager);
|
|
2262
|
+
}
|
|
2008
2263
|
loadState(state) {
|
|
2009
2264
|
this.historyRecorder.pause();
|
|
2010
2265
|
this.noteEditor.destroy(this.store);
|
|
@@ -2013,6 +2268,7 @@ var Viewport = class {
|
|
|
2013
2268
|
if (state.layers && state.layers.length > 0) {
|
|
2014
2269
|
this.layerManager.loadSnapshot(state.layers);
|
|
2015
2270
|
}
|
|
2271
|
+
this.reattachHtmlContent();
|
|
2016
2272
|
this.history.clear();
|
|
2017
2273
|
this.historyRecorder.resume();
|
|
2018
2274
|
this.camera.moveTo(state.camera.position.x, state.camera.position.y);
|
|
@@ -2044,7 +2300,13 @@ var Viewport = class {
|
|
|
2044
2300
|
return image.id;
|
|
2045
2301
|
}
|
|
2046
2302
|
addHtmlElement(dom, position, size = { w: 200, h: 150 }) {
|
|
2047
|
-
const
|
|
2303
|
+
const domId = dom.id || void 0;
|
|
2304
|
+
const el = createHtmlElement({
|
|
2305
|
+
position,
|
|
2306
|
+
size,
|
|
2307
|
+
domId,
|
|
2308
|
+
layerId: this.layerManager.activeLayerId
|
|
2309
|
+
});
|
|
2048
2310
|
this.htmlContent.set(el.id, dom);
|
|
2049
2311
|
this.historyRecorder.begin();
|
|
2050
2312
|
this.store.add(el);
|
|
@@ -2413,6 +2675,16 @@ var Viewport = class {
|
|
|
2413
2675
|
this.htmlContent.clear();
|
|
2414
2676
|
this.requestRender();
|
|
2415
2677
|
}
|
|
2678
|
+
reattachHtmlContent() {
|
|
2679
|
+
for (const el of this.store.getElementsByType("html")) {
|
|
2680
|
+
if (el.domId) {
|
|
2681
|
+
const dom = document.getElementById(el.domId);
|
|
2682
|
+
if (dom) {
|
|
2683
|
+
this.htmlContent.set(el.id, dom);
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
}
|
|
2416
2688
|
createWrapper() {
|
|
2417
2689
|
const el = document.createElement("div");
|
|
2418
2690
|
Object.assign(el.style, {
|
|
@@ -2671,10 +2943,11 @@ function applyArrowHandleDrag(handle, elementId, world, ctx) {
|
|
|
2671
2943
|
const el = ctx.store.getById(elementId);
|
|
2672
2944
|
if (!el || el.type !== "arrow") return;
|
|
2673
2945
|
const threshold = BIND_THRESHOLD / ctx.camera.zoom;
|
|
2946
|
+
const layerFilter = (candidate) => candidate.layerId === el.layerId;
|
|
2674
2947
|
switch (handle) {
|
|
2675
2948
|
case "start": {
|
|
2676
2949
|
const excludeId = el.toBinding?.elementId;
|
|
2677
|
-
const target = findBindTarget(world, ctx.store, threshold, excludeId);
|
|
2950
|
+
const target = findBindTarget(world, ctx.store, threshold, excludeId, layerFilter);
|
|
2678
2951
|
if (target) {
|
|
2679
2952
|
const center = getElementCenter(target);
|
|
2680
2953
|
ctx.store.update(elementId, {
|
|
@@ -2693,7 +2966,7 @@ function applyArrowHandleDrag(handle, elementId, world, ctx) {
|
|
|
2693
2966
|
}
|
|
2694
2967
|
case "end": {
|
|
2695
2968
|
const excludeId = el.fromBinding?.elementId;
|
|
2696
|
-
const target = findBindTarget(world, ctx.store, threshold, excludeId);
|
|
2969
|
+
const target = findBindTarget(world, ctx.store, threshold, excludeId, layerFilter);
|
|
2697
2970
|
if (target) {
|
|
2698
2971
|
const center = getElementCenter(target);
|
|
2699
2972
|
ctx.store.update(elementId, {
|
|
@@ -2722,7 +2995,8 @@ function getArrowHandleDragTarget(handle, elementId, world, ctx) {
|
|
|
2722
2995
|
if (!el || el.type !== "arrow") return null;
|
|
2723
2996
|
const threshold = BIND_THRESHOLD / ctx.camera.zoom;
|
|
2724
2997
|
const excludeId = handle === "start" ? el.toBinding?.elementId : el.fromBinding?.elementId;
|
|
2725
|
-
const
|
|
2998
|
+
const layerFilter = (candidate) => candidate.layerId === el.layerId;
|
|
2999
|
+
const target = findBindTarget(world, ctx.store, threshold, excludeId, layerFilter);
|
|
2726
3000
|
if (!target) return null;
|
|
2727
3001
|
return getElementBounds(target);
|
|
2728
3002
|
}
|
|
@@ -3182,8 +3456,10 @@ var ArrowTool = class {
|
|
|
3182
3456
|
if (options.width !== void 0) this.width = options.width;
|
|
3183
3457
|
}
|
|
3184
3458
|
layerFilter(ctx) {
|
|
3185
|
-
|
|
3459
|
+
const activeLayerId = ctx.activeLayerId;
|
|
3460
|
+
if (!activeLayerId && !ctx.isLayerVisible && !ctx.isLayerLocked) return void 0;
|
|
3186
3461
|
return (el) => {
|
|
3462
|
+
if (activeLayerId && el.layerId !== activeLayerId) return false;
|
|
3187
3463
|
if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) return false;
|
|
3188
3464
|
if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) return false;
|
|
3189
3465
|
return true;
|
|
@@ -3567,7 +3843,7 @@ var UpdateLayerCommand = class {
|
|
|
3567
3843
|
};
|
|
3568
3844
|
|
|
3569
3845
|
// src/index.ts
|
|
3570
|
-
var VERSION = "0.
|
|
3846
|
+
var VERSION = "0.8.0";
|
|
3571
3847
|
export {
|
|
3572
3848
|
AddElementCommand,
|
|
3573
3849
|
ArrowTool,
|
|
@@ -3609,6 +3885,7 @@ export {
|
|
|
3609
3885
|
createShape,
|
|
3610
3886
|
createStroke,
|
|
3611
3887
|
createText,
|
|
3888
|
+
exportImage,
|
|
3612
3889
|
exportState,
|
|
3613
3890
|
findBindTarget,
|
|
3614
3891
|
findBoundArrows,
|