canvu-react 0.3.10 → 0.3.11
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-3Iv5xHxM.d.cts +27 -0
- package/dist/asset-hydration-BEG21hMp.d.ts +27 -0
- package/dist/chatbot.d.cts +2 -2
- package/dist/chatbot.d.ts +2 -2
- package/dist/index.cjs +469 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +468 -9
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +645 -704
- package/dist/native.cjs.map +1 -1
- package/dist/native.js +645 -704
- package/dist/native.js.map +1 -1
- package/dist/react.cjs +354 -137
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +9 -16
- package/dist/react.d.ts +9 -16
- package/dist/react.js +354 -138
- package/dist/react.js.map +1 -1
- package/dist/realtime.cjs +537 -34
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.d.cts +40 -5
- package/dist/realtime.d.ts +40 -5
- package/dist/realtime.js +537 -35
- package/dist/realtime.js.map +1 -1
- package/dist/{shape-builders-DxPoOecg.d.cts → shape-builders-DFudWDFI.d.cts} +111 -1
- package/dist/{shape-builders-DTYvub8W.d.ts → shape-builders-ENwnK-zT.d.ts} +111 -1
- package/dist/{types-DgEArHkA.d.ts → types-BtAJFS_-.d.ts} +1 -0
- package/dist/{types-BtLGGw0r.d.cts → types-CTyASYIm.d.cts} +2 -105
- package/dist/{types-B58i5k-u.d.cts → types-DNwjgs5U.d.cts} +1 -0
- package/dist/{types-ChnTSRSe.d.ts → types-UvUy2Eed.d.ts} +2 -105
- package/package.json +1 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { V as VectorSceneItem } from './types-CB0TZZuk.cjs';
|
|
2
|
+
import { u as VectorViewportAssetStore } from './shape-builders-DFudWDFI.cjs';
|
|
3
|
+
|
|
4
|
+
declare class IndexedDbImageStore {
|
|
5
|
+
private dbPromise;
|
|
6
|
+
private getDb;
|
|
7
|
+
storeOriginal(blob: Blob): Promise<string>;
|
|
8
|
+
getOriginal(id: string): Promise<Blob | undefined>;
|
|
9
|
+
deleteOriginal(id: string): Promise<void>;
|
|
10
|
+
storeThumbnail(blob: Blob): Promise<string>;
|
|
11
|
+
getThumbnail(id: string): Promise<Blob | undefined>;
|
|
12
|
+
deleteThumbnail(id: string): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type HydrateSceneItemsWithAssetsOptions = {
|
|
16
|
+
imageStore?: IndexedDbImageStore;
|
|
17
|
+
pdfScale?: number;
|
|
18
|
+
pdfPageConcurrency?: number;
|
|
19
|
+
preferCachedRasters?: boolean;
|
|
20
|
+
};
|
|
21
|
+
type HydratedSceneItemsWithAssetsResult = {
|
|
22
|
+
items: VectorSceneItem[];
|
|
23
|
+
objectUrls: string[];
|
|
24
|
+
};
|
|
25
|
+
declare function hydrateSceneItemsWithAssets(items: readonly VectorSceneItem[], assetStore: VectorViewportAssetStore, options?: HydrateSceneItemsWithAssetsOptions): Promise<HydratedSceneItemsWithAssetsResult>;
|
|
26
|
+
|
|
27
|
+
export { type HydratedSceneItemsWithAssetsResult as H, IndexedDbImageStore as I, hydrateSceneItemsWithAssets as h };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { V as VectorSceneItem } from './types-CB0TZZuk.js';
|
|
2
|
+
import { u as VectorViewportAssetStore } from './shape-builders-ENwnK-zT.js';
|
|
3
|
+
|
|
4
|
+
declare class IndexedDbImageStore {
|
|
5
|
+
private dbPromise;
|
|
6
|
+
private getDb;
|
|
7
|
+
storeOriginal(blob: Blob): Promise<string>;
|
|
8
|
+
getOriginal(id: string): Promise<Blob | undefined>;
|
|
9
|
+
deleteOriginal(id: string): Promise<void>;
|
|
10
|
+
storeThumbnail(blob: Blob): Promise<string>;
|
|
11
|
+
getThumbnail(id: string): Promise<Blob | undefined>;
|
|
12
|
+
deleteThumbnail(id: string): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type HydrateSceneItemsWithAssetsOptions = {
|
|
16
|
+
imageStore?: IndexedDbImageStore;
|
|
17
|
+
pdfScale?: number;
|
|
18
|
+
pdfPageConcurrency?: number;
|
|
19
|
+
preferCachedRasters?: boolean;
|
|
20
|
+
};
|
|
21
|
+
type HydratedSceneItemsWithAssetsResult = {
|
|
22
|
+
items: VectorSceneItem[];
|
|
23
|
+
objectUrls: string[];
|
|
24
|
+
};
|
|
25
|
+
declare function hydrateSceneItemsWithAssets(items: readonly VectorSceneItem[], assetStore: VectorViewportAssetStore, options?: HydrateSceneItemsWithAssetsOptions): Promise<HydratedSceneItemsWithAssetsResult>;
|
|
26
|
+
|
|
27
|
+
export { type HydratedSceneItemsWithAssetsResult as H, IndexedDbImageStore as I, hydrateSceneItemsWithAssets as h };
|
package/dist/chatbot.d.cts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { C as CanvasPlugin } from './types-
|
|
2
|
+
import { C as CanvasPlugin } from './types-CTyASYIm.cjs';
|
|
3
3
|
import 'react';
|
|
4
4
|
import './types-CB0TZZuk.cjs';
|
|
5
5
|
import './camera-BwQjm5oh.cjs';
|
|
6
|
-
import './shape-builders-
|
|
6
|
+
import './shape-builders-DFudWDFI.cjs';
|
|
7
7
|
|
|
8
8
|
type ChatbotPluginPanelProps = {
|
|
9
9
|
/**
|
package/dist/chatbot.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { C as CanvasPlugin } from './types-
|
|
2
|
+
import { C as CanvasPlugin } from './types-UvUy2Eed.js';
|
|
3
3
|
import 'react';
|
|
4
4
|
import './types-CB0TZZuk.js';
|
|
5
5
|
import './camera-KwCYYPhm.js';
|
|
6
|
-
import './shape-builders-
|
|
6
|
+
import './shape-builders-ENwnK-zT.js';
|
|
7
7
|
|
|
8
8
|
type ChatbotPluginPanelProps = {
|
|
9
9
|
/**
|
package/dist/index.cjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var getStroke = require('perfect-freehand');
|
|
4
4
|
|
|
5
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
5
6
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
6
7
|
|
|
7
8
|
var getStroke__default = /*#__PURE__*/_interopDefault(getStroke);
|
|
@@ -84,6 +85,202 @@ var Camera2D = class {
|
|
|
84
85
|
}
|
|
85
86
|
};
|
|
86
87
|
|
|
88
|
+
// src/image/indexed-db-image-store.ts
|
|
89
|
+
var DB_NAME = "canvu-image-store";
|
|
90
|
+
var DB_VERSION = 1;
|
|
91
|
+
function openDb() {
|
|
92
|
+
return new Promise((resolve, reject) => {
|
|
93
|
+
const req = indexedDB.open(DB_NAME, DB_VERSION);
|
|
94
|
+
req.onupgradeneeded = () => {
|
|
95
|
+
const db = req.result;
|
|
96
|
+
if (!db.objectStoreNames.contains("images")) {
|
|
97
|
+
db.createObjectStore("images");
|
|
98
|
+
}
|
|
99
|
+
if (!db.objectStoreNames.contains("thumbnails")) {
|
|
100
|
+
db.createObjectStore("thumbnails");
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
req.onsuccess = () => resolve(req.result);
|
|
104
|
+
req.onerror = () => reject(req.error);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
function getFromStore(db, storeName, id) {
|
|
108
|
+
return new Promise((resolve, reject) => {
|
|
109
|
+
const tx = db.transaction(storeName, "readonly");
|
|
110
|
+
const req = tx.objectStore(storeName).get(id);
|
|
111
|
+
req.onsuccess = () => resolve(req.result ?? void 0);
|
|
112
|
+
req.onerror = () => reject(req.error);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function putInStore(db, storeName, id, blob) {
|
|
116
|
+
return new Promise((resolve, reject) => {
|
|
117
|
+
const tx = db.transaction(storeName, "readwrite");
|
|
118
|
+
const req = tx.objectStore(storeName).put(blob, id);
|
|
119
|
+
req.onsuccess = () => resolve();
|
|
120
|
+
req.onerror = () => reject(req.error);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
function deleteFromStore(db, storeName, id) {
|
|
124
|
+
return new Promise((resolve, reject) => {
|
|
125
|
+
const tx = db.transaction(storeName, "readwrite");
|
|
126
|
+
const req = tx.objectStore(storeName).delete(id);
|
|
127
|
+
req.onsuccess = () => resolve();
|
|
128
|
+
req.onerror = () => reject(req.error);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
function generateBlobId() {
|
|
132
|
+
return crypto.randomUUID();
|
|
133
|
+
}
|
|
134
|
+
var IndexedDbImageStore = class {
|
|
135
|
+
dbPromise = null;
|
|
136
|
+
getDb() {
|
|
137
|
+
if (!this.dbPromise) {
|
|
138
|
+
this.dbPromise = openDb();
|
|
139
|
+
}
|
|
140
|
+
return this.dbPromise;
|
|
141
|
+
}
|
|
142
|
+
async storeOriginal(blob) {
|
|
143
|
+
const id = generateBlobId();
|
|
144
|
+
const db = await this.getDb();
|
|
145
|
+
await putInStore(db, "images", id, blob);
|
|
146
|
+
return id;
|
|
147
|
+
}
|
|
148
|
+
async getOriginal(id) {
|
|
149
|
+
const db = await this.getDb();
|
|
150
|
+
return getFromStore(db, "images", id);
|
|
151
|
+
}
|
|
152
|
+
async deleteOriginal(id) {
|
|
153
|
+
const db = await this.getDb();
|
|
154
|
+
await deleteFromStore(db, "images", id);
|
|
155
|
+
}
|
|
156
|
+
async storeThumbnail(blob) {
|
|
157
|
+
const id = generateBlobId();
|
|
158
|
+
const db = await this.getDb();
|
|
159
|
+
await putInStore(db, "thumbnails", id, blob);
|
|
160
|
+
return id;
|
|
161
|
+
}
|
|
162
|
+
async getThumbnail(id) {
|
|
163
|
+
const db = await this.getDb();
|
|
164
|
+
return getFromStore(db, "thumbnails", id);
|
|
165
|
+
}
|
|
166
|
+
async deleteThumbnail(id) {
|
|
167
|
+
const db = await this.getDb();
|
|
168
|
+
await deleteFromStore(db, "thumbnails", id);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// src/image/pdf-loader.ts
|
|
173
|
+
var pdfjsPromise = null;
|
|
174
|
+
function getPdfJs() {
|
|
175
|
+
if (!pdfjsPromise) {
|
|
176
|
+
pdfjsPromise = import('pdfjs-dist').then((mod) => {
|
|
177
|
+
const workerSrc = new URL(
|
|
178
|
+
"pdfjs-dist/build/pdf.worker.min.mjs",
|
|
179
|
+
(typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))
|
|
180
|
+
).toString();
|
|
181
|
+
mod.GlobalWorkerOptions.workerSrc = workerSrc;
|
|
182
|
+
return mod;
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
return pdfjsPromise;
|
|
186
|
+
}
|
|
187
|
+
async function renderPageToCanvas(page, scale) {
|
|
188
|
+
const raw = page.getViewport({ scale: 1 });
|
|
189
|
+
const adjustedScale = Math.round(raw.width * scale) / raw.width;
|
|
190
|
+
const viewport = page.getViewport({ scale: adjustedScale });
|
|
191
|
+
const w = Math.round(viewport.width);
|
|
192
|
+
const h = Math.round(viewport.height);
|
|
193
|
+
const canvas = document.createElement("canvas");
|
|
194
|
+
canvas.width = w;
|
|
195
|
+
canvas.height = h;
|
|
196
|
+
const ctx = canvas.getContext("2d");
|
|
197
|
+
if (!ctx) throw new Error("Canvas 2D context unavailable");
|
|
198
|
+
ctx.imageSmoothingEnabled = true;
|
|
199
|
+
ctx.imageSmoothingQuality = "high";
|
|
200
|
+
await page.render({ canvas, viewport }).promise;
|
|
201
|
+
return { canvas, width: w, height: h };
|
|
202
|
+
}
|
|
203
|
+
function canvasToBlob(canvas, mime, quality) {
|
|
204
|
+
return new Promise((resolve, reject) => {
|
|
205
|
+
canvas.toBlob(
|
|
206
|
+
(blob) => {
|
|
207
|
+
if (!blob) {
|
|
208
|
+
reject(new Error("Could not encode blob"));
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
resolve(blob);
|
|
212
|
+
},
|
|
213
|
+
mime,
|
|
214
|
+
quality
|
|
215
|
+
);
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
function normalizePdfPageNumbers(pageNumbers, pageCount) {
|
|
219
|
+
if (!pageNumbers || pageNumbers.length === 0) {
|
|
220
|
+
return Array.from({ length: pageCount }, (_, index) => index + 1);
|
|
221
|
+
}
|
|
222
|
+
return [...new Set(pageNumbers)].filter((pageNumber) => pageNumber >= 1 && pageNumber <= pageCount).sort((left, right) => left - right);
|
|
223
|
+
}
|
|
224
|
+
async function runWithConcurrency(items, concurrency, execute) {
|
|
225
|
+
const results = new Array(items.length);
|
|
226
|
+
let nextIndex = 0;
|
|
227
|
+
const workerCount = Math.max(1, Math.min(concurrency, items.length));
|
|
228
|
+
await Promise.all(
|
|
229
|
+
Array.from({ length: workerCount }, async () => {
|
|
230
|
+
while (nextIndex < items.length) {
|
|
231
|
+
const currentIndex = nextIndex;
|
|
232
|
+
nextIndex += 1;
|
|
233
|
+
const item = items[currentIndex];
|
|
234
|
+
if (item === void 0) {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
results[currentIndex] = await execute(item);
|
|
238
|
+
}
|
|
239
|
+
})
|
|
240
|
+
);
|
|
241
|
+
return results;
|
|
242
|
+
}
|
|
243
|
+
async function loadPdfToStore(file, store, options) {
|
|
244
|
+
const scale = options?.scale ?? 1.5;
|
|
245
|
+
const pageConcurrency = options?.pageConcurrency ?? 2;
|
|
246
|
+
const pdfjs = await getPdfJs();
|
|
247
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
248
|
+
const pdf = await pdfjs.getDocument({ data: arrayBuffer }).promise;
|
|
249
|
+
const pageNumbers = normalizePdfPageNumbers(options?.pageNumbers, pdf.numPages);
|
|
250
|
+
return await runWithConcurrency(
|
|
251
|
+
pageNumbers,
|
|
252
|
+
pageConcurrency,
|
|
253
|
+
async (pageNumber) => {
|
|
254
|
+
const page = await pdf.getPage(pageNumber);
|
|
255
|
+
const { canvas, width, height } = await renderPageToCanvas(page, scale);
|
|
256
|
+
const mime = "image/png";
|
|
257
|
+
const pageBlob = await canvasToBlob(canvas, mime);
|
|
258
|
+
const blobId = await store.storeOriginal(pageBlob);
|
|
259
|
+
const thumbScale = Math.min(1, 256 / Math.max(width, height));
|
|
260
|
+
const tw = Math.max(1, Math.round(width * thumbScale));
|
|
261
|
+
const th = Math.max(1, Math.round(height * thumbScale));
|
|
262
|
+
const thumbCanvas = document.createElement("canvas");
|
|
263
|
+
thumbCanvas.width = tw;
|
|
264
|
+
thumbCanvas.height = th;
|
|
265
|
+
const tCtx = thumbCanvas.getContext("2d");
|
|
266
|
+
if (tCtx) {
|
|
267
|
+
tCtx.imageSmoothingEnabled = true;
|
|
268
|
+
tCtx.imageSmoothingQuality = "high";
|
|
269
|
+
tCtx.drawImage(canvas, 0, 0, tw, th);
|
|
270
|
+
}
|
|
271
|
+
const thumbBlob = await canvasToBlob(thumbCanvas, mime);
|
|
272
|
+
const thumbnailBlobId = await store.storeThumbnail(thumbBlob);
|
|
273
|
+
return {
|
|
274
|
+
blobId,
|
|
275
|
+
thumbnailBlobId,
|
|
276
|
+
width,
|
|
277
|
+
height,
|
|
278
|
+
pageNumber
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
87
284
|
// src/image/raster-image.ts
|
|
88
285
|
var MAX_RASTER_EMBED_DIMENSION = 4096;
|
|
89
286
|
function normalizeLoadOptions(maxDimensionOrOptions) {
|
|
@@ -1468,16 +1665,14 @@ function itemHitTestWorldPoint(item, worldX, worldY, options) {
|
|
|
1468
1665
|
return true;
|
|
1469
1666
|
}
|
|
1470
1667
|
}
|
|
1668
|
+
return false;
|
|
1471
1669
|
}
|
|
1472
|
-
if (pts
|
|
1670
|
+
if (pts && pts.length === 1) {
|
|
1473
1671
|
const p = pts[0];
|
|
1474
|
-
if (p)
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
return true;
|
|
1479
|
-
}
|
|
1480
|
-
}
|
|
1672
|
+
if (!p) return false;
|
|
1673
|
+
const cw = itemLocalToWorld(p.x, p.y, item.x, item.y, w, h, rot);
|
|
1674
|
+
const dsq = (worldX - cw.x) ** 2 + (worldY - cw.y) ** 2;
|
|
1675
|
+
return dsq <= tolSq;
|
|
1481
1676
|
}
|
|
1482
1677
|
return hitTestFilledShape(item, worldX, worldY);
|
|
1483
1678
|
}
|
|
@@ -1514,6 +1709,271 @@ function collectEraserTargetsAtWorldPoint(items, worldX, worldY, options) {
|
|
|
1514
1709
|
return ids;
|
|
1515
1710
|
}
|
|
1516
1711
|
|
|
1712
|
+
// src/react/asset-hydration.ts
|
|
1713
|
+
var HYDRATION_CACHE_NAME = "canvu-asset-hydration-v1";
|
|
1714
|
+
var DEFAULT_PDF_SCALE = 1.15;
|
|
1715
|
+
var DEFAULT_PDF_PAGE_CONCURRENCY = 2;
|
|
1716
|
+
var hydrationBlobPromises = /* @__PURE__ */ new Map();
|
|
1717
|
+
function buildImageHydrationKey(assetId) {
|
|
1718
|
+
return `image:${assetId}`;
|
|
1719
|
+
}
|
|
1720
|
+
function buildPdfHydrationKey(assetId, pageNumber, scale) {
|
|
1721
|
+
return `pdf:${assetId}:page:${pageNumber}:scale:${scale}`;
|
|
1722
|
+
}
|
|
1723
|
+
function getCacheRequest(key) {
|
|
1724
|
+
return new Request(
|
|
1725
|
+
`https://canvu.local/asset-hydration/${encodeURIComponent(key)}`
|
|
1726
|
+
);
|
|
1727
|
+
}
|
|
1728
|
+
async function openHydrationCache() {
|
|
1729
|
+
if (typeof caches === "undefined") return null;
|
|
1730
|
+
try {
|
|
1731
|
+
return await caches.open(HYDRATION_CACHE_NAME);
|
|
1732
|
+
} catch {
|
|
1733
|
+
return null;
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
async function readCachedHydrationBlob(key) {
|
|
1737
|
+
const cache = await openHydrationCache();
|
|
1738
|
+
if (!cache) return null;
|
|
1739
|
+
try {
|
|
1740
|
+
const response = await cache.match(getCacheRequest(key));
|
|
1741
|
+
if (!response?.ok) return null;
|
|
1742
|
+
return await response.blob();
|
|
1743
|
+
} catch {
|
|
1744
|
+
return null;
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
async function writeCachedHydrationBlob(key, blob) {
|
|
1748
|
+
const cache = await openHydrationCache();
|
|
1749
|
+
if (!cache) return;
|
|
1750
|
+
try {
|
|
1751
|
+
await cache.put(getCacheRequest(key), new Response(blob));
|
|
1752
|
+
} catch {
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
async function fetchBlob(url) {
|
|
1756
|
+
try {
|
|
1757
|
+
const response = await fetch(url);
|
|
1758
|
+
if (!response.ok) return null;
|
|
1759
|
+
return await response.blob();
|
|
1760
|
+
} catch {
|
|
1761
|
+
return null;
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
async function getHydrationBlob(key, preferCachedRasters, loader) {
|
|
1765
|
+
const cached = preferCachedRasters ? await readCachedHydrationBlob(key) : null;
|
|
1766
|
+
if (cached) return cached;
|
|
1767
|
+
const inFlight = hydrationBlobPromises.get(key);
|
|
1768
|
+
if (inFlight) return await inFlight;
|
|
1769
|
+
const nextPromise = (async () => {
|
|
1770
|
+
const blob = await loader();
|
|
1771
|
+
if (blob) {
|
|
1772
|
+
await writeCachedHydrationBlob(key, blob);
|
|
1773
|
+
}
|
|
1774
|
+
return blob;
|
|
1775
|
+
})();
|
|
1776
|
+
hydrationBlobPromises.set(key, nextPromise);
|
|
1777
|
+
try {
|
|
1778
|
+
return await nextPromise;
|
|
1779
|
+
} finally {
|
|
1780
|
+
hydrationBlobPromises.delete(key);
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
function registerObjectUrl(objectUrls, blob) {
|
|
1784
|
+
const href = URL.createObjectURL(blob);
|
|
1785
|
+
objectUrls.push(href);
|
|
1786
|
+
return href;
|
|
1787
|
+
}
|
|
1788
|
+
function getHydrationRequests(items, assetStore, pdfScale) {
|
|
1789
|
+
if (!assetStore.getHydrationRequest) return [];
|
|
1790
|
+
return items.flatMap((item) => {
|
|
1791
|
+
const request = assetStore.getHydrationRequest?.(item);
|
|
1792
|
+
if (!request) return [];
|
|
1793
|
+
return [
|
|
1794
|
+
{
|
|
1795
|
+
request: {
|
|
1796
|
+
...request,
|
|
1797
|
+
scale: request.scale ?? pdfScale
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
];
|
|
1801
|
+
});
|
|
1802
|
+
}
|
|
1803
|
+
function createPdfHydrationGroups(requests) {
|
|
1804
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1805
|
+
for (const entry of requests) {
|
|
1806
|
+
if (entry.request.kind !== "pdf" || entry.request.pageNumber == null) continue;
|
|
1807
|
+
const scale = entry.request.scale ?? DEFAULT_PDF_SCALE;
|
|
1808
|
+
const key = `${entry.request.assetId}:${scale}`;
|
|
1809
|
+
const existingGroup = groups.get(key);
|
|
1810
|
+
if (existingGroup) {
|
|
1811
|
+
if (!existingGroup.pageNumbers.includes(entry.request.pageNumber)) {
|
|
1812
|
+
existingGroup.pageNumbers.push(entry.request.pageNumber);
|
|
1813
|
+
}
|
|
1814
|
+
continue;
|
|
1815
|
+
}
|
|
1816
|
+
groups.set(key, {
|
|
1817
|
+
assetId: entry.request.assetId,
|
|
1818
|
+
scale,
|
|
1819
|
+
pageNumbers: [entry.request.pageNumber]
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
1822
|
+
return [...groups.values()];
|
|
1823
|
+
}
|
|
1824
|
+
async function hydrateImageAssets(requests, resolvedAssetUrls, objectUrls, preferCachedRasters) {
|
|
1825
|
+
const uniqueAssetIds = [
|
|
1826
|
+
...new Set(requests.map((entry) => entry.request.assetId))
|
|
1827
|
+
];
|
|
1828
|
+
const hydratedEntries = await Promise.all(
|
|
1829
|
+
uniqueAssetIds.map(async (assetId) => {
|
|
1830
|
+
const resolvedAsset = resolvedAssetUrls[assetId];
|
|
1831
|
+
if (!resolvedAsset?.url) {
|
|
1832
|
+
return [assetId, null];
|
|
1833
|
+
}
|
|
1834
|
+
const blob = await getHydrationBlob(
|
|
1835
|
+
buildImageHydrationKey(assetId),
|
|
1836
|
+
preferCachedRasters,
|
|
1837
|
+
async () => await fetchBlob(resolvedAsset.url)
|
|
1838
|
+
);
|
|
1839
|
+
if (!blob) {
|
|
1840
|
+
return [assetId, null];
|
|
1841
|
+
}
|
|
1842
|
+
return [
|
|
1843
|
+
assetId,
|
|
1844
|
+
{
|
|
1845
|
+
href: registerObjectUrl(objectUrls, blob)
|
|
1846
|
+
}
|
|
1847
|
+
];
|
|
1848
|
+
})
|
|
1849
|
+
);
|
|
1850
|
+
return new Map(hydratedEntries);
|
|
1851
|
+
}
|
|
1852
|
+
async function hydratePdfAssets(requests, resolvedAssetUrls, objectUrls, options) {
|
|
1853
|
+
const hydratedPages = /* @__PURE__ */ new Map();
|
|
1854
|
+
const groups = createPdfHydrationGroups(requests);
|
|
1855
|
+
for (const group of groups) {
|
|
1856
|
+
const resolvedAsset = resolvedAssetUrls[group.assetId];
|
|
1857
|
+
if (!resolvedAsset?.url) {
|
|
1858
|
+
continue;
|
|
1859
|
+
}
|
|
1860
|
+
const missingPages = [];
|
|
1861
|
+
for (const pageNumber of group.pageNumbers) {
|
|
1862
|
+
const cacheKey = buildPdfHydrationKey(group.assetId, pageNumber, group.scale);
|
|
1863
|
+
const cachedBlob = await readCachedHydrationBlob(cacheKey);
|
|
1864
|
+
if (!cachedBlob) {
|
|
1865
|
+
missingPages.push(pageNumber);
|
|
1866
|
+
continue;
|
|
1867
|
+
}
|
|
1868
|
+
hydratedPages.set(cacheKey, {
|
|
1869
|
+
href: registerObjectUrl(objectUrls, cachedBlob)
|
|
1870
|
+
});
|
|
1871
|
+
}
|
|
1872
|
+
if (missingPages.length === 0) {
|
|
1873
|
+
continue;
|
|
1874
|
+
}
|
|
1875
|
+
const pdfBlob = await fetchBlob(resolvedAsset.url);
|
|
1876
|
+
if (!pdfBlob) {
|
|
1877
|
+
continue;
|
|
1878
|
+
}
|
|
1879
|
+
const renderedPages = await loadPdfToStore(pdfBlob, options.imageStore, {
|
|
1880
|
+
scale: group.scale,
|
|
1881
|
+
pageNumbers: missingPages,
|
|
1882
|
+
pageConcurrency: options.pdfPageConcurrency
|
|
1883
|
+
});
|
|
1884
|
+
for (const renderedPage of renderedPages) {
|
|
1885
|
+
const cacheKey = buildPdfHydrationKey(
|
|
1886
|
+
group.assetId,
|
|
1887
|
+
renderedPage.pageNumber,
|
|
1888
|
+
group.scale
|
|
1889
|
+
);
|
|
1890
|
+
const pageBlob = await options.imageStore.getOriginal(renderedPage.blobId);
|
|
1891
|
+
if (!pageBlob) {
|
|
1892
|
+
continue;
|
|
1893
|
+
}
|
|
1894
|
+
await writeCachedHydrationBlob(cacheKey, pageBlob);
|
|
1895
|
+
hydratedPages.set(cacheKey, {
|
|
1896
|
+
href: registerObjectUrl(objectUrls, pageBlob),
|
|
1897
|
+
width: renderedPage.width,
|
|
1898
|
+
height: renderedPage.height
|
|
1899
|
+
});
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
return hydratedPages;
|
|
1903
|
+
}
|
|
1904
|
+
async function hydrateSceneItemsWithAssets(items, assetStore, options = {}) {
|
|
1905
|
+
if (!assetStore.resolve || !assetStore.getHydrationRequest) {
|
|
1906
|
+
return {
|
|
1907
|
+
items: [...items],
|
|
1908
|
+
objectUrls: []
|
|
1909
|
+
};
|
|
1910
|
+
}
|
|
1911
|
+
const pdfScale = options.pdfScale ?? DEFAULT_PDF_SCALE;
|
|
1912
|
+
const pdfPageConcurrency = options.pdfPageConcurrency ?? DEFAULT_PDF_PAGE_CONCURRENCY;
|
|
1913
|
+
const preferCachedRasters = options.preferCachedRasters ?? true;
|
|
1914
|
+
const imageStore = options.imageStore ?? new IndexedDbImageStore();
|
|
1915
|
+
const hydrationRequests = getHydrationRequests(items, assetStore, pdfScale);
|
|
1916
|
+
if (hydrationRequests.length === 0) {
|
|
1917
|
+
return {
|
|
1918
|
+
items: [...items],
|
|
1919
|
+
objectUrls: []
|
|
1920
|
+
};
|
|
1921
|
+
}
|
|
1922
|
+
const assetIds = [
|
|
1923
|
+
...new Set(hydrationRequests.map((entry) => entry.request.assetId))
|
|
1924
|
+
];
|
|
1925
|
+
const resolvedAssetUrls = await assetStore.resolve({ assetIds });
|
|
1926
|
+
const objectUrls = [];
|
|
1927
|
+
const hydratedImages = await hydrateImageAssets(
|
|
1928
|
+
hydrationRequests.filter((entry) => entry.request.kind === "image"),
|
|
1929
|
+
resolvedAssetUrls,
|
|
1930
|
+
objectUrls,
|
|
1931
|
+
preferCachedRasters
|
|
1932
|
+
);
|
|
1933
|
+
const hydratedPdfPages = await hydratePdfAssets(
|
|
1934
|
+
hydrationRequests.filter((entry) => entry.request.kind === "pdf"),
|
|
1935
|
+
resolvedAssetUrls,
|
|
1936
|
+
objectUrls,
|
|
1937
|
+
{
|
|
1938
|
+
imageStore,
|
|
1939
|
+
pdfPageConcurrency}
|
|
1940
|
+
);
|
|
1941
|
+
return {
|
|
1942
|
+
items: items.map((item) => {
|
|
1943
|
+
const request = assetStore.getHydrationRequest?.(item);
|
|
1944
|
+
if (!request || item.toolKind !== "image") return item;
|
|
1945
|
+
if (request.kind === "image") {
|
|
1946
|
+
const hydratedImage = hydratedImages.get(request.assetId);
|
|
1947
|
+
if (!hydratedImage) return item;
|
|
1948
|
+
return rebuildItemSvg({
|
|
1949
|
+
...item,
|
|
1950
|
+
imageRasterHref: hydratedImage.href,
|
|
1951
|
+
imageThumbnailHref: hydratedImage.href
|
|
1952
|
+
});
|
|
1953
|
+
}
|
|
1954
|
+
if (request.pageNumber == null) return item;
|
|
1955
|
+
const hydratedPdfPage = hydratedPdfPages.get(
|
|
1956
|
+
buildPdfHydrationKey(
|
|
1957
|
+
request.assetId,
|
|
1958
|
+
request.pageNumber,
|
|
1959
|
+
request.scale ?? pdfScale
|
|
1960
|
+
)
|
|
1961
|
+
);
|
|
1962
|
+
if (!hydratedPdfPage) return item;
|
|
1963
|
+
return rebuildItemSvg({
|
|
1964
|
+
...item,
|
|
1965
|
+
imageRasterHref: hydratedPdfPage.href,
|
|
1966
|
+
imageThumbnailHref: hydratedPdfPage.href,
|
|
1967
|
+
imageIntrinsicSize: {
|
|
1968
|
+
width: item.imageIntrinsicSize?.width ?? Math.max(1, Math.round(hydratedPdfPage.width ?? item.bounds.width)),
|
|
1969
|
+
height: item.imageIntrinsicSize?.height ?? Math.max(1, Math.round(hydratedPdfPage.height ?? item.bounds.height))
|
|
1970
|
+
}
|
|
1971
|
+
});
|
|
1972
|
+
}),
|
|
1973
|
+
objectUrls
|
|
1974
|
+
};
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1517
1977
|
// src/scene/spatial-cull.ts
|
|
1518
1978
|
var spatialIndexCache = /* @__PURE__ */ new WeakMap();
|
|
1519
1979
|
function cellKey(ix, iy) {
|
|
@@ -1794,6 +2254,7 @@ exports.expandCustomShapeTemplate = expandCustomShapeTemplate;
|
|
|
1794
2254
|
exports.formatCameraTransform = formatCameraTransform;
|
|
1795
2255
|
exports.formatItemPlacementTransform = formatItemPlacementTransform;
|
|
1796
2256
|
exports.hitTestWorldPoint = hitTestWorldPoint;
|
|
2257
|
+
exports.hydrateSceneItemsWithAssets = hydrateSceneItemsWithAssets;
|
|
1797
2258
|
exports.isArrowBindTarget = isArrowBindTarget;
|
|
1798
2259
|
exports.itemHitTestWorldPoint = itemHitTestWorldPoint;
|
|
1799
2260
|
exports.lineEndpointsToLocal = lineEndpointsToLocal;
|