@fieldnotes/core 0.50.8 → 0.52.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 +704 -675
- package/dist/index.cjs +267 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -4
- package/dist/index.d.ts +38 -4
- package/dist/index.js +267 -35
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -5442,7 +5442,71 @@ function renderTextOnCanvas(ctx, text) {
|
|
|
5442
5442
|
ctx.restore();
|
|
5443
5443
|
}
|
|
5444
5444
|
|
|
5445
|
+
// src/canvas/html-export.ts
|
|
5446
|
+
var DEFAULT_HTML_TIMEOUT_MS = 1e4;
|
|
5447
|
+
var TIMEOUT = /* @__PURE__ */ Symbol("html-export-timeout");
|
|
5448
|
+
function validateHtmlExportOptions(options) {
|
|
5449
|
+
const timeoutMs = options.htmlTimeoutMs ?? DEFAULT_HTML_TIMEOUT_MS;
|
|
5450
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
5451
|
+
throw new RangeError("htmlTimeoutMs must be a finite number greater than 0");
|
|
5452
|
+
}
|
|
5453
|
+
return timeoutMs;
|
|
5454
|
+
}
|
|
5455
|
+
async function renderHtmlElements(elements, options) {
|
|
5456
|
+
const timeoutMs = validateHtmlExportOptions(options);
|
|
5457
|
+
const sources = /* @__PURE__ */ new Map();
|
|
5458
|
+
await Promise.all(
|
|
5459
|
+
elements.map(async (element) => {
|
|
5460
|
+
if (!options.renderHtml) {
|
|
5461
|
+
options.onHtmlError?.({
|
|
5462
|
+
elementId: element.id,
|
|
5463
|
+
htmlType: element.htmlType,
|
|
5464
|
+
reason: "unsupported"
|
|
5465
|
+
});
|
|
5466
|
+
return;
|
|
5467
|
+
}
|
|
5468
|
+
let timer;
|
|
5469
|
+
try {
|
|
5470
|
+
const timeout = new Promise((resolve) => {
|
|
5471
|
+
timer = setTimeout(() => resolve(TIMEOUT), timeoutMs);
|
|
5472
|
+
});
|
|
5473
|
+
const result = await Promise.race([Promise.resolve(options.renderHtml(element)), timeout]);
|
|
5474
|
+
if (result === TIMEOUT) {
|
|
5475
|
+
options.onHtmlError?.({
|
|
5476
|
+
elementId: element.id,
|
|
5477
|
+
htmlType: element.htmlType,
|
|
5478
|
+
reason: "timeout"
|
|
5479
|
+
});
|
|
5480
|
+
return;
|
|
5481
|
+
}
|
|
5482
|
+
if (!result) {
|
|
5483
|
+
options.onHtmlError?.({
|
|
5484
|
+
elementId: element.id,
|
|
5485
|
+
htmlType: element.htmlType,
|
|
5486
|
+
reason: "render"
|
|
5487
|
+
});
|
|
5488
|
+
return;
|
|
5489
|
+
}
|
|
5490
|
+
sources.set(element.id, result);
|
|
5491
|
+
} catch (cause) {
|
|
5492
|
+
options.onHtmlError?.({
|
|
5493
|
+
elementId: element.id,
|
|
5494
|
+
htmlType: element.htmlType,
|
|
5495
|
+
reason: "render",
|
|
5496
|
+
cause
|
|
5497
|
+
});
|
|
5498
|
+
} finally {
|
|
5499
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
5500
|
+
}
|
|
5501
|
+
})
|
|
5502
|
+
);
|
|
5503
|
+
return sources;
|
|
5504
|
+
}
|
|
5505
|
+
|
|
5445
5506
|
// src/canvas/export-image.ts
|
|
5507
|
+
var DEFAULT_IMAGE_TIMEOUT_MS = 1e4;
|
|
5508
|
+
var DEFAULT_MAX_DIMENSION = 16384;
|
|
5509
|
+
var DEFAULT_MAX_PIXELS = 67108864;
|
|
5446
5510
|
var center = (b) => ({ x: b.x + b.w / 2, y: b.y + b.h / 2 });
|
|
5447
5511
|
function getStrokeBounds(el) {
|
|
5448
5512
|
if (el.type !== "stroke") return null;
|
|
@@ -5552,12 +5616,53 @@ function renderGridForBounds(ctx, grid, bounds) {
|
|
|
5552
5616
|
);
|
|
5553
5617
|
}
|
|
5554
5618
|
}
|
|
5555
|
-
function
|
|
5619
|
+
function positiveOption(value, fallback, name) {
|
|
5620
|
+
const resolved = value ?? fallback;
|
|
5621
|
+
if (!Number.isFinite(resolved) || resolved <= 0) {
|
|
5622
|
+
throw new RangeError(`${name} must be a finite number greater than 0`);
|
|
5623
|
+
}
|
|
5624
|
+
return resolved;
|
|
5625
|
+
}
|
|
5626
|
+
function nonNegativeOption(value, fallback, name) {
|
|
5627
|
+
const resolved = value ?? fallback;
|
|
5628
|
+
if (!Number.isFinite(resolved) || resolved < 0) {
|
|
5629
|
+
throw new RangeError(`${name} must be a finite number greater than or equal to 0`);
|
|
5630
|
+
}
|
|
5631
|
+
return resolved;
|
|
5632
|
+
}
|
|
5633
|
+
function assertExportSize(width, height, options) {
|
|
5634
|
+
const maxDimension = positiveOption(options.maxDimension, DEFAULT_MAX_DIMENSION, "maxDimension");
|
|
5635
|
+
const maxPixels = positiveOption(options.maxPixels, DEFAULT_MAX_PIXELS, "maxPixels");
|
|
5636
|
+
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
|
|
5637
|
+
throw new RangeError("Export dimensions must be finite numbers greater than 0");
|
|
5638
|
+
}
|
|
5639
|
+
if (width > maxDimension || height > maxDimension) {
|
|
5640
|
+
throw new RangeError(
|
|
5641
|
+
`Export dimensions ${width}x${height} exceed the maximum dimension of ${maxDimension}`
|
|
5642
|
+
);
|
|
5643
|
+
}
|
|
5644
|
+
if (width * height > maxPixels) {
|
|
5645
|
+
throw new RangeError(
|
|
5646
|
+
`Export size ${width}x${height} exceeds the maximum of ${maxPixels} pixels`
|
|
5647
|
+
);
|
|
5648
|
+
}
|
|
5649
|
+
}
|
|
5650
|
+
function validateExportResourceOptions(options) {
|
|
5651
|
+
positiveOption(options.imageTimeoutMs, DEFAULT_IMAGE_TIMEOUT_MS, "imageTimeoutMs");
|
|
5652
|
+
positiveOption(options.maxDimension, DEFAULT_MAX_DIMENSION, "maxDimension");
|
|
5653
|
+
positiveOption(options.maxPixels, DEFAULT_MAX_PIXELS, "maxPixels");
|
|
5654
|
+
}
|
|
5655
|
+
function loadImages(elements, options = {}) {
|
|
5556
5656
|
const imageElements = elements.filter(
|
|
5557
5657
|
(el) => el.type === "image" && "src" in el
|
|
5558
5658
|
);
|
|
5559
5659
|
const cache3 = /* @__PURE__ */ new Map();
|
|
5560
5660
|
if (imageElements.length === 0) return Promise.resolve(cache3);
|
|
5661
|
+
const timeoutMs = positiveOption(
|
|
5662
|
+
options.imageTimeoutMs,
|
|
5663
|
+
DEFAULT_IMAGE_TIMEOUT_MS,
|
|
5664
|
+
"imageTimeoutMs"
|
|
5665
|
+
);
|
|
5561
5666
|
return new Promise((resolve) => {
|
|
5562
5667
|
let remaining = imageElements.length;
|
|
5563
5668
|
const done = () => {
|
|
@@ -5567,19 +5672,42 @@ function loadImages(elements) {
|
|
|
5567
5672
|
for (const el of imageElements) {
|
|
5568
5673
|
const img = new Image();
|
|
5569
5674
|
img.crossOrigin = "anonymous";
|
|
5675
|
+
let settled = false;
|
|
5676
|
+
const timer = setTimeout(() => {
|
|
5677
|
+
if (settled) return;
|
|
5678
|
+
settled = true;
|
|
5679
|
+
img.onload = null;
|
|
5680
|
+
img.onerror = null;
|
|
5681
|
+
options.onAssetError?.({ elementId: el.id, src: el.src, reason: "timeout" });
|
|
5682
|
+
done();
|
|
5683
|
+
}, timeoutMs);
|
|
5684
|
+
const settle = () => {
|
|
5685
|
+
if (settled) return false;
|
|
5686
|
+
settled = true;
|
|
5687
|
+
clearTimeout(timer);
|
|
5688
|
+
img.onload = null;
|
|
5689
|
+
img.onerror = null;
|
|
5690
|
+
return true;
|
|
5691
|
+
};
|
|
5570
5692
|
img.onload = () => {
|
|
5693
|
+
if (!settle()) return;
|
|
5571
5694
|
cache3.set(el.id, img);
|
|
5572
5695
|
done();
|
|
5573
5696
|
};
|
|
5574
|
-
img.onerror =
|
|
5575
|
-
|
|
5576
|
-
|
|
5697
|
+
img.onerror = (cause) => {
|
|
5698
|
+
if (!settle()) return;
|
|
5699
|
+
options.onAssetError?.({ elementId: el.id, src: el.src, reason: "load", cause });
|
|
5700
|
+
done();
|
|
5701
|
+
};
|
|
5702
|
+
img.src = el.src;
|
|
5577
5703
|
}
|
|
5578
5704
|
});
|
|
5579
5705
|
}
|
|
5580
5706
|
async function exportImage(store, options = {}, layerManager) {
|
|
5581
|
-
const scale = options.scale
|
|
5582
|
-
const padding = options.padding
|
|
5707
|
+
const scale = positiveOption(options.scale, 2, "scale");
|
|
5708
|
+
const padding = nonNegativeOption(options.padding, 0, "padding");
|
|
5709
|
+
validateExportResourceOptions(options);
|
|
5710
|
+
validateHtmlExportOptions(options);
|
|
5583
5711
|
const background = options.background ?? "#ffffff";
|
|
5584
5712
|
const filter = options.filter;
|
|
5585
5713
|
const allElements = store.getAll();
|
|
@@ -5589,10 +5717,15 @@ async function exportImage(store, options = {}, layerManager) {
|
|
|
5589
5717
|
}
|
|
5590
5718
|
const bounds = computeBounds(visibleElements, padding);
|
|
5591
5719
|
if (!bounds) return null;
|
|
5592
|
-
const
|
|
5720
|
+
const width = Math.ceil(bounds.w * scale);
|
|
5721
|
+
const height = Math.ceil(bounds.h * scale);
|
|
5722
|
+
assertExportSize(width, height, options);
|
|
5723
|
+
const imageCache = await loadImages(visibleElements, options);
|
|
5724
|
+
const htmlElements = visibleElements.filter((el) => el.type === "html");
|
|
5725
|
+
const htmlSources = await renderHtmlElements(htmlElements, options);
|
|
5593
5726
|
const canvas = document.createElement("canvas");
|
|
5594
|
-
canvas.width =
|
|
5595
|
-
canvas.height =
|
|
5727
|
+
canvas.width = width;
|
|
5728
|
+
canvas.height = height;
|
|
5596
5729
|
const ctx = canvas.getContext("2d");
|
|
5597
5730
|
if (!ctx) return null;
|
|
5598
5731
|
ctx.scale(scale, scale);
|
|
@@ -5614,6 +5747,24 @@ async function exportImage(store, options = {}, layerManager) {
|
|
|
5614
5747
|
return;
|
|
5615
5748
|
}
|
|
5616
5749
|
if (el.type === "html") {
|
|
5750
|
+
const source = htmlSources.get(el.id);
|
|
5751
|
+
if (!source) return;
|
|
5752
|
+
const b = getElementBounds(el);
|
|
5753
|
+
try {
|
|
5754
|
+
withRotation(
|
|
5755
|
+
target,
|
|
5756
|
+
el,
|
|
5757
|
+
b ? center(b) : el.position,
|
|
5758
|
+
() => target.drawImage(source, el.position.x, el.position.y, el.size.w, el.size.h)
|
|
5759
|
+
);
|
|
5760
|
+
} catch (cause) {
|
|
5761
|
+
options.onHtmlError?.({
|
|
5762
|
+
elementId: el.id,
|
|
5763
|
+
htmlType: el.htmlType,
|
|
5764
|
+
reason: "render",
|
|
5765
|
+
cause
|
|
5766
|
+
});
|
|
5767
|
+
}
|
|
5617
5768
|
return;
|
|
5618
5769
|
}
|
|
5619
5770
|
if (el.type === "image") {
|
|
@@ -5769,20 +5920,23 @@ function emitArrow(arrow, store) {
|
|
|
5769
5920
|
return out;
|
|
5770
5921
|
}
|
|
5771
5922
|
function emitImage(image, dataUri) {
|
|
5772
|
-
const href = dataUri ?? image.src;
|
|
5923
|
+
const href = dataUri ?? ("src" in image ? image.src : "");
|
|
5773
5924
|
if (!href) return "";
|
|
5774
5925
|
const { x, y } = image.position;
|
|
5775
5926
|
const { w, h } = image.size;
|
|
5776
5927
|
return `<image href="${esc(href)}" x="${n(x)}" y="${n(y)}" width="${n(w)}" height="${n(h)}" />`;
|
|
5777
5928
|
}
|
|
5778
|
-
function emitText(text, rasterScale) {
|
|
5929
|
+
function emitText(text, rasterScale, resourceOptions) {
|
|
5779
5930
|
if (!text.text) return "";
|
|
5780
5931
|
const { x, y } = text.position;
|
|
5781
5932
|
const { w, h } = text.size;
|
|
5782
5933
|
if (typeof document === "undefined") return "";
|
|
5934
|
+
const width = Math.max(1, Math.ceil(w * rasterScale));
|
|
5935
|
+
const height = Math.max(1, Math.ceil(h * rasterScale));
|
|
5936
|
+
assertExportSize(width, height, resourceOptions);
|
|
5783
5937
|
const canvas = document.createElement("canvas");
|
|
5784
|
-
canvas.width =
|
|
5785
|
-
canvas.height =
|
|
5938
|
+
canvas.width = width;
|
|
5939
|
+
canvas.height = height;
|
|
5786
5940
|
const ctx = canvas.getContext("2d");
|
|
5787
5941
|
if (!ctx) return "";
|
|
5788
5942
|
ctx.scale(rasterScale, rasterScale);
|
|
@@ -5797,13 +5951,16 @@ function emitText(text, rasterScale) {
|
|
|
5797
5951
|
if (!dataUri || !dataUri.startsWith("data:")) return "";
|
|
5798
5952
|
return `<image href="${esc(dataUri)}" x="${n(x)}" y="${n(y)}" width="${n(w)}" height="${n(h)}" />`;
|
|
5799
5953
|
}
|
|
5800
|
-
function emitNote(note, rasterScale) {
|
|
5954
|
+
function emitNote(note, rasterScale, resourceOptions) {
|
|
5801
5955
|
const { x, y } = note.position;
|
|
5802
5956
|
const { w, h } = note.size;
|
|
5803
5957
|
if (typeof document === "undefined") return emitNotePlaceholder(note);
|
|
5958
|
+
const width = Math.max(1, Math.ceil(w * rasterScale));
|
|
5959
|
+
const height = Math.max(1, Math.ceil(h * rasterScale));
|
|
5960
|
+
assertExportSize(width, height, resourceOptions);
|
|
5804
5961
|
const canvas = document.createElement("canvas");
|
|
5805
|
-
canvas.width =
|
|
5806
|
-
canvas.height =
|
|
5962
|
+
canvas.width = width;
|
|
5963
|
+
canvas.height = height;
|
|
5807
5964
|
const ctx = canvas.getContext("2d");
|
|
5808
5965
|
if (!ctx) return emitNotePlaceholder(note);
|
|
5809
5966
|
ctx.scale(rasterScale, rasterScale);
|
|
@@ -5964,8 +6121,10 @@ function emitHexTemplate(t, grid) {
|
|
|
5964
6121
|
return `<path d="${d}" fill="${esc(t.fillColor)}" stroke="${esc(t.strokeColor)}" stroke-width="${n(t.strokeWidth)}" opacity="${n(t.opacity)}" />`;
|
|
5965
6122
|
}
|
|
5966
6123
|
async function exportSvg(store, options = {}, layerManager) {
|
|
5967
|
-
const padding = options.padding
|
|
5968
|
-
const rasterScale = options.rasterScale
|
|
6124
|
+
const padding = nonNegativeOption(options.padding, 0, "padding");
|
|
6125
|
+
const rasterScale = positiveOption(options.rasterScale, 2, "rasterScale");
|
|
6126
|
+
validateExportResourceOptions(options);
|
|
6127
|
+
validateHtmlExportOptions(options);
|
|
5969
6128
|
const filter = options.filter;
|
|
5970
6129
|
const allElements = store.getAll();
|
|
5971
6130
|
let visibleElements = layerManager ? allElements.filter((el) => layerManager.isLayerVisible(el.layerId)) : allElements;
|
|
@@ -5974,11 +6133,15 @@ async function exportSvg(store, options = {}, layerManager) {
|
|
|
5974
6133
|
if (!bounds) {
|
|
5975
6134
|
return `<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" viewBox="0 0 0 0"></svg>`;
|
|
5976
6135
|
}
|
|
6136
|
+
assertExportSize(Math.ceil(bounds.w), Math.ceil(bounds.h), options);
|
|
5977
6137
|
const remoteImages = visibleElements.filter(
|
|
5978
6138
|
(el) => el.type === "image" && !el.src.startsWith("data:")
|
|
5979
6139
|
);
|
|
5980
|
-
const imageCache = await loadImages(remoteImages);
|
|
5981
|
-
const imageDataUris = encodeImages(visibleElements, imageCache, rasterScale);
|
|
6140
|
+
const imageCache = await loadImages(remoteImages, options);
|
|
6141
|
+
const imageDataUris = encodeImages(visibleElements, imageCache, rasterScale, options);
|
|
6142
|
+
const htmlElements = visibleElements.filter((el) => el.type === "html");
|
|
6143
|
+
const htmlSources = await renderHtmlElements(htmlElements, options);
|
|
6144
|
+
const htmlDataUris = encodeHtmlElements(htmlElements, htmlSources, rasterScale, options);
|
|
5982
6145
|
const grids = visibleElements.filter((el) => el.type === "grid");
|
|
5983
6146
|
const firstGrid = grids[0];
|
|
5984
6147
|
let body = "";
|
|
@@ -5987,7 +6150,15 @@ async function exportSvg(store, options = {}, layerManager) {
|
|
|
5987
6150
|
}
|
|
5988
6151
|
const layerBodies = /* @__PURE__ */ new Map();
|
|
5989
6152
|
for (const el of visibleElements) {
|
|
5990
|
-
const emitted = emitElement(
|
|
6153
|
+
const emitted = emitElement(
|
|
6154
|
+
el,
|
|
6155
|
+
imageDataUris,
|
|
6156
|
+
htmlDataUris,
|
|
6157
|
+
rasterScale,
|
|
6158
|
+
firstGrid,
|
|
6159
|
+
store,
|
|
6160
|
+
options
|
|
6161
|
+
);
|
|
5991
6162
|
layerBodies.set(el.layerId, (layerBodies.get(el.layerId) ?? "") + emitted);
|
|
5992
6163
|
}
|
|
5993
6164
|
for (const [layerId, emitted] of layerBodies) {
|
|
@@ -6001,7 +6172,7 @@ async function exportSvg(store, options = {}, layerManager) {
|
|
|
6001
6172
|
}
|
|
6002
6173
|
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>`;
|
|
6003
6174
|
}
|
|
6004
|
-
function emitElement(el, imageDataUris, rasterScale, firstGrid, store) {
|
|
6175
|
+
function emitElement(el, imageDataUris, htmlDataUris, rasterScale, firstGrid, store, resourceOptions) {
|
|
6005
6176
|
switch (el.type) {
|
|
6006
6177
|
case "stroke":
|
|
6007
6178
|
return withRotationSvg(el, emitStroke(el));
|
|
@@ -6012,20 +6183,71 @@ function emitElement(el, imageDataUris, rasterScale, firstGrid, store) {
|
|
|
6012
6183
|
case "image":
|
|
6013
6184
|
return withRotationSvg(el, emitImage(el, imageDataUris.get(el.id)));
|
|
6014
6185
|
case "text":
|
|
6015
|
-
return withRotationSvg(el, emitText(el, rasterScale));
|
|
6186
|
+
return withRotationSvg(el, emitText(el, rasterScale, resourceOptions));
|
|
6016
6187
|
case "note":
|
|
6017
|
-
return withRotationSvg(el, emitNote(el, rasterScale));
|
|
6188
|
+
return withRotationSvg(el, emitNote(el, rasterScale, resourceOptions));
|
|
6018
6189
|
case "template":
|
|
6019
6190
|
return emitTemplate(el, firstGrid);
|
|
6020
6191
|
case "grid":
|
|
6021
6192
|
return "";
|
|
6022
6193
|
case "html":
|
|
6023
|
-
return
|
|
6194
|
+
return withRotationSvg(el, emitImage(el, htmlDataUris.get(el.id)));
|
|
6024
6195
|
default:
|
|
6025
6196
|
return "";
|
|
6026
6197
|
}
|
|
6027
6198
|
}
|
|
6028
|
-
function
|
|
6199
|
+
function encodeHtmlElements(elements, sources, rasterScale, options) {
|
|
6200
|
+
const encoded = /* @__PURE__ */ new Map();
|
|
6201
|
+
for (const element of elements) {
|
|
6202
|
+
const source = sources.get(element.id);
|
|
6203
|
+
if (!source) continue;
|
|
6204
|
+
const width = Math.max(1, Math.ceil(element.size.w * rasterScale));
|
|
6205
|
+
const height = Math.max(1, Math.ceil(element.size.h * rasterScale));
|
|
6206
|
+
assertExportSize(width, height, options);
|
|
6207
|
+
if (typeof document === "undefined") {
|
|
6208
|
+
options.onHtmlError?.({
|
|
6209
|
+
elementId: element.id,
|
|
6210
|
+
htmlType: element.htmlType,
|
|
6211
|
+
reason: "encode"
|
|
6212
|
+
});
|
|
6213
|
+
continue;
|
|
6214
|
+
}
|
|
6215
|
+
const canvas = document.createElement("canvas");
|
|
6216
|
+
canvas.width = width;
|
|
6217
|
+
canvas.height = height;
|
|
6218
|
+
const ctx = canvas.getContext("2d");
|
|
6219
|
+
if (!ctx) {
|
|
6220
|
+
options.onHtmlError?.({
|
|
6221
|
+
elementId: element.id,
|
|
6222
|
+
htmlType: element.htmlType,
|
|
6223
|
+
reason: "encode"
|
|
6224
|
+
});
|
|
6225
|
+
continue;
|
|
6226
|
+
}
|
|
6227
|
+
try {
|
|
6228
|
+
ctx.drawImage(source, 0, 0, width, height);
|
|
6229
|
+
const dataUri = canvas.toDataURL();
|
|
6230
|
+
if (dataUri.startsWith("data:")) {
|
|
6231
|
+
encoded.set(element.id, dataUri);
|
|
6232
|
+
} else {
|
|
6233
|
+
options.onHtmlError?.({
|
|
6234
|
+
elementId: element.id,
|
|
6235
|
+
htmlType: element.htmlType,
|
|
6236
|
+
reason: "encode"
|
|
6237
|
+
});
|
|
6238
|
+
}
|
|
6239
|
+
} catch (cause) {
|
|
6240
|
+
options.onHtmlError?.({
|
|
6241
|
+
elementId: element.id,
|
|
6242
|
+
htmlType: element.htmlType,
|
|
6243
|
+
reason: "encode",
|
|
6244
|
+
cause
|
|
6245
|
+
});
|
|
6246
|
+
}
|
|
6247
|
+
}
|
|
6248
|
+
return encoded;
|
|
6249
|
+
}
|
|
6250
|
+
function encodeImages(elements, imageCache, rasterScale, resourceOptions) {
|
|
6029
6251
|
const out = /* @__PURE__ */ new Map();
|
|
6030
6252
|
for (const el of elements) {
|
|
6031
6253
|
if (el.type !== "image") continue;
|
|
@@ -6035,16 +6257,24 @@ function encodeImages(elements, imageCache, rasterScale) {
|
|
|
6035
6257
|
}
|
|
6036
6258
|
const img = imageCache.get(el.id);
|
|
6037
6259
|
if (!img || typeof document === "undefined") continue;
|
|
6260
|
+
const width = Math.max(1, Math.ceil(el.size.w * rasterScale));
|
|
6261
|
+
const height = Math.max(1, Math.ceil(el.size.h * rasterScale));
|
|
6262
|
+
assertExportSize(width, height, resourceOptions);
|
|
6038
6263
|
const canvas = document.createElement("canvas");
|
|
6039
|
-
canvas.width =
|
|
6040
|
-
canvas.height =
|
|
6264
|
+
canvas.width = width;
|
|
6265
|
+
canvas.height = height;
|
|
6041
6266
|
const ctx = canvas.getContext("2d");
|
|
6042
|
-
if (!ctx)
|
|
6267
|
+
if (!ctx) {
|
|
6268
|
+
resourceOptions.onAssetError?.({ elementId: el.id, src: el.src, reason: "encode" });
|
|
6269
|
+
continue;
|
|
6270
|
+
}
|
|
6043
6271
|
try {
|
|
6044
6272
|
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
|
6045
6273
|
const uri = canvas.toDataURL();
|
|
6046
6274
|
if (uri.startsWith("data:")) out.set(el.id, uri);
|
|
6047
|
-
|
|
6275
|
+
else resourceOptions.onAssetError?.({ elementId: el.id, src: el.src, reason: "encode" });
|
|
6276
|
+
} catch (cause) {
|
|
6277
|
+
resourceOptions.onAssetError?.({ elementId: el.id, src: el.src, reason: "encode", cause });
|
|
6048
6278
|
}
|
|
6049
6279
|
}
|
|
6050
6280
|
return out;
|
|
@@ -6593,7 +6823,7 @@ var RenderLoop = class {
|
|
|
6593
6823
|
layerGroups = /* @__PURE__ */ new Map();
|
|
6594
6824
|
gridCacheCanvas = null;
|
|
6595
6825
|
gridCacheCtx = null;
|
|
6596
|
-
|
|
6826
|
+
lastGridRefs = [];
|
|
6597
6827
|
constructor(deps) {
|
|
6598
6828
|
this.canvasEl = deps.canvasEl;
|
|
6599
6829
|
this.camera = deps.camera;
|
|
@@ -6793,8 +7023,8 @@ var RenderLoop = class {
|
|
|
6793
7023
|
}
|
|
6794
7024
|
if (gridElements.length > 0) {
|
|
6795
7025
|
const gridT0 = performance.now();
|
|
6796
|
-
const
|
|
6797
|
-
const gridDirty = this.gridCacheDirty ||
|
|
7026
|
+
const gridsChanged = gridElements.length !== this.lastGridRefs.length || gridElements.some((grid, index) => grid !== this.lastGridRefs[index]);
|
|
7027
|
+
const gridDirty = this.gridCacheDirty || gridsChanged;
|
|
6798
7028
|
if (gridDirty) {
|
|
6799
7029
|
this.ensureGridCache();
|
|
6800
7030
|
if (this.gridCacheCtx && this.gridCacheCanvas) {
|
|
@@ -6822,7 +7052,7 @@ var RenderLoop = class {
|
|
|
6822
7052
|
}
|
|
6823
7053
|
}
|
|
6824
7054
|
this.gridCacheDirty = false;
|
|
6825
|
-
this.
|
|
7055
|
+
this.lastGridRefs = [...gridElements];
|
|
6826
7056
|
}
|
|
6827
7057
|
if (this.gridCacheCanvas) {
|
|
6828
7058
|
const offset = this.marginViewport.compositeOffset(
|
|
@@ -6842,6 +7072,8 @@ var RenderLoop = class {
|
|
|
6842
7072
|
}
|
|
6843
7073
|
}
|
|
6844
7074
|
gridMs = performance.now() - gridT0;
|
|
7075
|
+
} else {
|
|
7076
|
+
this.lastGridRefs = [];
|
|
6845
7077
|
}
|
|
6846
7078
|
const overlayT0 = performance.now();
|
|
6847
7079
|
const activeTool = this.toolManager.activeTool;
|
|
@@ -10815,7 +11047,7 @@ var LaserTool = class {
|
|
|
10815
11047
|
};
|
|
10816
11048
|
|
|
10817
11049
|
// src/index.ts
|
|
10818
|
-
var VERSION = "0.
|
|
11050
|
+
var VERSION = "0.52.0";
|
|
10819
11051
|
// Annotate the CommonJS export names for ESM import in node:
|
|
10820
11052
|
0 && (module.exports = {
|
|
10821
11053
|
ArrowTool,
|