maplibre-gl 2.2.0-pre.3 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -14
- package/build/generate-debug-index-file.ts +19 -0
- package/build/generate-style-code.ts +6 -1
- package/build/generate-style-spec.ts +151 -35
- package/build/generate-typings.ts +1 -1
- package/build/rollup_plugins.ts +4 -1
- package/dist/maplibre-gl-csp-worker.js +1 -1
- package/dist/maplibre-gl-csp-worker.js.map +1 -1
- package/dist/maplibre-gl-csp.js +1 -1
- package/dist/maplibre-gl-csp.js.map +1 -1
- package/dist/maplibre-gl-dev.js +364 -3124
- package/dist/maplibre-gl.css +1 -1
- package/dist/maplibre-gl.d.ts +439 -151
- package/dist/maplibre-gl.js +4 -4
- package/dist/maplibre-gl.js.map +1 -1
- package/package.json +68 -65
- package/src/css/maplibre-gl.css +39 -32
- package/src/data/bucket/fill_bucket.test.ts +1 -0
- package/src/data/bucket/symbol_bucket.test.ts +2 -0
- package/src/data/evaluation_feature.ts +1 -1
- package/src/data/program_configuration.ts +2 -2
- package/src/geo/transform.ts +4 -4
- package/src/gl/vertex_buffer.ts +4 -4
- package/src/index.ts +1 -1
- package/src/render/image_atlas.ts +1 -0
- package/src/render/image_manager.ts +1 -0
- package/src/render/program/debug_program.ts +1 -1
- package/src/render/render_to_texture.ts +3 -0
- package/src/render/terrain.ts +21 -21
- package/src/shaders/README.md +2 -2
- package/src/source/geojson_worker_source.test.ts +2 -2
- package/src/source/geojson_wrapper.test.ts +1 -1
- package/src/source/image_source.test.ts +8 -8
- package/src/source/image_source.ts +1 -1
- package/src/source/raster_tile_source.test.ts +1 -1
- package/src/source/source_cache.test.ts +12 -12
- package/src/source/source_cache.ts +1 -1
- package/src/source/terrain_source_cache.ts +3 -3
- package/src/source/vector_tile_source.test.ts +1 -1
- package/src/source/vector_tile_worker_source.test.ts +1 -1
- package/src/source/video_source.test.ts +2 -2
- package/src/source/worker.ts +2 -4
- package/src/style/light.test.ts +1 -1
- package/src/style/style.test.ts +3 -3
- package/src/style/style.ts +2 -2
- package/src/style/style_layer/background_style_layer_properties.g.ts +1 -0
- package/src/style/style_layer/circle_style_layer_properties.g.ts +1 -0
- package/src/style/style_layer/fill_extrusion_style_layer_properties.g.ts +1 -0
- package/src/style/style_layer/fill_style_layer_properties.g.ts +1 -0
- package/src/style/style_layer/heatmap_style_layer_properties.g.ts +1 -0
- package/src/style/style_layer/hillshade_style_layer_properties.g.ts +1 -0
- package/src/style/style_layer/line_style_layer_properties.g.ts +1 -0
- package/src/style/style_layer/raster_style_layer_properties.g.ts +1 -0
- package/src/style/style_layer/symbol_style_layer.ts +16 -1
- package/src/style/style_layer/symbol_style_layer_properties.g.ts +4 -3
- package/src/style-spec/CHANGELOG.md +5 -0
- package/src/style-spec/composite.test.ts +2 -0
- package/src/style-spec/diff.test.ts +3 -3
- package/src/style-spec/empty.ts +3 -2
- package/src/style-spec/expression/definitions/coercion.ts +13 -2
- package/src/style-spec/expression/definitions/interpolate.ts +1 -0
- package/src/style-spec/expression/expression.test.ts +1 -1
- package/src/style-spec/expression/expression.ts +3 -0
- package/src/style-spec/expression/index.ts +8 -2
- package/src/style-spec/expression/parsing_context.ts +2 -0
- package/src/style-spec/expression/types.ts +6 -1
- package/src/style-spec/expression/values.ts +9 -4
- package/src/style-spec/feature_filter/convert.ts +65 -65
- package/src/style-spec/feature_filter/feature_filter.test.ts +45 -4
- package/src/style-spec/feature_filter/index.ts +2 -1
- package/src/style-spec/function/index.test.ts +117 -1
- package/src/style-spec/function/index.ts +24 -12
- package/src/style-spec/migrate/expressions.ts +1 -1
- package/src/style-spec/migrate/v8.test.ts +2 -0
- package/src/style-spec/migrate/v9.test.ts +6 -4
- package/src/style-spec/migrate.test.ts +3 -1
- package/src/style-spec/package.json +1 -1
- package/src/style-spec/reference/latest.ts +2 -2
- package/src/style-spec/reference/v8.json +9 -6
- package/src/style-spec/style-spec.test.ts +2 -1
- package/src/style-spec/style-spec.ts +18 -9
- package/src/style-spec/types.g.ts +152 -36
- package/src/style-spec/util/interpolate.test.ts +5 -0
- package/src/style-spec/util/interpolate.ts +12 -0
- package/src/style-spec/util/padding.test.ts +27 -0
- package/src/style-spec/util/padding.ts +64 -0
- package/src/style-spec/validate/validate.ts +3 -1
- package/src/style-spec/validate/validate_padding.test.ts +82 -0
- package/src/style-spec/validate/validate_padding.ts +36 -0
- package/src/style-spec/validate_style.ts +1 -1
- package/src/symbol/check_max_angle.test.ts +5 -5
- package/src/symbol/collision_feature.test.ts +22 -5
- package/src/symbol/collision_feature.ts +7 -5
- package/src/symbol/collision_index.ts +1 -1
- package/src/symbol/get_anchors.test.ts +4 -4
- package/src/symbol/projection.ts +1 -1
- package/src/symbol/quads.test.ts +1 -1
- package/src/symbol/shaping.ts +10 -10
- package/src/symbol/symbol_layout.ts +5 -4
- package/src/symbol/symbol_style_layer.test.ts +1 -1
- package/src/ui/camera.test.ts +11 -11
- package/src/ui/control/geolocate_control.ts +1 -1
- package/src/ui/control/terrain_control.ts +4 -4
- package/src/ui/handler/cooperative_gestures.test.ts +167 -0
- package/src/ui/handler/drag_pan.test.ts +2 -1
- package/src/ui/handler/scroll_zoom.ts +7 -0
- package/src/ui/handler/touch_pan.ts +22 -2
- package/src/ui/handler/touch_zoom_rotate.ts +18 -1
- package/src/ui/handler_manager.ts +2 -2
- package/src/ui/map.test.ts +16 -16
- package/src/ui/map.ts +76 -8
- package/src/ui/map_events.test.ts +33 -32
- package/src/ui/popup.test.ts +2 -2
- package/src/util/ajax.test.ts +5 -5
- package/src/util/ajax.ts +1 -1
- package/src/util/classify_rings.test.ts +27 -27
- package/src/util/primitives.ts +4 -4
- package/src/util/resolve_tokens.test.ts +1 -1
- package/src/util/tile_request_cache.test.ts +5 -5
- package/src/util/util.test.ts +5 -5
- package/src/util/util.ts +2 -3
|
@@ -1,17 +1,8 @@
|
|
|
1
1
|
import {isExpressionFilter} from './index';
|
|
2
2
|
|
|
3
|
-
import type {FilterSpecification} from '../types.g';
|
|
3
|
+
import type {ExpressionFilterSpecification, ExpressionInputType, ExpressionSpecification, FilterSpecification, LegacyFilterSpecification} from '../types.g';
|
|
4
4
|
|
|
5
|
-
type ExpectedTypes = {[_: string]:
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Convert the given legacy filter to (the JSON representation of) an
|
|
9
|
-
* equivalent expression
|
|
10
|
-
* @private
|
|
11
|
-
*/
|
|
12
|
-
export default function convertFilter(filter: FilterSpecification): unknown {
|
|
13
|
-
return _convertFilter(filter, {});
|
|
14
|
-
}
|
|
5
|
+
type ExpectedTypes = {[_: string]: ExpressionInputType};
|
|
15
6
|
|
|
16
7
|
/*
|
|
17
8
|
* Convert the given filter to an expression, storing the expected types for
|
|
@@ -61,51 +52,58 @@ export default function convertFilter(filter: FilterSpecification): unknown {
|
|
|
61
52
|
* false (legacy filter semantics) are equivalent: they cause the filter to
|
|
62
53
|
* produce a `false` result.
|
|
63
54
|
*/
|
|
64
|
-
function
|
|
65
|
-
if (isExpressionFilter(filter))
|
|
66
|
-
|
|
55
|
+
export default function convertFilter(filter: FilterSpecification, expectedTypes: ExpectedTypes = {}): ExpressionFilterSpecification {
|
|
56
|
+
if (isExpressionFilter(filter)) return filter;
|
|
67
57
|
if (!filter) return true;
|
|
68
|
-
const op = filter[0];
|
|
69
|
-
if (filter.length <= 1) return (op !== 'any');
|
|
70
|
-
|
|
71
|
-
let converted;
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
-
op === '==' ||
|
|
75
|
-
op === '!=' ||
|
|
76
|
-
op === '<' ||
|
|
77
|
-
op === '>' ||
|
|
78
|
-
op === '<=' ||
|
|
79
|
-
op === '>='
|
|
80
|
-
) {
|
|
81
|
-
const [, property, value] = filter;
|
|
82
|
-
converted = convertComparisonOp(property as string, value, op, expectedTypes);
|
|
83
|
-
} else if (op === 'any') {
|
|
84
|
-
const children = (filter).slice(1).map((f: FilterSpecification) => {
|
|
85
|
-
const types = {};
|
|
86
|
-
const child = _convertFilter(f, types);
|
|
87
|
-
const typechecks = runtimeTypeChecks(types);
|
|
88
|
-
return typechecks === true ? child : ['case', typechecks, child, false];
|
|
89
|
-
});
|
|
90
|
-
return ['any'].concat(children as string[]);
|
|
91
|
-
} else if (op === 'all') {
|
|
92
|
-
const children = (filter).slice(1).map(f => _convertFilter(f as FilterSpecification, expectedTypes));
|
|
93
|
-
return children.length > 1 ? ['all'].concat(children as string[]) : [].concat(...children);
|
|
94
|
-
} else if (op === 'none') {
|
|
95
|
-
return ['!', _convertFilter(['any'].concat(filter.slice(1) as string[]) as string[], {})];
|
|
96
|
-
} else if (op === 'in') {
|
|
97
|
-
converted = convertInOp(filter[1] as string, filter.slice(2));
|
|
98
|
-
} else if (op === '!in') {
|
|
99
|
-
converted = convertInOp(filter[1] as string, filter.slice(2), true);
|
|
100
|
-
} else if (op === 'has') {
|
|
101
|
-
converted = convertHasOp(filter[1] as string);
|
|
102
|
-
} else if (op === '!has') {
|
|
103
|
-
converted = ['!', convertHasOp(filter[1] as string)];
|
|
104
|
-
} else {
|
|
105
|
-
converted = true;
|
|
106
|
-
}
|
|
107
58
|
|
|
108
|
-
|
|
59
|
+
const legacyFilter = filter as LegacyFilterSpecification;
|
|
60
|
+
const legacyOp = legacyFilter[0];
|
|
61
|
+
if (filter.length <= 1) return (legacyOp !== 'any');
|
|
62
|
+
|
|
63
|
+
switch (legacyOp) {
|
|
64
|
+
case '==':
|
|
65
|
+
case '!=':
|
|
66
|
+
case '<':
|
|
67
|
+
case '>':
|
|
68
|
+
case '<=':
|
|
69
|
+
case '>=': {
|
|
70
|
+
const [, property, value] = filter;
|
|
71
|
+
return convertComparisonOp(property as string, value, legacyOp, expectedTypes);
|
|
72
|
+
}
|
|
73
|
+
case 'any': {
|
|
74
|
+
const [, ...conditions] = legacyFilter;
|
|
75
|
+
const children = conditions.map((f: LegacyFilterSpecification) => {
|
|
76
|
+
const types = {};
|
|
77
|
+
const child = convertFilter(f, types);
|
|
78
|
+
const typechecks = runtimeTypeChecks(types);
|
|
79
|
+
return typechecks === true ? child : ['case', typechecks, child, false] as ExpressionSpecification;
|
|
80
|
+
});
|
|
81
|
+
return ['any', ...children];
|
|
82
|
+
}
|
|
83
|
+
case 'all': {
|
|
84
|
+
const [, ...conditions] = legacyFilter;
|
|
85
|
+
const children = conditions.map(f => convertFilter(f, expectedTypes));
|
|
86
|
+
return children.length > 1 ? ['all', ...children] : children[0];
|
|
87
|
+
}
|
|
88
|
+
case 'none': {
|
|
89
|
+
const [, ...conditions] = legacyFilter;
|
|
90
|
+
return ['!', convertFilter(['any', ...conditions], {})];
|
|
91
|
+
}
|
|
92
|
+
case 'in': {
|
|
93
|
+
const [, property, ...values] = legacyFilter;
|
|
94
|
+
return convertInOp(property, values);
|
|
95
|
+
}
|
|
96
|
+
case '!in': {
|
|
97
|
+
const [, property, ...values] = legacyFilter;
|
|
98
|
+
return convertInOp(property, values, true);
|
|
99
|
+
}
|
|
100
|
+
case 'has':
|
|
101
|
+
return convertHasOp(legacyFilter[1]);
|
|
102
|
+
case '!has':
|
|
103
|
+
return ['!', convertHasOp(legacyFilter[1])];
|
|
104
|
+
default:
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
109
107
|
}
|
|
110
108
|
|
|
111
109
|
// Given a set of feature properties and an expected type for each one,
|
|
@@ -116,7 +114,7 @@ function _convertFilter(filter: FilterSpecification, expectedTypes: ExpectedType
|
|
|
116
114
|
// ['==', ['typeof', ['get', 'name'], 'string']],
|
|
117
115
|
// ['==', ['typeof', ['get', 'population'], 'number]]
|
|
118
116
|
// ]
|
|
119
|
-
function runtimeTypeChecks(expectedTypes: ExpectedTypes) {
|
|
117
|
+
function runtimeTypeChecks(expectedTypes: ExpectedTypes): ExpressionFilterSpecification {
|
|
120
118
|
const conditions = [];
|
|
121
119
|
for (const property in expectedTypes) {
|
|
122
120
|
const get = property === '$id' ? ['id'] : ['get', property];
|
|
@@ -124,13 +122,13 @@ function runtimeTypeChecks(expectedTypes: ExpectedTypes) {
|
|
|
124
122
|
}
|
|
125
123
|
if (conditions.length === 0) return true;
|
|
126
124
|
if (conditions.length === 1) return conditions[0];
|
|
127
|
-
return ['all']
|
|
125
|
+
return ['all', ...conditions];
|
|
128
126
|
}
|
|
129
127
|
|
|
130
|
-
function convertComparisonOp(property: string, value: any, op: string, expectedTypes?: ExpectedTypes | null) {
|
|
128
|
+
function convertComparisonOp(property: string, value: any, op: string, expectedTypes?: ExpectedTypes | null): ExpressionFilterSpecification {
|
|
131
129
|
let get;
|
|
132
130
|
if (property === '$type') {
|
|
133
|
-
return [op, ['geometry-type'], value];
|
|
131
|
+
return [op, ['geometry-type'], value] as ExpressionFilterSpecification;
|
|
134
132
|
} else if (property === '$id') {
|
|
135
133
|
get = ['id'];
|
|
136
134
|
} else {
|
|
@@ -156,13 +154,13 @@ function convertComparisonOp(property: string, value: any, op: string, expectedT
|
|
|
156
154
|
];
|
|
157
155
|
}
|
|
158
156
|
|
|
159
|
-
return [op, get, value];
|
|
157
|
+
return [op, get, value] as ExpressionFilterSpecification;
|
|
160
158
|
}
|
|
161
159
|
|
|
162
|
-
function convertInOp(property: string, values: Array<any>, negate = false) {
|
|
160
|
+
function convertInOp(property: string, values: Array<any>, negate = false): ExpressionFilterSpecification {
|
|
163
161
|
if (values.length === 0) return negate;
|
|
164
162
|
|
|
165
|
-
let get;
|
|
163
|
+
let get: ExpressionSpecification;
|
|
166
164
|
if (property === '$type') {
|
|
167
165
|
get = ['geometry-type'];
|
|
168
166
|
} else if (property === '$id') {
|
|
@@ -190,12 +188,14 @@ function convertInOp(property: string, values: Array<any>, negate = false) {
|
|
|
190
188
|
return ['match', get, uniqueValues, !negate, negate];
|
|
191
189
|
}
|
|
192
190
|
|
|
193
|
-
|
|
194
|
-
values.map(v => [
|
|
195
|
-
|
|
191
|
+
if (negate) {
|
|
192
|
+
return ['all', ...values.map(v => ['!=', get, v] as ExpressionSpecification)];
|
|
193
|
+
} else {
|
|
194
|
+
return ['any', ...values.map(v => ['==', get, v] as ExpressionSpecification)];
|
|
195
|
+
}
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
function convertHasOp(property: string) {
|
|
198
|
+
function convertHasOp(property: string): ExpressionFilterSpecification {
|
|
199
199
|
if (property === '$type') {
|
|
200
200
|
return true;
|
|
201
201
|
} else if (property === '$id') {
|
|
@@ -5,10 +5,39 @@ import Point from '@mapbox/point-geometry';
|
|
|
5
5
|
import MercatorCoordinate from '../../geo/mercator_coordinate';
|
|
6
6
|
import EXTENT from '../../data/extent';
|
|
7
7
|
import {CanonicalTileID} from '../../source/tile_id';
|
|
8
|
-
import {FilterSpecification} from '../types.g';
|
|
8
|
+
import {ExpressionFilterSpecification, FilterSpecification} from '../types.g';
|
|
9
9
|
import {Feature} from '../expression';
|
|
10
10
|
|
|
11
11
|
describe('filter', () => {
|
|
12
|
+
test('exprssions transpilation test', () => {
|
|
13
|
+
function compileTimeCheck(_: ExpressionFilterSpecification) {
|
|
14
|
+
expect(true).toBeTruthy();
|
|
15
|
+
}
|
|
16
|
+
compileTimeCheck(['any']);
|
|
17
|
+
compileTimeCheck(['at', 2, ['array', 1, 2, 3]]);
|
|
18
|
+
compileTimeCheck(['case', ['has', 'color'], ['get', 'color'], 'white']);
|
|
19
|
+
compileTimeCheck(['case', ['all', ['has', 'point_count'], ['<', ['get', 'point_count'], 3]], ['get', 'cluster_routes'], '']);
|
|
20
|
+
compileTimeCheck(['interpolate', ['linear'], ['get', 'point_count'], 2, 18.0, 10, 24.0]);
|
|
21
|
+
compileTimeCheck(['case', ['has', 'point_count'], ['interpolate', ['linear'], ['get', 'point_count'], 2, 18.0, 10, 24.0], 12.0]);
|
|
22
|
+
compileTimeCheck([
|
|
23
|
+
'case',
|
|
24
|
+
['has', 'point_count'], ['interpolate', ['linear'], ['get', 'point_count'], 2, '#ccc', 10, '#444'],
|
|
25
|
+
['has', 'priorityValue'], ['interpolate', ['linear'], ['get', 'priorityValue'], 0, '#ff9', 1, '#f66'],
|
|
26
|
+
'#fcaf3e'
|
|
27
|
+
]);
|
|
28
|
+
compileTimeCheck([
|
|
29
|
+
'case',
|
|
30
|
+
['==', ['get', 'CAPITAL'], 1], 'city-capital',
|
|
31
|
+
['>=', ['get', 'POPULATION'], 1000000], 'city-1M',
|
|
32
|
+
['>=', ['get', 'POPULATION'], 500000], 'city-500k',
|
|
33
|
+
['>=', ['get', 'POPULATION'], 100000], 'city-100k',
|
|
34
|
+
'city'
|
|
35
|
+
]);
|
|
36
|
+
compileTimeCheck(['match', ['get', 'TYPE'], ['TARGETPOINT:HOSPITAL'], true, false]);
|
|
37
|
+
compileTimeCheck(['match', ['get', 'TYPE'], ['ADIZ', 'AMA', 'AWY', 'CLASS', 'NO-FIR', 'OCA', 'OTA', 'P', 'RAS', 'RCA', 'UTA', 'UTA-P'], true, false]);
|
|
38
|
+
compileTimeCheck(['==', ['get', 'MILITARYAIRPORT'], 1]);
|
|
39
|
+
});
|
|
40
|
+
|
|
12
41
|
test('expression, zoom', () => {
|
|
13
42
|
const f = createFilter(['>=', ['number', ['get', 'x']], ['zoom']]).filter;
|
|
14
43
|
expect(f({zoom: 1}, {properties: {x: 0}} as any as Feature)).toBe(false);
|
|
@@ -52,6 +81,18 @@ describe('filter', () => {
|
|
|
52
81
|
expect(createFilter(['any', false, false]).filter(undefined, undefined)).toBe(false);
|
|
53
82
|
});
|
|
54
83
|
|
|
84
|
+
test('expression, literal', () => {
|
|
85
|
+
expect(createFilter(['literal', true]).filter(undefined, undefined)).toBe(true);
|
|
86
|
+
expect(createFilter(['literal', false]).filter(undefined, undefined)).toBe(false);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test('expression, match', () => {
|
|
90
|
+
const match = createFilter(['match', ['get', 'x'], ['a', 'b', 'c'], true, false]).filter;
|
|
91
|
+
expect(match(undefined, {properties: {x: 'a'}} as any as Feature)).toBe(true);
|
|
92
|
+
expect(match(undefined, {properties: {x: 'c'}} as any as Feature)).toBe(true);
|
|
93
|
+
expect(match(undefined, {properties: {x: 'd'}} as any as Feature)).toBe(false);
|
|
94
|
+
});
|
|
95
|
+
|
|
55
96
|
test('expression, type error', () => {
|
|
56
97
|
expect(() => {
|
|
57
98
|
createFilter(['==', ['number', ['get', 'x']], ['string', ['get', 'y']]]);
|
|
@@ -77,7 +118,7 @@ describe('filter', () => {
|
|
|
77
118
|
};
|
|
78
119
|
const withinFilter = createFilter(['within', {'type': 'Polygon', 'coordinates': [[[0, 0], [5, 0], [5, 5], [0, 5], [0, 0]]]}]);
|
|
79
120
|
expect(withinFilter.needGeometry).toBe(true);
|
|
80
|
-
const canonical = {z: 3, x: 3, y:3} as CanonicalTileID;
|
|
121
|
+
const canonical = {z: 3, x: 3, y: 3} as CanonicalTileID;
|
|
81
122
|
expect(
|
|
82
123
|
withinFilter.filter({zoom: 3}, {type: 1, geometry: [[getPointFromLngLat(2, 2, canonical)]]} as Feature, canonical)
|
|
83
124
|
).toBe(true);
|
|
@@ -179,14 +220,14 @@ describe('convert legacy filters to expressions', () => {
|
|
|
179
220
|
['LineString', 'Point', 'Polygon'],
|
|
180
221
|
true,
|
|
181
222
|
false
|
|
182
|
-
]
|
|
223
|
+
],
|
|
183
224
|
[
|
|
184
225
|
'match',
|
|
185
226
|
['get', 'type'],
|
|
186
227
|
['island'],
|
|
187
228
|
true,
|
|
188
229
|
false
|
|
189
|
-
]
|
|
230
|
+
]
|
|
190
231
|
];
|
|
191
232
|
|
|
192
233
|
const converted = convertFilter(filter);
|
|
@@ -2,6 +2,7 @@ import {createExpression} from '../expression';
|
|
|
2
2
|
import type {GlobalProperties, Feature} from '../expression';
|
|
3
3
|
import type {CanonicalTileID} from '../../source/tile_id';
|
|
4
4
|
import {StylePropertySpecification} from '../style-spec';
|
|
5
|
+
import {ExpressionFilterSpecification} from '../types.g';
|
|
5
6
|
|
|
6
7
|
type FilterExpression = (
|
|
7
8
|
globalProperties: GlobalProperties,
|
|
@@ -17,7 +18,7 @@ export type FeatureFilter = {
|
|
|
17
18
|
export default createFilter;
|
|
18
19
|
export {isExpressionFilter};
|
|
19
20
|
|
|
20
|
-
function isExpressionFilter(filter: any) {
|
|
21
|
+
function isExpressionFilter(filter: any): filter is ExpressionFilterSpecification {
|
|
21
22
|
if (filter === true || filter === false) {
|
|
22
23
|
return true;
|
|
23
24
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {createFunction} from './index';
|
|
2
2
|
import Color from '../util/color';
|
|
3
3
|
import Formatted from '../expression/types/formatted';
|
|
4
|
+
import Padding from '../util/padding';
|
|
4
5
|
|
|
5
6
|
describe('binary search', () => {
|
|
6
7
|
test('will eventually terminate.', () => {
|
|
@@ -235,6 +236,19 @@ describe('exponential function', () => {
|
|
|
235
236
|
expect(params).toEqual(paramsCopy);
|
|
236
237
|
});
|
|
237
238
|
|
|
239
|
+
test('padding', () => {
|
|
240
|
+
const f = createFunction({
|
|
241
|
+
type: 'exponential',
|
|
242
|
+
stops: [[1, 2], [11, [2, 5, 2, 7]]]
|
|
243
|
+
}, {
|
|
244
|
+
type: 'padding'
|
|
245
|
+
}).evaluate;
|
|
246
|
+
|
|
247
|
+
expect(f({zoom: 0}, undefined)).toEqual(new Padding([2, 2, 2, 2]));
|
|
248
|
+
expect(f({zoom: 5}, undefined)).toEqual(new Padding([2, 3.2, 2, 4]));
|
|
249
|
+
expect(f({zoom: 11}, undefined)).toEqual(new Padding([2, 5, 2, 7]));
|
|
250
|
+
});
|
|
251
|
+
|
|
238
252
|
test('property present', () => {
|
|
239
253
|
const f = createFunction({
|
|
240
254
|
property: 'foo',
|
|
@@ -532,11 +546,24 @@ describe('interval function', () => {
|
|
|
532
546
|
}).evaluate;
|
|
533
547
|
|
|
534
548
|
expect(f({zoom: 0}, undefined)).toEqual(new Color(1, 0, 0, 1));
|
|
535
|
-
expect(f({zoom:
|
|
549
|
+
expect(f({zoom: 10}, undefined)).toEqual(new Color(1, 0, 0, 1));
|
|
536
550
|
expect(f({zoom: 11}, undefined)).toEqual(new Color(0, 0, 1, 1));
|
|
537
551
|
|
|
538
552
|
});
|
|
539
553
|
|
|
554
|
+
test('padding', () => {
|
|
555
|
+
const f = createFunction({
|
|
556
|
+
type: 'interval',
|
|
557
|
+
stops: [[1, 2], [11, 4]]
|
|
558
|
+
}, {
|
|
559
|
+
type: 'padding'
|
|
560
|
+
}).evaluate;
|
|
561
|
+
|
|
562
|
+
expect(f({zoom: 0}, undefined)).toEqual(new Padding([2, 2, 2, 2]));
|
|
563
|
+
expect(f({zoom: 10}, undefined)).toEqual(new Padding([2, 2, 2, 2]));
|
|
564
|
+
expect(f({zoom: 11}, undefined)).toEqual(new Padding([4, 4, 4, 4]));
|
|
565
|
+
});
|
|
566
|
+
|
|
540
567
|
test('property present', () => {
|
|
541
568
|
const f = createFunction({
|
|
542
569
|
property: 'foo',
|
|
@@ -746,6 +773,47 @@ describe('categorical function', () => {
|
|
|
746
773
|
|
|
747
774
|
});
|
|
748
775
|
|
|
776
|
+
test('padding', () => {
|
|
777
|
+
const f = createFunction({
|
|
778
|
+
property: 'foo',
|
|
779
|
+
type: 'categorical',
|
|
780
|
+
stops: [[0, 2], [1, 4]]
|
|
781
|
+
}, {
|
|
782
|
+
type: 'padding'
|
|
783
|
+
}).evaluate;
|
|
784
|
+
|
|
785
|
+
expect(f({zoom: 0}, {properties: {foo: 0}})).toEqual(new Padding([2, 2, 2, 2]));
|
|
786
|
+
expect(f({zoom: 1}, {properties: {foo: 1}})).toEqual(new Padding([4, 4, 4, 4]));
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
test('padding function default', () => {
|
|
790
|
+
const f = createFunction({
|
|
791
|
+
property: 'foo',
|
|
792
|
+
type: 'categorical',
|
|
793
|
+
stops: [[0, 2], [1, 4]],
|
|
794
|
+
default: 6
|
|
795
|
+
}, {
|
|
796
|
+
type: 'padding'
|
|
797
|
+
}).evaluate;
|
|
798
|
+
|
|
799
|
+
expect(f({zoom: 0}, {properties: {}})).toEqual(new Padding([6, 6, 6, 6]));
|
|
800
|
+
expect(f({zoom: 0}, {properties: {foo: 3}})).toEqual(new Padding([6, 6, 6, 6]));
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
test('padding spec default', () => {
|
|
804
|
+
const f = createFunction({
|
|
805
|
+
property: 'foo',
|
|
806
|
+
type: 'categorical',
|
|
807
|
+
stops: [[0, 2], [1, 4]]
|
|
808
|
+
}, {
|
|
809
|
+
type: 'padding',
|
|
810
|
+
default: 6
|
|
811
|
+
}).evaluate;
|
|
812
|
+
|
|
813
|
+
expect(f({zoom: 0}, {properties: {}})).toEqual(new Padding([6, 6, 6, 6]));
|
|
814
|
+
expect(f({zoom: 0}, {properties: {foo: 3}})).toEqual(new Padding([6, 6, 6, 6]));
|
|
815
|
+
});
|
|
816
|
+
|
|
749
817
|
test('boolean', () => {
|
|
750
818
|
const f = createFunction({
|
|
751
819
|
property: 'foo',
|
|
@@ -853,6 +921,54 @@ describe('identity function', () => {
|
|
|
853
921
|
|
|
854
922
|
});
|
|
855
923
|
|
|
924
|
+
test('padding', () => {
|
|
925
|
+
const f = createFunction({
|
|
926
|
+
property: 'foo',
|
|
927
|
+
type: 'identity'
|
|
928
|
+
}, {
|
|
929
|
+
type: 'padding'
|
|
930
|
+
}).evaluate;
|
|
931
|
+
|
|
932
|
+
expect(f({zoom: 0}, {properties: {foo: 3}})).toEqual(new Padding([3, 3, 3, 3]));
|
|
933
|
+
expect(f({zoom: 1}, {properties: {foo: [3, 4]}})).toEqual(new Padding([3, 4, 3, 4]));
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
test('padding function default', () => {
|
|
937
|
+
const f = createFunction({
|
|
938
|
+
property: 'foo',
|
|
939
|
+
type: 'identity',
|
|
940
|
+
default: [1, 2, 3, 4]
|
|
941
|
+
}, {
|
|
942
|
+
type: 'padding'
|
|
943
|
+
}).evaluate;
|
|
944
|
+
|
|
945
|
+
expect(f({zoom: 0}, {properties: {}})).toEqual(new Padding([1, 2, 3, 4]));
|
|
946
|
+
});
|
|
947
|
+
|
|
948
|
+
test('padding spec default', () => {
|
|
949
|
+
const f = createFunction({
|
|
950
|
+
property: 'foo',
|
|
951
|
+
type: 'identity'
|
|
952
|
+
}, {
|
|
953
|
+
type: 'padding',
|
|
954
|
+
default: [1, 2, 3, 4]
|
|
955
|
+
}).evaluate;
|
|
956
|
+
|
|
957
|
+
expect(f({zoom: 0}, {properties: {}})).toEqual(new Padding([1, 2, 3, 4]));
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
test('padding invalid', () => {
|
|
961
|
+
const f = createFunction({
|
|
962
|
+
property: 'foo',
|
|
963
|
+
type: 'identity'
|
|
964
|
+
}, {
|
|
965
|
+
type: 'padding',
|
|
966
|
+
default: [1, 2, 3, 4]
|
|
967
|
+
}).evaluate;
|
|
968
|
+
|
|
969
|
+
expect(f({zoom: 0}, {properties: {foo: 'invalid'}})).toEqual(new Padding([1, 2, 3, 4]));
|
|
970
|
+
});
|
|
971
|
+
|
|
856
972
|
test('property type mismatch, function default', () => {
|
|
857
973
|
const f = createFunction({
|
|
858
974
|
property: 'foo',
|
|
@@ -9,6 +9,7 @@ import Formatted from '../expression/types/formatted';
|
|
|
9
9
|
import ResolvedImage from '../expression/types/resolved_image';
|
|
10
10
|
import {supportsInterpolation} from '../util/properties';
|
|
11
11
|
import {findStopLessThanOrEqualTo} from '../expression/stops';
|
|
12
|
+
import Padding from '../util/padding';
|
|
12
13
|
|
|
13
14
|
export function isFunction(value) {
|
|
14
15
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
@@ -25,19 +26,21 @@ export function createFunction(parameters, propertySpec) {
|
|
|
25
26
|
const zoomDependent = zoomAndFeatureDependent || !featureDependent;
|
|
26
27
|
const type = parameters.type || (supportsInterpolation(propertySpec) ? 'exponential' : 'interval');
|
|
27
28
|
|
|
28
|
-
if (isColor) {
|
|
29
|
+
if (isColor || propertySpec.type === 'padding') {
|
|
30
|
+
const parseFn = isColor ? Color.parse : Padding.parse;
|
|
31
|
+
|
|
29
32
|
parameters = extend({}, parameters);
|
|
30
33
|
|
|
31
34
|
if (parameters.stops) {
|
|
32
35
|
parameters.stops = parameters.stops.map((stop) => {
|
|
33
|
-
return [stop[0],
|
|
36
|
+
return [stop[0], parseFn(stop[1])];
|
|
34
37
|
});
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
if (parameters.default) {
|
|
38
|
-
parameters.default =
|
|
41
|
+
parameters.default = parseFn(parameters.default);
|
|
39
42
|
} else {
|
|
40
|
-
parameters.default =
|
|
43
|
+
parameters.default = parseFn(propertySpec.default);
|
|
41
44
|
}
|
|
42
45
|
}
|
|
43
46
|
|
|
@@ -198,14 +201,23 @@ function evaluateExponentialFunction(parameters, propertySpec, input) {
|
|
|
198
201
|
}
|
|
199
202
|
|
|
200
203
|
function evaluateIdentityFunction(parameters, propertySpec, input) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
204
|
+
switch (propertySpec.type) {
|
|
205
|
+
case 'color':
|
|
206
|
+
input = Color.parse(input);
|
|
207
|
+
break;
|
|
208
|
+
case 'formatted':
|
|
209
|
+
input = Formatted.fromString(input.toString());
|
|
210
|
+
break;
|
|
211
|
+
case 'resolvedImage':
|
|
212
|
+
input = ResolvedImage.fromString(input.toString());
|
|
213
|
+
break;
|
|
214
|
+
case 'padding':
|
|
215
|
+
input = Padding.parse(input);
|
|
216
|
+
break;
|
|
217
|
+
default:
|
|
218
|
+
if (getType(input) !== propertySpec.type && (propertySpec.type !== 'enum' || !propertySpec.values[input])) {
|
|
219
|
+
input = undefined;
|
|
220
|
+
}
|
|
209
221
|
}
|
|
210
222
|
return coalesce(input, parameters.default, propertySpec.default);
|
|
211
223
|
}
|
|
@@ -15,7 +15,7 @@ export default function expressions(style: StyleSpecification) {
|
|
|
15
15
|
|
|
16
16
|
eachLayer(style, (layer: LayerSpecification & { filter?: FilterSpecification }) => {
|
|
17
17
|
if (layer.filter) {
|
|
18
|
-
layer.filter =
|
|
18
|
+
layer.filter = convertFilter(layer.filter);
|
|
19
19
|
}
|
|
20
20
|
});
|
|
21
21
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
|
|
1
3
|
import migrate from './v9';
|
|
2
4
|
|
|
3
5
|
describe('migrate v9', () => {
|
|
@@ -5,7 +7,7 @@ describe('migrate v9', () => {
|
|
|
5
7
|
const input = {
|
|
6
8
|
version: 8,
|
|
7
9
|
sources: {
|
|
8
|
-
a: {type: 'vector', tiles: [
|
|
10
|
+
a: {type: 'vector', tiles: ['http://dev/null']}
|
|
9
11
|
},
|
|
10
12
|
layers: [{
|
|
11
13
|
id: 'parent',
|
|
@@ -21,7 +23,7 @@ describe('migrate v9', () => {
|
|
|
21
23
|
expect(migrate(input)).toEqual({
|
|
22
24
|
version: 9,
|
|
23
25
|
sources: {
|
|
24
|
-
a: {type: 'vector', tiles: [
|
|
26
|
+
a: {type: 'vector', tiles: ['http://dev/null']}
|
|
25
27
|
},
|
|
26
28
|
layers: [{
|
|
27
29
|
id: 'parent',
|
|
@@ -42,7 +44,7 @@ describe('migrate v9', () => {
|
|
|
42
44
|
const input = {
|
|
43
45
|
version: 8,
|
|
44
46
|
sources: {
|
|
45
|
-
a: {type: 'vector', tiles: [
|
|
47
|
+
a: {type: 'vector', tiles: ['http://dev/null']}
|
|
46
48
|
},
|
|
47
49
|
layers: [{
|
|
48
50
|
id: 'a',
|
|
@@ -61,7 +63,7 @@ describe('migrate v9', () => {
|
|
|
61
63
|
expect(migrate(input)).toEqual({
|
|
62
64
|
version: 9,
|
|
63
65
|
sources: {
|
|
64
|
-
a: {type: 'vector', tiles: [
|
|
66
|
+
a: {type: 'vector', tiles: ['http://dev/null']}
|
|
65
67
|
},
|
|
66
68
|
layers: [{
|
|
67
69
|
id: 'a',
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
|
|
1
3
|
import migrate from './migrate';
|
|
2
4
|
import * as spec from './style-spec';
|
|
3
5
|
import v8 from './reference/v8.json';
|
|
@@ -102,7 +104,7 @@ describe('migrate', () => {
|
|
|
102
104
|
});
|
|
103
105
|
expect(migrated.layers[0].layout['icon-image']).toEqual([
|
|
104
106
|
'match',
|
|
105
|
-
['get', 'type'
|
|
107
|
+
['get', 'type'],
|
|
106
108
|
'park',
|
|
107
109
|
'some-icon',
|
|
108
110
|
''
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
|
|
2
|
-
import spec from './v8.json';
|
|
3
|
-
export default spec;
|
|
2
|
+
import spec from './v8.json' assert {type: 'json'};
|
|
3
|
+
export default spec as any;
|
|
@@ -1466,11 +1466,10 @@
|
|
|
1466
1466
|
"property-type": "data-driven"
|
|
1467
1467
|
},
|
|
1468
1468
|
"icon-padding": {
|
|
1469
|
-
"type": "
|
|
1470
|
-
"default": 2,
|
|
1471
|
-
"minimum": 0,
|
|
1469
|
+
"type": "padding",
|
|
1470
|
+
"default": [2],
|
|
1472
1471
|
"units": "pixels",
|
|
1473
|
-
"doc": "Size of
|
|
1472
|
+
"doc": "Size of additional area round the icon bounding box used for detecting symbol collisions. Values are declared using CSS margin shorthand syntax: a single value applies to all four sides; two values apply to [top/bottom, left/right]; three values apply to [top, left/right, bottom]; four values apply to [top, right, bottom, left]. For backwards compatibility, a single bare number is accepted, and treated the same as a one-element array - padding applied to all sides.",
|
|
1474
1473
|
"requires": [
|
|
1475
1474
|
"icon-image"
|
|
1476
1475
|
],
|
|
@@ -1480,15 +1479,19 @@
|
|
|
1480
1479
|
"android": "2.0.1",
|
|
1481
1480
|
"ios": "2.0.0",
|
|
1482
1481
|
"macos": "0.1.0"
|
|
1482
|
+
},
|
|
1483
|
+
"data-driven styling": {
|
|
1484
|
+
"js": "2.2.0"
|
|
1483
1485
|
}
|
|
1484
1486
|
},
|
|
1485
1487
|
"expression": {
|
|
1486
1488
|
"interpolated": true,
|
|
1487
1489
|
"parameters": [
|
|
1488
|
-
"zoom"
|
|
1490
|
+
"zoom",
|
|
1491
|
+
"feature"
|
|
1489
1492
|
]
|
|
1490
1493
|
},
|
|
1491
|
-
"property-type": "data-
|
|
1494
|
+
"property-type": "data-driven"
|
|
1492
1495
|
},
|
|
1493
1496
|
"icon-keep-upright": {
|
|
1494
1497
|
"type": "boolean",
|