canvu-react 0.4.71 → 0.4.73
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/{asset-hydration-BeWWxiBq.d.cts → asset-hydration-6swZ6ciN.d.cts} +1 -1
- package/dist/{asset-hydration-CLoDkZDh.d.ts → asset-hydration-P0M5hn-p.d.ts} +1 -1
- package/dist/chatbot.d.cts +2 -2
- package/dist/chatbot.d.ts +2 -2
- package/dist/index.cjs +87 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +87 -6
- package/dist/index.js.map +1 -1
- package/dist/{raster-image-canvas-Byq087t9.d.cts → raster-image-canvas-ByaCKEVw.d.cts} +2 -0
- package/dist/{raster-image-canvas-BqBgE8C-.d.ts → raster-image-canvas-D3ZrySjr.d.ts} +2 -0
- package/dist/react.cjs +182 -33
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +35 -8
- package/dist/react.d.ts +35 -8
- package/dist/react.js +182 -33
- package/dist/react.js.map +1 -1
- package/dist/realtime.d.cts +2 -2
- package/dist/realtime.d.ts +2 -2
- package/dist/{types-D_cQxUug.d.ts → types-C5wxwquF.d.ts} +1 -1
- package/dist/{types-f8d-2-6N.d.cts → types-DOUBapS4.d.cts} +1 -1
- package/package.json +1 -1
|
@@ -22,6 +22,8 @@ type VectorViewportAssetUploadRequest = {
|
|
|
22
22
|
file: File;
|
|
23
23
|
/** High-level bucket for routing image vs PDF upload behavior. */
|
|
24
24
|
kind: VectorViewportAssetKind;
|
|
25
|
+
/** Optional lifecycle signal for cancelling in-flight uploads. */
|
|
26
|
+
signal?: AbortSignal;
|
|
25
27
|
};
|
|
26
28
|
/**
|
|
27
29
|
* Persisted metadata returned by a custom asset upload.
|
|
@@ -22,6 +22,8 @@ type VectorViewportAssetUploadRequest = {
|
|
|
22
22
|
file: File;
|
|
23
23
|
/** High-level bucket for routing image vs PDF upload behavior. */
|
|
24
24
|
kind: VectorViewportAssetKind;
|
|
25
|
+
/** Optional lifecycle signal for cancelling in-flight uploads. */
|
|
26
|
+
signal?: AbortSignal;
|
|
25
27
|
};
|
|
26
28
|
/**
|
|
27
29
|
* Persisted metadata returned by a custom asset upload.
|
package/dist/react.cjs
CHANGED
|
@@ -1208,7 +1208,8 @@ function getPdfJs() {
|
|
|
1208
1208
|
}
|
|
1209
1209
|
return pdfjsPromise;
|
|
1210
1210
|
}
|
|
1211
|
-
async function renderPageToCanvas(page, scale) {
|
|
1211
|
+
async function renderPageToCanvas(page, scale, signal) {
|
|
1212
|
+
throwIfAborted(signal);
|
|
1212
1213
|
const raw = page.getViewport({ scale: 1 });
|
|
1213
1214
|
const adjustedScale = Math.round(raw.width * scale) / raw.width;
|
|
1214
1215
|
const viewport = page.getViewport({ scale: adjustedScale });
|
|
@@ -1221,22 +1222,48 @@ async function renderPageToCanvas(page, scale) {
|
|
|
1221
1222
|
if (!ctx) throw new Error("Canvas 2D context unavailable");
|
|
1222
1223
|
ctx.imageSmoothingEnabled = true;
|
|
1223
1224
|
ctx.imageSmoothingQuality = "high";
|
|
1224
|
-
|
|
1225
|
+
const renderTask = page.render({ canvas, viewport });
|
|
1226
|
+
if (signal) {
|
|
1227
|
+
const abortRender = () => {
|
|
1228
|
+
renderTask.cancel();
|
|
1229
|
+
};
|
|
1230
|
+
signal.addEventListener("abort", abortRender, { once: true });
|
|
1231
|
+
try {
|
|
1232
|
+
await renderTask.promise;
|
|
1233
|
+
} catch (error) {
|
|
1234
|
+
if (signal.aborted) throw createAbortError();
|
|
1235
|
+
throw error;
|
|
1236
|
+
} finally {
|
|
1237
|
+
signal.removeEventListener("abort", abortRender);
|
|
1238
|
+
}
|
|
1239
|
+
} else {
|
|
1240
|
+
await renderTask.promise;
|
|
1241
|
+
}
|
|
1242
|
+
throwIfAborted(signal);
|
|
1225
1243
|
return { canvas, width: w, height: h };
|
|
1226
1244
|
}
|
|
1245
|
+
function createAbortError() {
|
|
1246
|
+
return new DOMException("Aborted", "AbortError");
|
|
1247
|
+
}
|
|
1248
|
+
function throwIfAborted(signal) {
|
|
1249
|
+
if (signal?.aborted) {
|
|
1250
|
+
throw createAbortError();
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1227
1253
|
function normalizePdfPageNumbers(pageNumbers, pageCount) {
|
|
1228
1254
|
if (!pageNumbers || pageNumbers.length === 0) {
|
|
1229
1255
|
return Array.from({ length: pageCount }, (_, index) => index + 1);
|
|
1230
1256
|
}
|
|
1231
1257
|
return [...new Set(pageNumbers)].filter((pageNumber) => pageNumber >= 1 && pageNumber <= pageCount).sort((left, right) => left - right);
|
|
1232
1258
|
}
|
|
1233
|
-
async function runWithConcurrency(items, concurrency, execute) {
|
|
1259
|
+
async function runWithConcurrency(items, concurrency, execute, signal) {
|
|
1234
1260
|
const results = new Array(items.length);
|
|
1235
1261
|
let nextIndex = 0;
|
|
1236
1262
|
const workerCount = Math.max(1, Math.min(concurrency, items.length));
|
|
1237
1263
|
await Promise.all(
|
|
1238
1264
|
Array.from({ length: workerCount }, async () => {
|
|
1239
1265
|
while (nextIndex < items.length) {
|
|
1266
|
+
throwIfAborted(signal);
|
|
1240
1267
|
const currentIndex = nextIndex;
|
|
1241
1268
|
nextIndex += 1;
|
|
1242
1269
|
const item = items[currentIndex];
|
|
@@ -1244,6 +1271,7 @@ async function runWithConcurrency(items, concurrency, execute) {
|
|
|
1244
1271
|
continue;
|
|
1245
1272
|
}
|
|
1246
1273
|
results[currentIndex] = await execute(item);
|
|
1274
|
+
throwIfAborted(signal);
|
|
1247
1275
|
}
|
|
1248
1276
|
})
|
|
1249
1277
|
);
|
|
@@ -1253,9 +1281,49 @@ async function loadPdfToStore(file, store, options) {
|
|
|
1253
1281
|
const scale = options?.scale ?? 1.5;
|
|
1254
1282
|
const pageConcurrency = options?.pageConcurrency ?? 2;
|
|
1255
1283
|
const storeThumbnails = options?.storeThumbnails ?? false;
|
|
1284
|
+
const signal = options?.signal;
|
|
1285
|
+
throwIfAborted(signal);
|
|
1256
1286
|
const pdfjs = await getPdfJs();
|
|
1287
|
+
throwIfAborted(signal);
|
|
1257
1288
|
const arrayBuffer = await file.arrayBuffer();
|
|
1258
|
-
|
|
1289
|
+
throwIfAborted(signal);
|
|
1290
|
+
const loadingTask = pdfjs.getDocument({ data: arrayBuffer });
|
|
1291
|
+
if (signal) {
|
|
1292
|
+
const abortLoading = () => {
|
|
1293
|
+
void loadingTask.destroy();
|
|
1294
|
+
};
|
|
1295
|
+
signal.addEventListener("abort", abortLoading, { once: true });
|
|
1296
|
+
try {
|
|
1297
|
+
const pdf2 = await loadingTask.promise;
|
|
1298
|
+
signal.removeEventListener("abort", abortLoading);
|
|
1299
|
+
return await loadPdfDocumentToStore(pdf2, store, {
|
|
1300
|
+
scale,
|
|
1301
|
+
pageNumbers: options?.pageNumbers,
|
|
1302
|
+
pageConcurrency,
|
|
1303
|
+
storeThumbnails,
|
|
1304
|
+
signal,
|
|
1305
|
+
onPageStored: options?.onPageStored
|
|
1306
|
+
});
|
|
1307
|
+
} catch (error) {
|
|
1308
|
+
if (signal.aborted) throw createAbortError();
|
|
1309
|
+
throw error;
|
|
1310
|
+
} finally {
|
|
1311
|
+
signal.removeEventListener("abort", abortLoading);
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
const pdf = await loadingTask.promise;
|
|
1315
|
+
return await loadPdfDocumentToStore(pdf, store, {
|
|
1316
|
+
scale,
|
|
1317
|
+
pageNumbers: options?.pageNumbers,
|
|
1318
|
+
pageConcurrency,
|
|
1319
|
+
storeThumbnails,
|
|
1320
|
+
onPageStored: options?.onPageStored
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
async function loadPdfDocumentToStore(pdf, store, options) {
|
|
1324
|
+
const { pageConcurrency, scale, signal } = options;
|
|
1325
|
+
const storeThumbnails = options.storeThumbnails ?? false;
|
|
1326
|
+
throwIfAborted(signal);
|
|
1259
1327
|
const pageNumbers = normalizePdfPageNumbers(options?.pageNumbers, pdf.numPages);
|
|
1260
1328
|
const bufferedResults = /* @__PURE__ */ new Map();
|
|
1261
1329
|
let nextEmitIndex = 0;
|
|
@@ -1270,7 +1338,9 @@ async function loadPdfToStore(file, store, options) {
|
|
|
1270
1338
|
if (!bufferedResult) break;
|
|
1271
1339
|
bufferedResults.delete(nextPageNumber);
|
|
1272
1340
|
nextEmitIndex += 1;
|
|
1341
|
+
throwIfAborted(signal);
|
|
1273
1342
|
await options?.onPageStored?.(bufferedResult);
|
|
1343
|
+
throwIfAborted(signal);
|
|
1274
1344
|
}
|
|
1275
1345
|
};
|
|
1276
1346
|
const nextChain = emitChain.then(run, run);
|
|
@@ -1282,11 +1352,20 @@ async function loadPdfToStore(file, store, options) {
|
|
|
1282
1352
|
pageNumbers,
|
|
1283
1353
|
pageConcurrency,
|
|
1284
1354
|
async (pageNumber) => {
|
|
1355
|
+
throwIfAborted(signal);
|
|
1285
1356
|
const page = await pdf.getPage(pageNumber);
|
|
1286
|
-
|
|
1357
|
+
throwIfAborted(signal);
|
|
1358
|
+
const { canvas, width, height } = await renderPageToCanvas(
|
|
1359
|
+
page,
|
|
1360
|
+
scale,
|
|
1361
|
+
signal
|
|
1362
|
+
);
|
|
1363
|
+
throwIfAborted(signal);
|
|
1287
1364
|
const mime = "image/png";
|
|
1288
1365
|
const pageBlob = await encodeCanvasToBlob(canvas, { mimeType: mime });
|
|
1366
|
+
throwIfAborted(signal);
|
|
1289
1367
|
const blobId = await store.storeOriginal(pageBlob);
|
|
1368
|
+
throwIfAborted(signal);
|
|
1290
1369
|
const thumbnailBlobId = storeThumbnails ? await (async () => {
|
|
1291
1370
|
const thumbScale = Math.min(1, 256 / Math.max(width, height));
|
|
1292
1371
|
const tw = Math.max(1, Math.round(width * thumbScale));
|
|
@@ -1303,6 +1382,7 @@ async function loadPdfToStore(file, store, options) {
|
|
|
1303
1382
|
const thumbBlob = await encodeCanvasToBlob(thumbCanvas, {
|
|
1304
1383
|
mimeType: mime
|
|
1305
1384
|
});
|
|
1385
|
+
throwIfAborted(signal);
|
|
1306
1386
|
return await store.storeThumbnail(thumbBlob);
|
|
1307
1387
|
})() : "";
|
|
1308
1388
|
const pageResult = {
|
|
@@ -1314,7 +1394,8 @@ async function loadPdfToStore(file, store, options) {
|
|
|
1314
1394
|
};
|
|
1315
1395
|
await queuePageEmission(pageResult);
|
|
1316
1396
|
return pageResult;
|
|
1317
|
-
}
|
|
1397
|
+
},
|
|
1398
|
+
signal
|
|
1318
1399
|
);
|
|
1319
1400
|
}
|
|
1320
1401
|
|
|
@@ -1655,9 +1736,22 @@ function finalizeIngestedItem(item, context, uploadResult, decorateItem) {
|
|
|
1655
1736
|
const itemWithAssetData = applyAssetUploadResultToItem(item, uploadResult);
|
|
1656
1737
|
return decorateItem ? decorateItem(itemWithAssetData, context) : itemWithAssetData;
|
|
1657
1738
|
}
|
|
1658
|
-
|
|
1739
|
+
function createAbortError2() {
|
|
1740
|
+
return new DOMException("Aborted", "AbortError");
|
|
1741
|
+
}
|
|
1742
|
+
function throwIfAborted2(signal) {
|
|
1743
|
+
if (signal?.aborted) {
|
|
1744
|
+
throw createAbortError2();
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
function isAbortError(error) {
|
|
1748
|
+
return (error instanceof DOMException || error instanceof Error) && error.name === "AbortError";
|
|
1749
|
+
}
|
|
1750
|
+
async function uploadAssetIfNeeded(assetStore, file, kind, signal) {
|
|
1751
|
+
throwIfAborted2(signal);
|
|
1659
1752
|
if (!assetStore) return null;
|
|
1660
|
-
const result = await assetStore.upload({ file, kind });
|
|
1753
|
+
const result = await assetStore.upload({ file, kind, signal });
|
|
1754
|
+
throwIfAborted2(signal);
|
|
1661
1755
|
return result ?? null;
|
|
1662
1756
|
}
|
|
1663
1757
|
async function ingestAssetFilesToSceneItems(options) {
|
|
@@ -1671,6 +1765,7 @@ async function ingestAssetFilesToSceneItems(options) {
|
|
|
1671
1765
|
gapWorld = 16,
|
|
1672
1766
|
pdfScale = 1.15,
|
|
1673
1767
|
pdfPageConcurrency = 2,
|
|
1768
|
+
signal,
|
|
1674
1769
|
decorateItem,
|
|
1675
1770
|
onItemsReady,
|
|
1676
1771
|
onError
|
|
@@ -1679,6 +1774,7 @@ async function ingestAssetFilesToSceneItems(options) {
|
|
|
1679
1774
|
const errors = [];
|
|
1680
1775
|
let occupiedBottomY = existingItems.length > 0 ? Math.max(...existingItems.map((item) => item.bounds.y + item.bounds.height)) : null;
|
|
1681
1776
|
for (const file of files) {
|
|
1777
|
+
throwIfAborted2(signal);
|
|
1682
1778
|
const kind = getAssetKindForFile(file);
|
|
1683
1779
|
if (!kind) {
|
|
1684
1780
|
const error = {
|
|
@@ -1691,14 +1787,23 @@ async function ingestAssetFilesToSceneItems(options) {
|
|
|
1691
1787
|
}
|
|
1692
1788
|
try {
|
|
1693
1789
|
if (kind === "pdf") {
|
|
1694
|
-
const uploadResultPromise = uploadAssetIfNeeded(
|
|
1790
|
+
const uploadResultPromise = uploadAssetIfNeeded(
|
|
1791
|
+
assetStore,
|
|
1792
|
+
file,
|
|
1793
|
+
kind,
|
|
1794
|
+
signal
|
|
1795
|
+
);
|
|
1796
|
+
void uploadResultPromise.catch(() => void 0);
|
|
1695
1797
|
await loadPdfToStore(file, imageStore, {
|
|
1696
1798
|
scale: pdfScale,
|
|
1697
1799
|
pageConcurrency: pdfPageConcurrency,
|
|
1698
1800
|
storeThumbnails: false,
|
|
1801
|
+
signal,
|
|
1699
1802
|
onPageStored: async (page) => {
|
|
1803
|
+
throwIfAborted2(signal);
|
|
1700
1804
|
const uploadResult2 = await uploadResultPromise;
|
|
1701
1805
|
const fullUrl2 = await createBlobUrlFromStore(imageStore, page.blobId);
|
|
1806
|
+
throwIfAborted2(signal);
|
|
1702
1807
|
const naturalTopY2 = worldCenter.y - page.height / 2;
|
|
1703
1808
|
const stackedTopY2 = occupiedBottomY == null ? naturalTopY2 : occupiedBottomY + gapWorld;
|
|
1704
1809
|
const bounds2 = {
|
|
@@ -1738,15 +1843,18 @@ async function ingestAssetFilesToSceneItems(options) {
|
|
|
1738
1843
|
);
|
|
1739
1844
|
items.push(item2);
|
|
1740
1845
|
occupiedBottomY = bounds2.y + page.height;
|
|
1846
|
+
throwIfAborted2(signal);
|
|
1741
1847
|
onItemsReady?.([item2], { file, kind });
|
|
1742
1848
|
}
|
|
1743
1849
|
});
|
|
1744
1850
|
continue;
|
|
1745
1851
|
}
|
|
1852
|
+
throwIfAborted2(signal);
|
|
1746
1853
|
const [uploadResult, storedImage] = await Promise.all([
|
|
1747
|
-
uploadAssetIfNeeded(assetStore, file, kind),
|
|
1854
|
+
uploadAssetIfNeeded(assetStore, file, kind, signal),
|
|
1748
1855
|
loadImageToStore(file, imageStore)
|
|
1749
1856
|
]);
|
|
1857
|
+
throwIfAborted2(signal);
|
|
1750
1858
|
const { blobId, thumbnailBlobId, width, height } = storedImage;
|
|
1751
1859
|
const fullUrl = await createBlobUrlFromStore(imageStore, blobId);
|
|
1752
1860
|
const thumbBlob = await imageStore.getThumbnail(thumbnailBlobId);
|
|
@@ -1784,9 +1892,13 @@ async function ingestAssetFilesToSceneItems(options) {
|
|
|
1784
1892
|
decorateItem
|
|
1785
1893
|
);
|
|
1786
1894
|
items.push(item);
|
|
1895
|
+
throwIfAborted2(signal);
|
|
1787
1896
|
onItemsReady?.([item], { file, kind });
|
|
1788
1897
|
occupiedBottomY = occupiedBottomY == null ? bounds.y + height : Math.max(occupiedBottomY, bounds.y + height);
|
|
1789
1898
|
} catch (error) {
|
|
1899
|
+
if (isAbortError(error)) {
|
|
1900
|
+
throw error;
|
|
1901
|
+
}
|
|
1790
1902
|
const fileError = {
|
|
1791
1903
|
file,
|
|
1792
1904
|
kind,
|
|
@@ -2148,6 +2260,7 @@ function ImagesMenu({
|
|
|
2148
2260
|
onItemsChange,
|
|
2149
2261
|
onFocusItem,
|
|
2150
2262
|
labels,
|
|
2263
|
+
hiddenActions,
|
|
2151
2264
|
defaultOpen = false,
|
|
2152
2265
|
collapsedButtonClassName,
|
|
2153
2266
|
collapsedButtonStyle,
|
|
@@ -2163,6 +2276,10 @@ function ImagesMenu({
|
|
|
2163
2276
|
react.useEffect(() => {
|
|
2164
2277
|
ensureOpenKeyframe();
|
|
2165
2278
|
}, []);
|
|
2279
|
+
const hiddenActionSet = react.useMemo(
|
|
2280
|
+
() => new Set(hiddenActions ?? []),
|
|
2281
|
+
[hiddenActions]
|
|
2282
|
+
);
|
|
2166
2283
|
if (managed.length === 0) {
|
|
2167
2284
|
return null;
|
|
2168
2285
|
}
|
|
@@ -2237,6 +2354,7 @@ function ImagesMenu({
|
|
|
2237
2354
|
{
|
|
2238
2355
|
item,
|
|
2239
2356
|
labels: resolvedLabels,
|
|
2357
|
+
hiddenActionSet,
|
|
2240
2358
|
onFocus: onFocusItem ? () => onFocusItem(item) : void 0,
|
|
2241
2359
|
onCopy: () => onItemsChange(copyManagedImage(items, item.id)),
|
|
2242
2360
|
onRotate: () => onItemsChange(rotateManagedImage(items, item.id)),
|
|
@@ -2253,6 +2371,7 @@ function ImagesMenu({
|
|
|
2253
2371
|
function ImagesMenuRow({
|
|
2254
2372
|
item,
|
|
2255
2373
|
labels,
|
|
2374
|
+
hiddenActionSet,
|
|
2256
2375
|
onFocus,
|
|
2257
2376
|
onCopy,
|
|
2258
2377
|
onRotate,
|
|
@@ -2292,9 +2411,9 @@ function ImagesMenuRow({
|
|
|
2292
2411
|
),
|
|
2293
2412
|
/* @__PURE__ */ jsxRuntime.jsx(FocusTarget, { label: labels.focus, onFocus, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: thumbBoxStyle, children: src ? /* @__PURE__ */ jsxRuntime.jsx("img", { src, alt: "", style: thumbImgStyle, draggable: false }) : null }) }),
|
|
2294
2413
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: actionsColumnStyle, children: [
|
|
2295
|
-
/* @__PURE__ */ jsxRuntime.jsx(ImagesMenuAction, { label: labels.duplicate, onClick: onCopy, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CopyPlus, { size: 18 }) }),
|
|
2296
|
-
/* @__PURE__ */ jsxRuntime.jsx(ImagesMenuAction, { label: labels.rotate, onClick: onRotate, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCw, { size: 18 }) }),
|
|
2297
|
-
/* @__PURE__ */ jsxRuntime.jsx(ImagesMenuAction, { label: labels.delete, onClick: onDelete, danger: true, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: 18 }) })
|
|
2414
|
+
!hiddenActionSet.has("duplicate") ? /* @__PURE__ */ jsxRuntime.jsx(ImagesMenuAction, { label: labels.duplicate, onClick: onCopy, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CopyPlus, { size: 18 }) }) : null,
|
|
2415
|
+
!hiddenActionSet.has("rotate") ? /* @__PURE__ */ jsxRuntime.jsx(ImagesMenuAction, { label: labels.rotate, onClick: onRotate, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCw, { size: 18 }) }) : null,
|
|
2416
|
+
!hiddenActionSet.has("delete") ? /* @__PURE__ */ jsxRuntime.jsx(ImagesMenuAction, { label: labels.delete, onClick: onDelete, danger: true, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: 18 }) }) : null
|
|
2298
2417
|
] })
|
|
2299
2418
|
] });
|
|
2300
2419
|
}
|
|
@@ -8440,6 +8559,48 @@ function shallowEqualStringArray(a, b) {
|
|
|
8440
8559
|
return true;
|
|
8441
8560
|
}
|
|
8442
8561
|
|
|
8562
|
+
// src/react/stroke-input.ts
|
|
8563
|
+
var MAX_INTERPOLATED_POINTS_PER_SAMPLE = 192;
|
|
8564
|
+
function getPointerEventSamples(event) {
|
|
8565
|
+
if (typeof event.getCoalescedEvents !== "function") {
|
|
8566
|
+
return [event];
|
|
8567
|
+
}
|
|
8568
|
+
const samples = event.getCoalescedEvents();
|
|
8569
|
+
return samples.length > 0 ? samples : [event];
|
|
8570
|
+
}
|
|
8571
|
+
var resolveInterpolatedPressure = (lastPoint, nextPoint, ratio) => {
|
|
8572
|
+
if (lastPoint.pressure != null && nextPoint.pressure != null) {
|
|
8573
|
+
return lastPoint.pressure + (nextPoint.pressure - lastPoint.pressure) * ratio;
|
|
8574
|
+
}
|
|
8575
|
+
return ratio === 1 ? nextPoint.pressure : void 0;
|
|
8576
|
+
};
|
|
8577
|
+
var resolveMaxStepWorld = (maxStepWorld) => Number.isFinite(maxStepWorld) && maxStepWorld > 0 ? maxStepWorld : Number.POSITIVE_INFINITY;
|
|
8578
|
+
function appendInterpolatedStrokePoint(points, nextPoint, maxStepWorld) {
|
|
8579
|
+
if (points.length === 0) return [nextPoint];
|
|
8580
|
+
const lastPoint = points[points.length - 1];
|
|
8581
|
+
if (!lastPoint) return [...points, nextPoint];
|
|
8582
|
+
const deltaX = nextPoint.x - lastPoint.x;
|
|
8583
|
+
const deltaY = nextPoint.y - lastPoint.y;
|
|
8584
|
+
const distanceSquared = deltaX * deltaX + deltaY * deltaY;
|
|
8585
|
+
if (distanceSquared < 1e-12) return points;
|
|
8586
|
+
const distance = Math.sqrt(distanceSquared);
|
|
8587
|
+
const stepCount = Math.min(
|
|
8588
|
+
MAX_INTERPOLATED_POINTS_PER_SAMPLE,
|
|
8589
|
+
Math.max(1, Math.ceil(distance / resolveMaxStepWorld(maxStepWorld)))
|
|
8590
|
+
);
|
|
8591
|
+
if (stepCount === 1) return [...points, nextPoint];
|
|
8592
|
+
const interpolatedPoints = Array.from({ length: stepCount }, (_, index) => {
|
|
8593
|
+
const ratio = (index + 1) / stepCount;
|
|
8594
|
+
const pressure = resolveInterpolatedPressure(lastPoint, nextPoint, ratio);
|
|
8595
|
+
return {
|
|
8596
|
+
x: lastPoint.x + deltaX * ratio,
|
|
8597
|
+
y: lastPoint.y + deltaY * ratio,
|
|
8598
|
+
...pressure != null ? { pressure } : {}
|
|
8599
|
+
};
|
|
8600
|
+
});
|
|
8601
|
+
return [...points, ...interpolatedPoints];
|
|
8602
|
+
}
|
|
8603
|
+
|
|
8443
8604
|
// src/react/TextEditOverlay.tsx
|
|
8444
8605
|
init_rect();
|
|
8445
8606
|
init_text_svg();
|
|
@@ -8699,13 +8860,6 @@ function pointInSelectedItemBounds(item, worldX, worldY) {
|
|
|
8699
8860
|
);
|
|
8700
8861
|
return local.x >= 0 && local.x <= bounds.width && local.y >= 0 && local.y <= bounds.height;
|
|
8701
8862
|
}
|
|
8702
|
-
function pointerEventSamples(ev) {
|
|
8703
|
-
if (ev.pointerType !== "pen" || typeof ev.getCoalescedEvents !== "function") {
|
|
8704
|
-
return [ev];
|
|
8705
|
-
}
|
|
8706
|
-
const samples = ev.getCoalescedEvents();
|
|
8707
|
-
return samples.length > 0 ? samples : [ev];
|
|
8708
|
-
}
|
|
8709
8863
|
var CANVU_PEN_ACTIVE_UI_BLOCK_CSS = `
|
|
8710
8864
|
[data-canvu-pen-active="true"] [data-slot="vector-canvas-toolbar"],
|
|
8711
8865
|
[data-canvu-pen-active="true"] [data-slot="vector-canvas-toolbar"] *,
|
|
@@ -8807,15 +8961,6 @@ function VectorViewportPluginInstances({
|
|
|
8807
8961
|
] }, plugin.id);
|
|
8808
8962
|
}) });
|
|
8809
8963
|
}
|
|
8810
|
-
function appendInterpolatedPoints(points, next, maxStepWorld) {
|
|
8811
|
-
if (points.length === 0) return [next];
|
|
8812
|
-
const last = points[points.length - 1];
|
|
8813
|
-
if (!last) return [...points, next];
|
|
8814
|
-
const dx = next.x - last.x;
|
|
8815
|
-
const dy = next.y - last.y;
|
|
8816
|
-
if (dx * dx + dy * dy < 1e-12) return points;
|
|
8817
|
-
return [...points, next];
|
|
8818
|
-
}
|
|
8819
8964
|
function pointerSampleToWorldPoint(screenToWorldFn, clientX, clientY, pressure) {
|
|
8820
8965
|
const { worldX, worldY } = screenToWorldFn(clientX, clientY);
|
|
8821
8966
|
const safePressure = pressure != null && Number.isFinite(pressure) ? Math.min(1, Math.max(0, pressure)) : void 0;
|
|
@@ -8846,15 +8991,19 @@ function isLikelyStylusTouch(touch) {
|
|
|
8846
8991
|
}
|
|
8847
8992
|
function appendPointerEventSamplesToStrokePoints(points, ev, zoom, screenToWorldFn) {
|
|
8848
8993
|
let interpolated = points;
|
|
8849
|
-
ev.pointerType === "pen" ? 0.35 / zoom : 1 / zoom;
|
|
8850
|
-
for (const sample of
|
|
8994
|
+
const maxStepWorld = ev.pointerType === "pen" ? 0.35 / zoom : 1 / zoom;
|
|
8995
|
+
for (const sample of getPointerEventSamples(ev)) {
|
|
8851
8996
|
const nextPoint = pointerSampleToWorldPoint(
|
|
8852
8997
|
screenToWorldFn,
|
|
8853
8998
|
sample.clientX,
|
|
8854
8999
|
sample.clientY,
|
|
8855
9000
|
sample.pointerType === "pen" ? sample.pressure : void 0
|
|
8856
9001
|
);
|
|
8857
|
-
interpolated =
|
|
9002
|
+
interpolated = appendInterpolatedStrokePoint(
|
|
9003
|
+
interpolated,
|
|
9004
|
+
nextPoint,
|
|
9005
|
+
maxStepWorld
|
|
9006
|
+
);
|
|
8858
9007
|
}
|
|
8859
9008
|
return interpolated;
|
|
8860
9009
|
}
|
|
@@ -8865,7 +9014,7 @@ function appendTouchToStrokePoints(points, touch, zoom, screenToWorldFn) {
|
|
|
8865
9014
|
touch.clientY,
|
|
8866
9015
|
touchPressure(touch)
|
|
8867
9016
|
);
|
|
8868
|
-
return
|
|
9017
|
+
return appendInterpolatedStrokePoint(points, nextPoint, 0.35 / zoom);
|
|
8869
9018
|
}
|
|
8870
9019
|
function createStraightStrokeState(anchorPoint, clientX, clientY) {
|
|
8871
9020
|
return {
|