@mapwhit/tilerenderer 0.51.1 → 0.52.0
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 +6 -6
- package/src/data/bucket/circle_bucket.js +4 -1
- package/src/data/bucket/fill_bucket.js +5 -1
- package/src/data/bucket/fill_extrusion_bucket.js +5 -1
- package/src/data/bucket/line_bucket.js +5 -1
- package/src/data/bucket/symbol_bucket.js +2 -1
- package/src/render/glyph_atlas.js +1 -1
- package/src/render/image_atlas.js +1 -1
- package/src/render/image_manager.js +1 -1
- package/src/source/geojson_source.js +2 -1
- package/src/source/geojson_worker_source.js +4 -4
- package/src/source/vector_tile_source.js +2 -1
- package/src/source/vector_tile_worker_source.js +1 -0
- package/src/source/worker_tile.js +8 -6
- package/src/style/evaluation_parameters.js +6 -4
- package/src/style/properties.js +4 -0
- package/src/style/style.js +79 -2
- package/src/style/style_layer.js +33 -1
- package/src/style-spec/feature_filter/index.js +13 -4
- package/src/style-spec/reference/v8.json +53 -13
- package/src/ui/map.js +25 -1
- package/src/util/transfer_registry.js +1 -0
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.
|
|
4
|
+
"version": "0.52.0",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./src/index.js",
|
|
7
7
|
"./worker": "./src/worker.js"
|
|
@@ -19,18 +19,18 @@
|
|
|
19
19
|
"@mapwhit/events": "^0.0.1",
|
|
20
20
|
"@mapwhit/geojson-rewind": "^1.0.0",
|
|
21
21
|
"@mapwhit/pbf": "^1.0.0",
|
|
22
|
-
"@mapwhit/style-expressions": "^
|
|
23
|
-
"@mapwhit/vector-tile": "^
|
|
24
|
-
"@mapwhit/vt-pbf": "^
|
|
22
|
+
"@mapwhit/style-expressions": "^1.1.0",
|
|
23
|
+
"@mapwhit/vector-tile": "^2.0.1",
|
|
24
|
+
"@mapwhit/vt-pbf": "^2.0.0",
|
|
25
25
|
"@pirxpilot/nanoassert": "~1",
|
|
26
26
|
"csscolorparser": "^1.0.3",
|
|
27
27
|
"earcut": "^3.0.1",
|
|
28
28
|
"geojson-vt": "^4.0.2",
|
|
29
29
|
"grid-index": "^1.1.0",
|
|
30
30
|
"murmurhash-js": "^1.0.0",
|
|
31
|
-
"potpack": "^1.0
|
|
31
|
+
"potpack": "^2.1.0",
|
|
32
32
|
"quickselect": "^3.0.0",
|
|
33
|
-
"supercluster": "^
|
|
33
|
+
"supercluster": "^8.0.1",
|
|
34
34
|
"tinyqueue": "^3.0.0"
|
|
35
35
|
},
|
|
36
36
|
"browser": {
|
|
@@ -23,6 +23,7 @@ function addCircleVertex(layoutVertexArray, x, y, extrudeX, extrudeY) {
|
|
|
23
23
|
class CircleBucket {
|
|
24
24
|
constructor(options) {
|
|
25
25
|
this.zoom = options.zoom;
|
|
26
|
+
this.globalState = options.globalState;
|
|
26
27
|
this.overscaling = options.overscaling;
|
|
27
28
|
this.layers = options.layers;
|
|
28
29
|
this.layerIds = this.layers.map(layer => layer.id);
|
|
@@ -37,7 +38,9 @@ class CircleBucket {
|
|
|
37
38
|
|
|
38
39
|
populate(features, options) {
|
|
39
40
|
for (const { feature, index, sourceLayerIndex } of features) {
|
|
40
|
-
if (
|
|
41
|
+
if (
|
|
42
|
+
this.layers[0]._featureFilter(new EvaluationParameters(this.zoom, { globalState: this.globalState }), feature)
|
|
43
|
+
) {
|
|
41
44
|
const geometry = loadGeometry(feature);
|
|
42
45
|
this.addFeature(feature, geometry, index);
|
|
43
46
|
options.featureIndex.insert(feature, geometry, index, sourceLayerIndex, this.index);
|
|
@@ -16,6 +16,7 @@ const EvaluationParameters = require('../../style/evaluation_parameters');
|
|
|
16
16
|
class FillBucket {
|
|
17
17
|
constructor(options) {
|
|
18
18
|
this.zoom = options.zoom;
|
|
19
|
+
this.globalState = options.globalState;
|
|
19
20
|
this.overscaling = options.overscaling;
|
|
20
21
|
this.layers = options.layers;
|
|
21
22
|
this.layerIds = this.layers.map(layer => layer.id);
|
|
@@ -35,7 +36,10 @@ class FillBucket {
|
|
|
35
36
|
this.hasPattern = hasPattern('fill', this.layers, options);
|
|
36
37
|
|
|
37
38
|
for (const { feature, index, sourceLayerIndex } of features) {
|
|
38
|
-
if (
|
|
39
|
+
if (
|
|
40
|
+
!this.layers[0]._featureFilter(new EvaluationParameters(this.zoom, { globalState: this.globalState }), feature)
|
|
41
|
+
)
|
|
42
|
+
continue;
|
|
39
43
|
|
|
40
44
|
const geometry = loadGeometry(feature);
|
|
41
45
|
|
|
@@ -36,6 +36,7 @@ function addVertex(vertexArray, x, y, nx, ny, nz, t, e) {
|
|
|
36
36
|
class FillExtrusionBucket {
|
|
37
37
|
constructor(options) {
|
|
38
38
|
this.zoom = options.zoom;
|
|
39
|
+
this.globalState = options.globalState;
|
|
39
40
|
this.overscaling = options.overscaling;
|
|
40
41
|
this.layers = options.layers;
|
|
41
42
|
this.layerIds = this.layers.map(layer => layer.id);
|
|
@@ -53,7 +54,10 @@ class FillExtrusionBucket {
|
|
|
53
54
|
this.hasPattern = hasPattern('fill-extrusion', this.layers, options);
|
|
54
55
|
|
|
55
56
|
for (const { feature, index, sourceLayerIndex } of features) {
|
|
56
|
-
if (
|
|
57
|
+
if (
|
|
58
|
+
!this.layers[0]._featureFilter(new EvaluationParameters(this.zoom, { globalState: this.globalState }), feature)
|
|
59
|
+
)
|
|
60
|
+
continue;
|
|
57
61
|
|
|
58
62
|
const geometry = loadGeometry(feature);
|
|
59
63
|
|
|
@@ -72,6 +72,7 @@ function addLineVertex(layoutVertexBuffer, point, extrude, round, up, dir, lines
|
|
|
72
72
|
class LineBucket {
|
|
73
73
|
constructor(options) {
|
|
74
74
|
this.zoom = options.zoom;
|
|
75
|
+
this.globalState = options.globalState;
|
|
75
76
|
this.overscaling = options.overscaling;
|
|
76
77
|
this.layers = options.layers;
|
|
77
78
|
this.layerIds = this.layers.map(layer => layer.id);
|
|
@@ -90,7 +91,10 @@ class LineBucket {
|
|
|
90
91
|
this.hasPattern = hasPattern('line', this.layers, options);
|
|
91
92
|
|
|
92
93
|
for (const { feature, index, sourceLayerIndex } of features) {
|
|
93
|
-
if (
|
|
94
|
+
if (
|
|
95
|
+
!this.layers[0]._featureFilter(new EvaluationParameters(this.zoom, { globalState: this.globalState }), feature)
|
|
96
|
+
)
|
|
97
|
+
continue;
|
|
94
98
|
|
|
95
99
|
const geometry = loadGeometry(feature);
|
|
96
100
|
|
|
@@ -176,6 +176,7 @@ class SymbolBucket {
|
|
|
176
176
|
constructor(options) {
|
|
177
177
|
this.collisionBoxArray = options.collisionBoxArray;
|
|
178
178
|
this.zoom = options.zoom;
|
|
179
|
+
this.globalState = options.globalState;
|
|
179
180
|
this.overscaling = options.overscaling;
|
|
180
181
|
this.layers = options.layers;
|
|
181
182
|
this.layerIds = this.layers.map(layer => layer.id);
|
|
@@ -258,7 +259,7 @@ class SymbolBucket {
|
|
|
258
259
|
|
|
259
260
|
const icons = options.iconDependencies;
|
|
260
261
|
const stacks = options.glyphDependencies;
|
|
261
|
-
const globalProperties = new EvaluationParameters(this.zoom);
|
|
262
|
+
const globalProperties = new EvaluationParameters(this.zoom, { globalState: this.globalState });
|
|
262
263
|
|
|
263
264
|
for (const { feature, index, sourceLayerIndex } of features) {
|
|
264
265
|
if (!layer._featureFilter(globalProperties, feature)) {
|
|
@@ -184,7 +184,8 @@ class GeoJSONSource extends Evented {
|
|
|
184
184
|
tileSize: this.tileSize,
|
|
185
185
|
source: this.id,
|
|
186
186
|
pixelRatio: browser.devicePixelRatio,
|
|
187
|
-
showCollisionBoxes: this.map.showCollisionBoxes
|
|
187
|
+
showCollisionBoxes: this.map.showCollisionBoxes,
|
|
188
|
+
globalState: this.map.getGlobalState()
|
|
188
189
|
};
|
|
189
190
|
|
|
190
191
|
const justReloaded = tile.workerID != null;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const rewind = require('@mapwhit/geojson-rewind');
|
|
2
2
|
const GeoJSONWrapper = require('./geojson_wrapper');
|
|
3
|
-
const
|
|
4
|
-
const
|
|
3
|
+
const { fromVectorTileJs } = require('@mapwhit/vt-pbf');
|
|
4
|
+
const { default: Supercluster } = require('supercluster');
|
|
5
5
|
const { default: geojsonvt } = require('geojson-vt');
|
|
6
6
|
const VectorTileWorkerSource = require('./vector_tile_worker_source');
|
|
7
7
|
|
|
@@ -29,7 +29,7 @@ function loadGeoJSONTile(params) {
|
|
|
29
29
|
// Encode the geojson-vt tile into binary vector tile form. This
|
|
30
30
|
// is a convenience that allows `FeatureIndex` to operate the same way
|
|
31
31
|
// across `VectorTileSource` and `GeoJSONSource` data.
|
|
32
|
-
let pbf =
|
|
32
|
+
let pbf = fromVectorTileJs(geojsonWrapper);
|
|
33
33
|
if (pbf.byteOffset !== 0 || pbf.byteLength !== pbf.buffer.byteLength) {
|
|
34
34
|
// Compatibility with node Buffer (https://github.com/mapbox/pbf/issues/35)
|
|
35
35
|
pbf = new Uint8Array(pbf);
|
|
@@ -81,7 +81,7 @@ class GeoJSONWorkerSource extends VectorTileWorkerSource {
|
|
|
81
81
|
this._createGeoJSONIndex = params.cluster
|
|
82
82
|
? () => {
|
|
83
83
|
rewind(data, true);
|
|
84
|
-
return
|
|
84
|
+
return new Supercluster(params.superclusterOptions).load(data.features);
|
|
85
85
|
}
|
|
86
86
|
: () => {
|
|
87
87
|
rewind(data, true);
|
|
@@ -94,7 +94,8 @@ class VectorTileSource extends Evented {
|
|
|
94
94
|
type: this.type,
|
|
95
95
|
source: this.id,
|
|
96
96
|
pixelRatio: browser.devicePixelRatio,
|
|
97
|
-
showCollisionBoxes: this.map.showCollisionBoxes
|
|
97
|
+
showCollisionBoxes: this.map.showCollisionBoxes,
|
|
98
|
+
globalState: this.map.getGlobalState()
|
|
98
99
|
};
|
|
99
100
|
tile.workerID ??= this.dispatcher.nextWorkerId();
|
|
100
101
|
const data = await this.dispatcher.send('loadTile', params, tile.workerID);
|
|
@@ -49,6 +49,7 @@ class VectorTileWorkerSource {
|
|
|
49
49
|
}
|
|
50
50
|
const { vectorTile, rawData } = response;
|
|
51
51
|
const workerTile = new WorkerTile(params);
|
|
52
|
+
workerTile.globalState = params.globalState;
|
|
52
53
|
workerTile.vectorTile = vectorTile;
|
|
53
54
|
const result = await workerTile.parse(vectorTile, this.layerIndex, this.resources);
|
|
54
55
|
if (rawData) {
|
|
@@ -31,6 +31,7 @@ class WorkerTile {
|
|
|
31
31
|
this.source = params.source;
|
|
32
32
|
this.overscaling = this.tileID.overscaleFactor();
|
|
33
33
|
this.showCollisionBoxes = params.showCollisionBoxes;
|
|
34
|
+
this.globalState = params.globalState;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
async parse(data, layerIndex, resources) {
|
|
@@ -81,7 +82,7 @@ class WorkerTile {
|
|
|
81
82
|
if (layer.maxzoom && this.zoom >= layer.maxzoom) continue;
|
|
82
83
|
if (layer.visibility === 'none') continue;
|
|
83
84
|
|
|
84
|
-
recalculateLayers(family, this.zoom);
|
|
85
|
+
recalculateLayers(family, this.zoom, { globalState: this.globalState });
|
|
85
86
|
|
|
86
87
|
const bucket = (buckets[layer.id] = layer.createBucket({
|
|
87
88
|
index: featureIndex.bucketLayerIDs.length,
|
|
@@ -91,7 +92,8 @@ class WorkerTile {
|
|
|
91
92
|
overscaling: this.overscaling,
|
|
92
93
|
collisionBoxArray: this.collisionBoxArray,
|
|
93
94
|
sourceLayerIndex: sourceLayerIndex,
|
|
94
|
-
sourceID: this.source
|
|
95
|
+
sourceID: this.source,
|
|
96
|
+
globalState: this.globalState
|
|
95
97
|
}));
|
|
96
98
|
|
|
97
99
|
bucket.populate(features, options);
|
|
@@ -114,7 +116,7 @@ class WorkerTile {
|
|
|
114
116
|
for (const key in buckets) {
|
|
115
117
|
const bucket = buckets[key];
|
|
116
118
|
if (bucket instanceof SymbolBucket) {
|
|
117
|
-
recalculateLayers(bucket.layers, this.zoom);
|
|
119
|
+
recalculateLayers(bucket.layers, this.zoom, { globalState: this.globalState });
|
|
118
120
|
performSymbolLayout(
|
|
119
121
|
bucket,
|
|
120
122
|
glyphMap,
|
|
@@ -127,7 +129,7 @@ class WorkerTile {
|
|
|
127
129
|
bucket.hasPattern &&
|
|
128
130
|
(bucket instanceof LineBucket || bucket instanceof FillBucket || bucket instanceof FillExtrusionBucket)
|
|
129
131
|
) {
|
|
130
|
-
recalculateLayers(bucket.layers, this.zoom);
|
|
132
|
+
recalculateLayers(bucket.layers, this.zoom, { globalState: this.globalState });
|
|
131
133
|
bucket.addFeatures(options, imageAtlas.patternPositions);
|
|
132
134
|
}
|
|
133
135
|
}
|
|
@@ -143,9 +145,9 @@ class WorkerTile {
|
|
|
143
145
|
}
|
|
144
146
|
}
|
|
145
147
|
|
|
146
|
-
function recalculateLayers(layers, zoom) {
|
|
148
|
+
function recalculateLayers(layers, zoom, options) {
|
|
147
149
|
// Layers are shared and may have been used by a WorkerTile with a different zoom.
|
|
148
|
-
const parameters = new EvaluationParameters(zoom);
|
|
150
|
+
const parameters = new EvaluationParameters(zoom, options);
|
|
149
151
|
for (const layer of layers) {
|
|
150
152
|
layer.recalculate(parameters);
|
|
151
153
|
}
|
|
@@ -8,15 +8,17 @@ class EvaluationParameters {
|
|
|
8
8
|
this.zoom = zoom;
|
|
9
9
|
|
|
10
10
|
if (options) {
|
|
11
|
-
this.now = options.now;
|
|
12
|
-
this.fadeDuration = options.fadeDuration;
|
|
13
|
-
this.zoomHistory = options.zoomHistory;
|
|
14
|
-
this.transition = options.transition;
|
|
11
|
+
this.now = options.now || 0;
|
|
12
|
+
this.fadeDuration = options.fadeDuration || 0;
|
|
13
|
+
this.zoomHistory = options.zoomHistory || new ZoomHistory();
|
|
14
|
+
this.transition = options.transition || {};
|
|
15
|
+
this.globalState = options.globalState || {};
|
|
15
16
|
} else {
|
|
16
17
|
this.now = 0;
|
|
17
18
|
this.fadeDuration = 0;
|
|
18
19
|
this.zoomHistory = new ZoomHistory();
|
|
19
20
|
this.transition = {};
|
|
21
|
+
this.globalState = {};
|
|
20
22
|
}
|
|
21
23
|
}
|
|
22
24
|
|
package/src/style/properties.js
CHANGED
|
@@ -75,6 +75,10 @@ class PropertyValue {
|
|
|
75
75
|
return this.expression.kind === 'source' || this.expression.kind === 'composite';
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
getGlobalStateRefs() {
|
|
79
|
+
return this.expression.globalStateRefs ?? new Set();
|
|
80
|
+
}
|
|
81
|
+
|
|
78
82
|
possiblyEvaluate(parameters) {
|
|
79
83
|
return this.property.possiblyEvaluate(this, parameters);
|
|
80
84
|
}
|
package/src/style/style.js
CHANGED
|
@@ -41,6 +41,7 @@ class Style extends Evented {
|
|
|
41
41
|
this.sourceCaches = {};
|
|
42
42
|
this.zoomHistory = new ZoomHistory();
|
|
43
43
|
this._loaded = false;
|
|
44
|
+
this._globalState = {};
|
|
44
45
|
|
|
45
46
|
this._resetUpdates();
|
|
46
47
|
|
|
@@ -78,6 +79,80 @@ class Style extends Evented {
|
|
|
78
79
|
});
|
|
79
80
|
}
|
|
80
81
|
|
|
82
|
+
setGlobalStateProperty(name, value) {
|
|
83
|
+
this._checkLoaded();
|
|
84
|
+
|
|
85
|
+
const newValue = value === null ? (this.stylesheet.state?.[name]?.default ?? null) : value;
|
|
86
|
+
|
|
87
|
+
if (deepEqual(newValue, this._globalState[name])) {
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
this._globalState[name] = newValue;
|
|
92
|
+
|
|
93
|
+
const sourceIdsToReload = this._findGlobalStateAffectedSources([name]);
|
|
94
|
+
|
|
95
|
+
for (const id in this.sourceCaches) {
|
|
96
|
+
if (sourceIdsToReload.has(id)) {
|
|
97
|
+
this._reloadSource(id);
|
|
98
|
+
this._changed = true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
getGlobalState() {
|
|
104
|
+
return this._globalState;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
setGlobalState(newStylesheetState) {
|
|
108
|
+
this._checkLoaded();
|
|
109
|
+
|
|
110
|
+
const changedGlobalStateRefs = [];
|
|
111
|
+
|
|
112
|
+
for (const propertyName in newStylesheetState) {
|
|
113
|
+
const didChange = !deepEqual(this._globalState[propertyName], newStylesheetState[propertyName].default);
|
|
114
|
+
|
|
115
|
+
if (didChange) {
|
|
116
|
+
changedGlobalStateRefs.push(propertyName);
|
|
117
|
+
this._globalState[propertyName] = newStylesheetState[propertyName].default;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const sourceIdsToReload = this._findGlobalStateAffectedSources(changedGlobalStateRefs);
|
|
122
|
+
|
|
123
|
+
for (const id in this.sourceCaches) {
|
|
124
|
+
if (sourceIdsToReload.has(id)) {
|
|
125
|
+
this._reloadSource(id);
|
|
126
|
+
this._changed = true;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Find all sources that are affected by the global state changes.
|
|
133
|
+
* For example, if a layer filter uses global-state expression, this function will return the source id of that layer.
|
|
134
|
+
*/
|
|
135
|
+
_findGlobalStateAffectedSources(globalStateRefs) {
|
|
136
|
+
if (globalStateRefs.length === 0) {
|
|
137
|
+
return new Set();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const sourceIdsToReload = new Set();
|
|
141
|
+
|
|
142
|
+
for (const layerId in this._layers) {
|
|
143
|
+
const layer = this._layers[layerId];
|
|
144
|
+
const layoutAffectingGlobalStateRefs = layer.getLayoutAffectingGlobalStateRefs();
|
|
145
|
+
|
|
146
|
+
for (const ref of globalStateRefs) {
|
|
147
|
+
if (layoutAffectingGlobalStateRefs.has(ref)) {
|
|
148
|
+
sourceIdsToReload.add(layer.source);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return sourceIdsToReload;
|
|
154
|
+
}
|
|
155
|
+
|
|
81
156
|
loadJSON(json) {
|
|
82
157
|
this.fire(new Event('dataloading', { dataType: 'style' }));
|
|
83
158
|
|
|
@@ -128,6 +203,8 @@ class Style extends Evented {
|
|
|
128
203
|
|
|
129
204
|
this.light = new Light(this.stylesheet.light);
|
|
130
205
|
|
|
206
|
+
this.setGlobalState(this.stylesheet.state ?? null);
|
|
207
|
+
|
|
131
208
|
this.fire(new Event('data', { dataType: 'style' }));
|
|
132
209
|
this.fire(new Event('style.load'));
|
|
133
210
|
}
|
|
@@ -547,12 +624,12 @@ class Style extends Evented {
|
|
|
547
624
|
}
|
|
548
625
|
|
|
549
626
|
if (filter === null || filter === undefined) {
|
|
550
|
-
layer.
|
|
627
|
+
layer.setFilter(undefined);
|
|
551
628
|
this._updateLayer(layer);
|
|
552
629
|
return;
|
|
553
630
|
}
|
|
554
631
|
|
|
555
|
-
layer.
|
|
632
|
+
layer.setFilter(clone(filter));
|
|
556
633
|
this._updateLayer(layer);
|
|
557
634
|
}
|
|
558
635
|
|
package/src/style/style_layer.js
CHANGED
|
@@ -3,6 +3,7 @@ const { filterObject } = require('../util/object');
|
|
|
3
3
|
const { Evented } = require('@mapwhit/events');
|
|
4
4
|
const { Layout, Transitionable, PossiblyEvaluatedPropertyValue } = require('./properties');
|
|
5
5
|
const { supportsPropertyExpression } = require('@mapwhit/style-expressions');
|
|
6
|
+
const featureFilter = require('../style-spec/feature_filter');
|
|
6
7
|
|
|
7
8
|
const TRANSITION_SUFFIX = '-transition';
|
|
8
9
|
|
|
@@ -23,9 +24,10 @@ class StyleLayer extends Evented {
|
|
|
23
24
|
this.source = layer.source;
|
|
24
25
|
this.sourceLayer = layer['source-layer'];
|
|
25
26
|
this.filter = layer.filter;
|
|
27
|
+
this._featureFilter = featureFilter(layer.filter);
|
|
26
28
|
}
|
|
27
29
|
|
|
28
|
-
this._featureFilter
|
|
30
|
+
this._featureFilter ??= featureFilter.addGlobalStateRefs(() => true);
|
|
29
31
|
|
|
30
32
|
if (properties.layout) {
|
|
31
33
|
this._unevaluatedLayout = new Layout(properties.layout);
|
|
@@ -43,6 +45,11 @@ class StyleLayer extends Evented {
|
|
|
43
45
|
this._transitioningPaint = this._transitionablePaint.untransitioned();
|
|
44
46
|
}
|
|
45
47
|
|
|
48
|
+
setFilter(filter) {
|
|
49
|
+
this.filter = filter;
|
|
50
|
+
this._featureFilter = featureFilter(filter);
|
|
51
|
+
}
|
|
52
|
+
|
|
46
53
|
getCrossfadeParameters() {
|
|
47
54
|
return this._crossfadeParameters;
|
|
48
55
|
}
|
|
@@ -55,6 +62,31 @@ class StyleLayer extends Evented {
|
|
|
55
62
|
return this._unevaluatedLayout.getValue(name);
|
|
56
63
|
}
|
|
57
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Get list of global state references that are used within layout or filter properties.
|
|
67
|
+
* This is used to determine if layer source need to be reloaded when global state property changes.
|
|
68
|
+
*
|
|
69
|
+
*/
|
|
70
|
+
getLayoutAffectingGlobalStateRefs() {
|
|
71
|
+
const globalStateRefs = new Set();
|
|
72
|
+
|
|
73
|
+
if (this._unevaluatedLayout) {
|
|
74
|
+
for (const propertyName in this._unevaluatedLayout._values) {
|
|
75
|
+
const value = this._unevaluatedLayout._values[propertyName];
|
|
76
|
+
|
|
77
|
+
for (const globalStateRef of value.getGlobalStateRefs()) {
|
|
78
|
+
globalStateRefs.add(globalStateRef);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
for (const globalStateRef of this._featureFilter.getGlobalStateRefs()) {
|
|
84
|
+
globalStateRefs.add(globalStateRef);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return globalStateRefs;
|
|
88
|
+
}
|
|
89
|
+
|
|
58
90
|
setLayoutProperty(name, value) {
|
|
59
91
|
if (name === 'visibility') {
|
|
60
92
|
this.visibility = value === 'none' ? value : 'visible';
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
const { createExpression } = require('@mapwhit/style-expressions');
|
|
1
|
+
const { createExpression, findGlobalStateRefs } = require('@mapwhit/style-expressions');
|
|
2
2
|
|
|
3
3
|
module.exports = createFilter;
|
|
4
4
|
|
|
5
5
|
createFilter.isExpressionFilter = isExpressionFilter;
|
|
6
|
+
createFilter.addGlobalStateRefs = addGlobalStateRefs;
|
|
6
7
|
|
|
7
8
|
function isExpressionFilter(filter) {
|
|
8
9
|
if (filter === true || filter === false) {
|
|
@@ -66,7 +67,7 @@ const filterSpec = {
|
|
|
66
67
|
*/
|
|
67
68
|
function createFilter(filter) {
|
|
68
69
|
if (filter === null || filter === undefined) {
|
|
69
|
-
return () => true;
|
|
70
|
+
return addGlobalStateRefs(() => true);
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
if (!isExpressionFilter(filter)) {
|
|
@@ -77,7 +78,15 @@ function createFilter(filter) {
|
|
|
77
78
|
if (compiled.result === 'error') {
|
|
78
79
|
throw new Error(compiled.value.map(err => `${err.key}: ${err.message}`).join(', '));
|
|
79
80
|
}
|
|
80
|
-
return (
|
|
81
|
+
return addGlobalStateRefs(
|
|
82
|
+
(globalProperties, feature) => compiled.value.evaluate(globalProperties, feature),
|
|
83
|
+
() => findGlobalStateRefs(compiled.value.expression)
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function addGlobalStateRefs(filter, getGlobalStateRefs = () => new Set()) {
|
|
88
|
+
filter.getGlobalStateRefs = getGlobalStateRefs;
|
|
89
|
+
return filter;
|
|
81
90
|
}
|
|
82
91
|
|
|
83
92
|
// Comparison function to sort numbers and strings
|
|
@@ -86,7 +95,7 @@ function compare(a, b) {
|
|
|
86
95
|
}
|
|
87
96
|
|
|
88
97
|
function convertFilter(filter) {
|
|
89
|
-
if (!filter) return true;
|
|
98
|
+
if (!filter || filter.length === 0) return true;
|
|
90
99
|
const [op, ...args] = filter;
|
|
91
100
|
if (filter.length <= 1) return op !== 'any';
|
|
92
101
|
switch (op) {
|
|
@@ -48,6 +48,26 @@
|
|
|
48
48
|
"doc": "Default pitch, in degrees. Zero is perpendicular to the surface, for a look straight down at the map, while a greater value like 60 looks ahead towards the horizon. The style pitch will be used only if the map has not been positioned by other means (e.g. map options or user interaction).",
|
|
49
49
|
"example": 50
|
|
50
50
|
},
|
|
51
|
+
"state": {
|
|
52
|
+
"type": "state",
|
|
53
|
+
"default": {},
|
|
54
|
+
"doc": "An object used to define default values when using the [`global-state`](https://maplibre.org/maplibre-style-spec/expressions/#global-state) expression.",
|
|
55
|
+
"example": {
|
|
56
|
+
"chargerType": {
|
|
57
|
+
"default": ["CCS", "CHAdeMO", "Type2"]
|
|
58
|
+
},
|
|
59
|
+
"minPreferredChargingSpeed": {
|
|
60
|
+
"default": 50
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"sdk-support": {
|
|
64
|
+
"basic functionality": {
|
|
65
|
+
"js": "https://github.com/maplibre/maplibre-gl-js/issues/4964",
|
|
66
|
+
"android": "https://github.com/maplibre/maplibre-native/issues/3302",
|
|
67
|
+
"ios": "https://github.com/maplibre/maplibre-native/issues/3302"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
51
71
|
"light": {
|
|
52
72
|
"type": "light",
|
|
53
73
|
"doc": "The global light source.",
|
|
@@ -1293,8 +1313,8 @@
|
|
|
1293
1313
|
},
|
|
1294
1314
|
{
|
|
1295
1315
|
"symbol-placement": [
|
|
1296
|
-
|
|
1297
|
-
|
|
1316
|
+
"line",
|
|
1317
|
+
"line-center"
|
|
1298
1318
|
]
|
|
1299
1319
|
}
|
|
1300
1320
|
],
|
|
@@ -1816,10 +1836,10 @@
|
|
|
1816
1836
|
"requires": [
|
|
1817
1837
|
"text-field",
|
|
1818
1838
|
{
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1839
|
+
"symbol-placement": [
|
|
1840
|
+
"line",
|
|
1841
|
+
"line-center"
|
|
1842
|
+
]
|
|
1823
1843
|
}
|
|
1824
1844
|
],
|
|
1825
1845
|
"sdk-support": {
|
|
@@ -1907,10 +1927,10 @@
|
|
|
1907
1927
|
"text-rotation-alignment": "map"
|
|
1908
1928
|
},
|
|
1909
1929
|
{
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1930
|
+
"symbol-placement": [
|
|
1931
|
+
"line",
|
|
1932
|
+
"line-center"
|
|
1933
|
+
]
|
|
1914
1934
|
}
|
|
1915
1935
|
],
|
|
1916
1936
|
"sdk-support": {
|
|
@@ -2554,6 +2574,24 @@
|
|
|
2554
2574
|
}
|
|
2555
2575
|
}
|
|
2556
2576
|
},
|
|
2577
|
+
"global-state": {
|
|
2578
|
+
"doc": "Retrieves a property value from global state that can be set with platform-specific APIs. Defaults can be provided using the [`state`](https://maplibre.org/maplibre-style-spec/root/#state) root property. Returns `null` if no value nor default value is set for the retrieved property.",
|
|
2579
|
+
"group": "Lookup",
|
|
2580
|
+
"example": {
|
|
2581
|
+
"syntax": {
|
|
2582
|
+
"method": ["string"],
|
|
2583
|
+
"result": "value"
|
|
2584
|
+
},
|
|
2585
|
+
"value": ["global-state", "someProperty"]
|
|
2586
|
+
},
|
|
2587
|
+
"sdk-support": {
|
|
2588
|
+
"basic functionality": {
|
|
2589
|
+
"js": "https://github.com/maplibre/maplibre-gl-js/issues/4964",
|
|
2590
|
+
"android": "https://github.com/maplibre/maplibre-native/issues/3302",
|
|
2591
|
+
"ios": "https://github.com/maplibre/maplibre-native/issues/3302"
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2594
|
+
},
|
|
2557
2595
|
"to-string": {
|
|
2558
2596
|
"doc": "Converts the input value to a string. If the input is `null`, the result is `\"\"`. If the input is a boolean, the result is `\"true\"` or `\"false\"`. If the input is a number, it is converted to a string as specified by the [\"NumberToString\" algorithm](https://tc39.github.io/ecma262/#sec-tostring-applied-to-the-number-type) of the ECMAScript Language Specification. If the input is a color, it is converted to a string of the form `\"rgba(r,g,b,a)\"`, where `r`, `g`, and `b` are numerals ranging from 0 to 255, and `a` ranges from 0 to 1. Otherwise, the input is converted to a string in the format specified by the [`JSON.stringify`](https://tc39.github.io/ecma262/#sec-json.stringify) function of the ECMAScript Language Specification.",
|
|
2559
2597
|
"group": "Types",
|
|
@@ -3722,7 +3760,9 @@
|
|
|
3722
3760
|
},
|
|
3723
3761
|
"expression": {
|
|
3724
3762
|
"interpolated": false,
|
|
3725
|
-
"parameters": [
|
|
3763
|
+
"parameters": [
|
|
3764
|
+
"zoom"
|
|
3765
|
+
]
|
|
3726
3766
|
},
|
|
3727
3767
|
"property-type": "data-constant"
|
|
3728
3768
|
}
|
|
@@ -5232,10 +5272,10 @@
|
|
|
5232
5272
|
"type": "enum",
|
|
5233
5273
|
"values": {
|
|
5234
5274
|
"map": {
|
|
5235
|
-
|
|
5275
|
+
"doc": "The hillshade illumination is relative to the north direction."
|
|
5236
5276
|
},
|
|
5237
5277
|
"viewport": {
|
|
5238
|
-
|
|
5278
|
+
"doc": "The hillshade illumination is relative to the top of the viewport."
|
|
5239
5279
|
}
|
|
5240
5280
|
},
|
|
5241
5281
|
"default": "viewport",
|
package/src/ui/map.js
CHANGED
|
@@ -201,6 +201,29 @@ class Map extends Camera {
|
|
|
201
201
|
this.on('dataloading', this._onDataLoading);
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
+
/**
|
|
205
|
+
* Sets a global state property that can be retrieved with the [`global-state` expression](https://maplibre.org/maplibre-style-spec/expressions/#global-state).
|
|
206
|
+
* If the value is null, it resets the property to its default value defined in the [`state` style property](https://maplibre.org/maplibre-style-spec/root/#state).
|
|
207
|
+
*
|
|
208
|
+
* Note that changing `global-state` values defined in layout properties is not supported, and will be ignored.
|
|
209
|
+
*
|
|
210
|
+
* @param propertyName - The name of the state property to set.
|
|
211
|
+
* @param value - The value of the state property to set.
|
|
212
|
+
*/
|
|
213
|
+
setGlobalStateProperty(propertyName, value) {
|
|
214
|
+
this.style.setGlobalStateProperty(propertyName, value);
|
|
215
|
+
return this._update(true);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Returns the global map state
|
|
220
|
+
*
|
|
221
|
+
* @returns The map state object.
|
|
222
|
+
*/
|
|
223
|
+
getGlobalState() {
|
|
224
|
+
return this.style.getGlobalState();
|
|
225
|
+
}
|
|
226
|
+
|
|
204
227
|
/**
|
|
205
228
|
* Adds a {@link IControl} to the map, calling `control.onAdd(this)`.
|
|
206
229
|
*
|
|
@@ -1248,7 +1271,8 @@ class Map extends Camera {
|
|
|
1248
1271
|
now,
|
|
1249
1272
|
fadeDuration: this._fadeDuration,
|
|
1250
1273
|
zoomHistory: this.style.zoomHistory,
|
|
1251
|
-
transition: this.style.getTransition()
|
|
1274
|
+
transition: this.style.getTransition(),
|
|
1275
|
+
globalState: this.style.getGlobalState()
|
|
1252
1276
|
});
|
|
1253
1277
|
|
|
1254
1278
|
const factor = parameters.crossFadingFactor();
|