@tissuumaps/render 0.1.0-beta.1 → 0.1.0-beta.3
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/CHANGELOG.md +22 -0
- package/README.md +3 -3
- package/dist/index.d.ts +204 -164
- package/dist/index.js +325 -253
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -662,8 +662,10 @@ var OpenSeadragonContext = class OpenSeadragonContext {
|
|
|
662
662
|
OpenSeadragonUtils.fixTileCacheCounter();
|
|
663
663
|
this.viewer = new OpenSeadragon.Viewer({
|
|
664
664
|
...viewerOptions,
|
|
665
|
+
showNavigator: true,
|
|
665
666
|
element: viewerElement
|
|
666
667
|
});
|
|
668
|
+
this.viewer.navigator.setVisible(viewerOptions?.showNavigator !== false);
|
|
667
669
|
this._backgroundPixelUrl = OpenSeadragonUtils.createPixelUrl(backgroundColor.r, backgroundColor.g, backgroundColor.b, 1);
|
|
668
670
|
this.viewer.addHandler("canvas-key", (event) => {
|
|
669
671
|
if ([
|
|
@@ -787,11 +789,13 @@ var OpenSeadragonContext = class OpenSeadragonContext {
|
|
|
787
789
|
* Applies viewer options to the OpenSeadragon viewer and all existing tiled images
|
|
788
790
|
*
|
|
789
791
|
* For each option key, performs a shallow merge (one level deep) of nested objects
|
|
790
|
-
* on both the viewer instance and every tiled image in the world.
|
|
792
|
+
* on both the viewer instance and every tiled image in the world. `showNavigator`
|
|
793
|
+
* shows or hides the navigator, as OpenSeadragon reads it only on construction.
|
|
791
794
|
*
|
|
792
795
|
* @param viewerOptions - Options to apply
|
|
793
796
|
*/
|
|
794
797
|
setViewerOptions(viewerOptions) {
|
|
798
|
+
if (viewerOptions.showNavigator !== void 0) this.viewer.navigator.setVisible(viewerOptions.showNavigator);
|
|
795
799
|
for (const [key, value] of Object.entries(viewerOptions)) {
|
|
796
800
|
if (key in this.viewer && this.viewer[key] !== value) {
|
|
797
801
|
if (typeof value === "object" && value !== null) this.viewer[key] = {
|
|
@@ -1011,8 +1015,12 @@ var OpenSeadragonContext = class OpenSeadragonContext {
|
|
|
1011
1015
|
*/
|
|
1012
1016
|
async _openTileSource(tiledImageOptions, options) {
|
|
1013
1017
|
const { signal } = options ?? {};
|
|
1014
|
-
|
|
1018
|
+
let tileSource = await Promise.resolve(tiledImageOptions.tileSource);
|
|
1015
1019
|
signal?.throwIfAborted();
|
|
1020
|
+
if (typeof tileSource === "object" && tileSource !== null) {
|
|
1021
|
+
const prototype = Object.getPrototypeOf(tileSource);
|
|
1022
|
+
if (prototype === Object.prototype || prototype === null) tileSource = { ...tileSource };
|
|
1023
|
+
}
|
|
1016
1024
|
try {
|
|
1017
1025
|
const { source: openedTileSource } = await this.viewer.instantiateTileSourceClass({
|
|
1018
1026
|
...tiledImageOptions,
|
|
@@ -1381,18 +1389,20 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1381
1389
|
/**
|
|
1382
1390
|
* Synchronizes the viewer's tiled images with the current model
|
|
1383
1391
|
*
|
|
1384
|
-
*
|
|
1385
|
-
* {@link setModel}, removes the tiled images that are no
|
|
1386
|
-
*
|
|
1387
|
-
*
|
|
1388
|
-
*
|
|
1389
|
-
*
|
|
1390
|
-
*
|
|
1392
|
+
* Starts loading the objects on the layers of the model (see
|
|
1393
|
+
* {@link setModel}), and right away removes the tiled images that are no
|
|
1394
|
+
* longer needed (see {@link _cleanRenderedObjects}). Each object is then
|
|
1395
|
+
* synchronized as soon as it has loaded, without waiting for the others: its
|
|
1396
|
+
* tiled images are updated, or created at its position in the world (see
|
|
1397
|
+
* {@link _synchronizeRenderedObject}).
|
|
1398
|
+
*
|
|
1399
|
+
* Resolves once the tiled images of all objects are in the world. The model
|
|
1400
|
+
* is read once, so the synchronization sees one consistent state, but the
|
|
1401
|
+
* properties applied to the tiled images come from the current model (see
|
|
1391
1402
|
* {@link _updateRenderedObject}).
|
|
1392
1403
|
*
|
|
1393
|
-
* Objects whose tiled images cannot be created
|
|
1394
|
-
*
|
|
1395
|
-
* data failed to load (see {@link _loadObjects}). A synchronization that
|
|
1404
|
+
* Objects whose data fails to load, or whose tiled images cannot be created
|
|
1405
|
+
* (e.g. without tile sources), are logged and dropped. A synchronization that
|
|
1396
1406
|
* fails or is aborted leaves the model unsynchronized (see
|
|
1397
1407
|
* {@link needsSynchronization}).
|
|
1398
1408
|
*
|
|
@@ -1409,27 +1419,16 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1409
1419
|
const syncState = this.getSyncState();
|
|
1410
1420
|
this._lastSyncState = syncState;
|
|
1411
1421
|
try {
|
|
1412
|
-
const
|
|
1413
|
-
const
|
|
1414
|
-
this.retainObjects(
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
renderedObject = this._createRenderedObject(offset, newRef, { signal });
|
|
1421
|
-
} catch (error) {
|
|
1422
|
-
console.error(`Failed to create tiled images for object with ID '${newRef.object.id}'`, error);
|
|
1423
|
-
continue;
|
|
1424
|
-
}
|
|
1425
|
-
else this._updateRenderedObject(renderedObject, newRef);
|
|
1426
|
-
newRenderedObjects.push(renderedObject);
|
|
1427
|
-
offset += (renderedObject.usesBackdrop ? 1 : 0) + renderedObject.tileSourceCount;
|
|
1428
|
-
}
|
|
1429
|
-
this._renderedObjects = newRenderedObjects;
|
|
1430
|
-
await Promise.allSettled(newRenderedObjects.map((renderedObject) => renderedObject.tiledImagesPromise));
|
|
1422
|
+
const loadings = this._loadObjects(context, { signal });
|
|
1423
|
+
const renderedObjectsByLoading = await this._cleanRenderedObjects(loadings, { signal });
|
|
1424
|
+
this.retainObjects(loadings.map((loading) => loading.object));
|
|
1425
|
+
const syncResults = await Promise.allSettled(loadings.map((loading, index) => this._synchronizeRenderedObject(loadings.slice(0, index), loading.newRefPromise, renderedObjectsByLoading.get(loading), { signal })));
|
|
1426
|
+
signal?.throwIfAborted();
|
|
1427
|
+
const firstSyncFailure = syncResults.find((result) => result.status === "rejected");
|
|
1428
|
+
if (firstSyncFailure !== void 0) throw firstSyncFailure.reason;
|
|
1429
|
+
await Promise.allSettled(this._renderedObjects.map((renderedObject) => renderedObject.tiledImagesPromise));
|
|
1431
1430
|
signal?.throwIfAborted();
|
|
1432
|
-
await this._updateBoundsAndReveal(
|
|
1431
|
+
await this._updateBoundsAndReveal(this._renderedObjects, { signal });
|
|
1433
1432
|
} catch (error) {
|
|
1434
1433
|
if (this._lastSyncState === syncState) this._lastSyncState = void 0;
|
|
1435
1434
|
throw error;
|
|
@@ -1566,13 +1565,12 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1566
1565
|
/**
|
|
1567
1566
|
* Retains what was resolved for the given objects, and discards the rest
|
|
1568
1567
|
*
|
|
1569
|
-
* Called by {@link synchronize}
|
|
1570
|
-
*
|
|
1571
|
-
*
|
|
1572
|
-
*
|
|
1573
|
-
* state per object (see {@link resolveObject} and
|
|
1568
|
+
* Called by {@link synchronize} with the objects about to be displayed, i.e.
|
|
1569
|
+
* those assigned to a rendered layer, once the rendered objects of all others
|
|
1570
|
+
* have been deleted and before any object has loaded. Does nothing here;
|
|
1571
|
+
* subclasses that keep state per object (see {@link resolveObject} and
|
|
1574
1572
|
* {@link resolveTiledImageDataTransfer}) override this to drop the state of
|
|
1575
|
-
*
|
|
1573
|
+
* all other objects.
|
|
1576
1574
|
*
|
|
1577
1575
|
* @param _objects - The objects (images or labels) about to be displayed
|
|
1578
1576
|
*/
|
|
@@ -1580,15 +1578,15 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1580
1578
|
/**
|
|
1581
1579
|
* Resolves what a renderer derives from an object, once its data has loaded
|
|
1582
1580
|
*
|
|
1583
|
-
* Called by {@link _loadObjects} for
|
|
1584
|
-
*
|
|
1585
|
-
*
|
|
1586
|
-
*
|
|
1587
|
-
*
|
|
1588
|
-
*
|
|
1589
|
-
*
|
|
1590
|
-
*
|
|
1591
|
-
*
|
|
1581
|
+
* Called by {@link _loadObjects} for each object, concurrently, once its data
|
|
1582
|
+
* has loaded and before its tiled images are created or updated. An object
|
|
1583
|
+
* that cannot be resolved is logged, but kept: its tiled images are still
|
|
1584
|
+
* created or updated, with whatever the synchronous hooks return for it.
|
|
1585
|
+
*
|
|
1586
|
+
* Does nothing here. Subclasses override this to resolve what their
|
|
1587
|
+
* synchronous hooks return later (see {@link resolveTiledImageDataTransfer})
|
|
1588
|
+
* from the object, its data and the inputs of the synchronization, and to
|
|
1589
|
+
* keep it for as long as its outcome would not change.
|
|
1592
1590
|
*
|
|
1593
1591
|
* @param _object - The object (image or labels) to resolve
|
|
1594
1592
|
* @param _data - The loaded data of the object
|
|
@@ -1675,28 +1673,29 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1675
1673
|
*/
|
|
1676
1674
|
resolveTiledImageDataTransfer(_ref, _index) {}
|
|
1677
1675
|
/**
|
|
1678
|
-
*
|
|
1676
|
+
* Starts loading and resolving all objects assigned to the layers of the current model
|
|
1677
|
+
*
|
|
1678
|
+
* Loads each object's data with the context's `loadObject`, then resolves the
|
|
1679
|
+
* object (see {@link resolveObject}). Returns right away, with one loading
|
|
1680
|
+
* per object, in world order: by layer, then by object. A loading rejects if
|
|
1681
|
+
* the object's data fails to load, which is logged. An object that cannot be
|
|
1682
|
+
* resolved is logged, but kept.
|
|
1679
1683
|
*
|
|
1680
|
-
*
|
|
1681
|
-
*
|
|
1682
|
-
* ordered by layer and then by object, which determines the order of the
|
|
1683
|
-
* corresponding tiled images in the world. Objects whose data failed to load
|
|
1684
|
-
* are logged and skipped; objects that could not be resolved are logged, but
|
|
1685
|
-
* kept. The model is read once, before the first `await`, so one
|
|
1686
|
-
* synchronization sees one consistent model state, however often the model
|
|
1687
|
-
* is set while it runs.
|
|
1684
|
+
* The model is read once, right away, so one synchronization sees one
|
|
1685
|
+
* consistent model state.
|
|
1688
1686
|
*
|
|
1689
1687
|
* @param context - The inputs of the current synchronization
|
|
1690
1688
|
* @param options - Optional abort signal
|
|
1691
|
-
* @returns
|
|
1689
|
+
* @returns One loading per object, whose promise resolves to the object's
|
|
1690
|
+
* reference
|
|
1692
1691
|
* @throws Error if no model has been set (see {@link setModel})
|
|
1693
1692
|
*/
|
|
1694
|
-
|
|
1693
|
+
_loadObjects(context, options) {
|
|
1695
1694
|
const { signal } = options ?? {};
|
|
1696
1695
|
signal?.throwIfAborted();
|
|
1697
1696
|
const model = this._model;
|
|
1698
1697
|
if (model === void 0) throw new Error("Model not set");
|
|
1699
|
-
const
|
|
1698
|
+
const loadings = [];
|
|
1700
1699
|
for (const currentLayer of model.layers) for (const currentObject of model.objects.filter((object) => object.layer === currentLayer.id)) {
|
|
1701
1700
|
const newRefPromise = context.loadObject(currentObject, { signal }).then(async (data) => {
|
|
1702
1701
|
try {
|
|
@@ -1714,57 +1713,62 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1714
1713
|
newRefPromise.catch((error) => {
|
|
1715
1714
|
if (!signal?.aborted) console.error(`Failed to load object with ID '${currentObject.id}'`, error);
|
|
1716
1715
|
});
|
|
1717
|
-
|
|
1716
|
+
loadings.push({
|
|
1717
|
+
layer: currentLayer,
|
|
1718
|
+
object: currentObject,
|
|
1719
|
+
newRefPromise
|
|
1720
|
+
});
|
|
1718
1721
|
}
|
|
1719
|
-
|
|
1720
|
-
signal?.throwIfAborted();
|
|
1721
|
-
return results.filter((result) => result.status === "fulfilled").map((result) => result.value);
|
|
1722
|
+
return loadings;
|
|
1722
1723
|
}
|
|
1723
1724
|
/**
|
|
1724
|
-
*
|
|
1725
|
+
* Keeps the rendered objects that can be reused for a synchronization, and deletes the rest
|
|
1725
1726
|
*
|
|
1726
1727
|
* A rendered object is matched by the layer and object it references.
|
|
1727
|
-
* Unmatched
|
|
1728
|
-
*
|
|
1729
|
-
*
|
|
1730
|
-
*
|
|
1731
|
-
*
|
|
1732
|
-
*
|
|
1733
|
-
*
|
|
1734
|
-
*
|
|
1735
|
-
*
|
|
1736
|
-
*
|
|
1737
|
-
*
|
|
1738
|
-
*
|
|
1739
|
-
*
|
|
1740
|
-
*
|
|
1741
|
-
*
|
|
1742
|
-
*
|
|
1743
|
-
*
|
|
1744
|
-
* recreating the objects behind it.
|
|
1745
|
-
*
|
|
1746
|
-
*
|
|
1747
|
-
*
|
|
1748
|
-
*
|
|
1749
|
-
*
|
|
1750
|
-
* @
|
|
1728
|
+
* Unmatched ones are deleted first, so that their removal does not shift the
|
|
1729
|
+
* world indices of the objects behind them. Only the layers and objects of
|
|
1730
|
+
* the loadings are needed, not their data, so this runs before any of them
|
|
1731
|
+
* has loaded.
|
|
1732
|
+
*
|
|
1733
|
+
* A matched rendered object is reusable if it was loaded for its object's
|
|
1734
|
+
* data source, and if its backdrop, if any, and all of its tiled images sit
|
|
1735
|
+
* at the consecutive world indices expected for its position among the
|
|
1736
|
+
* loadings, counted from the anchor. All other matched rendered objects are
|
|
1737
|
+
* deleted as well, for the caller to recreate them (see
|
|
1738
|
+
* {@link _createRenderedObject}), which is also how the world is reordered.
|
|
1739
|
+
*
|
|
1740
|
+
* The expected indices count every matched rendered object, reusable or not,
|
|
1741
|
+
* by its current footprint. A matched object that is recreated, e.g. because
|
|
1742
|
+
* its data source changed, is reinserted at the same position, so the objects
|
|
1743
|
+
* behind it stay reusable. An object whose tiled images could not be added
|
|
1744
|
+
* has been forgotten (see {@link _createRenderedObject}), so it is created
|
|
1745
|
+
* anew, without recreating the objects behind it.
|
|
1746
|
+
*
|
|
1747
|
+
* The tiled images that an earlier synchronization is still adding are waited
|
|
1748
|
+
* for first, so that each rendered object is either fully in the world or not
|
|
1749
|
+
* at all. This does not delay the additions of this synchronization, which
|
|
1750
|
+
* are queued behind them anyway (see
|
|
1751
|
+
* {@link OpenSeadragonContext.addTiledImage}).
|
|
1752
|
+
*
|
|
1753
|
+
* @param loadings - The loadings of the synchronization (see
|
|
1754
|
+
* {@link _loadObjects}), in world order
|
|
1751
1755
|
* @param options - Optional abort signal
|
|
1752
|
-
* @returns A map of
|
|
1756
|
+
* @returns A map of loadings to their reusable rendered objects
|
|
1753
1757
|
* @throws Error if the renderer has no anchor, i.e. it is not initialized or
|
|
1754
1758
|
* already destroyed
|
|
1755
1759
|
*/
|
|
1756
|
-
async _cleanRenderedObjects(
|
|
1760
|
+
async _cleanRenderedObjects(loadings, options) {
|
|
1757
1761
|
const { signal } = options ?? {};
|
|
1758
1762
|
signal?.throwIfAborted();
|
|
1759
1763
|
await Promise.allSettled(this._renderedObjects.map((renderedObject) => renderedObject.tiledImagesPromise));
|
|
1760
1764
|
signal?.throwIfAborted();
|
|
1761
1765
|
const matchedRenderedObjects = /* @__PURE__ */ new Set();
|
|
1762
|
-
const
|
|
1763
|
-
for (const
|
|
1764
|
-
const renderedObject = this._renderedObjects.find((renderedObject) => renderedObject.ref.layer.id ===
|
|
1766
|
+
const matchedRenderedObjectsByLoading = /* @__PURE__ */ new Map();
|
|
1767
|
+
for (const loading of loadings) {
|
|
1768
|
+
const renderedObject = this._renderedObjects.find((renderedObject) => renderedObject.ref.layer.id === loading.layer.id && renderedObject.ref.object.id === loading.object.id);
|
|
1765
1769
|
if (renderedObject !== void 0) {
|
|
1766
1770
|
matchedRenderedObjects.add(renderedObject);
|
|
1767
|
-
|
|
1771
|
+
matchedRenderedObjectsByLoading.set(loading, renderedObject);
|
|
1768
1772
|
}
|
|
1769
1773
|
}
|
|
1770
1774
|
const unmatchedDeletions = this._renderedObjects.filter((renderedObject) => !matchedRenderedObjects.has(renderedObject)).map((renderedObject) => this._deleteRenderedObject(renderedObject));
|
|
@@ -1774,14 +1778,14 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1774
1778
|
if (this._anchor === void 0) throw new Error("Anchor not initialized");
|
|
1775
1779
|
const anchorIndex = this.context.getTiledImageIndex(this._anchor);
|
|
1776
1780
|
if (anchorIndex === -1) throw new Error("Anchor not found");
|
|
1777
|
-
const
|
|
1781
|
+
const renderedObjectsByLoading = /* @__PURE__ */ new Map();
|
|
1778
1782
|
const survivors = /* @__PURE__ */ new Set();
|
|
1779
1783
|
let offset = 1;
|
|
1780
|
-
for (const
|
|
1781
|
-
const renderedObject =
|
|
1784
|
+
for (const loading of loadings) {
|
|
1785
|
+
const renderedObject = matchedRenderedObjectsByLoading.get(loading);
|
|
1782
1786
|
if (renderedObject !== void 0) {
|
|
1783
|
-
if (deepEqual(renderedObject.ref.object.dataSource,
|
|
1784
|
-
|
|
1787
|
+
if (deepEqual(renderedObject.ref.object.dataSource, loading.object.dataSource) && renderedObject.tiledImages !== void 0 && (renderedObject.backdrop === void 0 || this.context.getTiledImageIndex(renderedObject.backdrop) === anchorIndex + offset) && renderedObject.tiledImages.every((tiledImage, c) => this.context.getTiledImageIndex(tiledImage) === anchorIndex + offset + (renderedObject.backdrop !== void 0 ? 1 : 0) + c)) {
|
|
1788
|
+
renderedObjectsByLoading.set(loading, renderedObject);
|
|
1785
1789
|
survivors.add(renderedObject);
|
|
1786
1790
|
}
|
|
1787
1791
|
offset += (renderedObject.backdrop !== void 0 ? 1 : 0) + (renderedObject.tiledImages?.length ?? 0);
|
|
@@ -1791,39 +1795,94 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1791
1795
|
this._renderedObjects = [...survivors];
|
|
1792
1796
|
await Promise.all(unreusableDeletions);
|
|
1793
1797
|
signal?.throwIfAborted();
|
|
1794
|
-
return
|
|
1798
|
+
return renderedObjectsByLoading;
|
|
1799
|
+
}
|
|
1800
|
+
/**
|
|
1801
|
+
* Synchronizes the rendered object of one object, once it has loaded
|
|
1802
|
+
*
|
|
1803
|
+
* A reusable rendered object (see {@link _cleanRenderedObjects}) is updated
|
|
1804
|
+
* with the new reference, or deleted if the object failed to load. Otherwise,
|
|
1805
|
+
* a rendered object is created behind those of the preceding loadings,
|
|
1806
|
+
* whether these are in the world already or still being added. Preceding
|
|
1807
|
+
* objects that arrive later are inserted in front of it, as world mutations
|
|
1808
|
+
* run in request order (see {@link OpenSeadragonContext.addTiledImage}).
|
|
1809
|
+
*
|
|
1810
|
+
* @param precedingLoadings - The loadings that precede the object's in world
|
|
1811
|
+
* order (see {@link _loadObjects})
|
|
1812
|
+
* @param newRefPromise - The promise of the object's reference, from its
|
|
1813
|
+
* loading
|
|
1814
|
+
* @param renderedObject - The object's reusable rendered object, if any
|
|
1815
|
+
* @param options - Optional abort signal
|
|
1816
|
+
* @returns A promise that resolves once the object's tiled images have been
|
|
1817
|
+
* updated, or their creation has been requested
|
|
1818
|
+
*/
|
|
1819
|
+
async _synchronizeRenderedObject(precedingLoadings, newRefPromise, renderedObject, options) {
|
|
1820
|
+
const { signal } = options ?? {};
|
|
1821
|
+
signal?.throwIfAborted();
|
|
1822
|
+
let newRef;
|
|
1823
|
+
try {
|
|
1824
|
+
newRef = await newRefPromise;
|
|
1825
|
+
signal?.throwIfAborted();
|
|
1826
|
+
} catch {
|
|
1827
|
+
signal?.throwIfAborted();
|
|
1828
|
+
if (renderedObject !== void 0) {
|
|
1829
|
+
this._renderedObjects = this._renderedObjects.filter((otherRenderedObject) => otherRenderedObject !== renderedObject);
|
|
1830
|
+
await this._deleteRenderedObject(renderedObject);
|
|
1831
|
+
}
|
|
1832
|
+
return;
|
|
1833
|
+
}
|
|
1834
|
+
if (renderedObject !== void 0) {
|
|
1835
|
+
this._updateRenderedObject(renderedObject, newRef);
|
|
1836
|
+
return;
|
|
1837
|
+
}
|
|
1838
|
+
const precedingRenderedObjects = this._renderedObjects.filter((otherRenderedObject) => precedingLoadings.some((precedingLoading) => precedingLoading.layer.id === otherRenderedObject.ref.layer.id && precedingLoading.object.id === otherRenderedObject.ref.object.id));
|
|
1839
|
+
let offset = 0;
|
|
1840
|
+
for (const otherRenderedObject of precedingRenderedObjects) offset += (otherRenderedObject.usesBackdrop ? 1 : 0) + otherRenderedObject.tileSourceCount;
|
|
1841
|
+
let newRenderedObject;
|
|
1842
|
+
try {
|
|
1843
|
+
newRenderedObject = this._createRenderedObject(offset, newRef, { signal });
|
|
1844
|
+
} catch (error) {
|
|
1845
|
+
console.error(`Failed to create tiled images for object with ID '${newRef.object.id}'`, error);
|
|
1846
|
+
return;
|
|
1847
|
+
}
|
|
1848
|
+
this._renderedObjects = [
|
|
1849
|
+
...precedingRenderedObjects,
|
|
1850
|
+
newRenderedObject,
|
|
1851
|
+
...this._renderedObjects.slice(precedingRenderedObjects.length)
|
|
1852
|
+
];
|
|
1795
1853
|
}
|
|
1796
1854
|
/**
|
|
1797
1855
|
* Creates a new rendered object for the given object reference and adds one TiledImage per channel, preceded by a backdrop where required, to the world
|
|
1798
1856
|
*
|
|
1799
|
-
* The TiledImages are inserted at consecutive indices, starting `offset`
|
|
1800
|
-
* after the anchor, which
|
|
1801
|
-
* {@link _cleanRenderedObjects} expects. `offset`
|
|
1802
|
-
* not objects
|
|
1803
|
-
*
|
|
1804
|
-
*
|
|
1805
|
-
*
|
|
1806
|
-
*
|
|
1807
|
-
*
|
|
1808
|
-
*
|
|
1809
|
-
*
|
|
1810
|
-
*
|
|
1811
|
-
*
|
|
1812
|
-
*
|
|
1813
|
-
*
|
|
1814
|
-
*
|
|
1815
|
-
*
|
|
1816
|
-
*
|
|
1817
|
-
*
|
|
1818
|
-
*
|
|
1819
|
-
* meantime, or if any
|
|
1820
|
-
*
|
|
1821
|
-
*
|
|
1822
|
-
*
|
|
1823
|
-
*
|
|
1824
|
-
*
|
|
1825
|
-
*
|
|
1826
|
-
*
|
|
1857
|
+
* The TiledImages are inserted at consecutive indices, starting `offset`
|
|
1858
|
+
* places after the anchor, which is the world layout that
|
|
1859
|
+
* {@link _cleanRenderedObjects} expects. `offset` thus counts TiledImages,
|
|
1860
|
+
* not objects: the backdrops and TiledImages of the preceding rendered
|
|
1861
|
+
* objects, including those still being added. The indices are resolved when
|
|
1862
|
+
* each addition is executed, as the anchor may have been replaced, and world
|
|
1863
|
+
* indices may have shifted, in the meantime.
|
|
1864
|
+
*
|
|
1865
|
+
* The tile sources are opened here, rather than by the additions, so that the
|
|
1866
|
+
* backdrop can be sized like the object's content, which is only known once
|
|
1867
|
+
* one of them has opened. All additions are requested before this function
|
|
1868
|
+
* returns, in world order, so that the TiledImages of the object created next
|
|
1869
|
+
* end up behind them.
|
|
1870
|
+
*
|
|
1871
|
+
* Returns before the TiledImages exist: they are added asynchronously, and
|
|
1872
|
+
* only then assigned to the rendered object, transformed and included in the
|
|
1873
|
+
* anchor bounds, which is when {@link RenderedObject.tiledImagesPromise}
|
|
1874
|
+
* resolves.
|
|
1875
|
+
*
|
|
1876
|
+
* If the rendered object is deleted or the operation is aborted in the
|
|
1877
|
+
* meantime, or if any TiledImage could not be added, the added backdrop and
|
|
1878
|
+
* TiledImages are removed again right away: a partially added object would
|
|
1879
|
+
* shift the world indices of every object behind it. For the same reason, a
|
|
1880
|
+
* tile source that fails to open is replaced by a transparent placeholder
|
|
1881
|
+
* rather than skipped, as the objects created after this one are placed
|
|
1882
|
+
* against its full footprint. The rendered object is dropped from
|
|
1883
|
+
* {@link _renderedObjects} as its removals are queued, so that objects
|
|
1884
|
+
* created from then on are placed without it. If the context is destroyed,
|
|
1885
|
+
* nothing is done at all, as the viewer tears down its world itself.
|
|
1827
1886
|
*
|
|
1828
1887
|
* @param offset - The number of TiledImages between the anchor and the object's first new TiledImage
|
|
1829
1888
|
* @param newRef - The object reference for which to create a rendered object
|
|
@@ -1896,8 +1955,9 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1896
1955
|
if (this.context.isDestroyed()) return tiledImages;
|
|
1897
1956
|
const failure = [...tileSourceResults, ...results].find((result) => result.status === "rejected");
|
|
1898
1957
|
if (signal?.aborted || failure !== void 0 || newRenderedObject.pendingDelete || this._destroyed) {
|
|
1899
|
-
|
|
1900
|
-
|
|
1958
|
+
this._renderedObjects = this._renderedObjects.filter((renderedObject) => renderedObject !== newRenderedObject);
|
|
1959
|
+
const addedTiledImages = backdrop !== void 0 ? [backdrop, ...tiledImages] : tiledImages;
|
|
1960
|
+
await Promise.all(addedTiledImages.map((tiledImage) => this.context.removeTiledImage(tiledImage)));
|
|
1901
1961
|
signal?.throwIfAborted();
|
|
1902
1962
|
if (failure !== void 0) {
|
|
1903
1963
|
console.error(`Failed to add tiled images for object with ID '${newRef.object.id}'`, failure.reason);
|
|
@@ -3983,7 +4043,6 @@ var WebGLRendererBase = class {
|
|
|
3983
4043
|
};
|
|
3984
4044
|
_model;
|
|
3985
4045
|
_lastSyncState;
|
|
3986
|
-
_hasUnreportedChanges = false;
|
|
3987
4046
|
_renderedObjects = /* @__PURE__ */ new Map();
|
|
3988
4047
|
_layerItemsInfosCache = /* @__PURE__ */ new WeakMap();
|
|
3989
4048
|
/**
|
|
@@ -4065,59 +4124,52 @@ var WebGLRendererBase = class {
|
|
|
4065
4124
|
/**
|
|
4066
4125
|
* Synchronizes the rendered objects with the current model and render options
|
|
4067
4126
|
*
|
|
4068
|
-
*
|
|
4069
|
-
* rendered objects that
|
|
4070
|
-
*
|
|
4071
|
-
*
|
|
4072
|
-
*
|
|
4073
|
-
*
|
|
4074
|
-
*
|
|
4075
|
-
*
|
|
4076
|
-
*
|
|
4077
|
-
*
|
|
4078
|
-
*
|
|
4079
|
-
*
|
|
4080
|
-
*
|
|
4081
|
-
*
|
|
4082
|
-
*
|
|
4127
|
+
* Starts loading the objects of the model (see {@link loadObjects}), and
|
|
4128
|
+
* right away drops the rendered objects that none of them addresses. Each
|
|
4129
|
+
* object is then synchronized on its own, as soon as its data has loaded: the
|
|
4130
|
+
* object is prepared (see {@link prepareRenderedObject}), and the preparation
|
|
4131
|
+
* is uploaded in one synchronous block, either into the reused rendered
|
|
4132
|
+
* object or into one that replaces it (see {@link createRenderedObject} and
|
|
4133
|
+
* {@link updateRenderedObject}). A draw thus never sees a half-updated
|
|
4134
|
+
* object, and a slow or failing object never holds back the others.
|
|
4135
|
+
*
|
|
4136
|
+
* An object issues its requests right after its data has loaded, without
|
|
4137
|
+
* awaiting in between. Requests are shared with a superseded synchronization,
|
|
4138
|
+
* and cancelled once it abandons them, unless they are reclaimed within the
|
|
4139
|
+
* same task. Data that has already loaded allows that.
|
|
4140
|
+
*
|
|
4141
|
+
* An object whose data or preparation fails, or that has nothing to render,
|
|
4142
|
+
* is logged and dropped. A synchronization that fails or is aborted leaves
|
|
4143
|
+
* the model unsynchronized (see {@link _discardSyncState}).
|
|
4083
4144
|
*
|
|
4084
4145
|
* @param syncContext - The inputs to synchronize with: the tables and
|
|
4085
|
-
* group-to-value maps that the objects resolve their properties from, and
|
|
4086
|
-
*
|
|
4087
|
-
*
|
|
4088
|
-
* @param options - Optional abort signal
|
|
4089
|
-
*
|
|
4090
|
-
*
|
|
4146
|
+
* group-to-value maps that the objects resolve their properties from, and the
|
|
4147
|
+
* loaders for object and table data. It carries inputs only; what an object
|
|
4148
|
+
* was resolved from is captured per object (see {@link ObjectRef})
|
|
4149
|
+
* @param options - Optional abort signal, and a callback that is called
|
|
4150
|
+
* synchronously whenever a rendered object is added, updated or dropped, so
|
|
4151
|
+
* that the caller can draw each object as soon as it is ready
|
|
4152
|
+
* @returns A promise that resolves once all objects have been synchronized
|
|
4091
4153
|
* @throws Error if no model has been set (see {@link setModel})
|
|
4092
4154
|
*/
|
|
4093
4155
|
async synchronize(syncContext, options) {
|
|
4094
|
-
const { signal } = options ?? {};
|
|
4156
|
+
const { signal, onChange } = options ?? {};
|
|
4095
4157
|
signal?.throwIfAborted();
|
|
4096
4158
|
const syncState = this._recordSyncState();
|
|
4097
4159
|
try {
|
|
4098
|
-
const
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
});
|
|
4108
|
-
for (const { newRef, renderedObject, preparedPromise } of preparations) {
|
|
4109
|
-
const prepared = await this._settleRenderedObjectPreparation(newRef, renderedObject, preparedPromise, { signal });
|
|
4110
|
-
if (prepared === void 0) continue;
|
|
4111
|
-
if (renderedObject === void 0) this.addRenderedObject(this.createRenderedObject(newRef, prepared));
|
|
4112
|
-
else if (this.updateRenderedObject(renderedObject, prepared)) this._hasUnreportedChanges = true;
|
|
4113
|
-
}
|
|
4160
|
+
const loadings = this.loadObjects(syncContext, { signal });
|
|
4161
|
+
if (this._cleanRenderedObjects(loadings)) onChange?.();
|
|
4162
|
+
const syncResults = await Promise.allSettled(loadings.map(({ layerId, object, newRefPromise }) => this._synchronizeRenderedObject(layerId, object.id, newRefPromise, syncContext, {
|
|
4163
|
+
signal,
|
|
4164
|
+
onChange
|
|
4165
|
+
})));
|
|
4166
|
+
signal?.throwIfAborted();
|
|
4167
|
+
const firstSyncFailure = syncResults.find((result) => result.status === "rejected");
|
|
4168
|
+
if (firstSyncFailure !== void 0) throw firstSyncFailure.reason;
|
|
4114
4169
|
} catch (error) {
|
|
4115
4170
|
this._discardSyncState(syncState);
|
|
4116
4171
|
throw error;
|
|
4117
4172
|
}
|
|
4118
|
-
const hasUnreportedChanges = this._hasUnreportedChanges;
|
|
4119
|
-
this._hasUnreportedChanges = false;
|
|
4120
|
-
return hasUnreportedChanges;
|
|
4121
4173
|
}
|
|
4122
4174
|
/**
|
|
4123
4175
|
* Returns the state of the current model and render options that a
|
|
@@ -4197,29 +4249,31 @@ var WebGLRendererBase = class {
|
|
|
4197
4249
|
*/
|
|
4198
4250
|
getRenderOptionsSyncState() {}
|
|
4199
4251
|
/**
|
|
4200
|
-
*
|
|
4252
|
+
* Starts loading the data of all objects to be rendered on the layers of the current model
|
|
4201
4253
|
*
|
|
4202
|
-
* An object assigned to a layer by layer ID is loaded for that layer only
|
|
4254
|
+
* An object assigned to a layer by layer ID is loaded for that layer only. An
|
|
4203
4255
|
* object assigned per item by a table column is loaded for every layer, with
|
|
4204
4256
|
* the items on each layer resolved from the table (see
|
|
4205
4257
|
* {@link _getLayerItemsInfos}). The data of an object, and of a table, is
|
|
4206
|
-
* loaded once,
|
|
4258
|
+
* loaded once, however many references share it.
|
|
4207
4259
|
*
|
|
4208
|
-
*
|
|
4209
|
-
*
|
|
4210
|
-
*
|
|
4211
|
-
*
|
|
4212
|
-
*
|
|
4213
|
-
* are
|
|
4260
|
+
* Returns right away, with one loading per object and layer, ordered by layer
|
|
4261
|
+
* and then by object. Each loading settles on its own. It rejects if the
|
|
4262
|
+
* object's data or table fails to load, which is logged. It resolves to
|
|
4263
|
+
* `null` if the object has no items on the layer, which is not logged: empty
|
|
4264
|
+
* objects and empty tables are legitimate states, not failures. An object
|
|
4265
|
+
* whose items are assigned per item, but that has no table to resolve the
|
|
4266
|
+
* assignment from, is logged and gets no loading.
|
|
4214
4267
|
*
|
|
4215
4268
|
* @param syncContext - The inputs of the current synchronization: the tables
|
|
4216
|
-
* that the objects resolve their item layers from, and the loaders for
|
|
4217
|
-
*
|
|
4269
|
+
* that the objects resolve their item layers from, and the loaders for object
|
|
4270
|
+
* and table data
|
|
4218
4271
|
* @param options - Optional abort signal
|
|
4219
|
-
* @returns
|
|
4272
|
+
* @returns One loading per object and layer, whose promise resolves to the
|
|
4273
|
+
* object's reference, or to `null` if the object has no items on the layer
|
|
4220
4274
|
* @throws Error if no model has been set (see {@link setModel})
|
|
4221
4275
|
*/
|
|
4222
|
-
|
|
4276
|
+
loadObjects(syncContext, options) {
|
|
4223
4277
|
const { signal } = options ?? {};
|
|
4224
4278
|
signal?.throwIfAborted();
|
|
4225
4279
|
const model = this._model;
|
|
@@ -4228,7 +4282,7 @@ var WebGLRendererBase = class {
|
|
|
4228
4282
|
const tableDataPromises = /* @__PURE__ */ new Map();
|
|
4229
4283
|
const tableLayersPromises = /* @__PURE__ */ new Map();
|
|
4230
4284
|
const layerItemsInfosPromises = /* @__PURE__ */ new Map();
|
|
4231
|
-
const
|
|
4285
|
+
const loadings = [];
|
|
4232
4286
|
const objectIdsWithoutTable = /* @__PURE__ */ new Set();
|
|
4233
4287
|
for (const currentLayer of model.layers) for (const currentObject of model.objects) {
|
|
4234
4288
|
if (typeof currentObject.layer === "string" && currentObject.layer !== currentLayer.id) continue;
|
|
@@ -4292,67 +4346,33 @@ var WebGLRendererBase = class {
|
|
|
4292
4346
|
}
|
|
4293
4347
|
const newRefPromise = Promise.all([dataPromise, layerItemsInfosPromise]).then(([data, layerItemsInfos]) => {
|
|
4294
4348
|
signal?.throwIfAborted();
|
|
4349
|
+
let newRef;
|
|
4295
4350
|
if (layerItemsInfos !== void 0) {
|
|
4296
4351
|
const itemsInfo = layerItemsInfos.get(currentLayer.id);
|
|
4297
|
-
|
|
4352
|
+
newRef = {
|
|
4298
4353
|
layerId: currentLayer.id,
|
|
4299
4354
|
object: currentObject,
|
|
4300
4355
|
itemIds: itemsInfo?.itemIds ?? [],
|
|
4301
4356
|
itemsMask: itemsInfo?.itemsMask,
|
|
4302
4357
|
data
|
|
4303
4358
|
};
|
|
4304
|
-
}
|
|
4305
|
-
return {
|
|
4359
|
+
} else newRef = {
|
|
4306
4360
|
layerId: currentLayer.id,
|
|
4307
4361
|
object: currentObject,
|
|
4308
4362
|
itemIds: data.getIds(),
|
|
4309
4363
|
itemsMask: void 0,
|
|
4310
4364
|
data
|
|
4311
4365
|
};
|
|
4366
|
+
return newRef.itemIds.length > 0 ? newRef : null;
|
|
4367
|
+
});
|
|
4368
|
+
newRefPromise.catch(() => {});
|
|
4369
|
+
loadings.push({
|
|
4370
|
+
layerId: currentLayer.id,
|
|
4371
|
+
object: currentObject,
|
|
4372
|
+
newRefPromise
|
|
4312
4373
|
});
|
|
4313
|
-
newRefPromises.push(newRefPromise);
|
|
4314
|
-
}
|
|
4315
|
-
const results = await Promise.allSettled(newRefPromises);
|
|
4316
|
-
signal?.throwIfAborted();
|
|
4317
|
-
return results.filter((result) => result.status === "fulfilled").filter((result) => result.value.itemIds.length > 0).map((result) => result.value);
|
|
4318
|
-
}
|
|
4319
|
-
/**
|
|
4320
|
-
* Matches the rendered objects to a new set of references, and destroys the
|
|
4321
|
-
* ones left over
|
|
4322
|
-
*
|
|
4323
|
-
* A rendered object is matched by the layer and object it is kept under, and
|
|
4324
|
-
* kept if its contributed items and data source are those of the reference,
|
|
4325
|
-
* which it then adopts and is returned for reuse with. Every other rendered
|
|
4326
|
-
* object - one that no reference addresses, or one whose items or data source
|
|
4327
|
-
* changed - is destroyed and dropped.
|
|
4328
|
-
*
|
|
4329
|
-
* @param newRefs - The object references to match against
|
|
4330
|
-
* @returns One match per reference, in the order of the references, each with
|
|
4331
|
-
* the rendered object to reuse for it, or `undefined` if it has none yet
|
|
4332
|
-
*/
|
|
4333
|
-
matchOrDestroyRenderedObjects(newRefs) {
|
|
4334
|
-
const matchedRenderedObjects = /* @__PURE__ */ new Set();
|
|
4335
|
-
const matches = newRefs.map((newRef) => {
|
|
4336
|
-
const renderedObject = this._renderedObjects.get(newRef.layerId)?.get(newRef.object.id);
|
|
4337
|
-
if (renderedObject !== void 0 && renderedObject.ref.itemIds === newRef.itemIds && renderedObject.ref.itemsMask === newRef.itemsMask && deepEqual(renderedObject.ref.object.dataSource, newRef.object.dataSource)) {
|
|
4338
|
-
renderedObject.ref = newRef;
|
|
4339
|
-
matchedRenderedObjects.add(renderedObject);
|
|
4340
|
-
return {
|
|
4341
|
-
newRef,
|
|
4342
|
-
renderedObject
|
|
4343
|
-
};
|
|
4344
|
-
}
|
|
4345
|
-
return {
|
|
4346
|
-
newRef,
|
|
4347
|
-
renderedObject: void 0
|
|
4348
|
-
};
|
|
4349
|
-
});
|
|
4350
|
-
for (const renderedObjects of this._renderedObjects.values()) for (const [objectId, renderedObject] of renderedObjects) if (!matchedRenderedObjects.has(renderedObject)) {
|
|
4351
|
-
renderedObjects.delete(objectId);
|
|
4352
|
-
this.destroyRenderedObject(renderedObject);
|
|
4353
|
-
this._hasUnreportedChanges = true;
|
|
4354
4374
|
}
|
|
4355
|
-
return
|
|
4375
|
+
return loadings;
|
|
4356
4376
|
}
|
|
4357
4377
|
/**
|
|
4358
4378
|
* Adds a newly created rendered object under its layer and object
|
|
@@ -4367,7 +4387,6 @@ var WebGLRendererBase = class {
|
|
|
4367
4387
|
this._renderedObjects.set(layerId, renderedObjects);
|
|
4368
4388
|
}
|
|
4369
4389
|
renderedObjects.set(object.id, renderedObject);
|
|
4370
|
-
this._hasUnreportedChanges = true;
|
|
4371
4390
|
}
|
|
4372
4391
|
/**
|
|
4373
4392
|
* Drops a rendered object and releases its GPU resources
|
|
@@ -4377,7 +4396,6 @@ var WebGLRendererBase = class {
|
|
|
4377
4396
|
removeRenderedObject(renderedObject) {
|
|
4378
4397
|
this._renderedObjects.get(renderedObject.ref.layerId)?.delete(renderedObject.ref.object.id);
|
|
4379
4398
|
this.destroyRenderedObject(renderedObject);
|
|
4380
|
-
this._hasUnreportedChanges = true;
|
|
4381
4399
|
}
|
|
4382
4400
|
/**
|
|
4383
4401
|
* Drops all rendered objects and releases their GPU resources
|
|
@@ -4385,7 +4403,6 @@ var WebGLRendererBase = class {
|
|
|
4385
4403
|
clearRenderedObjects() {
|
|
4386
4404
|
for (const renderedObjects of this._renderedObjects.values()) for (const renderedObject of renderedObjects.values()) this.destroyRenderedObject(renderedObject);
|
|
4387
4405
|
this._renderedObjects.clear();
|
|
4388
|
-
this._hasUnreportedChanges = true;
|
|
4389
4406
|
}
|
|
4390
4407
|
/**
|
|
4391
4408
|
* Returns one render pass per rendered object to draw, in draw order
|
|
@@ -4531,35 +4548,90 @@ var WebGLRendererBase = class {
|
|
|
4531
4548
|
return layerItemsInfos;
|
|
4532
4549
|
}
|
|
4533
4550
|
/**
|
|
4534
|
-
*
|
|
4535
|
-
* finds nothing to render
|
|
4551
|
+
* Drops the rendered objects that none of the given loadings addresses
|
|
4536
4552
|
*
|
|
4537
|
-
*
|
|
4538
|
-
*
|
|
4539
|
-
*
|
|
4540
|
-
*
|
|
4541
|
-
*
|
|
4542
|
-
*
|
|
4543
|
-
*
|
|
4553
|
+
* Their layer or object has left the model, or the object has moved to
|
|
4554
|
+
* another layer, so they are no longer drawn (see {@link getRenderPasses}).
|
|
4555
|
+
* They are dropped right away, rather than once the remaining objects have
|
|
4556
|
+
* loaded. Whether the others can be reused is decided per object, once its
|
|
4557
|
+
* data has loaded (see {@link _synchronizeRenderedObject}).
|
|
4558
|
+
*
|
|
4559
|
+
* @param loadings - The loadings of the current synchronization (see
|
|
4560
|
+
* {@link loadObjects})
|
|
4561
|
+
* @returns Whether any rendered object was dropped
|
|
4544
4562
|
*/
|
|
4545
|
-
|
|
4546
|
-
|
|
4563
|
+
_cleanRenderedObjects(loadings) {
|
|
4564
|
+
let removed = false;
|
|
4565
|
+
for (const [layerId, renderedObjects] of this._renderedObjects) for (const [objectId, renderedObject] of renderedObjects) if (!loadings.some((loading) => loading.layerId === layerId && loading.object.id === objectId)) {
|
|
4566
|
+
this.removeRenderedObject(renderedObject);
|
|
4567
|
+
removed = true;
|
|
4568
|
+
}
|
|
4569
|
+
return removed;
|
|
4570
|
+
}
|
|
4571
|
+
/**
|
|
4572
|
+
* Synchronizes the rendered object of one object and layer, once its data has loaded
|
|
4573
|
+
*
|
|
4574
|
+
* The rendered object kept under the layer and object is reused if its items
|
|
4575
|
+
* and data source match the new reference, which it then adopts. The object
|
|
4576
|
+
* is then prepared and uploaded (see {@link synchronize}). A rendered object
|
|
4577
|
+
* that is not reused stays drawn until its replacement is uploaded, and is
|
|
4578
|
+
* then dropped in the same synchronous block. If the object's data failed to
|
|
4579
|
+
* load, or it has no items on the layer, it is only dropped. So is it if its
|
|
4580
|
+
* preparation fails or finds nothing to render, which is logged.
|
|
4581
|
+
*
|
|
4582
|
+
* @param layerId - The ID of the layer
|
|
4583
|
+
* @param objectId - The ID of the object
|
|
4584
|
+
* @param newRefPromise - The object's loading (see {@link loadObjects})
|
|
4585
|
+
* @param syncContext - The inputs of the current synchronization
|
|
4586
|
+
* @param options - Optional abort signal, and the callback to call whenever
|
|
4587
|
+
* the rendered object is added, updated or dropped
|
|
4588
|
+
* @returns A promise that resolves once the object has been synchronized
|
|
4589
|
+
*/
|
|
4590
|
+
async _synchronizeRenderedObject(layerId, objectId, newRefPromise, syncContext, options) {
|
|
4591
|
+
const { signal, onChange } = options ?? {};
|
|
4592
|
+
signal?.throwIfAborted();
|
|
4593
|
+
let newRef;
|
|
4594
|
+
try {
|
|
4595
|
+
newRef = await newRefPromise;
|
|
4596
|
+
signal?.throwIfAborted();
|
|
4597
|
+
} catch {
|
|
4598
|
+
signal?.throwIfAborted();
|
|
4599
|
+
newRef = null;
|
|
4600
|
+
}
|
|
4601
|
+
let renderedObject;
|
|
4602
|
+
const oldRenderedObject = this._renderedObjects.get(layerId)?.get(objectId);
|
|
4603
|
+
if (oldRenderedObject !== void 0 && newRef !== null && oldRenderedObject.ref.itemIds === newRef.itemIds && oldRenderedObject.ref.itemsMask === newRef.itemsMask && deepEqual(oldRenderedObject.ref.object.dataSource, newRef.object.dataSource)) {
|
|
4604
|
+
oldRenderedObject.ref = newRef;
|
|
4605
|
+
renderedObject = oldRenderedObject;
|
|
4606
|
+
}
|
|
4607
|
+
if (newRef === null) {
|
|
4608
|
+
if (oldRenderedObject !== void 0) {
|
|
4609
|
+
this.removeRenderedObject(oldRenderedObject);
|
|
4610
|
+
onChange?.();
|
|
4611
|
+
}
|
|
4612
|
+
return;
|
|
4613
|
+
}
|
|
4547
4614
|
let prepared;
|
|
4548
4615
|
try {
|
|
4549
|
-
prepared = await
|
|
4616
|
+
prepared = await this.prepareRenderedObject(newRef, renderedObject, syncContext, { signal });
|
|
4617
|
+
signal?.throwIfAborted();
|
|
4550
4618
|
} catch (error) {
|
|
4551
4619
|
signal?.throwIfAborted();
|
|
4552
4620
|
console.error(`Failed to prepare object with ID '${newRef.object.id}'`, error);
|
|
4553
|
-
if (renderedObject !== void 0) this.removeRenderedObject(renderedObject);
|
|
4554
|
-
return;
|
|
4555
4621
|
}
|
|
4556
|
-
|
|
4557
|
-
if (prepared === null) {
|
|
4558
|
-
|
|
4559
|
-
|
|
4622
|
+
if (prepared === null) console.warn(`Object with ID '${newRef.object.id}' has nothing to render, skipping`);
|
|
4623
|
+
if (prepared === void 0 || prepared === null) {
|
|
4624
|
+
if (oldRenderedObject !== void 0) {
|
|
4625
|
+
this.removeRenderedObject(oldRenderedObject);
|
|
4626
|
+
onChange?.();
|
|
4627
|
+
}
|
|
4560
4628
|
return;
|
|
4561
4629
|
}
|
|
4562
|
-
|
|
4630
|
+
if (renderedObject === void 0) {
|
|
4631
|
+
if (oldRenderedObject !== void 0) this.removeRenderedObject(oldRenderedObject);
|
|
4632
|
+
this.addRenderedObject(this.createRenderedObject(newRef, prepared));
|
|
4633
|
+
onChange?.();
|
|
4634
|
+
} else if (this.updateRenderedObject(renderedObject, prepared)) onChange?.();
|
|
4563
4635
|
}
|
|
4564
4636
|
/**
|
|
4565
4637
|
* Creates the loader for the tables that an object resolves its properties
|