@fieldnotes/core 0.50.8 → 0.51.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 +683 -675
- package/dist/index.cjs +120 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -4
- package/dist/index.d.ts +21 -4
- package/dist/index.js +120 -33
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -447,15 +447,32 @@ declare class HistoryStack {
|
|
|
447
447
|
private notifyChange;
|
|
448
448
|
}
|
|
449
449
|
|
|
450
|
-
interface ExportImageOptions {
|
|
450
|
+
interface ExportImageOptions extends ExportResourceOptions {
|
|
451
451
|
scale?: number;
|
|
452
452
|
padding?: number;
|
|
453
453
|
background?: string;
|
|
454
454
|
filter?: (element: CanvasElement) => boolean;
|
|
455
455
|
}
|
|
456
|
+
type ExportAssetErrorReason = 'load' | 'timeout' | 'encode';
|
|
457
|
+
interface ExportAssetError {
|
|
458
|
+
elementId: string;
|
|
459
|
+
src: string;
|
|
460
|
+
reason: ExportAssetErrorReason;
|
|
461
|
+
cause?: unknown;
|
|
462
|
+
}
|
|
463
|
+
interface ExportResourceOptions {
|
|
464
|
+
/** Maximum wait for each image asset. Defaults to 10 seconds. */
|
|
465
|
+
imageTimeoutMs?: number;
|
|
466
|
+
/** Maximum width or height of any allocated export canvas. Defaults to 16,384. */
|
|
467
|
+
maxDimension?: number;
|
|
468
|
+
/** Maximum pixel count of any allocated export canvas. Defaults to 67,108,864. */
|
|
469
|
+
maxPixels?: number;
|
|
470
|
+
/** Called when an image cannot be loaded or embedded. The export continues. */
|
|
471
|
+
onAssetError?: (error: ExportAssetError) => void;
|
|
472
|
+
}
|
|
456
473
|
declare function exportImage(store: ElementStore, options?: ExportImageOptions, layerManager?: LayerManager): Promise<Blob | null>;
|
|
457
474
|
|
|
458
|
-
interface ExportSvgOptions {
|
|
475
|
+
interface ExportSvgOptions extends ExportResourceOptions {
|
|
459
476
|
padding?: number;
|
|
460
477
|
background?: string;
|
|
461
478
|
filter?: (el: CanvasElement) => boolean;
|
|
@@ -1123,6 +1140,6 @@ declare class LaserTool implements Tool {
|
|
|
1123
1140
|
private notifyOptionsChange;
|
|
1124
1141
|
}
|
|
1125
1142
|
|
|
1126
|
-
declare const VERSION = "0.
|
|
1143
|
+
declare const VERSION = "0.51.0";
|
|
1127
1144
|
|
|
1128
|
-
export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, type ElementChangeMeta, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportImageOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, IndexedDBAdapter, type IndexedDBAdapterOptions, LaserTool, type LaserToolOptions, type Layer, LayerManager, LocalStorageAdapter, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, type RenderStatsSnapshot, type RotateDirection, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StorageAdapter, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInRectangle, getHexCellsInSquare, getHexDistance, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|
|
1145
|
+
export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, type ElementChangeMeta, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportAssetError, type ExportAssetErrorReason, type ExportImageOptions, type ExportResourceOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, IndexedDBAdapter, type IndexedDBAdapterOptions, LaserTool, type LaserToolOptions, type Layer, LayerManager, LocalStorageAdapter, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, type RenderStatsSnapshot, type RotateDirection, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StorageAdapter, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInRectangle, getHexCellsInSquare, getHexDistance, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|
package/dist/index.d.ts
CHANGED
|
@@ -447,15 +447,32 @@ declare class HistoryStack {
|
|
|
447
447
|
private notifyChange;
|
|
448
448
|
}
|
|
449
449
|
|
|
450
|
-
interface ExportImageOptions {
|
|
450
|
+
interface ExportImageOptions extends ExportResourceOptions {
|
|
451
451
|
scale?: number;
|
|
452
452
|
padding?: number;
|
|
453
453
|
background?: string;
|
|
454
454
|
filter?: (element: CanvasElement) => boolean;
|
|
455
455
|
}
|
|
456
|
+
type ExportAssetErrorReason = 'load' | 'timeout' | 'encode';
|
|
457
|
+
interface ExportAssetError {
|
|
458
|
+
elementId: string;
|
|
459
|
+
src: string;
|
|
460
|
+
reason: ExportAssetErrorReason;
|
|
461
|
+
cause?: unknown;
|
|
462
|
+
}
|
|
463
|
+
interface ExportResourceOptions {
|
|
464
|
+
/** Maximum wait for each image asset. Defaults to 10 seconds. */
|
|
465
|
+
imageTimeoutMs?: number;
|
|
466
|
+
/** Maximum width or height of any allocated export canvas. Defaults to 16,384. */
|
|
467
|
+
maxDimension?: number;
|
|
468
|
+
/** Maximum pixel count of any allocated export canvas. Defaults to 67,108,864. */
|
|
469
|
+
maxPixels?: number;
|
|
470
|
+
/** Called when an image cannot be loaded or embedded. The export continues. */
|
|
471
|
+
onAssetError?: (error: ExportAssetError) => void;
|
|
472
|
+
}
|
|
456
473
|
declare function exportImage(store: ElementStore, options?: ExportImageOptions, layerManager?: LayerManager): Promise<Blob | null>;
|
|
457
474
|
|
|
458
|
-
interface ExportSvgOptions {
|
|
475
|
+
interface ExportSvgOptions extends ExportResourceOptions {
|
|
459
476
|
padding?: number;
|
|
460
477
|
background?: string;
|
|
461
478
|
filter?: (el: CanvasElement) => boolean;
|
|
@@ -1123,6 +1140,6 @@ declare class LaserTool implements Tool {
|
|
|
1123
1140
|
private notifyOptionsChange;
|
|
1124
1141
|
}
|
|
1125
1142
|
|
|
1126
|
-
declare const VERSION = "0.
|
|
1143
|
+
declare const VERSION = "0.51.0";
|
|
1127
1144
|
|
|
1128
|
-
export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, type ElementChangeMeta, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportImageOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, IndexedDBAdapter, type IndexedDBAdapterOptions, LaserTool, type LaserToolOptions, type Layer, LayerManager, LocalStorageAdapter, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, type RenderStatsSnapshot, type RotateDirection, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StorageAdapter, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInRectangle, getHexCellsInSquare, getHexDistance, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|
|
1145
|
+
export { type ActiveFormats, type AlignEdge, type ArrowElement, type ArrowStrokeStyle, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, type BackgroundOptions, type BackgroundPattern, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, DEFAULT_NOTE_FONT_SIZE, type DistributeAxis, type ElementChangeMeta, ElementStore, type ElementStyle, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, type ExportAssetError, type ExportAssetErrorReason, type ExportImageOptions, type ExportResourceOptions, type ExportSvgOptions, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, IndexedDBAdapter, type IndexedDBAdapterOptions, LaserTool, type LaserToolOptions, type Layer, LayerManager, LocalStorageAdapter, MeasureTool, type MeasureToolOptions, type Measurement, MemoryAdapter, type NoteElement, NoteTool, type NoteToolOptions, PencilTool, type PencilToolOptions, type Point, type PointerState, type RenderStatsSnapshot, type RotateDirection, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StorageAdapter, type StrokeElement, type StrokePoint, type TemplateElement, type TemplateRenderStyle, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, VERSION, Viewport, type ViewportOptions, boundsIntersect, createArrow, createGrid, createHtmlElement, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportSvg, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getElementBounds, getElementStyle, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInRectangle, getHexCellsInSquare, getHexDistance, isNearBezier, setFontSize, smartSnap, snapPoint, snapToHexCenter, styleToPatch, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline };
|
package/dist/index.js
CHANGED
|
@@ -5356,6 +5356,9 @@ function renderTextOnCanvas(ctx, text) {
|
|
|
5356
5356
|
}
|
|
5357
5357
|
|
|
5358
5358
|
// src/canvas/export-image.ts
|
|
5359
|
+
var DEFAULT_IMAGE_TIMEOUT_MS = 1e4;
|
|
5360
|
+
var DEFAULT_MAX_DIMENSION = 16384;
|
|
5361
|
+
var DEFAULT_MAX_PIXELS = 67108864;
|
|
5359
5362
|
var center = (b) => ({ x: b.x + b.w / 2, y: b.y + b.h / 2 });
|
|
5360
5363
|
function getStrokeBounds(el) {
|
|
5361
5364
|
if (el.type !== "stroke") return null;
|
|
@@ -5465,12 +5468,53 @@ function renderGridForBounds(ctx, grid, bounds) {
|
|
|
5465
5468
|
);
|
|
5466
5469
|
}
|
|
5467
5470
|
}
|
|
5468
|
-
function
|
|
5471
|
+
function positiveOption(value, fallback, name) {
|
|
5472
|
+
const resolved = value ?? fallback;
|
|
5473
|
+
if (!Number.isFinite(resolved) || resolved <= 0) {
|
|
5474
|
+
throw new RangeError(`${name} must be a finite number greater than 0`);
|
|
5475
|
+
}
|
|
5476
|
+
return resolved;
|
|
5477
|
+
}
|
|
5478
|
+
function nonNegativeOption(value, fallback, name) {
|
|
5479
|
+
const resolved = value ?? fallback;
|
|
5480
|
+
if (!Number.isFinite(resolved) || resolved < 0) {
|
|
5481
|
+
throw new RangeError(`${name} must be a finite number greater than or equal to 0`);
|
|
5482
|
+
}
|
|
5483
|
+
return resolved;
|
|
5484
|
+
}
|
|
5485
|
+
function assertExportSize(width, height, options) {
|
|
5486
|
+
const maxDimension = positiveOption(options.maxDimension, DEFAULT_MAX_DIMENSION, "maxDimension");
|
|
5487
|
+
const maxPixels = positiveOption(options.maxPixels, DEFAULT_MAX_PIXELS, "maxPixels");
|
|
5488
|
+
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
|
|
5489
|
+
throw new RangeError("Export dimensions must be finite numbers greater than 0");
|
|
5490
|
+
}
|
|
5491
|
+
if (width > maxDimension || height > maxDimension) {
|
|
5492
|
+
throw new RangeError(
|
|
5493
|
+
`Export dimensions ${width}x${height} exceed the maximum dimension of ${maxDimension}`
|
|
5494
|
+
);
|
|
5495
|
+
}
|
|
5496
|
+
if (width * height > maxPixels) {
|
|
5497
|
+
throw new RangeError(
|
|
5498
|
+
`Export size ${width}x${height} exceeds the maximum of ${maxPixels} pixels`
|
|
5499
|
+
);
|
|
5500
|
+
}
|
|
5501
|
+
}
|
|
5502
|
+
function validateExportResourceOptions(options) {
|
|
5503
|
+
positiveOption(options.imageTimeoutMs, DEFAULT_IMAGE_TIMEOUT_MS, "imageTimeoutMs");
|
|
5504
|
+
positiveOption(options.maxDimension, DEFAULT_MAX_DIMENSION, "maxDimension");
|
|
5505
|
+
positiveOption(options.maxPixels, DEFAULT_MAX_PIXELS, "maxPixels");
|
|
5506
|
+
}
|
|
5507
|
+
function loadImages(elements, options = {}) {
|
|
5469
5508
|
const imageElements = elements.filter(
|
|
5470
5509
|
(el) => el.type === "image" && "src" in el
|
|
5471
5510
|
);
|
|
5472
5511
|
const cache3 = /* @__PURE__ */ new Map();
|
|
5473
5512
|
if (imageElements.length === 0) return Promise.resolve(cache3);
|
|
5513
|
+
const timeoutMs = positiveOption(
|
|
5514
|
+
options.imageTimeoutMs,
|
|
5515
|
+
DEFAULT_IMAGE_TIMEOUT_MS,
|
|
5516
|
+
"imageTimeoutMs"
|
|
5517
|
+
);
|
|
5474
5518
|
return new Promise((resolve) => {
|
|
5475
5519
|
let remaining = imageElements.length;
|
|
5476
5520
|
const done = () => {
|
|
@@ -5480,19 +5524,41 @@ function loadImages(elements) {
|
|
|
5480
5524
|
for (const el of imageElements) {
|
|
5481
5525
|
const img = new Image();
|
|
5482
5526
|
img.crossOrigin = "anonymous";
|
|
5527
|
+
let settled = false;
|
|
5528
|
+
const timer = setTimeout(() => {
|
|
5529
|
+
if (settled) return;
|
|
5530
|
+
settled = true;
|
|
5531
|
+
img.onload = null;
|
|
5532
|
+
img.onerror = null;
|
|
5533
|
+
options.onAssetError?.({ elementId: el.id, src: el.src, reason: "timeout" });
|
|
5534
|
+
done();
|
|
5535
|
+
}, timeoutMs);
|
|
5536
|
+
const settle = () => {
|
|
5537
|
+
if (settled) return false;
|
|
5538
|
+
settled = true;
|
|
5539
|
+
clearTimeout(timer);
|
|
5540
|
+
img.onload = null;
|
|
5541
|
+
img.onerror = null;
|
|
5542
|
+
return true;
|
|
5543
|
+
};
|
|
5483
5544
|
img.onload = () => {
|
|
5545
|
+
if (!settle()) return;
|
|
5484
5546
|
cache3.set(el.id, img);
|
|
5485
5547
|
done();
|
|
5486
5548
|
};
|
|
5487
|
-
img.onerror =
|
|
5488
|
-
|
|
5489
|
-
|
|
5549
|
+
img.onerror = (cause) => {
|
|
5550
|
+
if (!settle()) return;
|
|
5551
|
+
options.onAssetError?.({ elementId: el.id, src: el.src, reason: "load", cause });
|
|
5552
|
+
done();
|
|
5553
|
+
};
|
|
5554
|
+
img.src = el.src;
|
|
5490
5555
|
}
|
|
5491
5556
|
});
|
|
5492
5557
|
}
|
|
5493
5558
|
async function exportImage(store, options = {}, layerManager) {
|
|
5494
|
-
const scale = options.scale
|
|
5495
|
-
const padding = options.padding
|
|
5559
|
+
const scale = positiveOption(options.scale, 2, "scale");
|
|
5560
|
+
const padding = nonNegativeOption(options.padding, 0, "padding");
|
|
5561
|
+
validateExportResourceOptions(options);
|
|
5496
5562
|
const background = options.background ?? "#ffffff";
|
|
5497
5563
|
const filter = options.filter;
|
|
5498
5564
|
const allElements = store.getAll();
|
|
@@ -5502,10 +5568,13 @@ async function exportImage(store, options = {}, layerManager) {
|
|
|
5502
5568
|
}
|
|
5503
5569
|
const bounds = computeBounds(visibleElements, padding);
|
|
5504
5570
|
if (!bounds) return null;
|
|
5505
|
-
const
|
|
5571
|
+
const width = Math.ceil(bounds.w * scale);
|
|
5572
|
+
const height = Math.ceil(bounds.h * scale);
|
|
5573
|
+
assertExportSize(width, height, options);
|
|
5574
|
+
const imageCache = await loadImages(visibleElements, options);
|
|
5506
5575
|
const canvas = document.createElement("canvas");
|
|
5507
|
-
canvas.width =
|
|
5508
|
-
canvas.height =
|
|
5576
|
+
canvas.width = width;
|
|
5577
|
+
canvas.height = height;
|
|
5509
5578
|
const ctx = canvas.getContext("2d");
|
|
5510
5579
|
if (!ctx) return null;
|
|
5511
5580
|
ctx.scale(scale, scale);
|
|
@@ -5688,14 +5757,17 @@ function emitImage(image, dataUri) {
|
|
|
5688
5757
|
const { w, h } = image.size;
|
|
5689
5758
|
return `<image href="${esc(href)}" x="${n(x)}" y="${n(y)}" width="${n(w)}" height="${n(h)}" />`;
|
|
5690
5759
|
}
|
|
5691
|
-
function emitText(text, rasterScale) {
|
|
5760
|
+
function emitText(text, rasterScale, resourceOptions) {
|
|
5692
5761
|
if (!text.text) return "";
|
|
5693
5762
|
const { x, y } = text.position;
|
|
5694
5763
|
const { w, h } = text.size;
|
|
5695
5764
|
if (typeof document === "undefined") return "";
|
|
5765
|
+
const width = Math.max(1, Math.ceil(w * rasterScale));
|
|
5766
|
+
const height = Math.max(1, Math.ceil(h * rasterScale));
|
|
5767
|
+
assertExportSize(width, height, resourceOptions);
|
|
5696
5768
|
const canvas = document.createElement("canvas");
|
|
5697
|
-
canvas.width =
|
|
5698
|
-
canvas.height =
|
|
5769
|
+
canvas.width = width;
|
|
5770
|
+
canvas.height = height;
|
|
5699
5771
|
const ctx = canvas.getContext("2d");
|
|
5700
5772
|
if (!ctx) return "";
|
|
5701
5773
|
ctx.scale(rasterScale, rasterScale);
|
|
@@ -5710,13 +5782,16 @@ function emitText(text, rasterScale) {
|
|
|
5710
5782
|
if (!dataUri || !dataUri.startsWith("data:")) return "";
|
|
5711
5783
|
return `<image href="${esc(dataUri)}" x="${n(x)}" y="${n(y)}" width="${n(w)}" height="${n(h)}" />`;
|
|
5712
5784
|
}
|
|
5713
|
-
function emitNote(note, rasterScale) {
|
|
5785
|
+
function emitNote(note, rasterScale, resourceOptions) {
|
|
5714
5786
|
const { x, y } = note.position;
|
|
5715
5787
|
const { w, h } = note.size;
|
|
5716
5788
|
if (typeof document === "undefined") return emitNotePlaceholder(note);
|
|
5789
|
+
const width = Math.max(1, Math.ceil(w * rasterScale));
|
|
5790
|
+
const height = Math.max(1, Math.ceil(h * rasterScale));
|
|
5791
|
+
assertExportSize(width, height, resourceOptions);
|
|
5717
5792
|
const canvas = document.createElement("canvas");
|
|
5718
|
-
canvas.width =
|
|
5719
|
-
canvas.height =
|
|
5793
|
+
canvas.width = width;
|
|
5794
|
+
canvas.height = height;
|
|
5720
5795
|
const ctx = canvas.getContext("2d");
|
|
5721
5796
|
if (!ctx) return emitNotePlaceholder(note);
|
|
5722
5797
|
ctx.scale(rasterScale, rasterScale);
|
|
@@ -5877,8 +5952,9 @@ function emitHexTemplate(t, grid) {
|
|
|
5877
5952
|
return `<path d="${d}" fill="${esc(t.fillColor)}" stroke="${esc(t.strokeColor)}" stroke-width="${n(t.strokeWidth)}" opacity="${n(t.opacity)}" />`;
|
|
5878
5953
|
}
|
|
5879
5954
|
async function exportSvg(store, options = {}, layerManager) {
|
|
5880
|
-
const padding = options.padding
|
|
5881
|
-
const rasterScale = options.rasterScale
|
|
5955
|
+
const padding = nonNegativeOption(options.padding, 0, "padding");
|
|
5956
|
+
const rasterScale = positiveOption(options.rasterScale, 2, "rasterScale");
|
|
5957
|
+
validateExportResourceOptions(options);
|
|
5882
5958
|
const filter = options.filter;
|
|
5883
5959
|
const allElements = store.getAll();
|
|
5884
5960
|
let visibleElements = layerManager ? allElements.filter((el) => layerManager.isLayerVisible(el.layerId)) : allElements;
|
|
@@ -5887,11 +5963,12 @@ async function exportSvg(store, options = {}, layerManager) {
|
|
|
5887
5963
|
if (!bounds) {
|
|
5888
5964
|
return `<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" viewBox="0 0 0 0"></svg>`;
|
|
5889
5965
|
}
|
|
5966
|
+
assertExportSize(Math.ceil(bounds.w), Math.ceil(bounds.h), options);
|
|
5890
5967
|
const remoteImages = visibleElements.filter(
|
|
5891
5968
|
(el) => el.type === "image" && !el.src.startsWith("data:")
|
|
5892
5969
|
);
|
|
5893
|
-
const imageCache = await loadImages(remoteImages);
|
|
5894
|
-
const imageDataUris = encodeImages(visibleElements, imageCache, rasterScale);
|
|
5970
|
+
const imageCache = await loadImages(remoteImages, options);
|
|
5971
|
+
const imageDataUris = encodeImages(visibleElements, imageCache, rasterScale, options);
|
|
5895
5972
|
const grids = visibleElements.filter((el) => el.type === "grid");
|
|
5896
5973
|
const firstGrid = grids[0];
|
|
5897
5974
|
let body = "";
|
|
@@ -5900,7 +5977,7 @@ async function exportSvg(store, options = {}, layerManager) {
|
|
|
5900
5977
|
}
|
|
5901
5978
|
const layerBodies = /* @__PURE__ */ new Map();
|
|
5902
5979
|
for (const el of visibleElements) {
|
|
5903
|
-
const emitted = emitElement(el, imageDataUris, rasterScale, firstGrid, store);
|
|
5980
|
+
const emitted = emitElement(el, imageDataUris, rasterScale, firstGrid, store, options);
|
|
5904
5981
|
layerBodies.set(el.layerId, (layerBodies.get(el.layerId) ?? "") + emitted);
|
|
5905
5982
|
}
|
|
5906
5983
|
for (const [layerId, emitted] of layerBodies) {
|
|
@@ -5914,7 +5991,7 @@ async function exportSvg(store, options = {}, layerManager) {
|
|
|
5914
5991
|
}
|
|
5915
5992
|
return `<svg xmlns="http://www.w3.org/2000/svg" width="${n(bounds.w)}" height="${n(bounds.h)}" viewBox="${n(bounds.x)} ${n(bounds.y)} ${n(bounds.w)} ${n(bounds.h)}">${body}</svg>`;
|
|
5916
5993
|
}
|
|
5917
|
-
function emitElement(el, imageDataUris, rasterScale, firstGrid, store) {
|
|
5994
|
+
function emitElement(el, imageDataUris, rasterScale, firstGrid, store, resourceOptions) {
|
|
5918
5995
|
switch (el.type) {
|
|
5919
5996
|
case "stroke":
|
|
5920
5997
|
return withRotationSvg(el, emitStroke(el));
|
|
@@ -5925,9 +6002,9 @@ function emitElement(el, imageDataUris, rasterScale, firstGrid, store) {
|
|
|
5925
6002
|
case "image":
|
|
5926
6003
|
return withRotationSvg(el, emitImage(el, imageDataUris.get(el.id)));
|
|
5927
6004
|
case "text":
|
|
5928
|
-
return withRotationSvg(el, emitText(el, rasterScale));
|
|
6005
|
+
return withRotationSvg(el, emitText(el, rasterScale, resourceOptions));
|
|
5929
6006
|
case "note":
|
|
5930
|
-
return withRotationSvg(el, emitNote(el, rasterScale));
|
|
6007
|
+
return withRotationSvg(el, emitNote(el, rasterScale, resourceOptions));
|
|
5931
6008
|
case "template":
|
|
5932
6009
|
return emitTemplate(el, firstGrid);
|
|
5933
6010
|
case "grid":
|
|
@@ -5938,7 +6015,7 @@ function emitElement(el, imageDataUris, rasterScale, firstGrid, store) {
|
|
|
5938
6015
|
return "";
|
|
5939
6016
|
}
|
|
5940
6017
|
}
|
|
5941
|
-
function encodeImages(elements, imageCache, rasterScale) {
|
|
6018
|
+
function encodeImages(elements, imageCache, rasterScale, resourceOptions) {
|
|
5942
6019
|
const out = /* @__PURE__ */ new Map();
|
|
5943
6020
|
for (const el of elements) {
|
|
5944
6021
|
if (el.type !== "image") continue;
|
|
@@ -5948,16 +6025,24 @@ function encodeImages(elements, imageCache, rasterScale) {
|
|
|
5948
6025
|
}
|
|
5949
6026
|
const img = imageCache.get(el.id);
|
|
5950
6027
|
if (!img || typeof document === "undefined") continue;
|
|
6028
|
+
const width = Math.max(1, Math.ceil(el.size.w * rasterScale));
|
|
6029
|
+
const height = Math.max(1, Math.ceil(el.size.h * rasterScale));
|
|
6030
|
+
assertExportSize(width, height, resourceOptions);
|
|
5951
6031
|
const canvas = document.createElement("canvas");
|
|
5952
|
-
canvas.width =
|
|
5953
|
-
canvas.height =
|
|
6032
|
+
canvas.width = width;
|
|
6033
|
+
canvas.height = height;
|
|
5954
6034
|
const ctx = canvas.getContext("2d");
|
|
5955
|
-
if (!ctx)
|
|
6035
|
+
if (!ctx) {
|
|
6036
|
+
resourceOptions.onAssetError?.({ elementId: el.id, src: el.src, reason: "encode" });
|
|
6037
|
+
continue;
|
|
6038
|
+
}
|
|
5956
6039
|
try {
|
|
5957
6040
|
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
|
5958
6041
|
const uri = canvas.toDataURL();
|
|
5959
6042
|
if (uri.startsWith("data:")) out.set(el.id, uri);
|
|
5960
|
-
|
|
6043
|
+
else resourceOptions.onAssetError?.({ elementId: el.id, src: el.src, reason: "encode" });
|
|
6044
|
+
} catch (cause) {
|
|
6045
|
+
resourceOptions.onAssetError?.({ elementId: el.id, src: el.src, reason: "encode", cause });
|
|
5961
6046
|
}
|
|
5962
6047
|
}
|
|
5963
6048
|
return out;
|
|
@@ -6506,7 +6591,7 @@ var RenderLoop = class {
|
|
|
6506
6591
|
layerGroups = /* @__PURE__ */ new Map();
|
|
6507
6592
|
gridCacheCanvas = null;
|
|
6508
6593
|
gridCacheCtx = null;
|
|
6509
|
-
|
|
6594
|
+
lastGridRefs = [];
|
|
6510
6595
|
constructor(deps) {
|
|
6511
6596
|
this.canvasEl = deps.canvasEl;
|
|
6512
6597
|
this.camera = deps.camera;
|
|
@@ -6706,8 +6791,8 @@ var RenderLoop = class {
|
|
|
6706
6791
|
}
|
|
6707
6792
|
if (gridElements.length > 0) {
|
|
6708
6793
|
const gridT0 = performance.now();
|
|
6709
|
-
const
|
|
6710
|
-
const gridDirty = this.gridCacheDirty ||
|
|
6794
|
+
const gridsChanged = gridElements.length !== this.lastGridRefs.length || gridElements.some((grid, index) => grid !== this.lastGridRefs[index]);
|
|
6795
|
+
const gridDirty = this.gridCacheDirty || gridsChanged;
|
|
6711
6796
|
if (gridDirty) {
|
|
6712
6797
|
this.ensureGridCache();
|
|
6713
6798
|
if (this.gridCacheCtx && this.gridCacheCanvas) {
|
|
@@ -6735,7 +6820,7 @@ var RenderLoop = class {
|
|
|
6735
6820
|
}
|
|
6736
6821
|
}
|
|
6737
6822
|
this.gridCacheDirty = false;
|
|
6738
|
-
this.
|
|
6823
|
+
this.lastGridRefs = [...gridElements];
|
|
6739
6824
|
}
|
|
6740
6825
|
if (this.gridCacheCanvas) {
|
|
6741
6826
|
const offset = this.marginViewport.compositeOffset(
|
|
@@ -6755,6 +6840,8 @@ var RenderLoop = class {
|
|
|
6755
6840
|
}
|
|
6756
6841
|
}
|
|
6757
6842
|
gridMs = performance.now() - gridT0;
|
|
6843
|
+
} else {
|
|
6844
|
+
this.lastGridRefs = [];
|
|
6758
6845
|
}
|
|
6759
6846
|
const overlayT0 = performance.now();
|
|
6760
6847
|
const activeTool = this.toolManager.activeTool;
|
|
@@ -10728,7 +10815,7 @@ var LaserTool = class {
|
|
|
10728
10815
|
};
|
|
10729
10816
|
|
|
10730
10817
|
// src/index.ts
|
|
10731
|
-
var VERSION = "0.
|
|
10818
|
+
var VERSION = "0.51.0";
|
|
10732
10819
|
export {
|
|
10733
10820
|
ArrowTool,
|
|
10734
10821
|
AutoSave,
|