easy-three-utils 0.0.1
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/package.json +12 -0
- package/src/common/index.ts +24 -0
- package/src/common/useLine2.ts +87 -0
- package/src/common/useLoader.ts +184 -0
- package/src/common/useLocationCalculator.ts +145 -0
- package/src/common/useMark.ts +42 -0
- package/src/common/useTween.ts +86 -0
- package/src/core/basic/camera.ts +28 -0
- package/src/core/basic/clock.ts +11 -0
- package/src/core/basic/control.ts +32 -0
- package/src/core/basic/index.ts +35 -0
- package/src/core/basic/labelRenderer.ts +26 -0
- package/src/core/basic/light.ts +63 -0
- package/src/core/basic/renderer.ts +37 -0
- package/src/core/basic/scene.ts +11 -0
- package/src/core/basic/stats.ts +16 -0
- package/src/core/event.ts +74 -0
- package/src/core/index.ts +11 -0
- package/src/core/main.ts +389 -0
- package/src/draco/README.md +32 -0
- package/src/draco/draco_decoder.js +34 -0
- package/src/draco/draco_decoder.wasm +0 -0
- package/src/draco/draco_encoder.js +33 -0
- package/src/draco/draco_wasm_wrapper.js +117 -0
- package/src/draco/gltf/draco_decoder.js +33 -0
- package/src/draco/gltf/draco_decoder.wasm +0 -0
- package/src/draco/gltf/draco_encoder.js +33 -0
- package/src/draco/gltf/draco_wasm_wrapper.js +116 -0
- package/src/tileRenderer/base/Tile.d.ts +50 -0
- package/src/tileRenderer/base/TileBase.d.ts +76 -0
- package/src/tileRenderer/base/TileInternal.d.ts +36 -0
- package/src/tileRenderer/base/TilesRendererBase.d.ts +35 -0
- package/src/tileRenderer/base/TilesRendererBase.js +847 -0
- package/src/tileRenderer/base/Tileset.d.ts +66 -0
- package/src/tileRenderer/base/constants.d.ts +6 -0
- package/src/tileRenderer/base/constants.js +16 -0
- package/src/tileRenderer/base/loaders/B3DMLoaderBase.d.ts +18 -0
- package/src/tileRenderer/base/loaders/B3DMLoaderBase.js +85 -0
- package/src/tileRenderer/base/loaders/CMPTLoaderBase.d.ts +22 -0
- package/src/tileRenderer/base/loaders/CMPTLoaderBase.js +61 -0
- package/src/tileRenderer/base/loaders/I3DMLoaderBase.d.ts +21 -0
- package/src/tileRenderer/base/loaders/I3DMLoaderBase.js +130 -0
- package/src/tileRenderer/base/loaders/LoaderBase.d.ts +10 -0
- package/src/tileRenderer/base/loaders/LoaderBase.js +73 -0
- package/src/tileRenderer/base/loaders/PNTSLoaderBase.d.ts +17 -0
- package/src/tileRenderer/base/loaders/PNTSLoaderBase.js +82 -0
- package/src/tileRenderer/base/plugins/ImplicitTilingPlugin.js +12 -0
- package/src/tileRenderer/base/traverseFunctions.js +468 -0
- package/src/tileRenderer/gltf.js +144 -0
- package/src/tileRenderer/index.d.ts +41 -0
- package/src/tileRenderer/index.js +44 -0
- package/src/tileRenderer/plugins/README.md +578 -0
- package/src/tileRenderer/plugins/base/ImplicitTilingPlugin.d.ts +2 -0
- package/src/tileRenderer/plugins/base/ImplicitTilingPlugin.js +84 -0
- package/src/tileRenderer/plugins/base/SUBTREELoader.js +876 -0
- package/src/tileRenderer/plugins/index.d.ts +17 -0
- package/src/tileRenderer/plugins/index.js +17 -0
- package/src/tileRenderer/plugins/three/CesiumIonAuthPlugin.d.ts +9 -0
- package/src/tileRenderer/plugins/three/CesiumIonAuthPlugin.js +175 -0
- package/src/tileRenderer/plugins/three/DebugTilesPlugin.d.ts +29 -0
- package/src/tileRenderer/plugins/three/DebugTilesPlugin.js +677 -0
- package/src/tileRenderer/plugins/three/GLTFExtensionsPlugin.d.ts +18 -0
- package/src/tileRenderer/plugins/three/GLTFExtensionsPlugin.js +86 -0
- package/src/tileRenderer/plugins/three/GoogleAttributionsManager.js +62 -0
- package/src/tileRenderer/plugins/three/GoogleCloudAuthPlugin.d.ts +5 -0
- package/src/tileRenderer/plugins/three/GoogleCloudAuthPlugin.js +200 -0
- package/src/tileRenderer/plugins/three/ReorientationPlugin.d.ts +12 -0
- package/src/tileRenderer/plugins/three/ReorientationPlugin.js +136 -0
- package/src/tileRenderer/plugins/three/TileCompressionPlugin.d.ts +18 -0
- package/src/tileRenderer/plugins/three/TileCompressionPlugin.js +223 -0
- package/src/tileRenderer/plugins/three/UpdateOnChangePlugin.d.ts +5 -0
- package/src/tileRenderer/plugins/three/UpdateOnChangePlugin.js +87 -0
- package/src/tileRenderer/plugins/three/fade/FadeManager.js +370 -0
- package/src/tileRenderer/plugins/three/fade/TilesFadePlugin.d.ts +9 -0
- package/src/tileRenderer/plugins/three/fade/TilesFadePlugin.js +318 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFCesiumRTCExtension.d.ts +5 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFCesiumRTCExtension.js +27 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFMeshFeaturesExtension.d.ts +30 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFMeshFeaturesExtension.js +76 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFStructuralMetadataExtension.d.ts +49 -0
- package/src/tileRenderer/plugins/three/gltf/GLTFStructuralMetadataExtension.js +147 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/ClassProperty.js +149 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/MeshFeatures.js +215 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyAttributeAccessor.js +107 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertySetAccessor.js +45 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyTableAccessor.js +209 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyTextureAccessor.js +244 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/classes/StructuralMetadata.js +202 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/math/Matrix2.js +55 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/utilities/ClassPropertyHelpers.js +495 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/utilities/TexCoordUtilities.js +72 -0
- package/src/tileRenderer/plugins/three/gltf/metadata/utilities/TextureReadUtility.js +154 -0
- package/src/tileRenderer/plugins/three/objects/EllipsoidRegionHelper.js +186 -0
- package/src/tileRenderer/plugins/three/objects/SphereHelper.js +55 -0
- package/src/tileRenderer/r3f/README.md +238 -0
- package/src/tileRenderer/r3f/components/CameraControls.jsx +132 -0
- package/src/tileRenderer/r3f/components/CameraTransition.jsx +177 -0
- package/src/tileRenderer/r3f/components/CanvasDOMOverlay.jsx +54 -0
- package/src/tileRenderer/r3f/components/CompassGizmo.jsx +260 -0
- package/src/tileRenderer/r3f/components/TilesAttributionOverlay.jsx +110 -0
- package/src/tileRenderer/r3f/components/TilesRenderer.jsx +239 -0
- package/src/tileRenderer/r3f/index.jsx +6 -0
- package/src/tileRenderer/r3f/utilities/useForceUpdate.jsx +8 -0
- package/src/tileRenderer/r3f/utilities/useObjectDep.jsx +59 -0
- package/src/tileRenderer/r3f/utilities/useOptions.jsx +143 -0
- package/src/tileRenderer/three/DebugTilesRenderer.d.ts +28 -0
- package/src/tileRenderer/three/DebugTilesRenderer.js +58 -0
- package/src/tileRenderer/three/TilesGroup.d.ts +9 -0
- package/src/tileRenderer/three/TilesGroup.js +91 -0
- package/src/tileRenderer/three/TilesRenderer.d.ts +37 -0
- package/src/tileRenderer/three/TilesRenderer.js +1049 -0
- package/src/tileRenderer/three/controls/CameraTransitionManager.js +305 -0
- package/src/tileRenderer/three/controls/EnvironmentControls.js +1295 -0
- package/src/tileRenderer/three/controls/GlobeControls.js +684 -0
- package/src/tileRenderer/three/controls/PivotPointMesh.js +104 -0
- package/src/tileRenderer/three/controls/PointerTracker.js +257 -0
- package/src/tileRenderer/three/controls/utils.js +113 -0
- package/src/tileRenderer/three/loaders/B3DMLoader.d.ts +26 -0
- package/src/tileRenderer/three/loaders/B3DMLoader.js +85 -0
- package/src/tileRenderer/three/loaders/CMPTLoader.d.ts +19 -0
- package/src/tileRenderer/three/loaders/CMPTLoader.js +97 -0
- package/src/tileRenderer/three/loaders/GLTFExtensionLoader.d.ts +11 -0
- package/src/tileRenderer/three/loaders/GLTFExtensionLoader.js +68 -0
- package/src/tileRenderer/three/loaders/I3DMLoader.d.ts +26 -0
- package/src/tileRenderer/three/loaders/I3DMLoader.js +256 -0
- package/src/tileRenderer/three/loaders/PNTSLoader.d.ts +25 -0
- package/src/tileRenderer/three/loaders/PNTSLoader.js +202 -0
- package/src/tileRenderer/three/loaders/gltf/GLTFCesiumRTCExtension.js +12 -0
- package/src/tileRenderer/three/loaders/gltf/GLTFMeshFeaturesExtension.js +12 -0
- package/src/tileRenderer/three/loaders/gltf/GLTFStructuralMetadataExtension.js +12 -0
- package/src/tileRenderer/three/math/Ellipsoid.d.ts +31 -0
- package/src/tileRenderer/three/math/Ellipsoid.js +337 -0
- package/src/tileRenderer/three/math/EllipsoidRegion.d.ts +23 -0
- package/src/tileRenderer/three/math/EllipsoidRegion.js +178 -0
- package/src/tileRenderer/three/math/ExtendedFrustum.js +65 -0
- package/src/tileRenderer/three/math/GeoConstants.d.ts +4 -0
- package/src/tileRenderer/three/math/GeoConstants.js +5 -0
- package/src/tileRenderer/three/math/GeoUtils.d.ts +9 -0
- package/src/tileRenderer/three/math/GeoUtils.js +106 -0
- package/src/tileRenderer/three/math/OBB.js +179 -0
- package/src/tileRenderer/three/math/TileBoundingVolume.js +272 -0
- package/src/tileRenderer/three/plugins/CesiumIonAuthPlugin.js +12 -0
- package/src/tileRenderer/three/plugins/DebugTilesPlugin.js +26 -0
- package/src/tileRenderer/three/plugins/GoogleCloudAuthPlugin.js +12 -0
- package/src/tileRenderer/three/raycastTraverse.js +178 -0
- package/src/tileRenderer/three/renderers/CesiumIonTilesRenderer.d.ts +14 -0
- package/src/tileRenderer/three/renderers/CesiumIonTilesRenderer.js +21 -0
- package/src/tileRenderer/three/renderers/GoogleTilesRenderer.d.ts +43 -0
- package/src/tileRenderer/three/renderers/GoogleTilesRenderer.js +48 -0
- package/src/tileRenderer/three/utilities.js +54 -0
- package/src/tileRenderer/utilities/BatchTable.d.ts +24 -0
- package/src/tileRenderer/utilities/BatchTable.js +82 -0
- package/src/tileRenderer/utilities/BatchTableHierarchyExtension.js +127 -0
- package/src/tileRenderer/utilities/FeatureTable.d.ts +30 -0
- package/src/tileRenderer/utilities/FeatureTable.js +159 -0
- package/src/tileRenderer/utilities/LRUCache.d.ts +8 -0
- package/src/tileRenderer/utilities/LRUCache.js +385 -0
- package/src/tileRenderer/utilities/PriorityQueue.d.ts +16 -0
- package/src/tileRenderer/utilities/PriorityQueue.js +137 -0
- package/src/tileRenderer/utilities/arrayToString.js +7 -0
- package/src/tileRenderer/utilities/readMagicBytes.js +29 -0
- package/src/tileRenderer/utilities/rgb565torgb.js +22 -0
- package/src/tileRenderer/utilities/urlExtension.js +34 -0
- package/tsconfig.json +42 -0
- package/tsconfig.node.json +11 -0
- package/typings/three.d.ts +27 -0
|
@@ -0,0 +1,847 @@
|
|
|
1
|
+
import { getUrlExtension } from '../utilities/urlExtension.js';
|
|
2
|
+
import { LRUCache } from '../utilities/LRUCache.js';
|
|
3
|
+
import { PriorityQueue } from '../utilities/PriorityQueue.js';
|
|
4
|
+
import { markUsedTiles, toggleTiles, markVisibleTiles, markUsedSetLeaves, traverseSet } from './traverseFunctions.js';
|
|
5
|
+
import { UNLOADED, LOADING, PARSING, LOADED, FAILED } from './constants.js';
|
|
6
|
+
|
|
7
|
+
const PLUGIN_REGISTERED = Symbol('PLUGIN_REGISTERED');
|
|
8
|
+
|
|
9
|
+
// priority queue sort function that takes two tiles to compare. Returning 1 means
|
|
10
|
+
// "tile a" is loaded first.
|
|
11
|
+
const priorityCallback = (a, b) => {
|
|
12
|
+
|
|
13
|
+
if (a.__depthFromRenderedParent !== b.__depthFromRenderedParent) {
|
|
14
|
+
|
|
15
|
+
// load shallower tiles first using "depth from rendered parent" to help
|
|
16
|
+
// even out depth disparities caused by non-content parent tiles
|
|
17
|
+
return a.__depthFromRenderedParent > b.__depthFromRenderedParent ? - 1 : 1;
|
|
18
|
+
|
|
19
|
+
} else if (a.__inFrustum !== b.__inFrustum) {
|
|
20
|
+
|
|
21
|
+
// load tiles that are in the frustum at the current depth
|
|
22
|
+
return a.__inFrustum ? 1 : - 1;
|
|
23
|
+
|
|
24
|
+
} else if (a.__used !== b.__used) {
|
|
25
|
+
|
|
26
|
+
// load tiles that have been used
|
|
27
|
+
return a.__used ? 1 : - 1;
|
|
28
|
+
|
|
29
|
+
} else if (a.__error !== b.__error) {
|
|
30
|
+
|
|
31
|
+
// load the tile with the higher error
|
|
32
|
+
return a.__error > b.__error ? 1 : - 1;
|
|
33
|
+
|
|
34
|
+
} else if (a.__distanceFromCamera !== b.__distanceFromCamera) {
|
|
35
|
+
|
|
36
|
+
// and finally visible tiles which have equal error (ex: if geometricError === 0)
|
|
37
|
+
// should prioritize based on distance.
|
|
38
|
+
return a.__distanceFromCamera > b.__distanceFromCamera ? - 1 : 1;
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return 0;
|
|
43
|
+
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// lru cache unload callback that takes two tiles to compare. Returning 1 means "tile a"
|
|
47
|
+
// is unloaded first.
|
|
48
|
+
const lruPriorityCallback = (a, b) => {
|
|
49
|
+
|
|
50
|
+
if (a.__depthFromRenderedParent !== b.__depthFromRenderedParent) {
|
|
51
|
+
|
|
52
|
+
// dispose of deeper tiles first
|
|
53
|
+
return a.__depthFromRenderedParent > b.__depthFromRenderedParent ? 1 : - 1;
|
|
54
|
+
|
|
55
|
+
} else if (a.__loadingState !== b.__loadingState) {
|
|
56
|
+
|
|
57
|
+
// dispose of tiles that are earlier along in the loading process first
|
|
58
|
+
return a.__loadingState > b.__loadingState ? - 1 : 1;
|
|
59
|
+
|
|
60
|
+
} else if (a.__lastFrameVisited !== b.__lastFrameVisited) {
|
|
61
|
+
|
|
62
|
+
// dispose of least recent tiles first
|
|
63
|
+
return a.__lastFrameVisited > b.__lastFrameVisited ? - 1 : 1;
|
|
64
|
+
|
|
65
|
+
} else if (a.__hasUnrenderableContent !== b.__hasUnrenderableContent) {
|
|
66
|
+
|
|
67
|
+
// dispose of external tile sets last
|
|
68
|
+
return a.__hasUnrenderableContent ? - 1 : 1;
|
|
69
|
+
|
|
70
|
+
} else if (a.__error !== b.__error) {
|
|
71
|
+
|
|
72
|
+
// unload the tile with lower error
|
|
73
|
+
return a.__error > b.__error ? - 1 : 1;
|
|
74
|
+
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return 0;
|
|
78
|
+
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export class TilesRendererBase {
|
|
82
|
+
|
|
83
|
+
get root() {
|
|
84
|
+
|
|
85
|
+
const tileSet = this.rootTileSet;
|
|
86
|
+
return tileSet ? tileSet.root : null;
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
set loadSiblings(v) {
|
|
91
|
+
|
|
92
|
+
console.warn('TilesRenderer: "loadSiblings" option has been removed.');
|
|
93
|
+
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
set stopAtEmptyTiles(v) {
|
|
97
|
+
|
|
98
|
+
console.warn('TilesRenderer: "stopAtEmptyTiles" option has been removed.');
|
|
99
|
+
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
set preprocessURL(v) {
|
|
103
|
+
|
|
104
|
+
console.warn('TilesRendererBase: The "preprocessURL" callback has been deprecated. Use a plugin, instead.');
|
|
105
|
+
this._preprocessURL = v;
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
get preprocessURL() {
|
|
110
|
+
|
|
111
|
+
return this._preprocessURL;
|
|
112
|
+
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
constructor(url = null) {
|
|
116
|
+
// state
|
|
117
|
+
this.rootLoadingState = UNLOADED;
|
|
118
|
+
this.rootTileSet = null;
|
|
119
|
+
this.rootURL = url;
|
|
120
|
+
this.fetchOptions = {};
|
|
121
|
+
this.plugins = [];
|
|
122
|
+
this.queuedTiles = [];
|
|
123
|
+
|
|
124
|
+
this._preprocessURL = null;
|
|
125
|
+
|
|
126
|
+
const lruCache = new LRUCache();
|
|
127
|
+
lruCache.unloadPriorityCallback = lruPriorityCallback;
|
|
128
|
+
|
|
129
|
+
const downloadQueue = new PriorityQueue();
|
|
130
|
+
downloadQueue.maxJobs = 10;
|
|
131
|
+
downloadQueue.priorityCallback = priorityCallback;
|
|
132
|
+
|
|
133
|
+
const parseQueue = new PriorityQueue();
|
|
134
|
+
parseQueue.maxJobs = 1;
|
|
135
|
+
parseQueue.priorityCallback = priorityCallback;
|
|
136
|
+
|
|
137
|
+
this.lruCache = lruCache;
|
|
138
|
+
this.downloadQueue = downloadQueue;
|
|
139
|
+
this.parseQueue = parseQueue;
|
|
140
|
+
this.stats = {
|
|
141
|
+
parsing: 0,
|
|
142
|
+
downloading: 0,
|
|
143
|
+
failed: 0,
|
|
144
|
+
inFrustum: 0,
|
|
145
|
+
used: 0,
|
|
146
|
+
active: 0,
|
|
147
|
+
visible: 0,
|
|
148
|
+
};
|
|
149
|
+
this.frameCount = 0;
|
|
150
|
+
|
|
151
|
+
// options
|
|
152
|
+
this.errorTarget = 6.0;
|
|
153
|
+
this.errorThreshold = Infinity;
|
|
154
|
+
this.displayActiveTiles = false;
|
|
155
|
+
this.maxDepth = Infinity;
|
|
156
|
+
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Plugins
|
|
160
|
+
registerPlugin(plugin) {
|
|
161
|
+
|
|
162
|
+
if (plugin[PLUGIN_REGISTERED] === true) {
|
|
163
|
+
|
|
164
|
+
throw new Error('TilesRendererBase: A plugin can only be registered to a single tile set');
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
this.plugins.push(plugin);
|
|
169
|
+
plugin[PLUGIN_REGISTERED] = true;
|
|
170
|
+
if (plugin.init) {
|
|
171
|
+
|
|
172
|
+
plugin.init(this);
|
|
173
|
+
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
unregisterPlugin(plugin) {
|
|
179
|
+
|
|
180
|
+
const plugins = this.plugins;
|
|
181
|
+
if (typeof plugin === 'string') {
|
|
182
|
+
|
|
183
|
+
plugin = this.getPluginByName(name);
|
|
184
|
+
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (plugins.includes(plugin)) {
|
|
188
|
+
|
|
189
|
+
const index = plugins.indexOf(plugin);
|
|
190
|
+
plugins.splice(index, 1);
|
|
191
|
+
if (plugin.dispose) {
|
|
192
|
+
|
|
193
|
+
plugin.dispose();
|
|
194
|
+
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return true;
|
|
198
|
+
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return false;
|
|
202
|
+
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
getPluginByName(name) {
|
|
206
|
+
|
|
207
|
+
return this.plugins.find(p => p.name === name) || null;
|
|
208
|
+
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
traverse(beforecb, aftercb) {
|
|
212
|
+
|
|
213
|
+
if (!this.root) return;
|
|
214
|
+
|
|
215
|
+
traverseSet(this.root, (tile, ...args) => {
|
|
216
|
+
|
|
217
|
+
this.ensureChildrenArePreprocessed(tile);
|
|
218
|
+
return beforecb ? beforecb(tile, ...args) : false;
|
|
219
|
+
|
|
220
|
+
}, aftercb);
|
|
221
|
+
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
queueTileForDownload(tile) {
|
|
225
|
+
|
|
226
|
+
this.queuedTiles.push(tile);
|
|
227
|
+
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Public API
|
|
231
|
+
update() {
|
|
232
|
+
|
|
233
|
+
const stats = this.stats;
|
|
234
|
+
const lruCache = this.lruCache;
|
|
235
|
+
if (this.rootLoadingState === UNLOADED) {
|
|
236
|
+
|
|
237
|
+
this.rootLoadingState = LOADING;
|
|
238
|
+
this.invokeOnePlugin(plugin => plugin.loadRootTileSet && plugin.loadRootTileSet())
|
|
239
|
+
.then(() => this.rootLoadingState = LOADED)
|
|
240
|
+
.catch(() => this.rootLoadingState = FAILED);
|
|
241
|
+
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (!this.root) {
|
|
245
|
+
|
|
246
|
+
return;
|
|
247
|
+
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const root = this.root;
|
|
251
|
+
|
|
252
|
+
stats.inFrustum = 0;
|
|
253
|
+
stats.used = 0;
|
|
254
|
+
stats.active = 0;
|
|
255
|
+
stats.visible = 0;
|
|
256
|
+
this.frameCount++;
|
|
257
|
+
|
|
258
|
+
markUsedTiles(root, this);
|
|
259
|
+
markUsedSetLeaves(root, this);
|
|
260
|
+
markVisibleTiles(root, this);
|
|
261
|
+
toggleTiles(root, this);
|
|
262
|
+
|
|
263
|
+
// TODO: This will only sort for one tile set. We may want to store this queue on the
|
|
264
|
+
// LRUCache so multiple tile sets can use it at once
|
|
265
|
+
// start the downloads of the tiles as needed
|
|
266
|
+
const queuedTiles = this.queuedTiles;
|
|
267
|
+
queuedTiles.sort(lruCache.unloadPriorityCallback);
|
|
268
|
+
|
|
269
|
+
for (let i = 0, l = queuedTiles.length; i < l && !lruCache.isFull(); i++) {
|
|
270
|
+
|
|
271
|
+
this.requestTileContents(queuedTiles[i]);
|
|
272
|
+
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
queuedTiles.length = 0;
|
|
276
|
+
|
|
277
|
+
// start the downloads
|
|
278
|
+
lruCache.scheduleUnload();
|
|
279
|
+
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
resetFailedTiles() {
|
|
283
|
+
|
|
284
|
+
// reset the root tile if it's finished but never loaded
|
|
285
|
+
if (this.rootLoadingState === FAILED) {
|
|
286
|
+
|
|
287
|
+
this.rootLoadingState = UNLOADED;
|
|
288
|
+
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const stats = this.stats;
|
|
292
|
+
if (stats.failed === 0) {
|
|
293
|
+
|
|
294
|
+
return;
|
|
295
|
+
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
this.traverse(tile => {
|
|
299
|
+
|
|
300
|
+
if (tile.__loadingState === FAILED) {
|
|
301
|
+
|
|
302
|
+
tile.__loadingState = UNLOADED;
|
|
303
|
+
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
stats.failed = 0;
|
|
309
|
+
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
dispose() {
|
|
313
|
+
|
|
314
|
+
// dispose of all the plugins
|
|
315
|
+
this.invokeAllPlugins(plugin => {
|
|
316
|
+
|
|
317
|
+
plugin !== this && plugin.dispose && plugin.dispose();
|
|
318
|
+
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
const lruCache = this.lruCache;
|
|
322
|
+
|
|
323
|
+
// Make sure we've collected all children before disposing of the internal tilesets to avoid
|
|
324
|
+
// dangling children that we inadvertantly skip when deleting the nested tileset.
|
|
325
|
+
const toRemove = [];
|
|
326
|
+
this.traverse(t => {
|
|
327
|
+
|
|
328
|
+
toRemove.push(t);
|
|
329
|
+
return false;
|
|
330
|
+
|
|
331
|
+
});
|
|
332
|
+
for (let i = 0, l = toRemove.length; i < l; i++) {
|
|
333
|
+
|
|
334
|
+
lruCache.remove(toRemove[i]);
|
|
335
|
+
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
this.stats = {
|
|
339
|
+
parsing: 0,
|
|
340
|
+
downloading: 0,
|
|
341
|
+
failed: 0,
|
|
342
|
+
inFrustum: 0,
|
|
343
|
+
used: 0,
|
|
344
|
+
active: 0,
|
|
345
|
+
visible: 0,
|
|
346
|
+
};
|
|
347
|
+
this.frameCount = 0;
|
|
348
|
+
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Overrideable
|
|
352
|
+
fetchData(url, options) {
|
|
353
|
+
|
|
354
|
+
return fetch(url, options);
|
|
355
|
+
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
parseTile(buffer, tile, extension) {
|
|
359
|
+
|
|
360
|
+
return null;
|
|
361
|
+
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
disposeTile(tile) {
|
|
365
|
+
|
|
366
|
+
if (tile.__visible) {
|
|
367
|
+
|
|
368
|
+
this.setTileVisible(tile, false);
|
|
369
|
+
tile.__visible = false;
|
|
370
|
+
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (tile.__active) {
|
|
374
|
+
|
|
375
|
+
this.setTileActive(tile, false);
|
|
376
|
+
tile.__active = false;
|
|
377
|
+
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
preprocessNode(tile, tileSetDir, parentTile = null) {
|
|
383
|
+
|
|
384
|
+
if (tile.content) {
|
|
385
|
+
// Fix old file formats
|
|
386
|
+
if (!('uri' in tile.content) && 'url' in tile.content) {
|
|
387
|
+
tile.content.uri = tile.content.url;
|
|
388
|
+
delete tile.content.url;
|
|
389
|
+
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// NOTE: fix for some cases where tilesets provide the bounding volume
|
|
393
|
+
// but volumes are not present.
|
|
394
|
+
if (
|
|
395
|
+
tile.content.boundingVolume &&
|
|
396
|
+
!(
|
|
397
|
+
'box' in tile.content.boundingVolume ||
|
|
398
|
+
'sphere' in tile.content.boundingVolume ||
|
|
399
|
+
'region' in tile.content.boundingVolume
|
|
400
|
+
)
|
|
401
|
+
) {
|
|
402
|
+
delete tile.content.boundingVolume;
|
|
403
|
+
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
tile.parent = parentTile;
|
|
409
|
+
tile.children = tile.children || [];
|
|
410
|
+
|
|
411
|
+
if (tile.content?.uri) {
|
|
412
|
+
|
|
413
|
+
// "content" should only indicate loadable meshes, not external tile sets
|
|
414
|
+
const extension = getUrlExtension(tile.content.uri);
|
|
415
|
+
|
|
416
|
+
tile.__hasContent = true;
|
|
417
|
+
tile.__hasUnrenderableContent = Boolean(extension && /json$/.test(extension));
|
|
418
|
+
tile.__hasRenderableContent = !tile.__hasUnrenderableContent;
|
|
419
|
+
|
|
420
|
+
} else {
|
|
421
|
+
|
|
422
|
+
tile.__hasContent = false;
|
|
423
|
+
tile.__hasUnrenderableContent = false;
|
|
424
|
+
tile.__hasRenderableContent = false;
|
|
425
|
+
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Expected to be set during calculateError()
|
|
429
|
+
tile.__distanceFromCamera = Infinity;
|
|
430
|
+
tile.__error = Infinity;
|
|
431
|
+
|
|
432
|
+
tile.__inFrustum = false;
|
|
433
|
+
tile.__isLeaf = false;
|
|
434
|
+
|
|
435
|
+
tile.__usedLastFrame = false;
|
|
436
|
+
tile.__used = false;
|
|
437
|
+
|
|
438
|
+
tile.__wasSetVisible = false;
|
|
439
|
+
tile.__visible = false;
|
|
440
|
+
tile.__childrenWereVisible = false;
|
|
441
|
+
tile.__allChildrenLoaded = false;
|
|
442
|
+
|
|
443
|
+
tile.__wasSetActive = false;
|
|
444
|
+
tile.__active = false;
|
|
445
|
+
|
|
446
|
+
tile.__loadingState = UNLOADED;
|
|
447
|
+
tile.__loadIndex = 0;
|
|
448
|
+
|
|
449
|
+
tile.__loadAbort = null;
|
|
450
|
+
|
|
451
|
+
if (parentTile === null) {
|
|
452
|
+
|
|
453
|
+
tile.__depth = 0;
|
|
454
|
+
tile.__depthFromRenderedParent = 0;
|
|
455
|
+
tile.refine = tile.refine || 'REPLACE';
|
|
456
|
+
|
|
457
|
+
} else {
|
|
458
|
+
|
|
459
|
+
// increment the "depth from parent" when we encounter a new tile with content
|
|
460
|
+
tile.__depth = parentTile.__depth + 1;
|
|
461
|
+
tile.__depthFromRenderedParent = parentTile.__depthFromRenderedParent + (tile.__hasRenderableContent ? 1 : 0);
|
|
462
|
+
|
|
463
|
+
tile.refine = tile.refine || parentTile.refine;
|
|
464
|
+
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
tile.__basePath = tileSetDir;
|
|
468
|
+
|
|
469
|
+
tile.__lastFrameVisited = - 1;
|
|
470
|
+
|
|
471
|
+
this.invokeAllPlugins(plugin => {
|
|
472
|
+
|
|
473
|
+
plugin !== this && plugin.preprocessNode && plugin.preprocessNode(tile, tileSetDir, parentTile);
|
|
474
|
+
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
setTileActive(tile, state) {
|
|
480
|
+
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
setTileVisible(tile, state) {
|
|
484
|
+
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
calculateError(tile) {
|
|
488
|
+
|
|
489
|
+
return 0;
|
|
490
|
+
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
tileInView(tile) {
|
|
494
|
+
|
|
495
|
+
return true;
|
|
496
|
+
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
ensureChildrenArePreprocessed(tile) {
|
|
500
|
+
|
|
501
|
+
const children = tile.children;
|
|
502
|
+
for (let i = 0, l = children.length; i < l; i++) {
|
|
503
|
+
|
|
504
|
+
const child = children[i];
|
|
505
|
+
if ('__depth' in child) {
|
|
506
|
+
|
|
507
|
+
break;
|
|
508
|
+
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
this.preprocessNode(child, tile.__basePath, tile);
|
|
512
|
+
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Private Functions
|
|
518
|
+
preprocessTileSet(json, url, parent = null) {
|
|
519
|
+
|
|
520
|
+
const version = json.asset.version;
|
|
521
|
+
const [major, minor] = version.split('.').map(v => parseInt(v));
|
|
522
|
+
console.assert(
|
|
523
|
+
major <= 1,
|
|
524
|
+
'TilesRenderer: asset.version is expected to be a 1.x or a compatible version.',
|
|
525
|
+
);
|
|
526
|
+
|
|
527
|
+
if (major === 1 && minor > 0) {
|
|
528
|
+
|
|
529
|
+
console.warn('TilesRenderer: tiles versions at 1.1 or higher have limited support. Some new extensions and features may not be supported.');
|
|
530
|
+
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// remove trailing slash and last path-segment from the URL
|
|
534
|
+
let basePath = url.replace(/\/[^/]*\/?$/, '');
|
|
535
|
+
basePath = new URL(basePath, window.location.href).toString();
|
|
536
|
+
this.preprocessNode(json.root, basePath, parent);
|
|
537
|
+
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
loadRootTileSet() {
|
|
541
|
+
|
|
542
|
+
// transform the url
|
|
543
|
+
let processedUrl = this.rootURL;
|
|
544
|
+
this.invokeAllPlugins(plugin => processedUrl = plugin.preprocessURL ? plugin.preprocessURL(processedUrl, null) : processedUrl);
|
|
545
|
+
|
|
546
|
+
// load the tile set root
|
|
547
|
+
const pr = this
|
|
548
|
+
.invokeOnePlugin(plugin => plugin.fetchData && plugin.fetchData(processedUrl, this.fetchOptions))
|
|
549
|
+
.then(res => {
|
|
550
|
+
|
|
551
|
+
if (res.ok) {
|
|
552
|
+
|
|
553
|
+
return res.json();
|
|
554
|
+
|
|
555
|
+
} else {
|
|
556
|
+
|
|
557
|
+
throw new Error(`TilesRenderer: Failed to load tileset "${processedUrl}" with status ${res.status} : ${res.statusText}`);
|
|
558
|
+
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
})
|
|
562
|
+
.then(json => {
|
|
563
|
+
|
|
564
|
+
this.preprocessTileSet(json, processedUrl);
|
|
565
|
+
this.rootTileSet = json;
|
|
566
|
+
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
pr.catch(err => {
|
|
570
|
+
|
|
571
|
+
console.error(err);
|
|
572
|
+
this.rootTileSet = null;
|
|
573
|
+
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
return pr;
|
|
577
|
+
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
requestTileContents(tile) {
|
|
581
|
+
// If the tile is already being loaded then don't
|
|
582
|
+
// start it again.
|
|
583
|
+
if (tile.__loadingState !== UNLOADED) {
|
|
584
|
+
|
|
585
|
+
return;
|
|
586
|
+
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
let isExternalTileSet = false;
|
|
590
|
+
let uri = new URL(tile.content.uri, tile.__basePath + '/').toString();
|
|
591
|
+
this.invokeAllPlugins(plugin => uri = plugin.preprocessURL ? plugin.preprocessURL(uri, tile) : uri);
|
|
592
|
+
|
|
593
|
+
const stats = this.stats;
|
|
594
|
+
const lruCache = this.lruCache;
|
|
595
|
+
const downloadQueue = this.downloadQueue;
|
|
596
|
+
const parseQueue = this.parseQueue;
|
|
597
|
+
const extension = getUrlExtension(uri);
|
|
598
|
+
const addedSuccessfully = lruCache.add(tile, t => {
|
|
599
|
+
|
|
600
|
+
// Stop the load if it's started
|
|
601
|
+
if (t.__loadingState === LOADING) {
|
|
602
|
+
|
|
603
|
+
t.__loadAbort.abort();
|
|
604
|
+
t.__loadAbort = null;
|
|
605
|
+
|
|
606
|
+
} else if (isExternalTileSet) {
|
|
607
|
+
|
|
608
|
+
t.children.length = 0;
|
|
609
|
+
|
|
610
|
+
} else {
|
|
611
|
+
|
|
612
|
+
this.invokeAllPlugins(plugin => {
|
|
613
|
+
|
|
614
|
+
plugin.disposeTile && plugin.disposeTile(t);
|
|
615
|
+
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// Decrement stats
|
|
621
|
+
if (t.__loadingState === LOADING) {
|
|
622
|
+
|
|
623
|
+
stats.downloading--;
|
|
624
|
+
|
|
625
|
+
} else if (t.__loadingState === PARSING) {
|
|
626
|
+
|
|
627
|
+
stats.parsing--;
|
|
628
|
+
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
t.__loadingState = UNLOADED;
|
|
632
|
+
t.__loadIndex++;
|
|
633
|
+
|
|
634
|
+
parseQueue.remove(t);
|
|
635
|
+
downloadQueue.remove(t);
|
|
636
|
+
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
// if we couldn't add the tile to the lru cache because it's full then skip
|
|
640
|
+
if (!addedSuccessfully) {
|
|
641
|
+
|
|
642
|
+
return;
|
|
643
|
+
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// Track a new load index so we avoid the condition where this load is stopped and
|
|
647
|
+
// another begins soon after so we don't parse twice.
|
|
648
|
+
tile.__loadIndex++;
|
|
649
|
+
const loadIndex = tile.__loadIndex;
|
|
650
|
+
const controller = new AbortController();
|
|
651
|
+
const signal = controller.signal;
|
|
652
|
+
|
|
653
|
+
stats.downloading++;
|
|
654
|
+
tile.__loadAbort = controller;
|
|
655
|
+
tile.__loadingState = LOADING;
|
|
656
|
+
|
|
657
|
+
const errorCallback = e => {
|
|
658
|
+
|
|
659
|
+
// if it has been unloaded then the tile has been disposed
|
|
660
|
+
if (tile.__loadIndex !== loadIndex) {
|
|
661
|
+
|
|
662
|
+
return;
|
|
663
|
+
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
if (e.name !== 'AbortError') {
|
|
667
|
+
|
|
668
|
+
parseQueue.remove(tile);
|
|
669
|
+
downloadQueue.remove(tile);
|
|
670
|
+
|
|
671
|
+
if (tile.__loadingState === PARSING) {
|
|
672
|
+
|
|
673
|
+
stats.parsing--;
|
|
674
|
+
|
|
675
|
+
} else if (tile.__loadingState === LOADING) {
|
|
676
|
+
|
|
677
|
+
stats.downloading--;
|
|
678
|
+
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
stats.failed++;
|
|
682
|
+
|
|
683
|
+
console.error(`TilesRenderer : Failed to load tile at url "${tile.content.uri}".`);
|
|
684
|
+
console.error(e);
|
|
685
|
+
tile.__loadingState = FAILED;
|
|
686
|
+
lruCache.setLoaded(tile, true);
|
|
687
|
+
|
|
688
|
+
} else {
|
|
689
|
+
|
|
690
|
+
lruCache.remove(tile);
|
|
691
|
+
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
// queue the download and parse
|
|
697
|
+
return downloadQueue.add(tile, downloadTile => {
|
|
698
|
+
|
|
699
|
+
if (downloadTile.__loadIndex !== loadIndex) {
|
|
700
|
+
|
|
701
|
+
return Promise.resolve();
|
|
702
|
+
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
return this.invokeOnePlugin(plugin => plugin.fetchData && plugin.fetchData(uri, { ...this.fetchOptions, signal }));
|
|
706
|
+
|
|
707
|
+
})
|
|
708
|
+
.then(res => {
|
|
709
|
+
|
|
710
|
+
if (tile.__loadIndex !== loadIndex) {
|
|
711
|
+
|
|
712
|
+
return;
|
|
713
|
+
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
if (res.ok) {
|
|
717
|
+
|
|
718
|
+
return extension === 'json' ? res.json() : res.arrayBuffer();
|
|
719
|
+
|
|
720
|
+
} else {
|
|
721
|
+
|
|
722
|
+
throw new Error(`Failed to load model with error code ${res.status}`);
|
|
723
|
+
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
})
|
|
727
|
+
.then(content => {
|
|
728
|
+
|
|
729
|
+
// if it has been unloaded then the tile has been disposed
|
|
730
|
+
if (tile.__loadIndex !== loadIndex) {
|
|
731
|
+
|
|
732
|
+
return;
|
|
733
|
+
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
stats.downloading--;
|
|
737
|
+
stats.parsing++;
|
|
738
|
+
tile.__loadAbort = null;
|
|
739
|
+
tile.__loadingState = PARSING;
|
|
740
|
+
|
|
741
|
+
return parseQueue.add(tile, parseTile => {
|
|
742
|
+
|
|
743
|
+
// if it has been unloaded then the tile has been disposed
|
|
744
|
+
if (parseTile.__loadIndex !== loadIndex) {
|
|
745
|
+
|
|
746
|
+
return Promise.resolve();
|
|
747
|
+
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
if (extension === 'json' && content.root) {
|
|
751
|
+
|
|
752
|
+
this.preprocessTileSet(content, uri, tile);
|
|
753
|
+
tile.children.push(content.root);
|
|
754
|
+
isExternalTileSet = true;
|
|
755
|
+
return Promise.resolve();
|
|
756
|
+
|
|
757
|
+
} else {
|
|
758
|
+
|
|
759
|
+
return this.invokeOnePlugin(plugin => plugin.parseTile && plugin.parseTile(content, parseTile, extension, uri));
|
|
760
|
+
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
})
|
|
766
|
+
.then(() => {
|
|
767
|
+
|
|
768
|
+
// if it has been unloaded then the tile has been disposed
|
|
769
|
+
if (tile.__loadIndex !== loadIndex) {
|
|
770
|
+
|
|
771
|
+
return;
|
|
772
|
+
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
stats.parsing--;
|
|
776
|
+
tile.__loadingState = LOADED;
|
|
777
|
+
lruCache.setLoaded(tile, true);
|
|
778
|
+
|
|
779
|
+
// If the memory of the item hasn't been registered yet then that means the memory usage hasn't
|
|
780
|
+
// been accounted for by the cache yet so we need to check if it fits or if we should remove it.
|
|
781
|
+
if (lruCache.getMemoryUsage(tile) === null) {
|
|
782
|
+
|
|
783
|
+
if (lruCache.isFull() && lruCache.computeMemoryUsageCallback(tile) > 0) {
|
|
784
|
+
|
|
785
|
+
// And if the cache is full due to newly loaded memory then lets discard this tile - it will
|
|
786
|
+
// be loaded again later from the disk cache if needed.
|
|
787
|
+
lruCache.remove(tile);
|
|
788
|
+
|
|
789
|
+
} else {
|
|
790
|
+
|
|
791
|
+
// Otherwise update the item to the latest known value
|
|
792
|
+
lruCache.updateMemoryUsage(tile);
|
|
793
|
+
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
})
|
|
799
|
+
.catch(errorCallback);
|
|
800
|
+
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
getAttributions(target = []) {
|
|
804
|
+
|
|
805
|
+
this.invokeAllPlugins(plugin => plugin !== this && plugin.getAttributions && plugin.getAttributions(target));
|
|
806
|
+
return target;
|
|
807
|
+
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
invokeOnePlugin(func) {
|
|
811
|
+
|
|
812
|
+
const plugins = [...this.plugins, this];
|
|
813
|
+
for (let i = 0; i < plugins.length; i++) {
|
|
814
|
+
|
|
815
|
+
const result = func(plugins[i]);
|
|
816
|
+
if (result) {
|
|
817
|
+
|
|
818
|
+
return result;
|
|
819
|
+
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
return null;
|
|
825
|
+
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
invokeAllPlugins(func) {
|
|
829
|
+
|
|
830
|
+
const plugins = [...this.plugins, this];
|
|
831
|
+
const pending = [];
|
|
832
|
+
for (let i = 0; i < plugins.length; i++) {
|
|
833
|
+
|
|
834
|
+
const result = func(plugins[i]);
|
|
835
|
+
if (result) {
|
|
836
|
+
|
|
837
|
+
pending.push(result);
|
|
838
|
+
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
return pending.length === 0 ? null : Promise.all(pending);
|
|
844
|
+
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
}
|