@mapwhit/tilerenderer 0.47.1 → 0.47.2
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/build/min/package.json +1 -1
- package/package.json +1 -2
- package/src/data/array_types.js +1 -1
- package/src/data/bucket/circle_bucket.js +1 -1
- package/src/data/bucket/fill_bucket.js +1 -1
- package/src/data/bucket/fill_extrusion_bucket.js +1 -1
- package/src/data/bucket/heatmap_bucket.js +1 -1
- package/src/data/bucket/line_bucket.js +1 -1
- package/src/data/bucket/symbol_bucket.js +1 -1
- package/src/data/dem_data.js +1 -1
- package/src/data/feature_index.js +43 -82
- package/src/data/program_configuration.js +1 -1
- package/src/data/segment.js +2 -2
- package/src/gl/color_mode.js +6 -6
- package/src/index.js +2 -0
- package/src/render/glyph_atlas.js +1 -1
- package/src/render/glyph_manager.js +43 -48
- package/src/render/image_atlas.js +1 -1
- package/src/render/image_manager.js +9 -37
- package/src/source/geojson_source.js +49 -93
- package/src/source/geojson_worker_source.js +33 -134
- package/src/source/image_source.js +9 -14
- package/src/source/load_tilejson.js +27 -34
- package/src/source/raster_dem_tile_source.js +27 -40
- package/src/source/raster_tile_source.js +53 -62
- package/src/source/rtl_text_plugin.js +2 -1
- package/src/source/source_cache.js +22 -20
- package/src/source/source_state.js +17 -26
- package/src/source/tile_id.js +1 -1
- package/src/source/vector_tile_source.js +56 -73
- package/src/source/vector_tile_worker_source.js +20 -85
- package/src/source/worker.js +38 -95
- package/src/source/worker_tile.js +39 -84
- package/src/style/load_sprite.js +14 -17
- package/src/style/properties.js +1 -1
- package/src/style/style.js +22 -22
- package/src/style/style_layer_index.js +17 -23
- package/src/style-spec/reference/v8.json +2 -2
- package/src/symbol/anchor.js +1 -1
- package/src/symbol/collision_index.js +23 -16
- package/src/symbol/grid_index.js +176 -182
- package/src/symbol/mergelines.js +48 -48
- package/src/symbol/opacity_state.js +1 -1
- package/src/ui/camera.js +82 -85
- package/src/ui/map.js +5 -32
- package/src/util/actor.js +46 -42
- package/src/util/browser.js +6 -0
- package/src/util/dictionary_coder.js +13 -21
- package/src/util/dispatcher.js +14 -17
- package/src/util/image.js +1 -1
- package/src/util/loader/image.js +11 -11
- package/src/util/polyfill.js +16 -0
- package/src/util/task_queue.js +39 -43
- package/src/util/transfer_registry.js +167 -0
- package/src/util/web_worker_transfer.js +5 -190
- package/src/source/raster_dem_tile_worker_source.js +0 -26
package/build/min/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mapwhit/tilerenderer",
|
|
3
3
|
"description": "A WebGL interactive maps library",
|
|
4
|
-
"version": "0.47.
|
|
4
|
+
"version": "0.47.2",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"license": "BSD-3-Clause",
|
|
7
7
|
"repository": {
|
|
@@ -26,7 +26,6 @@
|
|
|
26
26
|
"grid-index": "^1.1.0",
|
|
27
27
|
"quickselect": "^2.0.0",
|
|
28
28
|
"supercluster": "^2.0.1",
|
|
29
|
-
"tile-cache": "^1.0.2",
|
|
30
29
|
"tinyqueue": "^1.1.0"
|
|
31
30
|
},
|
|
32
31
|
"browser": {
|
package/src/data/array_types.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const assert = require('assert');
|
|
4
4
|
const { Struct, StructArray } = require('../util/struct_array');
|
|
5
|
-
const { register } = require('../util/
|
|
5
|
+
const { register } = require('../util/transfer_registry');
|
|
6
6
|
const Point = require('@mapbox/point-geometry');
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -6,7 +6,7 @@ const { ProgramConfigurationSet } = require('../program_configuration');
|
|
|
6
6
|
const { TriangleIndexArray } = require('../index_array_type');
|
|
7
7
|
const loadGeometry = require('../load_geometry');
|
|
8
8
|
const EXTENT = require('../extent');
|
|
9
|
-
const { register } = require('../../util/
|
|
9
|
+
const { register } = require('../../util/transfer_registry');
|
|
10
10
|
const EvaluationParameters = require('../../style/evaluation_parameters');
|
|
11
11
|
|
|
12
12
|
function addCircleVertex(layoutVertexArray, x, y, extrudeX, extrudeY) {
|
|
@@ -8,7 +8,7 @@ const earcut = require('earcut');
|
|
|
8
8
|
const classifyRings = require('../../util/classify_rings');
|
|
9
9
|
const assert = require('assert');
|
|
10
10
|
const EARCUT_MAX_RINGS = 500;
|
|
11
|
-
const { register } = require('../../util/
|
|
11
|
+
const { register } = require('../../util/transfer_registry');
|
|
12
12
|
const { hasPattern, addPatternDependencies } = require('./pattern_bucket_features');
|
|
13
13
|
const loadGeometry = require('../load_geometry');
|
|
14
14
|
const EvaluationParameters = require('../../style/evaluation_parameters');
|
|
@@ -12,7 +12,7 @@ const {
|
|
|
12
12
|
const classifyRings = require('../../util/classify_rings');
|
|
13
13
|
const assert = require('assert');
|
|
14
14
|
const EARCUT_MAX_RINGS = 500;
|
|
15
|
-
const { register } = require('../../util/
|
|
15
|
+
const { register } = require('../../util/transfer_registry');
|
|
16
16
|
const { hasPattern, addPatternDependencies } = require('./pattern_bucket_features');
|
|
17
17
|
const loadGeometry = require('../load_geometry');
|
|
18
18
|
const EvaluationParameters = require('../../style/evaluation_parameters');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const CircleBucket = require('./circle_bucket');
|
|
2
2
|
|
|
3
|
-
const { register } = require('../../util/
|
|
3
|
+
const { register } = require('../../util/transfer_registry');
|
|
4
4
|
|
|
5
5
|
class HeatmapBucket extends CircleBucket {
|
|
6
6
|
// Needed for flow to accept omit: ['layers'] below, due to
|
|
@@ -7,7 +7,7 @@ const { TriangleIndexArray } = require('../index_array_type');
|
|
|
7
7
|
const EXTENT = require('../extent');
|
|
8
8
|
const mvt = require('@mapbox/vector-tile');
|
|
9
9
|
const vectorTileFeatureTypes = mvt.VectorTileFeature.types;
|
|
10
|
-
const { register } = require('../../util/
|
|
10
|
+
const { register } = require('../../util/transfer_registry');
|
|
11
11
|
const { hasPattern, addPatternDependencies } = require('./pattern_bucket_features');
|
|
12
12
|
const loadGeometry = require('../load_geometry');
|
|
13
13
|
const EvaluationParameters = require('../../style/evaluation_parameters');
|
|
@@ -29,7 +29,7 @@ const mvt = require('@mapbox/vector-tile');
|
|
|
29
29
|
const vectorTileFeatureTypes = mvt.VectorTileFeature.types;
|
|
30
30
|
const { verticalizedCharacterMap } = require('../../util/verticalize_punctuation');
|
|
31
31
|
const { getSizeData } = require('../../symbol/symbol_size');
|
|
32
|
-
const { register } = require('../../util/
|
|
32
|
+
const { register } = require('../../util/transfer_registry');
|
|
33
33
|
const EvaluationParameters = require('../../style/evaluation_parameters');
|
|
34
34
|
|
|
35
35
|
// Opacity arrays are frequently updated but don't contain a lot of information, so we pack them
|
package/src/data/dem_data.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { RGBAImage } = require('../util/image');
|
|
2
2
|
|
|
3
3
|
const warn = require('../util/warn');
|
|
4
|
-
const { register } = require('../util/
|
|
4
|
+
const { register } = require('../util/transfer_registry');
|
|
5
5
|
|
|
6
6
|
// DEMData is a data structure for decoding, backfilling, and storing elevation data for processing in the hillshade shaders
|
|
7
7
|
// data can be populated either from a pngraw image tile or from serliazed data sent back from a worker. When data is initially
|
|
@@ -2,26 +2,23 @@ const loadGeometry = require('./load_geometry');
|
|
|
2
2
|
const EXTENT = require('./extent');
|
|
3
3
|
const featureFilter = require('../style-spec/feature_filter');
|
|
4
4
|
const Grid = require('grid-index');
|
|
5
|
-
const
|
|
5
|
+
const dictionaryCoder = require('../util/dictionary_coder');
|
|
6
6
|
const vt = require('@mapbox/vector-tile');
|
|
7
7
|
const Protobuf = require('@mapwhit/pbf');
|
|
8
8
|
const GeoJSONFeature = require('../util/vectortile_to_geojson');
|
|
9
9
|
const { arraysIntersect } = require('../util/object');
|
|
10
|
-
const { register } = require('../util/
|
|
10
|
+
const { register } = require('../util/transfer_registry');
|
|
11
11
|
const EvaluationParameters = require('../style/evaluation_parameters');
|
|
12
12
|
const { polygonIntersectsBox } = require('../util/intersection_tests');
|
|
13
13
|
|
|
14
14
|
const { FeatureIndexArray } = require('./array_types');
|
|
15
15
|
|
|
16
16
|
class FeatureIndex {
|
|
17
|
-
constructor(tileID, grid, featureIndexArray) {
|
|
17
|
+
constructor(tileID, grid = new Grid(EXTENT, 16, 0), featureIndexArray = new FeatureIndexArray()) {
|
|
18
18
|
this.tileID = tileID;
|
|
19
|
-
this.
|
|
20
|
-
this.y = tileID.canonical.y;
|
|
21
|
-
this.z = tileID.canonical.z;
|
|
22
|
-
this.grid = grid || new Grid(EXTENT, 16, 0);
|
|
19
|
+
this.grid = grid;
|
|
23
20
|
this.grid3D = new Grid(EXTENT, 16, 0);
|
|
24
|
-
this.featureIndexArray = featureIndexArray
|
|
21
|
+
this.featureIndexArray = featureIndexArray;
|
|
25
22
|
}
|
|
26
23
|
|
|
27
24
|
insert(feature, geometry, featureIndex, sourceLayerIndex, bucketIndex, is3D) {
|
|
@@ -30,25 +27,10 @@ class FeatureIndex {
|
|
|
30
27
|
|
|
31
28
|
const grid = is3D ? this.grid3D : this.grid;
|
|
32
29
|
|
|
33
|
-
for (
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
Number.POSITIVE_INFINITY,
|
|
38
|
-
Number.POSITIVE_INFINITY,
|
|
39
|
-
Number.NEGATIVE_INFINITY,
|
|
40
|
-
Number.NEGATIVE_INFINITY
|
|
41
|
-
];
|
|
42
|
-
for (let i = 0; i < ring.length; i++) {
|
|
43
|
-
const p = ring[i];
|
|
44
|
-
bbox[0] = Math.min(bbox[0], p.x);
|
|
45
|
-
bbox[1] = Math.min(bbox[1], p.y);
|
|
46
|
-
bbox[2] = Math.max(bbox[2], p.x);
|
|
47
|
-
bbox[3] = Math.max(bbox[3], p.y);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (bbox[0] < EXTENT && bbox[1] < EXTENT && bbox[2] >= 0 && bbox[3] >= 0) {
|
|
51
|
-
grid.insert(key, bbox[0], bbox[1], bbox[2], bbox[3]);
|
|
30
|
+
for (const ring of geometry) {
|
|
31
|
+
const { minX, minY, maxX, maxY } = getBounds(ring);
|
|
32
|
+
if (minX < EXTENT && minY < EXTENT && maxX >= 0 && maxY >= 0) {
|
|
33
|
+
grid.insert(key, minX, minY, maxX, maxY);
|
|
52
34
|
}
|
|
53
35
|
}
|
|
54
36
|
}
|
|
@@ -56,9 +38,7 @@ class FeatureIndex {
|
|
|
56
38
|
loadVTLayers() {
|
|
57
39
|
if (!this.vtLayers) {
|
|
58
40
|
this.vtLayers = new vt.VectorTile(new Protobuf(this.rawTileData)).layers;
|
|
59
|
-
this.sourceLayerCoder =
|
|
60
|
-
this.vtLayers ? Object.keys(this.vtLayers).sort() : ['_geojsonTileLayer']
|
|
61
|
-
);
|
|
41
|
+
this.sourceLayerCoder = dictionaryCoder(this.vtLayers ? Object.keys(this.vtLayers) : ['_geojsonTileLayer']);
|
|
62
42
|
}
|
|
63
43
|
return this.vtLayers;
|
|
64
44
|
}
|
|
@@ -99,10 +79,7 @@ class FeatureIndex {
|
|
|
99
79
|
}
|
|
100
80
|
);
|
|
101
81
|
|
|
102
|
-
|
|
103
|
-
matching.push(key);
|
|
104
|
-
}
|
|
105
|
-
|
|
82
|
+
matching.push(...matching3D);
|
|
106
83
|
matching.sort(topDownFeatureComparator);
|
|
107
84
|
|
|
108
85
|
const result = {};
|
|
@@ -116,6 +93,26 @@ class FeatureIndex {
|
|
|
116
93
|
|
|
117
94
|
const match = this.featureIndexArray.get(index);
|
|
118
95
|
let featureGeometry = null;
|
|
96
|
+
const intersectionTest = (feature, styleLayer) => {
|
|
97
|
+
if (!featureGeometry) {
|
|
98
|
+
featureGeometry = loadGeometry(feature);
|
|
99
|
+
}
|
|
100
|
+
let featureState = {};
|
|
101
|
+
if (feature.id) {
|
|
102
|
+
// `feature-state` expression evaluation requires feature state to be available
|
|
103
|
+
featureState = sourceFeatureState.getState(styleLayer.sourceLayer || '_geojsonTileLayer', String(feature.id));
|
|
104
|
+
}
|
|
105
|
+
return styleLayer.queryIntersectsFeature(
|
|
106
|
+
queryGeometry,
|
|
107
|
+
feature,
|
|
108
|
+
featureState,
|
|
109
|
+
featureGeometry,
|
|
110
|
+
this.tileID.canonical.z,
|
|
111
|
+
args.transform,
|
|
112
|
+
pixelsToTileUnits,
|
|
113
|
+
args.pixelPosMatrix
|
|
114
|
+
);
|
|
115
|
+
};
|
|
119
116
|
this.loadMatchingFeature(
|
|
120
117
|
result,
|
|
121
118
|
match.bucketIndex,
|
|
@@ -124,29 +121,7 @@ class FeatureIndex {
|
|
|
124
121
|
filter,
|
|
125
122
|
params.layers,
|
|
126
123
|
styleLayers,
|
|
127
|
-
|
|
128
|
-
if (!featureGeometry) {
|
|
129
|
-
featureGeometry = loadGeometry(feature);
|
|
130
|
-
}
|
|
131
|
-
let featureState = {};
|
|
132
|
-
if (feature.id) {
|
|
133
|
-
// `feature-state` expression evaluation requires feature state to be available
|
|
134
|
-
featureState = sourceFeatureState.getState(
|
|
135
|
-
styleLayer.sourceLayer || '_geojsonTileLayer',
|
|
136
|
-
String(feature.id)
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
return styleLayer.queryIntersectsFeature(
|
|
140
|
-
queryGeometry,
|
|
141
|
-
feature,
|
|
142
|
-
featureState,
|
|
143
|
-
featureGeometry,
|
|
144
|
-
this.z,
|
|
145
|
-
args.transform,
|
|
146
|
-
pixelsToTileUnits,
|
|
147
|
-
args.pixelPosMatrix
|
|
148
|
-
);
|
|
149
|
-
}
|
|
124
|
+
intersectionTest
|
|
150
125
|
);
|
|
151
126
|
}
|
|
152
127
|
|
|
@@ -172,10 +147,9 @@ class FeatureIndex {
|
|
|
172
147
|
|
|
173
148
|
if (!filter(new EvaluationParameters(this.tileID.overscaledZ), feature)) return;
|
|
174
149
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (filterLayerIDs && filterLayerIDs.indexOf(layerID) < 0) {
|
|
150
|
+
const { x, y, z } = this.tileID.canonical;
|
|
151
|
+
for (const layerID of layerIDs) {
|
|
152
|
+
if (filterLayerIDs && !filterLayerIDs.includes(layerID)) {
|
|
179
153
|
continue;
|
|
180
154
|
}
|
|
181
155
|
|
|
@@ -188,13 +162,10 @@ class FeatureIndex {
|
|
|
188
162
|
continue;
|
|
189
163
|
}
|
|
190
164
|
|
|
191
|
-
const geojsonFeature = new GeoJSONFeature(feature,
|
|
165
|
+
const geojsonFeature = new GeoJSONFeature(feature, z, x, y);
|
|
192
166
|
geojsonFeature.layer = styleLayer.serialize();
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
layerResult = result[layerID] = [];
|
|
196
|
-
}
|
|
197
|
-
layerResult.push({ featureIndex: featureIndex, feature: geojsonFeature, intersectionZ });
|
|
167
|
+
const layerResult = (result[layerID] ??= []);
|
|
168
|
+
layerResult.push({ featureIndex, feature: geojsonFeature, intersectionZ });
|
|
198
169
|
}
|
|
199
170
|
}
|
|
200
171
|
|
|
@@ -219,16 +190,6 @@ class FeatureIndex {
|
|
|
219
190
|
}
|
|
220
191
|
return result;
|
|
221
192
|
}
|
|
222
|
-
|
|
223
|
-
hasLayer(id) {
|
|
224
|
-
for (const layerIDs of this.bucketLayerIDs) {
|
|
225
|
-
for (const layerID of layerIDs) {
|
|
226
|
-
if (id === layerID) return true;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
return false;
|
|
231
|
-
}
|
|
232
193
|
}
|
|
233
194
|
|
|
234
195
|
register('FeatureIndex', FeatureIndex, { omit: ['rawTileData', 'sourceLayerCoder'] });
|
|
@@ -240,11 +201,11 @@ function getBounds(geometry) {
|
|
|
240
201
|
let minY = Number.POSITIVE_INFINITY;
|
|
241
202
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
242
203
|
let maxY = Number.NEGATIVE_INFINITY;
|
|
243
|
-
for (const
|
|
244
|
-
minX =
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
maxY =
|
|
204
|
+
for (const { x, y } of geometry) {
|
|
205
|
+
if (x < minX) minX = x;
|
|
206
|
+
if (x > maxX) maxX = x;
|
|
207
|
+
if (y < minY) minY = y;
|
|
208
|
+
if (y > maxY) maxY = y;
|
|
248
209
|
}
|
|
249
210
|
return { minX, minY, maxX, maxY };
|
|
250
211
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { packUint8ToFloat } = require('../shaders/encode_attribute');
|
|
2
2
|
const { supportsPropertyExpression } = require('../style-spec/util/properties');
|
|
3
|
-
const { register } = require('../util/
|
|
3
|
+
const { register } = require('../util/transfer_registry');
|
|
4
4
|
const { PossiblyEvaluatedPropertyValue } = require('../style/properties');
|
|
5
5
|
const {
|
|
6
6
|
StructArrayLayout1f4,
|
package/src/data/segment.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const warn = require('../util/warn');
|
|
2
2
|
|
|
3
|
-
const { register } = require('../util/
|
|
3
|
+
const { register } = require('../util/transfer_registry');
|
|
4
4
|
|
|
5
5
|
class SegmentVector {
|
|
6
6
|
constructor(segments = []) {
|
|
@@ -8,11 +8,11 @@ class SegmentVector {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
prepareSegment(numVertices, layoutVertexArray, indexArray) {
|
|
11
|
-
let segment = this.segments[this.segments.length - 1];
|
|
12
11
|
if (numVertices > SegmentVector.MAX_VERTEX_ARRAY_LENGTH)
|
|
13
12
|
warn.once(
|
|
14
13
|
`Max vertices per segment is ${SegmentVector.MAX_VERTEX_ARRAY_LENGTH}: bucket requested ${numVertices}`
|
|
15
14
|
);
|
|
15
|
+
let segment = this.segments.at(-1);
|
|
16
16
|
if (!segment || segment.vertexLength + numVertices > SegmentVector.MAX_VERTEX_ARRAY_LENGTH) {
|
|
17
17
|
segment = {
|
|
18
18
|
vertexOffset: layoutVertexArray.length,
|
package/src/gl/color_mode.js
CHANGED
|
@@ -5,6 +5,12 @@ const ONE = 0x0001;
|
|
|
5
5
|
const ONE_MINUS_SRC_ALPHA = 0x0303;
|
|
6
6
|
|
|
7
7
|
class ColorMode {
|
|
8
|
+
static Replace = [ONE, ZERO];
|
|
9
|
+
|
|
10
|
+
static disabled = new ColorMode(ColorMode.Replace, Color.transparent, [false, false, false, false]);
|
|
11
|
+
static unblended = new ColorMode(ColorMode.Replace, Color.transparent, [true, true, true, true]);
|
|
12
|
+
static alphaBlended = new ColorMode([ONE, ONE_MINUS_SRC_ALPHA], Color.transparent, [true, true, true, true]);
|
|
13
|
+
|
|
8
14
|
constructor(blendFunction, blendColor, mask) {
|
|
9
15
|
this.blendFunction = blendFunction;
|
|
10
16
|
this.blendColor = blendColor;
|
|
@@ -12,10 +18,4 @@ class ColorMode {
|
|
|
12
18
|
}
|
|
13
19
|
}
|
|
14
20
|
|
|
15
|
-
ColorMode.Replace = [ONE, ZERO];
|
|
16
|
-
|
|
17
|
-
ColorMode.disabled = new ColorMode(ColorMode.Replace, Color.transparent, [false, false, false, false]);
|
|
18
|
-
ColorMode.unblended = new ColorMode(ColorMode.Replace, Color.transparent, [true, true, true, true]);
|
|
19
|
-
ColorMode.alphaBlended = new ColorMode([ONE, ONE_MINUS_SRC_ALPHA], Color.transparent, [true, true, true, true]);
|
|
20
|
-
|
|
21
21
|
module.exports = ColorMode;
|
package/src/index.js
CHANGED
|
@@ -3,7 +3,6 @@ const loadGlyphRange = require('../style/load_glyph_range');
|
|
|
3
3
|
const TinySDF = require('@mapbox/tiny-sdf');
|
|
4
4
|
const isChar = require('../util/is_char_in_unicode_block');
|
|
5
5
|
const { AlphaImage } = require('../util/image');
|
|
6
|
-
const { callback } = require('../util/callback');
|
|
7
6
|
|
|
8
7
|
class GlyphManager {
|
|
9
8
|
// exposed as statics to enable stubbing in unit tests
|
|
@@ -19,62 +18,58 @@ class GlyphManager {
|
|
|
19
18
|
this.loader = loader;
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
getGlyphs(glyphs
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
for (const stack in glyphs) {
|
|
28
|
-
for (const id of glyphs[stack]) {
|
|
29
|
-
all.push(retrieveGlyph(this, { stack, id }));
|
|
30
|
-
}
|
|
21
|
+
async getGlyphs(glyphs) {
|
|
22
|
+
const all = [];
|
|
23
|
+
for (const stack in glyphs) {
|
|
24
|
+
for (const id of glyphs[stack]) {
|
|
25
|
+
all.push(retrieveGlyph(this, { stack, id }));
|
|
31
26
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
27
|
+
}
|
|
28
|
+
const fetchedGlyphs = await Promise.all(all);
|
|
29
|
+
const result = {};
|
|
30
|
+
for (const { stack, id, glyph } of fetchedGlyphs) {
|
|
31
|
+
// Clone the glyph so that our own copy of its ArrayBuffer doesn't get transferred.
|
|
32
|
+
(result[stack] ??= {})[id] = cloneGlyph(glyph);
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
|
|
36
|
+
function cloneGlyph(glyph) {
|
|
37
|
+
if (glyph) {
|
|
38
|
+
return {
|
|
39
|
+
id: glyph.id,
|
|
40
|
+
bitmap: glyph.bitmap.clone(),
|
|
41
|
+
metrics: glyph.metrics
|
|
42
|
+
};
|
|
48
43
|
}
|
|
44
|
+
}
|
|
49
45
|
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
async function retrieveGlyph({ entries, loader, localIdeographFontFamily }, { stack, id }) {
|
|
47
|
+
const entry = (entries[stack] ??= { glyphs: {}, requests: {} });
|
|
52
48
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
let glyph = entry.glyphs[id];
|
|
50
|
+
if (glyph) {
|
|
51
|
+
return { stack, id, glyph };
|
|
52
|
+
}
|
|
57
53
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
54
|
+
glyph = tinySDF(localIdeographFontFamily, entry, stack, id);
|
|
55
|
+
if (glyph) {
|
|
56
|
+
return { stack, id, glyph };
|
|
57
|
+
}
|
|
62
58
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
59
|
+
const range = Math.floor(id / 256);
|
|
60
|
+
if (range * 256 > 65535) {
|
|
61
|
+
throw new Error('glyphs > 65535 not supported');
|
|
62
|
+
}
|
|
67
63
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
64
|
+
const promise = (entry.requests[range] ??= GlyphManager.loadGlyphRange(stack, range, loader));
|
|
65
|
+
const response = await promise;
|
|
66
|
+
if (response) {
|
|
67
|
+
for (const id in response) {
|
|
68
|
+
entry.glyphs[+id] = response[+id];
|
|
74
69
|
}
|
|
75
|
-
delete entry.requests[range];
|
|
76
|
-
return { stack, id, glyph: response?.[id] || null };
|
|
77
70
|
}
|
|
71
|
+
delete entry.requests[range];
|
|
72
|
+
return { stack, id, glyph: response?.[id] || null };
|
|
78
73
|
}
|
|
79
74
|
}
|
|
80
75
|
}
|
|
@@ -22,10 +22,9 @@ const padding = 1;
|
|
|
22
22
|
to refactor this.
|
|
23
23
|
*/
|
|
24
24
|
class ImageManager {
|
|
25
|
+
#loadedState = Promise.withResolvers();
|
|
25
26
|
constructor() {
|
|
26
27
|
this.images = {};
|
|
27
|
-
this.loaded = false;
|
|
28
|
-
this.requestors = [];
|
|
29
28
|
|
|
30
29
|
this.shelfPack = new ShelfPack(64, 64, { autoResize: true });
|
|
31
30
|
this.patterns = {};
|
|
@@ -34,22 +33,15 @@ class ImageManager {
|
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
isLoaded() {
|
|
37
|
-
return this.loaded;
|
|
36
|
+
return !!this.#loadedState.loaded;
|
|
38
37
|
}
|
|
39
38
|
|
|
40
|
-
setLoaded(
|
|
41
|
-
if (this.loaded
|
|
39
|
+
setLoaded() {
|
|
40
|
+
if (this.#loadedState.loaded) {
|
|
42
41
|
return;
|
|
43
42
|
}
|
|
44
|
-
|
|
45
|
-
this.
|
|
46
|
-
|
|
47
|
-
if (loaded) {
|
|
48
|
-
for (const { ids, callback } of this.requestors) {
|
|
49
|
-
this._notify(ids, callback);
|
|
50
|
-
}
|
|
51
|
-
this.requestors = [];
|
|
52
|
-
}
|
|
43
|
+
this.#loadedState.loaded = true;
|
|
44
|
+
this.#loadedState.resolve();
|
|
53
45
|
}
|
|
54
46
|
|
|
55
47
|
getImage(id) {
|
|
@@ -76,29 +68,10 @@ class ImageManager {
|
|
|
76
68
|
return Object.keys(this.images);
|
|
77
69
|
}
|
|
78
70
|
|
|
79
|
-
getImages(ids
|
|
80
|
-
|
|
81
|
-
// (i.e. if they've been addeded via runtime styling), then notify the requestor immediately.
|
|
82
|
-
// Otherwise, delay notification until the sprite is loaded. At that point, if any of the
|
|
83
|
-
// dependencies are still unavailable, we'll just assume they are permanently missing.
|
|
84
|
-
let hasAllDependencies = true;
|
|
85
|
-
if (!this.isLoaded()) {
|
|
86
|
-
for (const id of ids) {
|
|
87
|
-
if (!this.images[id]) {
|
|
88
|
-
hasAllDependencies = false;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
if (this.isLoaded() || hasAllDependencies) {
|
|
93
|
-
this._notify(ids, callback);
|
|
94
|
-
} else {
|
|
95
|
-
this.requestors.push({ ids, callback });
|
|
96
|
-
}
|
|
97
|
-
}
|
|
71
|
+
async getImages(ids) {
|
|
72
|
+
await this.#loadedState.promise;
|
|
98
73
|
|
|
99
|
-
_notify(ids, callback) {
|
|
100
74
|
const response = {};
|
|
101
|
-
|
|
102
75
|
for (const id of ids) {
|
|
103
76
|
const image = this.images[id];
|
|
104
77
|
if (image) {
|
|
@@ -110,8 +83,7 @@ class ImageManager {
|
|
|
110
83
|
};
|
|
111
84
|
}
|
|
112
85
|
}
|
|
113
|
-
|
|
114
|
-
callback(null, response);
|
|
86
|
+
return response;
|
|
115
87
|
}
|
|
116
88
|
|
|
117
89
|
// Pattern stuff
|