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,159 @@
|
|
|
1
|
+
import { arrayToString } from './arrayToString.js';
|
|
2
|
+
|
|
3
|
+
export function parseBinArray( buffer, arrayStart, count, type, componentType, propertyName ) {
|
|
4
|
+
|
|
5
|
+
let stride;
|
|
6
|
+
switch ( type ) {
|
|
7
|
+
|
|
8
|
+
case 'SCALAR':
|
|
9
|
+
stride = 1;
|
|
10
|
+
break;
|
|
11
|
+
|
|
12
|
+
case 'VEC2':
|
|
13
|
+
stride = 2;
|
|
14
|
+
break;
|
|
15
|
+
|
|
16
|
+
case 'VEC3':
|
|
17
|
+
stride = 3;
|
|
18
|
+
break;
|
|
19
|
+
|
|
20
|
+
case 'VEC4':
|
|
21
|
+
stride = 4;
|
|
22
|
+
break;
|
|
23
|
+
|
|
24
|
+
default:
|
|
25
|
+
throw new Error( `FeatureTable : Feature type not provided for "${ propertyName }".` );
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let data;
|
|
30
|
+
const arrayLength = count * stride;
|
|
31
|
+
|
|
32
|
+
switch ( componentType ) {
|
|
33
|
+
|
|
34
|
+
case 'BYTE':
|
|
35
|
+
data = new Int8Array( buffer, arrayStart, arrayLength );
|
|
36
|
+
break;
|
|
37
|
+
|
|
38
|
+
case 'UNSIGNED_BYTE':
|
|
39
|
+
data = new Uint8Array( buffer, arrayStart, arrayLength );
|
|
40
|
+
break;
|
|
41
|
+
|
|
42
|
+
case 'SHORT':
|
|
43
|
+
data = new Int16Array( buffer, arrayStart, arrayLength );
|
|
44
|
+
break;
|
|
45
|
+
|
|
46
|
+
case 'UNSIGNED_SHORT':
|
|
47
|
+
data = new Uint16Array( buffer, arrayStart, arrayLength );
|
|
48
|
+
break;
|
|
49
|
+
|
|
50
|
+
case 'INT':
|
|
51
|
+
data = new Int32Array( buffer, arrayStart, arrayLength );
|
|
52
|
+
break;
|
|
53
|
+
|
|
54
|
+
case 'UNSIGNED_INT':
|
|
55
|
+
data = new Uint32Array( buffer, arrayStart, arrayLength );
|
|
56
|
+
break;
|
|
57
|
+
|
|
58
|
+
case 'FLOAT':
|
|
59
|
+
data = new Float32Array( buffer, arrayStart, arrayLength );
|
|
60
|
+
break;
|
|
61
|
+
|
|
62
|
+
case 'DOUBLE':
|
|
63
|
+
data = new Float64Array( buffer, arrayStart, arrayLength );
|
|
64
|
+
break;
|
|
65
|
+
|
|
66
|
+
default:
|
|
67
|
+
throw new Error( `FeatureTable : Feature component type not provided for "${ propertyName }".` );
|
|
68
|
+
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return data;
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export class FeatureTable {
|
|
76
|
+
|
|
77
|
+
constructor( buffer, start, headerLength, binLength ) {
|
|
78
|
+
|
|
79
|
+
this.buffer = buffer;
|
|
80
|
+
this.binOffset = start + headerLength;
|
|
81
|
+
this.binLength = binLength;
|
|
82
|
+
|
|
83
|
+
let header = null;
|
|
84
|
+
if ( headerLength !== 0 ) {
|
|
85
|
+
|
|
86
|
+
const headerData = new Uint8Array( buffer, start, headerLength );
|
|
87
|
+
header = JSON.parse( arrayToString( headerData ) );
|
|
88
|
+
|
|
89
|
+
} else {
|
|
90
|
+
|
|
91
|
+
header = {};
|
|
92
|
+
|
|
93
|
+
}
|
|
94
|
+
this.header = header;
|
|
95
|
+
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
getKeys() {
|
|
99
|
+
|
|
100
|
+
return Object.keys( this.header );
|
|
101
|
+
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
getData( key, count, defaultComponentType = null, defaultType = null ) {
|
|
105
|
+
|
|
106
|
+
const header = this.header;
|
|
107
|
+
|
|
108
|
+
if ( ! ( key in header ) ) {
|
|
109
|
+
|
|
110
|
+
return null;
|
|
111
|
+
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const feature = header[ key ];
|
|
115
|
+
if ( ! ( feature instanceof Object ) ) {
|
|
116
|
+
|
|
117
|
+
return feature;
|
|
118
|
+
|
|
119
|
+
} else if ( Array.isArray( feature ) ) {
|
|
120
|
+
|
|
121
|
+
return feature;
|
|
122
|
+
|
|
123
|
+
} else {
|
|
124
|
+
|
|
125
|
+
const { buffer, binOffset, binLength } = this;
|
|
126
|
+
const byteOffset = feature.byteOffset || 0;
|
|
127
|
+
const featureType = feature.type || defaultType;
|
|
128
|
+
const featureComponentType = feature.componentType || defaultComponentType;
|
|
129
|
+
|
|
130
|
+
if ( 'type' in feature && defaultType && feature.type !== defaultType ) {
|
|
131
|
+
|
|
132
|
+
throw new Error( 'FeatureTable: Specified type does not match expected type.' );
|
|
133
|
+
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const arrayStart = binOffset + byteOffset;
|
|
137
|
+
const data = parseBinArray( buffer, arrayStart, count, featureType, featureComponentType, key );
|
|
138
|
+
|
|
139
|
+
const dataEnd = arrayStart + data.byteLength;
|
|
140
|
+
if ( dataEnd > binOffset + binLength ) {
|
|
141
|
+
|
|
142
|
+
throw new Error( 'FeatureTable: Feature data read outside binary body length.' );
|
|
143
|
+
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return data;
|
|
147
|
+
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
getBuffer( byteOffset, byteLength ) {
|
|
153
|
+
|
|
154
|
+
const { buffer, binOffset } = this;
|
|
155
|
+
return buffer.slice( binOffset + byteOffset, binOffset + byteOffset + byteLength );
|
|
156
|
+
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
}
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
const GIGABYTE_BYTES = 2 ** 30;
|
|
2
|
+
|
|
3
|
+
class LRUCache {
|
|
4
|
+
|
|
5
|
+
get unloadPriorityCallback() {
|
|
6
|
+
|
|
7
|
+
return this._unloadPriorityCallback;
|
|
8
|
+
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
set unloadPriorityCallback( cb ) {
|
|
12
|
+
|
|
13
|
+
if ( cb.length === 1 ) {
|
|
14
|
+
|
|
15
|
+
console.warn( 'LRUCache: "unloadPriorityCallback" function has been changed to take two arguments.' );
|
|
16
|
+
this._unloadPriorityCallback = ( a, b ) => {
|
|
17
|
+
|
|
18
|
+
const valA = cb( a );
|
|
19
|
+
const valB = cb( b );
|
|
20
|
+
|
|
21
|
+
if ( valA < valB ) return - 1;
|
|
22
|
+
if ( valA > valB ) return 1;
|
|
23
|
+
return 0;
|
|
24
|
+
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
} else {
|
|
28
|
+
|
|
29
|
+
this._unloadPriorityCallback = cb;
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
constructor() {
|
|
36
|
+
|
|
37
|
+
// options
|
|
38
|
+
this.minSize = 6000;
|
|
39
|
+
this.maxSize = 8000;
|
|
40
|
+
this.minBytesSize = 0.3 * GIGABYTE_BYTES;
|
|
41
|
+
this.maxBytesSize = 0.4 * GIGABYTE_BYTES;
|
|
42
|
+
this.unloadPercent = 0.05;
|
|
43
|
+
|
|
44
|
+
// "itemSet" doubles as both the list of the full set of items currently
|
|
45
|
+
// stored in the cache (keys) as well as a map to the time the item was last
|
|
46
|
+
// used so it can be sorted appropriately.
|
|
47
|
+
this.itemSet = new Map();
|
|
48
|
+
this.itemList = [];
|
|
49
|
+
this.usedSet = new Set();
|
|
50
|
+
this.callbacks = new Map();
|
|
51
|
+
this.markUnusedQueued = false;
|
|
52
|
+
this.unloadingHandle = - 1;
|
|
53
|
+
this.cachedBytes = 0;
|
|
54
|
+
this.bytesMap = new Map();
|
|
55
|
+
this.loadedSet = new Set();
|
|
56
|
+
|
|
57
|
+
this._unloadPriorityCallback = null;
|
|
58
|
+
this.computeMemoryUsageCallback = () => null;
|
|
59
|
+
|
|
60
|
+
const itemSet = this.itemSet;
|
|
61
|
+
this.defaultPriorityCallback = item => itemSet.get( item );
|
|
62
|
+
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Returns whether or not the cache has reached the maximum size
|
|
66
|
+
isFull() {
|
|
67
|
+
|
|
68
|
+
return this.itemSet.size >= this.maxSize || this.cachedBytes >= this.maxBytesSize;
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
getMemoryUsage( item ) {
|
|
73
|
+
|
|
74
|
+
return this.bytesMap.get( item ) ?? null;
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
add( item, removeCb ) {
|
|
79
|
+
|
|
80
|
+
if ( this.markUnusedQueued ) {
|
|
81
|
+
|
|
82
|
+
this.markAllUnused();
|
|
83
|
+
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const itemSet = this.itemSet;
|
|
87
|
+
if ( itemSet.has( item ) ) {
|
|
88
|
+
|
|
89
|
+
return false;
|
|
90
|
+
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if ( this.isFull() ) {
|
|
94
|
+
|
|
95
|
+
return false;
|
|
96
|
+
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const usedSet = this.usedSet;
|
|
100
|
+
const itemList = this.itemList;
|
|
101
|
+
const callbacks = this.callbacks;
|
|
102
|
+
const bytesMap = this.bytesMap;
|
|
103
|
+
itemList.push( item );
|
|
104
|
+
usedSet.add( item );
|
|
105
|
+
itemSet.set( item, Date.now() );
|
|
106
|
+
callbacks.set( item, removeCb );
|
|
107
|
+
|
|
108
|
+
// computeMemoryUsageCallback can return "null" if memory usage is not known, yet
|
|
109
|
+
const bytes = this.computeMemoryUsageCallback( item );
|
|
110
|
+
this.cachedBytes += bytes || 0;
|
|
111
|
+
bytesMap.set( item, bytes );
|
|
112
|
+
|
|
113
|
+
return true;
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
remove( item ) {
|
|
118
|
+
|
|
119
|
+
const usedSet = this.usedSet;
|
|
120
|
+
const itemSet = this.itemSet;
|
|
121
|
+
const itemList = this.itemList;
|
|
122
|
+
const bytesMap = this.bytesMap;
|
|
123
|
+
const callbacks = this.callbacks;
|
|
124
|
+
const loadedSet = this.loadedSet;
|
|
125
|
+
|
|
126
|
+
if ( itemSet.has( item ) ) {
|
|
127
|
+
|
|
128
|
+
this.cachedBytes -= bytesMap.get( item ) || 0;
|
|
129
|
+
bytesMap.delete( item );
|
|
130
|
+
|
|
131
|
+
callbacks.get( item )( item );
|
|
132
|
+
|
|
133
|
+
const index = itemList.indexOf( item );
|
|
134
|
+
itemList.splice( index, 1 );
|
|
135
|
+
usedSet.delete( item );
|
|
136
|
+
itemSet.delete( item );
|
|
137
|
+
callbacks.delete( item );
|
|
138
|
+
loadedSet.delete( item );
|
|
139
|
+
|
|
140
|
+
return true;
|
|
141
|
+
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return false;
|
|
145
|
+
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Marks whether tiles in the cache have been completely loaded or not. Tiles that have not been completely
|
|
149
|
+
// loaded are subject to being disposed early if the cache is full above its max size limits, even if they
|
|
150
|
+
// are marked as used.
|
|
151
|
+
setLoaded( item, value ) {
|
|
152
|
+
|
|
153
|
+
const { itemSet, loadedSet } = this;
|
|
154
|
+
if ( itemSet.has( item ) ) {
|
|
155
|
+
|
|
156
|
+
if ( value === true ) {
|
|
157
|
+
|
|
158
|
+
loadedSet.add( item );
|
|
159
|
+
|
|
160
|
+
} else {
|
|
161
|
+
|
|
162
|
+
loadedSet.delete( item );
|
|
163
|
+
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
updateMemoryUsage( item ) {
|
|
171
|
+
|
|
172
|
+
const itemSet = this.itemSet;
|
|
173
|
+
const bytesMap = this.bytesMap;
|
|
174
|
+
if ( ! itemSet.has( item ) ) {
|
|
175
|
+
|
|
176
|
+
return;
|
|
177
|
+
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
this.cachedBytes -= bytesMap.get( item ) || 0;
|
|
181
|
+
|
|
182
|
+
const bytes = this.computeMemoryUsageCallback( item );
|
|
183
|
+
bytesMap.set( item, bytes );
|
|
184
|
+
this.cachedBytes += bytes;
|
|
185
|
+
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
markUsed( item ) {
|
|
189
|
+
|
|
190
|
+
if ( this.markUnusedQueued ) {
|
|
191
|
+
|
|
192
|
+
this.markAllUnused();
|
|
193
|
+
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const itemSet = this.itemSet;
|
|
197
|
+
const usedSet = this.usedSet;
|
|
198
|
+
if ( itemSet.has( item ) && ! usedSet.has( item ) ) {
|
|
199
|
+
|
|
200
|
+
itemSet.set( item, Date.now() );
|
|
201
|
+
usedSet.add( item );
|
|
202
|
+
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
markAllUnused() {
|
|
208
|
+
|
|
209
|
+
this.usedSet.clear();
|
|
210
|
+
this.markUnusedQueued = false;
|
|
211
|
+
if ( this.unloadingHandle !== - 1 ) {
|
|
212
|
+
|
|
213
|
+
cancelAnimationFrame( this.unloadingHandle );
|
|
214
|
+
this.unloadingHandle = - 1;
|
|
215
|
+
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// TODO: this should be renamed because it's not necessarily unloading all unused content
|
|
221
|
+
// Maybe call it "cleanup" or "unloadToMinSize"
|
|
222
|
+
unloadUnusedContent() {
|
|
223
|
+
|
|
224
|
+
const {
|
|
225
|
+
unloadPercent,
|
|
226
|
+
minSize,
|
|
227
|
+
maxSize,
|
|
228
|
+
itemList,
|
|
229
|
+
itemSet,
|
|
230
|
+
usedSet,
|
|
231
|
+
loadedSet,
|
|
232
|
+
callbacks,
|
|
233
|
+
bytesMap,
|
|
234
|
+
minBytesSize,
|
|
235
|
+
maxBytesSize,
|
|
236
|
+
} = this;
|
|
237
|
+
|
|
238
|
+
const unused = itemList.length - usedSet.size;
|
|
239
|
+
const unloaded = itemList.length - loadedSet.size;
|
|
240
|
+
const excessNodes = Math.max( Math.min( itemList.length - minSize, unused ), 0 );
|
|
241
|
+
const excessBytes = this.cachedBytes - minBytesSize;
|
|
242
|
+
const unloadPriorityCallback = this.unloadPriorityCallback || this.defaultPriorityCallback;
|
|
243
|
+
let needsRerun = false;
|
|
244
|
+
|
|
245
|
+
const hasNodesToUnload = excessNodes > 0 && unused > 0 || unloaded && itemList.length > maxSize;
|
|
246
|
+
const hasBytesToUnload = unused && this.cachedBytes > minBytesSize || unloaded && this.cachedBytes > maxBytesSize;
|
|
247
|
+
if ( hasBytesToUnload || hasNodesToUnload ) {
|
|
248
|
+
|
|
249
|
+
// used items should be at the end of the array, "unloaded" items in the middle of the array
|
|
250
|
+
itemList.sort( ( a, b ) => {
|
|
251
|
+
|
|
252
|
+
const usedA = usedSet.has( a );
|
|
253
|
+
const usedB = usedSet.has( b );
|
|
254
|
+
if ( usedA === usedB ) {
|
|
255
|
+
|
|
256
|
+
const loadedA = loadedSet.has( a );
|
|
257
|
+
const loadedB = loadedSet.has( b );
|
|
258
|
+
if ( loadedA === loadedB ) {
|
|
259
|
+
|
|
260
|
+
// Use the sort function otherwise
|
|
261
|
+
// higher priority should be further to the left
|
|
262
|
+
return - unloadPriorityCallback( a, b );
|
|
263
|
+
|
|
264
|
+
} else {
|
|
265
|
+
|
|
266
|
+
return loadedA ? 1 : - 1;
|
|
267
|
+
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
} else {
|
|
271
|
+
|
|
272
|
+
// If one is used and the other is not move the used one towards the end of the array
|
|
273
|
+
return usedA ? 1 : - 1;
|
|
274
|
+
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
} );
|
|
278
|
+
|
|
279
|
+
// address corner cases where the minSize might be zero or smaller than maxSize - minSize,
|
|
280
|
+
// which would result in a very small or no items being unloaded.
|
|
281
|
+
const maxUnload = Math.max( minSize * unloadPercent, excessNodes * unloadPercent );
|
|
282
|
+
const nodesToUnload = Math.ceil( Math.min( maxUnload, unused, excessNodes ) );
|
|
283
|
+
const maxBytesUnload = Math.max( unloadPercent * excessBytes, unloadPercent * minBytesSize );
|
|
284
|
+
const bytesToUnload = Math.min( maxBytesUnload, excessBytes );
|
|
285
|
+
|
|
286
|
+
let removedNodes = 0;
|
|
287
|
+
let removedBytes = 0;
|
|
288
|
+
|
|
289
|
+
// evict up to the max node or bytes size, keeping one more item over the max bytes limit
|
|
290
|
+
// so the "full" function behaves correctly.
|
|
291
|
+
while (
|
|
292
|
+
this.cachedBytes - removedBytes > maxBytesSize ||
|
|
293
|
+
itemList.length - removedNodes > maxSize
|
|
294
|
+
) {
|
|
295
|
+
|
|
296
|
+
const item = itemList[ removedNodes ];
|
|
297
|
+
const bytes = bytesMap.get( item ) || 0;
|
|
298
|
+
if (
|
|
299
|
+
usedSet.has( item ) && loadedSet.has( item ) ||
|
|
300
|
+
this.cachedBytes - removedBytes - bytes < maxBytesSize &&
|
|
301
|
+
itemList.length - removedNodes <= maxSize
|
|
302
|
+
) {
|
|
303
|
+
|
|
304
|
+
break;
|
|
305
|
+
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
removedBytes += bytes;
|
|
309
|
+
removedNodes ++;
|
|
310
|
+
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// evict up to the min node or bytes size, keeping one more item over the min bytes limit
|
|
314
|
+
// so we're meeting it
|
|
315
|
+
while (
|
|
316
|
+
removedBytes < bytesToUnload ||
|
|
317
|
+
removedNodes < nodesToUnload
|
|
318
|
+
) {
|
|
319
|
+
|
|
320
|
+
const item = itemList[ removedNodes ];
|
|
321
|
+
const bytes = bytesMap.get( item ) || 0;
|
|
322
|
+
if (
|
|
323
|
+
usedSet.has( item ) ||
|
|
324
|
+
this.cachedBytes - removedBytes - bytes < minBytesSize &&
|
|
325
|
+
removedNodes >= nodesToUnload
|
|
326
|
+
) {
|
|
327
|
+
|
|
328
|
+
break;
|
|
329
|
+
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
removedBytes += bytes;
|
|
333
|
+
removedNodes ++;
|
|
334
|
+
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// remove the nodes
|
|
338
|
+
itemList.splice( 0, removedNodes ).forEach( item => {
|
|
339
|
+
|
|
340
|
+
this.cachedBytes -= bytesMap.get( item ) || 0;
|
|
341
|
+
|
|
342
|
+
callbacks.get( item )( item );
|
|
343
|
+
bytesMap.delete( item );
|
|
344
|
+
itemSet.delete( item );
|
|
345
|
+
callbacks.delete( item );
|
|
346
|
+
loadedSet.delete( item );
|
|
347
|
+
usedSet.delete( item );
|
|
348
|
+
|
|
349
|
+
} );
|
|
350
|
+
|
|
351
|
+
// if we didn't remove enough nodes or we still have excess bytes and there are nodes to removed
|
|
352
|
+
// then we want to fire another round of unloading
|
|
353
|
+
needsRerun = removedNodes < excessNodes || removedBytes < excessBytes && removedNodes < unused;
|
|
354
|
+
needsRerun = needsRerun && removedNodes > 0;
|
|
355
|
+
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if ( needsRerun ) {
|
|
359
|
+
|
|
360
|
+
this.unloadingHandle = requestAnimationFrame( () => this.scheduleUnload() );
|
|
361
|
+
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
scheduleUnload() {
|
|
367
|
+
|
|
368
|
+
if ( ! this.scheduled ) {
|
|
369
|
+
|
|
370
|
+
this.scheduled = true;
|
|
371
|
+
queueMicrotask( () => {
|
|
372
|
+
|
|
373
|
+
this.scheduled = false;
|
|
374
|
+
this.unloadUnusedContent();
|
|
375
|
+
this.markUnusedQueued = true;
|
|
376
|
+
|
|
377
|
+
} );
|
|
378
|
+
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
export { LRUCache };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export class PriorityQueue {
|
|
2
|
+
|
|
3
|
+
maxJobs : Number;
|
|
4
|
+
autoUpdate : Boolean;
|
|
5
|
+
priorityCallback : ( itemA : any, itemB : any ) => Number;
|
|
6
|
+
|
|
7
|
+
schedulingCallback : ( func : Function ) => void;
|
|
8
|
+
|
|
9
|
+
sort() : void;
|
|
10
|
+
add( item : any, callback : ( item : any ) => any ) : Promise< any >;
|
|
11
|
+
remove( item : any ) : void;
|
|
12
|
+
|
|
13
|
+
tryRunJobs() : void;
|
|
14
|
+
scheduleJobRun() : void;
|
|
15
|
+
|
|
16
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
class PriorityQueue {
|
|
2
|
+
|
|
3
|
+
constructor() {
|
|
4
|
+
|
|
5
|
+
// options
|
|
6
|
+
this.maxJobs = 6;
|
|
7
|
+
|
|
8
|
+
this.items = [];
|
|
9
|
+
this.callbacks = new Map();
|
|
10
|
+
this.currJobs = 0;
|
|
11
|
+
this.scheduled = false;
|
|
12
|
+
this.autoUpdate = true;
|
|
13
|
+
|
|
14
|
+
this.priorityCallback = () => {
|
|
15
|
+
|
|
16
|
+
throw new Error( 'PriorityQueue: PriorityCallback function not defined.' );
|
|
17
|
+
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Customizable scheduling callback. Default using requestAnimationFrame()
|
|
21
|
+
this.schedulingCallback = func => {
|
|
22
|
+
|
|
23
|
+
requestAnimationFrame( func );
|
|
24
|
+
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
this._runjobs = () => {
|
|
28
|
+
|
|
29
|
+
this.tryRunJobs();
|
|
30
|
+
this.scheduled = false;
|
|
31
|
+
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
sort() {
|
|
37
|
+
|
|
38
|
+
const priorityCallback = this.priorityCallback;
|
|
39
|
+
const items = this.items;
|
|
40
|
+
items.sort( priorityCallback );
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
add( item, callback ) {
|
|
45
|
+
|
|
46
|
+
return new Promise( ( resolve, reject ) => {
|
|
47
|
+
|
|
48
|
+
const prCallback = ( ...args ) => callback( ...args ).then( resolve ).catch( reject );
|
|
49
|
+
const items = this.items;
|
|
50
|
+
const callbacks = this.callbacks;
|
|
51
|
+
|
|
52
|
+
items.push( item );
|
|
53
|
+
callbacks.set( item, prCallback );
|
|
54
|
+
|
|
55
|
+
if ( this.autoUpdate ) {
|
|
56
|
+
|
|
57
|
+
this.scheduleJobRun();
|
|
58
|
+
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
} );
|
|
62
|
+
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
remove( item ) {
|
|
66
|
+
|
|
67
|
+
const items = this.items;
|
|
68
|
+
const callbacks = this.callbacks;
|
|
69
|
+
|
|
70
|
+
const index = items.indexOf( item );
|
|
71
|
+
if ( index !== - 1 ) {
|
|
72
|
+
|
|
73
|
+
items.splice( index, 1 );
|
|
74
|
+
callbacks.delete( item );
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
tryRunJobs() {
|
|
81
|
+
|
|
82
|
+
this.sort();
|
|
83
|
+
|
|
84
|
+
const items = this.items;
|
|
85
|
+
const callbacks = this.callbacks;
|
|
86
|
+
const maxJobs = this.maxJobs;
|
|
87
|
+
let currJobs = this.currJobs;
|
|
88
|
+
while ( maxJobs > currJobs && items.length > 0 ) {
|
|
89
|
+
|
|
90
|
+
currJobs ++;
|
|
91
|
+
const item = items.pop();
|
|
92
|
+
const callback = callbacks.get( item );
|
|
93
|
+
callbacks.delete( item );
|
|
94
|
+
callback( item )
|
|
95
|
+
.then( () => {
|
|
96
|
+
|
|
97
|
+
this.currJobs --;
|
|
98
|
+
|
|
99
|
+
if ( this.autoUpdate ) {
|
|
100
|
+
|
|
101
|
+
this.scheduleJobRun();
|
|
102
|
+
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
} )
|
|
106
|
+
.catch( () => {
|
|
107
|
+
|
|
108
|
+
this.currJobs --;
|
|
109
|
+
|
|
110
|
+
if ( this.autoUpdate ) {
|
|
111
|
+
|
|
112
|
+
this.scheduleJobRun();
|
|
113
|
+
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
} );
|
|
117
|
+
|
|
118
|
+
}
|
|
119
|
+
this.currJobs = currJobs;
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
scheduleJobRun() {
|
|
124
|
+
|
|
125
|
+
if ( ! this.scheduled ) {
|
|
126
|
+
|
|
127
|
+
this.schedulingCallback( this._runjobs );
|
|
128
|
+
|
|
129
|
+
this.scheduled = true;
|
|
130
|
+
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export { PriorityQueue };
|