@tissuumaps/render 0.1.0-beta.2 → 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 +14 -0
- package/README.md +3 -3
- package/dist/index.d.ts +204 -164
- package/dist/index.js +320 -252
- package/package.json +4 -4
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] = {
|
|
@@ -1385,18 +1389,20 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1385
1389
|
/**
|
|
1386
1390
|
* Synchronizes the viewer's tiled images with the current model
|
|
1387
1391
|
*
|
|
1388
|
-
*
|
|
1389
|
-
* {@link setModel}, removes the tiled images that are no
|
|
1390
|
-
*
|
|
1391
|
-
*
|
|
1392
|
-
*
|
|
1393
|
-
*
|
|
1394
|
-
*
|
|
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
|
|
1395
1402
|
* {@link _updateRenderedObject}).
|
|
1396
1403
|
*
|
|
1397
|
-
* Objects whose tiled images cannot be created
|
|
1398
|
-
*
|
|
1399
|
-
* 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
|
|
1400
1406
|
* fails or is aborted leaves the model unsynchronized (see
|
|
1401
1407
|
* {@link needsSynchronization}).
|
|
1402
1408
|
*
|
|
@@ -1413,27 +1419,16 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1413
1419
|
const syncState = this.getSyncState();
|
|
1414
1420
|
this._lastSyncState = syncState;
|
|
1415
1421
|
try {
|
|
1416
|
-
const
|
|
1417
|
-
const
|
|
1418
|
-
this.retainObjects(
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
renderedObject = this._createRenderedObject(offset, newRef, { signal });
|
|
1425
|
-
} catch (error) {
|
|
1426
|
-
console.error(`Failed to create tiled images for object with ID '${newRef.object.id}'`, error);
|
|
1427
|
-
continue;
|
|
1428
|
-
}
|
|
1429
|
-
else this._updateRenderedObject(renderedObject, newRef);
|
|
1430
|
-
newRenderedObjects.push(renderedObject);
|
|
1431
|
-
offset += (renderedObject.usesBackdrop ? 1 : 0) + renderedObject.tileSourceCount;
|
|
1432
|
-
}
|
|
1433
|
-
this._renderedObjects = newRenderedObjects;
|
|
1434
|
-
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));
|
|
1435
1430
|
signal?.throwIfAborted();
|
|
1436
|
-
await this._updateBoundsAndReveal(
|
|
1431
|
+
await this._updateBoundsAndReveal(this._renderedObjects, { signal });
|
|
1437
1432
|
} catch (error) {
|
|
1438
1433
|
if (this._lastSyncState === syncState) this._lastSyncState = void 0;
|
|
1439
1434
|
throw error;
|
|
@@ -1570,13 +1565,12 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1570
1565
|
/**
|
|
1571
1566
|
* Retains what was resolved for the given objects, and discards the rest
|
|
1572
1567
|
*
|
|
1573
|
-
* Called by {@link synchronize}
|
|
1574
|
-
*
|
|
1575
|
-
*
|
|
1576
|
-
*
|
|
1577
|
-
* 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
|
|
1578
1572
|
* {@link resolveTiledImageDataTransfer}) override this to drop the state of
|
|
1579
|
-
*
|
|
1573
|
+
* all other objects.
|
|
1580
1574
|
*
|
|
1581
1575
|
* @param _objects - The objects (images or labels) about to be displayed
|
|
1582
1576
|
*/
|
|
@@ -1584,15 +1578,15 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1584
1578
|
/**
|
|
1585
1579
|
* Resolves what a renderer derives from an object, once its data has loaded
|
|
1586
1580
|
*
|
|
1587
|
-
* Called by {@link _loadObjects} for
|
|
1588
|
-
*
|
|
1589
|
-
*
|
|
1590
|
-
*
|
|
1591
|
-
*
|
|
1592
|
-
*
|
|
1593
|
-
*
|
|
1594
|
-
*
|
|
1595
|
-
*
|
|
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.
|
|
1596
1590
|
*
|
|
1597
1591
|
* @param _object - The object (image or labels) to resolve
|
|
1598
1592
|
* @param _data - The loaded data of the object
|
|
@@ -1679,28 +1673,29 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1679
1673
|
*/
|
|
1680
1674
|
resolveTiledImageDataTransfer(_ref, _index) {}
|
|
1681
1675
|
/**
|
|
1682
|
-
*
|
|
1676
|
+
* Starts loading and resolving all objects assigned to the layers of the current model
|
|
1683
1677
|
*
|
|
1684
|
-
*
|
|
1685
|
-
*
|
|
1686
|
-
*
|
|
1687
|
-
*
|
|
1688
|
-
*
|
|
1689
|
-
*
|
|
1690
|
-
*
|
|
1691
|
-
*
|
|
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.
|
|
1683
|
+
*
|
|
1684
|
+
* The model is read once, right away, so one synchronization sees one
|
|
1685
|
+
* consistent model state.
|
|
1692
1686
|
*
|
|
1693
1687
|
* @param context - The inputs of the current synchronization
|
|
1694
1688
|
* @param options - Optional abort signal
|
|
1695
|
-
* @returns
|
|
1689
|
+
* @returns One loading per object, whose promise resolves to the object's
|
|
1690
|
+
* reference
|
|
1696
1691
|
* @throws Error if no model has been set (see {@link setModel})
|
|
1697
1692
|
*/
|
|
1698
|
-
|
|
1693
|
+
_loadObjects(context, options) {
|
|
1699
1694
|
const { signal } = options ?? {};
|
|
1700
1695
|
signal?.throwIfAborted();
|
|
1701
1696
|
const model = this._model;
|
|
1702
1697
|
if (model === void 0) throw new Error("Model not set");
|
|
1703
|
-
const
|
|
1698
|
+
const loadings = [];
|
|
1704
1699
|
for (const currentLayer of model.layers) for (const currentObject of model.objects.filter((object) => object.layer === currentLayer.id)) {
|
|
1705
1700
|
const newRefPromise = context.loadObject(currentObject, { signal }).then(async (data) => {
|
|
1706
1701
|
try {
|
|
@@ -1718,57 +1713,62 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1718
1713
|
newRefPromise.catch((error) => {
|
|
1719
1714
|
if (!signal?.aborted) console.error(`Failed to load object with ID '${currentObject.id}'`, error);
|
|
1720
1715
|
});
|
|
1721
|
-
|
|
1716
|
+
loadings.push({
|
|
1717
|
+
layer: currentLayer,
|
|
1718
|
+
object: currentObject,
|
|
1719
|
+
newRefPromise
|
|
1720
|
+
});
|
|
1722
1721
|
}
|
|
1723
|
-
|
|
1724
|
-
signal?.throwIfAborted();
|
|
1725
|
-
return results.filter((result) => result.status === "fulfilled").map((result) => result.value);
|
|
1722
|
+
return loadings;
|
|
1726
1723
|
}
|
|
1727
1724
|
/**
|
|
1728
|
-
*
|
|
1725
|
+
* Keeps the rendered objects that can be reused for a synchronization, and deletes the rest
|
|
1729
1726
|
*
|
|
1730
1727
|
* A rendered object is matched by the layer and object it references.
|
|
1731
|
-
* Unmatched
|
|
1732
|
-
*
|
|
1733
|
-
*
|
|
1734
|
-
*
|
|
1735
|
-
*
|
|
1736
|
-
*
|
|
1737
|
-
*
|
|
1738
|
-
*
|
|
1739
|
-
*
|
|
1740
|
-
*
|
|
1741
|
-
*
|
|
1742
|
-
*
|
|
1743
|
-
*
|
|
1744
|
-
*
|
|
1745
|
-
*
|
|
1746
|
-
*
|
|
1747
|
-
*
|
|
1748
|
-
* recreating the objects behind it.
|
|
1749
|
-
*
|
|
1750
|
-
*
|
|
1751
|
-
*
|
|
1752
|
-
*
|
|
1753
|
-
*
|
|
1754
|
-
* @
|
|
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
|
|
1755
1755
|
* @param options - Optional abort signal
|
|
1756
|
-
* @returns A map of
|
|
1756
|
+
* @returns A map of loadings to their reusable rendered objects
|
|
1757
1757
|
* @throws Error if the renderer has no anchor, i.e. it is not initialized or
|
|
1758
1758
|
* already destroyed
|
|
1759
1759
|
*/
|
|
1760
|
-
async _cleanRenderedObjects(
|
|
1760
|
+
async _cleanRenderedObjects(loadings, options) {
|
|
1761
1761
|
const { signal } = options ?? {};
|
|
1762
1762
|
signal?.throwIfAborted();
|
|
1763
1763
|
await Promise.allSettled(this._renderedObjects.map((renderedObject) => renderedObject.tiledImagesPromise));
|
|
1764
1764
|
signal?.throwIfAborted();
|
|
1765
1765
|
const matchedRenderedObjects = /* @__PURE__ */ new Set();
|
|
1766
|
-
const
|
|
1767
|
-
for (const
|
|
1768
|
-
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);
|
|
1769
1769
|
if (renderedObject !== void 0) {
|
|
1770
1770
|
matchedRenderedObjects.add(renderedObject);
|
|
1771
|
-
|
|
1771
|
+
matchedRenderedObjectsByLoading.set(loading, renderedObject);
|
|
1772
1772
|
}
|
|
1773
1773
|
}
|
|
1774
1774
|
const unmatchedDeletions = this._renderedObjects.filter((renderedObject) => !matchedRenderedObjects.has(renderedObject)).map((renderedObject) => this._deleteRenderedObject(renderedObject));
|
|
@@ -1778,14 +1778,14 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1778
1778
|
if (this._anchor === void 0) throw new Error("Anchor not initialized");
|
|
1779
1779
|
const anchorIndex = this.context.getTiledImageIndex(this._anchor);
|
|
1780
1780
|
if (anchorIndex === -1) throw new Error("Anchor not found");
|
|
1781
|
-
const
|
|
1781
|
+
const renderedObjectsByLoading = /* @__PURE__ */ new Map();
|
|
1782
1782
|
const survivors = /* @__PURE__ */ new Set();
|
|
1783
1783
|
let offset = 1;
|
|
1784
|
-
for (const
|
|
1785
|
-
const renderedObject =
|
|
1784
|
+
for (const loading of loadings) {
|
|
1785
|
+
const renderedObject = matchedRenderedObjectsByLoading.get(loading);
|
|
1786
1786
|
if (renderedObject !== void 0) {
|
|
1787
|
-
if (deepEqual(renderedObject.ref.object.dataSource,
|
|
1788
|
-
|
|
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);
|
|
1789
1789
|
survivors.add(renderedObject);
|
|
1790
1790
|
}
|
|
1791
1791
|
offset += (renderedObject.backdrop !== void 0 ? 1 : 0) + (renderedObject.tiledImages?.length ?? 0);
|
|
@@ -1795,39 +1795,94 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1795
1795
|
this._renderedObjects = [...survivors];
|
|
1796
1796
|
await Promise.all(unreusableDeletions);
|
|
1797
1797
|
signal?.throwIfAborted();
|
|
1798
|
-
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
|
+
];
|
|
1799
1853
|
}
|
|
1800
1854
|
/**
|
|
1801
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
|
|
1802
1856
|
*
|
|
1803
|
-
* The TiledImages are inserted at consecutive indices, starting `offset`
|
|
1804
|
-
* after the anchor, which
|
|
1805
|
-
* {@link _cleanRenderedObjects} expects. `offset`
|
|
1806
|
-
* not objects
|
|
1807
|
-
*
|
|
1808
|
-
*
|
|
1809
|
-
*
|
|
1810
|
-
*
|
|
1811
|
-
*
|
|
1812
|
-
*
|
|
1813
|
-
*
|
|
1814
|
-
*
|
|
1815
|
-
*
|
|
1816
|
-
*
|
|
1817
|
-
*
|
|
1818
|
-
*
|
|
1819
|
-
*
|
|
1820
|
-
*
|
|
1821
|
-
*
|
|
1822
|
-
*
|
|
1823
|
-
* meantime, or if any
|
|
1824
|
-
*
|
|
1825
|
-
*
|
|
1826
|
-
*
|
|
1827
|
-
*
|
|
1828
|
-
*
|
|
1829
|
-
*
|
|
1830
|
-
*
|
|
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.
|
|
1831
1886
|
*
|
|
1832
1887
|
* @param offset - The number of TiledImages between the anchor and the object's first new TiledImage
|
|
1833
1888
|
* @param newRef - The object reference for which to create a rendered object
|
|
@@ -1900,8 +1955,9 @@ var OpenSeadragonRendererBase = class OpenSeadragonRendererBase {
|
|
|
1900
1955
|
if (this.context.isDestroyed()) return tiledImages;
|
|
1901
1956
|
const failure = [...tileSourceResults, ...results].find((result) => result.status === "rejected");
|
|
1902
1957
|
if (signal?.aborted || failure !== void 0 || newRenderedObject.pendingDelete || this._destroyed) {
|
|
1903
|
-
|
|
1904
|
-
|
|
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)));
|
|
1905
1961
|
signal?.throwIfAborted();
|
|
1906
1962
|
if (failure !== void 0) {
|
|
1907
1963
|
console.error(`Failed to add tiled images for object with ID '${newRef.object.id}'`, failure.reason);
|
|
@@ -3987,7 +4043,6 @@ var WebGLRendererBase = class {
|
|
|
3987
4043
|
};
|
|
3988
4044
|
_model;
|
|
3989
4045
|
_lastSyncState;
|
|
3990
|
-
_hasUnreportedChanges = false;
|
|
3991
4046
|
_renderedObjects = /* @__PURE__ */ new Map();
|
|
3992
4047
|
_layerItemsInfosCache = /* @__PURE__ */ new WeakMap();
|
|
3993
4048
|
/**
|
|
@@ -4069,59 +4124,52 @@ var WebGLRendererBase = class {
|
|
|
4069
4124
|
/**
|
|
4070
4125
|
* Synchronizes the rendered objects with the current model and render options
|
|
4071
4126
|
*
|
|
4072
|
-
*
|
|
4073
|
-
* rendered objects that
|
|
4074
|
-
*
|
|
4075
|
-
*
|
|
4076
|
-
*
|
|
4077
|
-
*
|
|
4078
|
-
*
|
|
4079
|
-
*
|
|
4080
|
-
*
|
|
4081
|
-
*
|
|
4082
|
-
*
|
|
4083
|
-
*
|
|
4084
|
-
*
|
|
4085
|
-
*
|
|
4086
|
-
*
|
|
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}).
|
|
4087
4144
|
*
|
|
4088
4145
|
* @param syncContext - The inputs to synchronize with: the tables and
|
|
4089
|
-
* group-to-value maps that the objects resolve their properties from, and
|
|
4090
|
-
*
|
|
4091
|
-
*
|
|
4092
|
-
* @param options - Optional abort signal
|
|
4093
|
-
*
|
|
4094
|
-
*
|
|
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
|
|
4095
4153
|
* @throws Error if no model has been set (see {@link setModel})
|
|
4096
4154
|
*/
|
|
4097
4155
|
async synchronize(syncContext, options) {
|
|
4098
|
-
const { signal } = options ?? {};
|
|
4156
|
+
const { signal, onChange } = options ?? {};
|
|
4099
4157
|
signal?.throwIfAborted();
|
|
4100
4158
|
const syncState = this._recordSyncState();
|
|
4101
4159
|
try {
|
|
4102
|
-
const
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
});
|
|
4112
|
-
for (const { newRef, renderedObject, preparedPromise } of preparations) {
|
|
4113
|
-
const prepared = await this._settleRenderedObjectPreparation(newRef, renderedObject, preparedPromise, { signal });
|
|
4114
|
-
if (prepared === void 0) continue;
|
|
4115
|
-
if (renderedObject === void 0) this.addRenderedObject(this.createRenderedObject(newRef, prepared));
|
|
4116
|
-
else if (this.updateRenderedObject(renderedObject, prepared)) this._hasUnreportedChanges = true;
|
|
4117
|
-
}
|
|
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;
|
|
4118
4169
|
} catch (error) {
|
|
4119
4170
|
this._discardSyncState(syncState);
|
|
4120
4171
|
throw error;
|
|
4121
4172
|
}
|
|
4122
|
-
const hasUnreportedChanges = this._hasUnreportedChanges;
|
|
4123
|
-
this._hasUnreportedChanges = false;
|
|
4124
|
-
return hasUnreportedChanges;
|
|
4125
4173
|
}
|
|
4126
4174
|
/**
|
|
4127
4175
|
* Returns the state of the current model and render options that a
|
|
@@ -4201,29 +4249,31 @@ var WebGLRendererBase = class {
|
|
|
4201
4249
|
*/
|
|
4202
4250
|
getRenderOptionsSyncState() {}
|
|
4203
4251
|
/**
|
|
4204
|
-
*
|
|
4252
|
+
* Starts loading the data of all objects to be rendered on the layers of the current model
|
|
4205
4253
|
*
|
|
4206
|
-
* 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
|
|
4207
4255
|
* object assigned per item by a table column is loaded for every layer, with
|
|
4208
4256
|
* the items on each layer resolved from the table (see
|
|
4209
4257
|
* {@link _getLayerItemsInfos}). The data of an object, and of a table, is
|
|
4210
|
-
* loaded once,
|
|
4258
|
+
* loaded once, however many references share it.
|
|
4211
4259
|
*
|
|
4212
|
-
*
|
|
4213
|
-
*
|
|
4214
|
-
*
|
|
4215
|
-
*
|
|
4216
|
-
*
|
|
4217
|
-
* 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.
|
|
4218
4267
|
*
|
|
4219
4268
|
* @param syncContext - The inputs of the current synchronization: the tables
|
|
4220
|
-
* that the objects resolve their item layers from, and the loaders for
|
|
4221
|
-
*
|
|
4269
|
+
* that the objects resolve their item layers from, and the loaders for object
|
|
4270
|
+
* and table data
|
|
4222
4271
|
* @param options - Optional abort signal
|
|
4223
|
-
* @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
|
|
4224
4274
|
* @throws Error if no model has been set (see {@link setModel})
|
|
4225
4275
|
*/
|
|
4226
|
-
|
|
4276
|
+
loadObjects(syncContext, options) {
|
|
4227
4277
|
const { signal } = options ?? {};
|
|
4228
4278
|
signal?.throwIfAborted();
|
|
4229
4279
|
const model = this._model;
|
|
@@ -4232,7 +4282,7 @@ var WebGLRendererBase = class {
|
|
|
4232
4282
|
const tableDataPromises = /* @__PURE__ */ new Map();
|
|
4233
4283
|
const tableLayersPromises = /* @__PURE__ */ new Map();
|
|
4234
4284
|
const layerItemsInfosPromises = /* @__PURE__ */ new Map();
|
|
4235
|
-
const
|
|
4285
|
+
const loadings = [];
|
|
4236
4286
|
const objectIdsWithoutTable = /* @__PURE__ */ new Set();
|
|
4237
4287
|
for (const currentLayer of model.layers) for (const currentObject of model.objects) {
|
|
4238
4288
|
if (typeof currentObject.layer === "string" && currentObject.layer !== currentLayer.id) continue;
|
|
@@ -4296,67 +4346,33 @@ var WebGLRendererBase = class {
|
|
|
4296
4346
|
}
|
|
4297
4347
|
const newRefPromise = Promise.all([dataPromise, layerItemsInfosPromise]).then(([data, layerItemsInfos]) => {
|
|
4298
4348
|
signal?.throwIfAborted();
|
|
4349
|
+
let newRef;
|
|
4299
4350
|
if (layerItemsInfos !== void 0) {
|
|
4300
4351
|
const itemsInfo = layerItemsInfos.get(currentLayer.id);
|
|
4301
|
-
|
|
4352
|
+
newRef = {
|
|
4302
4353
|
layerId: currentLayer.id,
|
|
4303
4354
|
object: currentObject,
|
|
4304
4355
|
itemIds: itemsInfo?.itemIds ?? [],
|
|
4305
4356
|
itemsMask: itemsInfo?.itemsMask,
|
|
4306
4357
|
data
|
|
4307
4358
|
};
|
|
4308
|
-
}
|
|
4309
|
-
return {
|
|
4359
|
+
} else newRef = {
|
|
4310
4360
|
layerId: currentLayer.id,
|
|
4311
4361
|
object: currentObject,
|
|
4312
4362
|
itemIds: data.getIds(),
|
|
4313
4363
|
itemsMask: void 0,
|
|
4314
4364
|
data
|
|
4315
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
|
|
4316
4373
|
});
|
|
4317
|
-
newRefPromises.push(newRefPromise);
|
|
4318
|
-
}
|
|
4319
|
-
const results = await Promise.allSettled(newRefPromises);
|
|
4320
|
-
signal?.throwIfAborted();
|
|
4321
|
-
return results.filter((result) => result.status === "fulfilled").filter((result) => result.value.itemIds.length > 0).map((result) => result.value);
|
|
4322
|
-
}
|
|
4323
|
-
/**
|
|
4324
|
-
* Matches the rendered objects to a new set of references, and destroys the
|
|
4325
|
-
* ones left over
|
|
4326
|
-
*
|
|
4327
|
-
* A rendered object is matched by the layer and object it is kept under, and
|
|
4328
|
-
* kept if its contributed items and data source are those of the reference,
|
|
4329
|
-
* which it then adopts and is returned for reuse with. Every other rendered
|
|
4330
|
-
* object - one that no reference addresses, or one whose items or data source
|
|
4331
|
-
* changed - is destroyed and dropped.
|
|
4332
|
-
*
|
|
4333
|
-
* @param newRefs - The object references to match against
|
|
4334
|
-
* @returns One match per reference, in the order of the references, each with
|
|
4335
|
-
* the rendered object to reuse for it, or `undefined` if it has none yet
|
|
4336
|
-
*/
|
|
4337
|
-
matchOrDestroyRenderedObjects(newRefs) {
|
|
4338
|
-
const matchedRenderedObjects = /* @__PURE__ */ new Set();
|
|
4339
|
-
const matches = newRefs.map((newRef) => {
|
|
4340
|
-
const renderedObject = this._renderedObjects.get(newRef.layerId)?.get(newRef.object.id);
|
|
4341
|
-
if (renderedObject !== void 0 && renderedObject.ref.itemIds === newRef.itemIds && renderedObject.ref.itemsMask === newRef.itemsMask && deepEqual(renderedObject.ref.object.dataSource, newRef.object.dataSource)) {
|
|
4342
|
-
renderedObject.ref = newRef;
|
|
4343
|
-
matchedRenderedObjects.add(renderedObject);
|
|
4344
|
-
return {
|
|
4345
|
-
newRef,
|
|
4346
|
-
renderedObject
|
|
4347
|
-
};
|
|
4348
|
-
}
|
|
4349
|
-
return {
|
|
4350
|
-
newRef,
|
|
4351
|
-
renderedObject: void 0
|
|
4352
|
-
};
|
|
4353
|
-
});
|
|
4354
|
-
for (const renderedObjects of this._renderedObjects.values()) for (const [objectId, renderedObject] of renderedObjects) if (!matchedRenderedObjects.has(renderedObject)) {
|
|
4355
|
-
renderedObjects.delete(objectId);
|
|
4356
|
-
this.destroyRenderedObject(renderedObject);
|
|
4357
|
-
this._hasUnreportedChanges = true;
|
|
4358
4374
|
}
|
|
4359
|
-
return
|
|
4375
|
+
return loadings;
|
|
4360
4376
|
}
|
|
4361
4377
|
/**
|
|
4362
4378
|
* Adds a newly created rendered object under its layer and object
|
|
@@ -4371,7 +4387,6 @@ var WebGLRendererBase = class {
|
|
|
4371
4387
|
this._renderedObjects.set(layerId, renderedObjects);
|
|
4372
4388
|
}
|
|
4373
4389
|
renderedObjects.set(object.id, renderedObject);
|
|
4374
|
-
this._hasUnreportedChanges = true;
|
|
4375
4390
|
}
|
|
4376
4391
|
/**
|
|
4377
4392
|
* Drops a rendered object and releases its GPU resources
|
|
@@ -4381,7 +4396,6 @@ var WebGLRendererBase = class {
|
|
|
4381
4396
|
removeRenderedObject(renderedObject) {
|
|
4382
4397
|
this._renderedObjects.get(renderedObject.ref.layerId)?.delete(renderedObject.ref.object.id);
|
|
4383
4398
|
this.destroyRenderedObject(renderedObject);
|
|
4384
|
-
this._hasUnreportedChanges = true;
|
|
4385
4399
|
}
|
|
4386
4400
|
/**
|
|
4387
4401
|
* Drops all rendered objects and releases their GPU resources
|
|
@@ -4389,7 +4403,6 @@ var WebGLRendererBase = class {
|
|
|
4389
4403
|
clearRenderedObjects() {
|
|
4390
4404
|
for (const renderedObjects of this._renderedObjects.values()) for (const renderedObject of renderedObjects.values()) this.destroyRenderedObject(renderedObject);
|
|
4391
4405
|
this._renderedObjects.clear();
|
|
4392
|
-
this._hasUnreportedChanges = true;
|
|
4393
4406
|
}
|
|
4394
4407
|
/**
|
|
4395
4408
|
* Returns one render pass per rendered object to draw, in draw order
|
|
@@ -4535,35 +4548,90 @@ var WebGLRendererBase = class {
|
|
|
4535
4548
|
return layerItemsInfos;
|
|
4536
4549
|
}
|
|
4537
4550
|
/**
|
|
4538
|
-
*
|
|
4539
|
-
* finds nothing to render
|
|
4551
|
+
* Drops the rendered objects that none of the given loadings addresses
|
|
4540
4552
|
*
|
|
4541
|
-
*
|
|
4542
|
-
*
|
|
4543
|
-
*
|
|
4544
|
-
*
|
|
4545
|
-
*
|
|
4546
|
-
*
|
|
4547
|
-
*
|
|
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
|
|
4548
4562
|
*/
|
|
4549
|
-
|
|
4550
|
-
|
|
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
|
+
}
|
|
4551
4614
|
let prepared;
|
|
4552
4615
|
try {
|
|
4553
|
-
prepared = await
|
|
4616
|
+
prepared = await this.prepareRenderedObject(newRef, renderedObject, syncContext, { signal });
|
|
4617
|
+
signal?.throwIfAborted();
|
|
4554
4618
|
} catch (error) {
|
|
4555
4619
|
signal?.throwIfAborted();
|
|
4556
4620
|
console.error(`Failed to prepare object with ID '${newRef.object.id}'`, error);
|
|
4557
|
-
if (renderedObject !== void 0) this.removeRenderedObject(renderedObject);
|
|
4558
|
-
return;
|
|
4559
4621
|
}
|
|
4560
|
-
|
|
4561
|
-
if (prepared === null) {
|
|
4562
|
-
|
|
4563
|
-
|
|
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
|
+
}
|
|
4564
4628
|
return;
|
|
4565
4629
|
}
|
|
4566
|
-
|
|
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?.();
|
|
4567
4635
|
}
|
|
4568
4636
|
/**
|
|
4569
4637
|
* Creates the loader for the tables that an object resolves its properties
|