itowns 2.44.3-next.35 → 2.44.3-next.36
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/dist/itowns.js +1 -1
- package/dist/itowns.js.map +1 -1
- package/lib/Core/MainLoop.js +1 -3
- package/lib/Core/Prefab/TileBuilder.js +8 -5
- package/lib/Core/Scheduler/Cache.js +1 -240
- package/lib/Core/Style.js +11 -8
- package/lib/Core/TileGeometry.js +2 -2
- package/lib/Layer/Layer.js +10 -5
- package/lib/Source/FileSource.js +8 -6
- package/lib/Source/OrientedImageSource.js +2 -2
- package/lib/Source/Source.js +24 -41
- package/lib/Source/VectorTilesSource.js +5 -11
- package/lib/Source/WFSSource.js +3 -3
- package/package.json +2 -1
package/lib/Core/MainLoop.js
CHANGED
|
@@ -42,7 +42,6 @@ function updateElements(context, geometryLayer, elements) {
|
|
|
42
42
|
for (const attachedLayer of geometryLayer.attachedLayers) {
|
|
43
43
|
if (attachedLayer.ready) {
|
|
44
44
|
attachedLayer.update(context, attachedLayer, sub.element, sub.parent);
|
|
45
|
-
attachedLayer.cache.flush();
|
|
46
45
|
}
|
|
47
46
|
}
|
|
48
47
|
} else if (sub.elements) {
|
|
@@ -56,7 +55,6 @@ function updateElements(context, geometryLayer, elements) {
|
|
|
56
55
|
for (const attachedLayer of geometryLayer.attachedLayers) {
|
|
57
56
|
if (attachedLayer.ready) {
|
|
58
57
|
attachedLayer.update(context, attachedLayer, sub.elements[i], sub.parent);
|
|
59
|
-
attachedLayer.cache.flush();
|
|
60
58
|
}
|
|
61
59
|
}
|
|
62
60
|
}
|
|
@@ -140,7 +138,7 @@ class MainLoop extends EventDispatcher {
|
|
|
140
138
|
}
|
|
141
139
|
|
|
142
140
|
// Clear the cache of expired resources
|
|
143
|
-
|
|
141
|
+
|
|
144
142
|
view.execFrameRequesters(MAIN_LOOP_EVENTS.AFTER_LAYER_UPDATE, dt, this.#updateLoopRestarted, geometryLayer);
|
|
145
143
|
}
|
|
146
144
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
import { TileGeometry } from "../TileGeometry.js";
|
|
3
|
-
import
|
|
3
|
+
import { LRUCache } from 'lru-cache';
|
|
4
4
|
import { computeBuffers } from "./computeBufferTileGeometry.js";
|
|
5
5
|
import OBB from "../../Renderer/OBB.js";
|
|
6
6
|
const cacheBuffer = new Map();
|
|
7
|
-
const cacheTile = new
|
|
7
|
+
const cacheTile = new LRUCache({
|
|
8
|
+
max: 500
|
|
9
|
+
});
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Reference to a tile's extent with rigid transformations.
|
|
@@ -19,7 +21,8 @@ export function newTileGeometry(builder, params) {
|
|
|
19
21
|
} = builder.computeShareableExtent(params.extent);
|
|
20
22
|
const south = shareableExtent.south.toFixed(6);
|
|
21
23
|
const bufferKey = `${builder.crs}_${params.disableSkirt ? 0 : 1}_${params.segments}`;
|
|
22
|
-
|
|
24
|
+
const key = `s${south}l${params.level}bK${bufferKey}`;
|
|
25
|
+
let promiseGeometry = cacheTile.get(key);
|
|
23
26
|
|
|
24
27
|
// build geometry if doesn't exist
|
|
25
28
|
if (!promiseGeometry) {
|
|
@@ -27,7 +30,7 @@ export function newTileGeometry(builder, params) {
|
|
|
27
30
|
promiseGeometry = new Promise(r => {
|
|
28
31
|
resolve = r;
|
|
29
32
|
});
|
|
30
|
-
cacheTile.set(
|
|
33
|
+
cacheTile.set(key, promiseGeometry);
|
|
31
34
|
params.extent = shareableExtent;
|
|
32
35
|
params.center = builder.center(params.extent).clone();
|
|
33
36
|
// Read previously cached values (index and uv.wgs84 only
|
|
@@ -63,7 +66,7 @@ export function newTileGeometry(builder, params) {
|
|
|
63
66
|
};
|
|
64
67
|
const geometry = new TileGeometry(builder, params, gpuBuffers);
|
|
65
68
|
geometry.OBB = new OBB(geometry.boundingBox.min, geometry.boundingBox.max);
|
|
66
|
-
geometry.initRefCount(cacheTile,
|
|
69
|
+
geometry.initRefCount(cacheTile, key);
|
|
67
70
|
resolve(geometry);
|
|
68
71
|
return Promise.resolve({
|
|
69
72
|
geometry,
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
let entry;
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Cache policies for flushing. Those policies can be used when something is
|
|
5
3
|
* [set]{@link Cache.set} into the Cache, as the lifetime property.
|
|
@@ -16,241 +14,4 @@ export const CACHE_POLICIES = {
|
|
|
16
14
|
INFINITE: Infinity,
|
|
17
15
|
TEXTURE: 900000,
|
|
18
16
|
GEOMETRY: 900000
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* This is a copy of the Map object, except that it also store a value for last
|
|
23
|
-
* time used. This value is used for cache expiration mechanism.
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* import Cache, { CACHE_POLICIES } from 'Core/Scheduler/Cache';
|
|
27
|
-
*
|
|
28
|
-
* const cache = new Cache(CACHE_POLICIES.TEXTURE)
|
|
29
|
-
* cache.set({ bar: 1 }, 'foo');
|
|
30
|
-
* cache.set({ bar: 32 }, 'foo', 'toto');
|
|
31
|
-
*
|
|
32
|
-
* cache.get('foo');
|
|
33
|
-
*
|
|
34
|
-
* cache.delete('foo');
|
|
35
|
-
*
|
|
36
|
-
* cache.clear();
|
|
37
|
-
*
|
|
38
|
-
* cache.flush();
|
|
39
|
-
*/
|
|
40
|
-
class Cache {
|
|
41
|
-
/**
|
|
42
|
-
* @param {number} [lifetime=CACHE_POLICIES.INFINITE] The cache expiration time for all values.
|
|
43
|
-
*/
|
|
44
|
-
constructor() {
|
|
45
|
-
let lifetime = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : CACHE_POLICIES.INFINITE;
|
|
46
|
-
this.lifeTime = lifetime;
|
|
47
|
-
this.lastTimeFlush = Date.now();
|
|
48
|
-
this.data = new Map();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Returns the entry related to the specified key, content in array, from the cache.
|
|
53
|
-
* The array contents one to three key.
|
|
54
|
-
* The last time used property of the entry is updated to extend the longevity of the
|
|
55
|
-
* entry.
|
|
56
|
-
*
|
|
57
|
-
* @param {string[]|number[]} keyArray key array ([key0, key1, key3])
|
|
58
|
-
*
|
|
59
|
-
* @return {Object}
|
|
60
|
-
*/
|
|
61
|
-
|
|
62
|
-
getByArray(keyArray) {
|
|
63
|
-
return this.get(keyArray[0], keyArray[1], keyArray[2]);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Adds or updates an entry with specified keys array ([key0, key1, key3]).
|
|
68
|
-
* Caution: it overrides any existing entry already set at this/those key/s.
|
|
69
|
-
*
|
|
70
|
-
* @param {Object} value to add in cache
|
|
71
|
-
* @param {string[]|number[]} keyArray key array ([key0, key1, key3])
|
|
72
|
-
*
|
|
73
|
-
* @return {Object} the added value
|
|
74
|
-
*/
|
|
75
|
-
setByArray(value, keyArray) {
|
|
76
|
-
return this.set(value, keyArray[0], keyArray[1], keyArray[2]);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Returns the entry related to the specified key from the cache. The last
|
|
81
|
-
* time used property of the entry is updated to extend the longevity of the
|
|
82
|
-
* entry.
|
|
83
|
-
*
|
|
84
|
-
* @param {string|number} key1
|
|
85
|
-
* @param {string|number} [key2]
|
|
86
|
-
* @param {string|number} [key3]
|
|
87
|
-
*
|
|
88
|
-
* @return {Object}
|
|
89
|
-
*/
|
|
90
|
-
get(key1, key2, key3) {
|
|
91
|
-
const entry_1 = this.data.get(key1);
|
|
92
|
-
if (entry_1 == undefined) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
if (entry_1.lastTimeUsed != undefined) {
|
|
96
|
-
entry = entry_1;
|
|
97
|
-
} else {
|
|
98
|
-
const entry_2 = entry_1.get(key2);
|
|
99
|
-
if (entry_2 == undefined) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
if (entry_2.lastTimeUsed != undefined) {
|
|
103
|
-
entry = entry_2;
|
|
104
|
-
} else {
|
|
105
|
-
const entry_3 = entry_2.get(key3);
|
|
106
|
-
if (entry_3 == undefined) {
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
entry = entry_3;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (entry.value) {
|
|
113
|
-
entry.lastTimeUsed = Date.now();
|
|
114
|
-
return entry.value;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Adds or updates an entry with specified keys (up to 3).
|
|
120
|
-
* Caution: it overrides any existing entry already set at this/those key/s.
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* @param {Object} value to add in cache
|
|
124
|
-
* @param {string|number} key1
|
|
125
|
-
* @param {string|number} [key2]
|
|
126
|
-
* @param {string|number} [key3]
|
|
127
|
-
*
|
|
128
|
-
* @return {Object} the added value
|
|
129
|
-
*/
|
|
130
|
-
set(value, key1, key2, key3) {
|
|
131
|
-
entry = {
|
|
132
|
-
value,
|
|
133
|
-
lastTimeUsed: Date.now()
|
|
134
|
-
};
|
|
135
|
-
if (key2 == undefined) {
|
|
136
|
-
this.data.set(key1, entry);
|
|
137
|
-
return value;
|
|
138
|
-
}
|
|
139
|
-
if (!this.data.get(key1)) {
|
|
140
|
-
this.data.set(key1, new Map());
|
|
141
|
-
}
|
|
142
|
-
const entry_map = this.data.get(key1);
|
|
143
|
-
if (key3 == undefined) {
|
|
144
|
-
entry_map.set(key2, entry);
|
|
145
|
-
return value;
|
|
146
|
-
}
|
|
147
|
-
if (!entry_map.get(key2)) {
|
|
148
|
-
entry_map.set(key2, new Map());
|
|
149
|
-
}
|
|
150
|
-
entry_map.get(key2).set(key3, entry);
|
|
151
|
-
return value;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Deletes the specified entry from the cache.
|
|
156
|
-
*
|
|
157
|
-
* @param {string|number} key1
|
|
158
|
-
* @param {string|number} [key2]
|
|
159
|
-
* @param {string|number} [key3]
|
|
160
|
-
*/
|
|
161
|
-
delete(key1, key2, key3) {
|
|
162
|
-
const entry_1 = this.data.get(key1);
|
|
163
|
-
if (entry_1 === undefined) {
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
if (entry_1.lastTimeUsed != undefined) {
|
|
167
|
-
delete this.data.get(key1);
|
|
168
|
-
this.data.delete(key1);
|
|
169
|
-
} else {
|
|
170
|
-
const entry_2 = entry_1.get(key2);
|
|
171
|
-
if (entry_2 === undefined) {
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
if (entry_2.lastTimeUsed != undefined) {
|
|
175
|
-
delete entry_1.get(key2);
|
|
176
|
-
entry_1.delete(key2);
|
|
177
|
-
if (entry_1.size == 0) {
|
|
178
|
-
this.data.delete(key1);
|
|
179
|
-
}
|
|
180
|
-
} else {
|
|
181
|
-
const entry_3 = entry_2.get(key3);
|
|
182
|
-
if (entry_3 === undefined) {
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
delete entry_2.get(key3);
|
|
186
|
-
entry_2.delete(key3);
|
|
187
|
-
if (entry_2.size == 0) {
|
|
188
|
-
entry_1.delete(key2);
|
|
189
|
-
if (entry_1.size == 0) {
|
|
190
|
-
this.data.delete(key1);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Removes all entries of the cache.
|
|
199
|
-
*
|
|
200
|
-
*/
|
|
201
|
-
clear() {
|
|
202
|
-
this.data.clear();
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Flush the cache: entries that have been present for too long since the
|
|
207
|
-
* last time they were used, are removed from the cache. By default, the
|
|
208
|
-
* time is the current time, but the interval can be reduced by doing
|
|
209
|
-
* something like `Cache.flush(Date.now() - reductionTime)`. If you want to
|
|
210
|
-
* clear the whole cache, use {@link Cache.clear} instead.
|
|
211
|
-
*
|
|
212
|
-
* @param {number} [time=Date.now()]
|
|
213
|
-
*/
|
|
214
|
-
flush() {
|
|
215
|
-
let time = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Date.now();
|
|
216
|
-
if (this.lifeTime == CACHE_POLICIES.INFINITE || this.lifeTime > time - this.lastTimeFlush || !this.data.size) {
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
this.lastTimeFlush = Infinity;
|
|
220
|
-
this.data.forEach((v1, i) => {
|
|
221
|
-
if (this.lifeTime < time - v1.lastTimeUsed) {
|
|
222
|
-
delete this.data.get(i);
|
|
223
|
-
this.data.delete(i);
|
|
224
|
-
} else {
|
|
225
|
-
v1.forEach((v2, j) => {
|
|
226
|
-
if (this.lifeTime < time - v2.lastTimeUsed) {
|
|
227
|
-
delete v1.get(j);
|
|
228
|
-
v1.delete(j);
|
|
229
|
-
} else {
|
|
230
|
-
v2.forEach((v3, k) => {
|
|
231
|
-
if (this.lifeTime < time - v3.lastTimeUsed) {
|
|
232
|
-
delete v2.get(k);
|
|
233
|
-
v2.delete(k);
|
|
234
|
-
} else {
|
|
235
|
-
// Work for the moment because all flushed caches have 3 key!
|
|
236
|
-
this.lastTimeFlush = Math.min(this.lastTimeFlush, v3.lastTimeUsed);
|
|
237
|
-
}
|
|
238
|
-
});
|
|
239
|
-
if (!v2.size) {
|
|
240
|
-
delete v1.get(j);
|
|
241
|
-
v1.delete(j);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
if (!v1.size) {
|
|
246
|
-
delete this.data.get(i);
|
|
247
|
-
this.data.delete(i);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
if (this.data.size == 0) {
|
|
252
|
-
this.lastTimeFlush = Date.now();
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
export default Cache;
|
|
17
|
+
};
|
package/lib/Core/Style.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { LRUCache } from 'lru-cache';
|
|
2
2
|
import Fetcher from "../Provider/Fetcher.js";
|
|
3
3
|
import { Color } from 'three';
|
|
4
4
|
import { deltaE } from "../Renderer/Color.js";
|
|
5
5
|
import Coordinates from "./Geographic/Coordinates.js";
|
|
6
6
|
/* babel-plugin-inline-import './StyleChunk/itowns_stroke_single_before.css' */
|
|
7
7
|
const itowns_stroke_single_before = ".itowns-stroke-single:before {\n display: var(--text_stroke_display);\n content: attr(data-before);\n opacity: 1;\n position: absolute;\n -webkit-text-stroke-width: var(--text_stroke_width);\n -webkit-text-stroke-color: var(--text_stroke_color);\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n z-index: -1;\n white-space: inherit;\n overflow-wrap: inherit;\n letter-spacing: inherit;\n text-align: inherit;\n padding: inherit;\n font-family: inherit;\n text-transform: inherit;\n max-width: inherit;\n font-size: inherit;\n}\n";
|
|
8
|
-
const
|
|
8
|
+
const cachedImg = new LRUCache({
|
|
9
|
+
max: 500
|
|
10
|
+
});
|
|
9
11
|
const matrix = document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGMatrix();
|
|
10
12
|
const canvas = document.createElement('canvas');
|
|
11
13
|
function baseAltitudeDefault(properties, ctx) {
|
|
@@ -37,13 +39,14 @@ export function readExpression(property, ctx) {
|
|
|
37
39
|
}
|
|
38
40
|
return property;
|
|
39
41
|
}
|
|
40
|
-
async function loadImage(
|
|
41
|
-
|
|
42
|
+
async function loadImage(url) {
|
|
43
|
+
const imgUrl = url.split('?')[0];
|
|
44
|
+
let promise = cachedImg.get(imgUrl);
|
|
42
45
|
if (!promise) {
|
|
43
|
-
promise = Fetcher.texture(
|
|
46
|
+
promise = Fetcher.texture(url, {
|
|
44
47
|
crossOrigin: 'anonymous'
|
|
45
48
|
});
|
|
46
|
-
|
|
49
|
+
cachedImg.set(imgUrl, promise);
|
|
47
50
|
}
|
|
48
51
|
return (await promise).image;
|
|
49
52
|
}
|
|
@@ -64,7 +67,7 @@ function replaceWhitePxl(imgd, color, id) {
|
|
|
64
67
|
if (!color) {
|
|
65
68
|
return imgd;
|
|
66
69
|
}
|
|
67
|
-
const imgdColored =
|
|
70
|
+
const imgdColored = cachedImg.get(`${id}_${color}`);
|
|
68
71
|
if (!imgdColored) {
|
|
69
72
|
const pix = imgd.data;
|
|
70
73
|
const newColor = new Color(color);
|
|
@@ -75,7 +78,7 @@ function replaceWhitePxl(imgd, color, id) {
|
|
|
75
78
|
pix[i + 1] = pix[i + 1] * d + newColor.g * 255 * (1 - d);
|
|
76
79
|
pix[i + 2] = pix[i + 2] * d + newColor.b * 255 * (1 - d);
|
|
77
80
|
}
|
|
78
|
-
|
|
81
|
+
cachedImg.set(`${id}_${color}`, imgd);
|
|
79
82
|
return imgd;
|
|
80
83
|
}
|
|
81
84
|
return imgdColored;
|
package/lib/Core/TileGeometry.js
CHANGED
|
@@ -71,7 +71,7 @@ export class TileGeometry extends THREE.BufferGeometry {
|
|
|
71
71
|
* @param cacheTile - The [Cache] used to store this geometry.
|
|
72
72
|
* @param keys - The [south, level, epsg] key of this geometry.
|
|
73
73
|
*/
|
|
74
|
-
initRefCount(cacheTile,
|
|
74
|
+
initRefCount(cacheTile, key) {
|
|
75
75
|
if (this._refCount !== null) {
|
|
76
76
|
return;
|
|
77
77
|
}
|
|
@@ -87,7 +87,7 @@ export class TileGeometry extends THREE.BufferGeometry {
|
|
|
87
87
|
// (in THREE.WebGLBindingStates code).
|
|
88
88
|
this.index = null;
|
|
89
89
|
delete this.attributes.uv;
|
|
90
|
-
cacheTile.delete(
|
|
90
|
+
cacheTile.delete(key);
|
|
91
91
|
super.dispose();
|
|
92
92
|
// THREE.BufferGeometry.prototype.dispose.call(this);
|
|
93
93
|
}
|
package/lib/Layer/Layer.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as THREE from 'three';
|
|
|
2
2
|
import { STRATEGY_MIN_NETWORK_TRAFFIC } from "./LayerUpdateStrategy.js";
|
|
3
3
|
import InfoLayer from "./InfoLayer.js";
|
|
4
4
|
import Source from "../Source/Source.js";
|
|
5
|
-
import
|
|
5
|
+
import { LRUCache } from 'lru-cache';
|
|
6
6
|
import Style from "../Core/Style.js";
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -195,7 +195,12 @@ class Layer extends THREE.EventDispatcher {
|
|
|
195
195
|
/**
|
|
196
196
|
* @type {Cache}
|
|
197
197
|
*/
|
|
198
|
-
this.cache = new
|
|
198
|
+
this.cache = new LRUCache({
|
|
199
|
+
max: 500,
|
|
200
|
+
...(cacheLifeTime !== Infinity && {
|
|
201
|
+
ttl: cacheLifeTime
|
|
202
|
+
})
|
|
203
|
+
});
|
|
199
204
|
this.mergeFeatures = mergeFeatures;
|
|
200
205
|
}
|
|
201
206
|
addInitializationStep() {
|
|
@@ -267,13 +272,13 @@ class Layer extends THREE.EventDispatcher {
|
|
|
267
272
|
return data;
|
|
268
273
|
}
|
|
269
274
|
getData(from, to) {
|
|
270
|
-
const key = this.source.
|
|
271
|
-
let data = this.cache.
|
|
275
|
+
const key = this.source.getDataKey(this.source.isVectorSource ? to : from);
|
|
276
|
+
let data = this.cache.get(key);
|
|
272
277
|
if (!data) {
|
|
273
278
|
data = this.source.loadData(from, this).then(feat => this.convert(feat, to), err => {
|
|
274
279
|
throw err;
|
|
275
280
|
});
|
|
276
|
-
this.cache.
|
|
281
|
+
this.cache.set(key, data);
|
|
277
282
|
}
|
|
278
283
|
return data;
|
|
279
284
|
}
|
package/lib/Source/FileSource.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Source from "./Source.js";
|
|
2
|
-
import
|
|
2
|
+
import { LRUCache } from 'lru-cache';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* An object defining the source of a single resource to get from a direct
|
|
@@ -133,8 +133,10 @@ class FileSource extends Source {
|
|
|
133
133
|
this.fetchedData = f;
|
|
134
134
|
});
|
|
135
135
|
} else if (source.features) {
|
|
136
|
-
this._featuresCaches[source.features.crs] = new
|
|
137
|
-
|
|
136
|
+
this._featuresCaches[source.features.crs] = new LRUCache({
|
|
137
|
+
max: 500
|
|
138
|
+
});
|
|
139
|
+
this._featuresCaches[source.features.crs].set(0, Promise.resolve(source.features));
|
|
138
140
|
}
|
|
139
141
|
this.whenReady.then(() => this.fetchedData);
|
|
140
142
|
this.zoom = {
|
|
@@ -148,14 +150,14 @@ class FileSource extends Source {
|
|
|
148
150
|
onLayerAdded(options) {
|
|
149
151
|
options.in = this;
|
|
150
152
|
super.onLayerAdded(options);
|
|
151
|
-
let features = this._featuresCaches[options.out.crs].
|
|
153
|
+
let features = this._featuresCaches[options.out.crs].get(0);
|
|
152
154
|
if (!features) {
|
|
153
155
|
options.out.buildExtent = this.crs != 'EPSG:4978';
|
|
154
156
|
if (options.out.buildExtent) {
|
|
155
157
|
options.out.forcedExtentCrs = options.out.crs != 'EPSG:4978' ? options.out.crs : this.crs;
|
|
156
158
|
}
|
|
157
159
|
features = this.parser(this.fetchedData, options);
|
|
158
|
-
this._featuresCaches[options.out.crs].
|
|
160
|
+
this._featuresCaches[options.out.crs].set(0, features);
|
|
159
161
|
}
|
|
160
162
|
features.then(data => {
|
|
161
163
|
if (data.extent) {
|
|
@@ -177,7 +179,7 @@ class FileSource extends Source {
|
|
|
177
179
|
* @return {FeatureCollection|Texture} The parsed data.
|
|
178
180
|
*/
|
|
179
181
|
loadData(extent, out) {
|
|
180
|
-
return this._featuresCaches[out.crs].
|
|
182
|
+
return this._featuresCaches[out.crs].get(0);
|
|
181
183
|
}
|
|
182
184
|
extentInsideLimit(extent) {
|
|
183
185
|
return this.extent.intersectsExtent(extent);
|
|
@@ -41,8 +41,8 @@ class OrientedImageSource extends Source {
|
|
|
41
41
|
urlFromExtent(imageInfo) {
|
|
42
42
|
return this.imageUrl(imageInfo.cameraId, imageInfo.panoId);
|
|
43
43
|
}
|
|
44
|
-
|
|
45
|
-
return
|
|
44
|
+
getDataKey(image) {
|
|
45
|
+
return `c${image.cameraId}p${image.panoId}`;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/**
|
package/lib/Source/Source.js
CHANGED
|
@@ -8,38 +8,17 @@ import GTXParser from "../Parser/GTXParser.js";
|
|
|
8
8
|
import ISGParser from "../Parser/ISGParser.js";
|
|
9
9
|
import VectorTileParser from "../Parser/VectorTileParser.js";
|
|
10
10
|
import Fetcher from "../Provider/Fetcher.js";
|
|
11
|
-
import Cache from
|
|
11
|
+
// import Cache from 'Core/Scheduler/Cache';
|
|
12
|
+
import { LRUCache } from 'lru-cache';
|
|
12
13
|
|
|
13
14
|
/** @private */
|
|
14
15
|
export const supportedParsers = new Map([['application/geo+json', GeoJsonParser.parse], ['application/json', GeoJsonParser.parse], ['application/kml', KMLParser.parse], ['application/gpx', GpxParser.parse], ['application/x-protobuf;type=mapbox-vector', VectorTileParser.parse], ['application/gtx', GTXParser.parse], ['application/isg', ISGParser.parse], ['application/gdf', GDFParser.parse]]);
|
|
15
16
|
const noCache = {
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
get: () => {},
|
|
18
|
+
set: a => a,
|
|
18
19
|
clear: () => {}
|
|
19
20
|
};
|
|
20
21
|
|
|
21
|
-
/**
|
|
22
|
-
* @property {string} crs - data crs projection.
|
|
23
|
-
* @property {boolean} isInverted - This option is to be set to the
|
|
24
|
-
* correct value, true or false (default being false), if the computation of
|
|
25
|
-
* the coordinates needs to be inverted to same scheme as OSM, Google Maps
|
|
26
|
-
* or other system. See [this link](
|
|
27
|
-
* https://alastaira.wordpress.com/2011/07/06/converting-tms-tile-coordinates-to-googlebingosm-tile-coordinates)
|
|
28
|
-
* for more informations.
|
|
29
|
-
*
|
|
30
|
-
*/
|
|
31
|
-
class InformationsData {
|
|
32
|
-
constructor(options) {
|
|
33
|
-
if (options.projection) {
|
|
34
|
-
console.warn('Source projection parameter is deprecated, use crs instead.');
|
|
35
|
-
options.crs = options.crs || options.projection;
|
|
36
|
-
}
|
|
37
|
-
if (options.crs) {
|
|
38
|
-
CRS.isValid(options.crs);
|
|
39
|
-
}
|
|
40
|
-
this.crs = options.crs;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
22
|
/**
|
|
44
23
|
* This interface describes parsing options.
|
|
45
24
|
* @typedef {Object} ParsingOptions
|
|
@@ -93,13 +72,20 @@ let uid = 0;
|
|
|
93
72
|
* depending on the current fetched tile for example</li>
|
|
94
73
|
* </ul>
|
|
95
74
|
*/
|
|
96
|
-
class Source
|
|
75
|
+
class Source {
|
|
97
76
|
/**
|
|
98
77
|
* @param {Object} source - An object that can contain all properties of a
|
|
99
78
|
* Source. Only the `url` property is mandatory.
|
|
100
79
|
*/
|
|
101
80
|
constructor(source) {
|
|
102
|
-
|
|
81
|
+
if (source.projection) {
|
|
82
|
+
console.warn('Source projection parameter is deprecated, use crs instead.');
|
|
83
|
+
source.crs = source.crs || source.projection;
|
|
84
|
+
}
|
|
85
|
+
if (source.crs) {
|
|
86
|
+
CRS.isValid(source.crs);
|
|
87
|
+
}
|
|
88
|
+
this.crs = source.crs;
|
|
103
89
|
this.isSource = true;
|
|
104
90
|
if (!source.url) {
|
|
105
91
|
throw new Error('New Source: url is required');
|
|
@@ -141,8 +127,8 @@ class Source extends InformationsData {
|
|
|
141
127
|
urlFromExtent() {
|
|
142
128
|
throw new Error('In extended Source, you have to implement the method urlFromExtent!');
|
|
143
129
|
}
|
|
144
|
-
|
|
145
|
-
return
|
|
130
|
+
getDataKey(extent) {
|
|
131
|
+
return `z${extent.zoom}r${extent.row}c${extent.col}`;
|
|
146
132
|
}
|
|
147
133
|
|
|
148
134
|
/**
|
|
@@ -155,23 +141,18 @@ class Source extends InformationsData {
|
|
|
155
141
|
*/
|
|
156
142
|
loadData(extent, out) {
|
|
157
143
|
const cache = this._featuresCaches[out.crs];
|
|
158
|
-
const key = this.
|
|
144
|
+
const key = this.getDataKey(extent);
|
|
145
|
+
// console.log('Source.loadData', key);
|
|
159
146
|
// try to get parsed data from cache
|
|
160
|
-
let features = cache.
|
|
147
|
+
let features = cache.get(key);
|
|
161
148
|
if (!features) {
|
|
162
149
|
// otherwise fetch/parse the data
|
|
163
|
-
features =
|
|
150
|
+
features = this.fetcher(this.urlFromExtent(extent), this.networkOptions).then(file => this.parser(file, {
|
|
164
151
|
out,
|
|
165
152
|
in: this,
|
|
166
153
|
extent
|
|
167
|
-
})).catch(err => this.handlingError(err))
|
|
168
|
-
|
|
169
|
-
features.then(feat => {
|
|
170
|
-
this.onParsedFile(feat);
|
|
171
|
-
console.warn('Source.onParsedFile was deprecated');
|
|
172
|
-
return feat;
|
|
173
|
-
});
|
|
174
|
-
}
|
|
154
|
+
})).catch(err => this.handlingError(err));
|
|
155
|
+
cache.set(key, features);
|
|
175
156
|
}
|
|
176
157
|
return features;
|
|
177
158
|
}
|
|
@@ -187,7 +168,9 @@ class Source extends InformationsData {
|
|
|
187
168
|
// Cache feature only if it's vector data, the feature are cached in source.
|
|
188
169
|
// It's not necessary to cache raster in Source,
|
|
189
170
|
// because it's already cached on layer.
|
|
190
|
-
this._featuresCaches[options.out.crs] = this.isVectorSource ? new
|
|
171
|
+
this._featuresCaches[options.out.crs] = this.isVectorSource ? new LRUCache({
|
|
172
|
+
max: 500
|
|
173
|
+
}) : noCache;
|
|
191
174
|
}
|
|
192
175
|
}
|
|
193
176
|
|
|
@@ -164,23 +164,17 @@ class VectorTilesSource extends TMSSource {
|
|
|
164
164
|
}
|
|
165
165
|
loadData(extent, out) {
|
|
166
166
|
const cache = this._featuresCaches[out.crs];
|
|
167
|
-
const key = this.
|
|
167
|
+
const key = this.getDataKey(extent);
|
|
168
168
|
// try to get parsed data from cache
|
|
169
|
-
let features = cache.
|
|
169
|
+
let features = cache.get(key);
|
|
170
170
|
if (!features) {
|
|
171
171
|
// otherwise fetch/parse the data
|
|
172
|
-
features =
|
|
172
|
+
features = Promise.all(this.urls.map(url => this.fetcher(this.urlFromExtent(extent, url), this.networkOptions).then(file => this.parser(file, {
|
|
173
173
|
out,
|
|
174
174
|
in: this,
|
|
175
175
|
extent
|
|
176
|
-
})))).then(collections => mergeCollections(collections)).catch(err => this.handlingError(err))
|
|
177
|
-
|
|
178
|
-
features.then(feat => {
|
|
179
|
-
this.onParsedFile(feat);
|
|
180
|
-
console.warn('Source.onParsedFile was deprecated');
|
|
181
|
-
return feat;
|
|
182
|
-
});
|
|
183
|
-
}
|
|
176
|
+
})))).then(collections => mergeCollections(collections)).catch(err => this.handlingError(err));
|
|
177
|
+
cache.set(key, features);
|
|
184
178
|
}
|
|
185
179
|
return features;
|
|
186
180
|
}
|
package/lib/Source/WFSSource.js
CHANGED
|
@@ -152,11 +152,11 @@ class WFSSource extends Source {
|
|
|
152
152
|
}
|
|
153
153
|
return super.handlingError(err);
|
|
154
154
|
}
|
|
155
|
-
|
|
155
|
+
getDataKey(extent) {
|
|
156
156
|
if (extent.isTile) {
|
|
157
|
-
return super.
|
|
157
|
+
return super.getDataKey(extent);
|
|
158
158
|
} else {
|
|
159
|
-
return
|
|
159
|
+
return `z${extent.zoom}s${extent.south}w${extent.west}`;
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
urlFromExtent(extentOrTile) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "itowns",
|
|
3
|
-
"version": "2.44.3-next.
|
|
3
|
+
"version": "2.44.3-next.36",
|
|
4
4
|
"description": "A JS/WebGL framework for 3D geospatial data visualization",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/Main.js",
|
|
@@ -66,6 +66,7 @@
|
|
|
66
66
|
"copc": "^0.0.6",
|
|
67
67
|
"earcut": "^3.0.0",
|
|
68
68
|
"js-priority-queue": "^0.1.5",
|
|
69
|
+
"lru-cache": "^11.0.1",
|
|
69
70
|
"pbf": "^4.0.1",
|
|
70
71
|
"shpjs": "^6.1.0",
|
|
71
72
|
"threads": "^1.7.0"
|