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.
Files changed (166) hide show
  1. package/package.json +12 -0
  2. package/src/common/index.ts +24 -0
  3. package/src/common/useLine2.ts +87 -0
  4. package/src/common/useLoader.ts +184 -0
  5. package/src/common/useLocationCalculator.ts +145 -0
  6. package/src/common/useMark.ts +42 -0
  7. package/src/common/useTween.ts +86 -0
  8. package/src/core/basic/camera.ts +28 -0
  9. package/src/core/basic/clock.ts +11 -0
  10. package/src/core/basic/control.ts +32 -0
  11. package/src/core/basic/index.ts +35 -0
  12. package/src/core/basic/labelRenderer.ts +26 -0
  13. package/src/core/basic/light.ts +63 -0
  14. package/src/core/basic/renderer.ts +37 -0
  15. package/src/core/basic/scene.ts +11 -0
  16. package/src/core/basic/stats.ts +16 -0
  17. package/src/core/event.ts +74 -0
  18. package/src/core/index.ts +11 -0
  19. package/src/core/main.ts +389 -0
  20. package/src/draco/README.md +32 -0
  21. package/src/draco/draco_decoder.js +34 -0
  22. package/src/draco/draco_decoder.wasm +0 -0
  23. package/src/draco/draco_encoder.js +33 -0
  24. package/src/draco/draco_wasm_wrapper.js +117 -0
  25. package/src/draco/gltf/draco_decoder.js +33 -0
  26. package/src/draco/gltf/draco_decoder.wasm +0 -0
  27. package/src/draco/gltf/draco_encoder.js +33 -0
  28. package/src/draco/gltf/draco_wasm_wrapper.js +116 -0
  29. package/src/tileRenderer/base/Tile.d.ts +50 -0
  30. package/src/tileRenderer/base/TileBase.d.ts +76 -0
  31. package/src/tileRenderer/base/TileInternal.d.ts +36 -0
  32. package/src/tileRenderer/base/TilesRendererBase.d.ts +35 -0
  33. package/src/tileRenderer/base/TilesRendererBase.js +847 -0
  34. package/src/tileRenderer/base/Tileset.d.ts +66 -0
  35. package/src/tileRenderer/base/constants.d.ts +6 -0
  36. package/src/tileRenderer/base/constants.js +16 -0
  37. package/src/tileRenderer/base/loaders/B3DMLoaderBase.d.ts +18 -0
  38. package/src/tileRenderer/base/loaders/B3DMLoaderBase.js +85 -0
  39. package/src/tileRenderer/base/loaders/CMPTLoaderBase.d.ts +22 -0
  40. package/src/tileRenderer/base/loaders/CMPTLoaderBase.js +61 -0
  41. package/src/tileRenderer/base/loaders/I3DMLoaderBase.d.ts +21 -0
  42. package/src/tileRenderer/base/loaders/I3DMLoaderBase.js +130 -0
  43. package/src/tileRenderer/base/loaders/LoaderBase.d.ts +10 -0
  44. package/src/tileRenderer/base/loaders/LoaderBase.js +73 -0
  45. package/src/tileRenderer/base/loaders/PNTSLoaderBase.d.ts +17 -0
  46. package/src/tileRenderer/base/loaders/PNTSLoaderBase.js +82 -0
  47. package/src/tileRenderer/base/plugins/ImplicitTilingPlugin.js +12 -0
  48. package/src/tileRenderer/base/traverseFunctions.js +468 -0
  49. package/src/tileRenderer/gltf.js +144 -0
  50. package/src/tileRenderer/index.d.ts +41 -0
  51. package/src/tileRenderer/index.js +44 -0
  52. package/src/tileRenderer/plugins/README.md +578 -0
  53. package/src/tileRenderer/plugins/base/ImplicitTilingPlugin.d.ts +2 -0
  54. package/src/tileRenderer/plugins/base/ImplicitTilingPlugin.js +84 -0
  55. package/src/tileRenderer/plugins/base/SUBTREELoader.js +876 -0
  56. package/src/tileRenderer/plugins/index.d.ts +17 -0
  57. package/src/tileRenderer/plugins/index.js +17 -0
  58. package/src/tileRenderer/plugins/three/CesiumIonAuthPlugin.d.ts +9 -0
  59. package/src/tileRenderer/plugins/three/CesiumIonAuthPlugin.js +175 -0
  60. package/src/tileRenderer/plugins/three/DebugTilesPlugin.d.ts +29 -0
  61. package/src/tileRenderer/plugins/three/DebugTilesPlugin.js +677 -0
  62. package/src/tileRenderer/plugins/three/GLTFExtensionsPlugin.d.ts +18 -0
  63. package/src/tileRenderer/plugins/three/GLTFExtensionsPlugin.js +86 -0
  64. package/src/tileRenderer/plugins/three/GoogleAttributionsManager.js +62 -0
  65. package/src/tileRenderer/plugins/three/GoogleCloudAuthPlugin.d.ts +5 -0
  66. package/src/tileRenderer/plugins/three/GoogleCloudAuthPlugin.js +200 -0
  67. package/src/tileRenderer/plugins/three/ReorientationPlugin.d.ts +12 -0
  68. package/src/tileRenderer/plugins/three/ReorientationPlugin.js +136 -0
  69. package/src/tileRenderer/plugins/three/TileCompressionPlugin.d.ts +18 -0
  70. package/src/tileRenderer/plugins/three/TileCompressionPlugin.js +223 -0
  71. package/src/tileRenderer/plugins/three/UpdateOnChangePlugin.d.ts +5 -0
  72. package/src/tileRenderer/plugins/three/UpdateOnChangePlugin.js +87 -0
  73. package/src/tileRenderer/plugins/three/fade/FadeManager.js +370 -0
  74. package/src/tileRenderer/plugins/three/fade/TilesFadePlugin.d.ts +9 -0
  75. package/src/tileRenderer/plugins/three/fade/TilesFadePlugin.js +318 -0
  76. package/src/tileRenderer/plugins/three/gltf/GLTFCesiumRTCExtension.d.ts +5 -0
  77. package/src/tileRenderer/plugins/three/gltf/GLTFCesiumRTCExtension.js +27 -0
  78. package/src/tileRenderer/plugins/three/gltf/GLTFMeshFeaturesExtension.d.ts +30 -0
  79. package/src/tileRenderer/plugins/three/gltf/GLTFMeshFeaturesExtension.js +76 -0
  80. package/src/tileRenderer/plugins/three/gltf/GLTFStructuralMetadataExtension.d.ts +49 -0
  81. package/src/tileRenderer/plugins/three/gltf/GLTFStructuralMetadataExtension.js +147 -0
  82. package/src/tileRenderer/plugins/three/gltf/metadata/classes/ClassProperty.js +149 -0
  83. package/src/tileRenderer/plugins/three/gltf/metadata/classes/MeshFeatures.js +215 -0
  84. package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyAttributeAccessor.js +107 -0
  85. package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertySetAccessor.js +45 -0
  86. package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyTableAccessor.js +209 -0
  87. package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyTextureAccessor.js +244 -0
  88. package/src/tileRenderer/plugins/three/gltf/metadata/classes/StructuralMetadata.js +202 -0
  89. package/src/tileRenderer/plugins/three/gltf/metadata/math/Matrix2.js +55 -0
  90. package/src/tileRenderer/plugins/three/gltf/metadata/utilities/ClassPropertyHelpers.js +495 -0
  91. package/src/tileRenderer/plugins/three/gltf/metadata/utilities/TexCoordUtilities.js +72 -0
  92. package/src/tileRenderer/plugins/three/gltf/metadata/utilities/TextureReadUtility.js +154 -0
  93. package/src/tileRenderer/plugins/three/objects/EllipsoidRegionHelper.js +186 -0
  94. package/src/tileRenderer/plugins/three/objects/SphereHelper.js +55 -0
  95. package/src/tileRenderer/r3f/README.md +238 -0
  96. package/src/tileRenderer/r3f/components/CameraControls.jsx +132 -0
  97. package/src/tileRenderer/r3f/components/CameraTransition.jsx +177 -0
  98. package/src/tileRenderer/r3f/components/CanvasDOMOverlay.jsx +54 -0
  99. package/src/tileRenderer/r3f/components/CompassGizmo.jsx +260 -0
  100. package/src/tileRenderer/r3f/components/TilesAttributionOverlay.jsx +110 -0
  101. package/src/tileRenderer/r3f/components/TilesRenderer.jsx +239 -0
  102. package/src/tileRenderer/r3f/index.jsx +6 -0
  103. package/src/tileRenderer/r3f/utilities/useForceUpdate.jsx +8 -0
  104. package/src/tileRenderer/r3f/utilities/useObjectDep.jsx +59 -0
  105. package/src/tileRenderer/r3f/utilities/useOptions.jsx +143 -0
  106. package/src/tileRenderer/three/DebugTilesRenderer.d.ts +28 -0
  107. package/src/tileRenderer/three/DebugTilesRenderer.js +58 -0
  108. package/src/tileRenderer/three/TilesGroup.d.ts +9 -0
  109. package/src/tileRenderer/three/TilesGroup.js +91 -0
  110. package/src/tileRenderer/three/TilesRenderer.d.ts +37 -0
  111. package/src/tileRenderer/three/TilesRenderer.js +1049 -0
  112. package/src/tileRenderer/three/controls/CameraTransitionManager.js +305 -0
  113. package/src/tileRenderer/three/controls/EnvironmentControls.js +1295 -0
  114. package/src/tileRenderer/three/controls/GlobeControls.js +684 -0
  115. package/src/tileRenderer/three/controls/PivotPointMesh.js +104 -0
  116. package/src/tileRenderer/three/controls/PointerTracker.js +257 -0
  117. package/src/tileRenderer/three/controls/utils.js +113 -0
  118. package/src/tileRenderer/three/loaders/B3DMLoader.d.ts +26 -0
  119. package/src/tileRenderer/three/loaders/B3DMLoader.js +85 -0
  120. package/src/tileRenderer/three/loaders/CMPTLoader.d.ts +19 -0
  121. package/src/tileRenderer/three/loaders/CMPTLoader.js +97 -0
  122. package/src/tileRenderer/three/loaders/GLTFExtensionLoader.d.ts +11 -0
  123. package/src/tileRenderer/three/loaders/GLTFExtensionLoader.js +68 -0
  124. package/src/tileRenderer/three/loaders/I3DMLoader.d.ts +26 -0
  125. package/src/tileRenderer/three/loaders/I3DMLoader.js +256 -0
  126. package/src/tileRenderer/three/loaders/PNTSLoader.d.ts +25 -0
  127. package/src/tileRenderer/three/loaders/PNTSLoader.js +202 -0
  128. package/src/tileRenderer/three/loaders/gltf/GLTFCesiumRTCExtension.js +12 -0
  129. package/src/tileRenderer/three/loaders/gltf/GLTFMeshFeaturesExtension.js +12 -0
  130. package/src/tileRenderer/three/loaders/gltf/GLTFStructuralMetadataExtension.js +12 -0
  131. package/src/tileRenderer/three/math/Ellipsoid.d.ts +31 -0
  132. package/src/tileRenderer/three/math/Ellipsoid.js +337 -0
  133. package/src/tileRenderer/three/math/EllipsoidRegion.d.ts +23 -0
  134. package/src/tileRenderer/three/math/EllipsoidRegion.js +178 -0
  135. package/src/tileRenderer/three/math/ExtendedFrustum.js +65 -0
  136. package/src/tileRenderer/three/math/GeoConstants.d.ts +4 -0
  137. package/src/tileRenderer/three/math/GeoConstants.js +5 -0
  138. package/src/tileRenderer/three/math/GeoUtils.d.ts +9 -0
  139. package/src/tileRenderer/three/math/GeoUtils.js +106 -0
  140. package/src/tileRenderer/three/math/OBB.js +179 -0
  141. package/src/tileRenderer/three/math/TileBoundingVolume.js +272 -0
  142. package/src/tileRenderer/three/plugins/CesiumIonAuthPlugin.js +12 -0
  143. package/src/tileRenderer/three/plugins/DebugTilesPlugin.js +26 -0
  144. package/src/tileRenderer/three/plugins/GoogleCloudAuthPlugin.js +12 -0
  145. package/src/tileRenderer/three/raycastTraverse.js +178 -0
  146. package/src/tileRenderer/three/renderers/CesiumIonTilesRenderer.d.ts +14 -0
  147. package/src/tileRenderer/three/renderers/CesiumIonTilesRenderer.js +21 -0
  148. package/src/tileRenderer/three/renderers/GoogleTilesRenderer.d.ts +43 -0
  149. package/src/tileRenderer/three/renderers/GoogleTilesRenderer.js +48 -0
  150. package/src/tileRenderer/three/utilities.js +54 -0
  151. package/src/tileRenderer/utilities/BatchTable.d.ts +24 -0
  152. package/src/tileRenderer/utilities/BatchTable.js +82 -0
  153. package/src/tileRenderer/utilities/BatchTableHierarchyExtension.js +127 -0
  154. package/src/tileRenderer/utilities/FeatureTable.d.ts +30 -0
  155. package/src/tileRenderer/utilities/FeatureTable.js +159 -0
  156. package/src/tileRenderer/utilities/LRUCache.d.ts +8 -0
  157. package/src/tileRenderer/utilities/LRUCache.js +385 -0
  158. package/src/tileRenderer/utilities/PriorityQueue.d.ts +16 -0
  159. package/src/tileRenderer/utilities/PriorityQueue.js +137 -0
  160. package/src/tileRenderer/utilities/arrayToString.js +7 -0
  161. package/src/tileRenderer/utilities/readMagicBytes.js +29 -0
  162. package/src/tileRenderer/utilities/rgb565torgb.js +22 -0
  163. package/src/tileRenderer/utilities/urlExtension.js +34 -0
  164. package/tsconfig.json +42 -0
  165. package/tsconfig.node.json +11 -0
  166. 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,8 @@
1
+ export class LRUCache {
2
+
3
+ maxSize : Number;
4
+ minSize : Number;
5
+ unloadPercent : Number;
6
+ unloadPriorityCallback : ( item : any ) => Number;
7
+
8
+ }
@@ -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 };
@@ -0,0 +1,7 @@
1
+ const utf8decoder = new TextDecoder();
2
+
3
+ export function arrayToString( array ) {
4
+
5
+ return utf8decoder.decode( array );
6
+
7
+ }