@mapwhit/tilerenderer 0.47.2 → 0.49.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 +3 -2
- package/src/data/array_types.js +169 -0
- package/src/data/bucket/symbol_attributes.js +18 -0
- package/src/data/bucket/symbol_bucket.js +116 -73
- package/src/data/program_configuration.js +18 -10
- package/src/geo/transform.js +17 -7
- package/src/index.js +1 -1
- package/src/render/glyph_atlas.js +3 -6
- package/src/render/image_atlas.js +3 -6
- package/src/render/image_manager.js +41 -41
- package/src/source/rtl_text_plugin.js +1 -0
- package/src/source/source_cache.js +1 -1
- package/src/source/tile.js +6 -5
- package/src/source/worker.js +1 -10
- package/src/style/style.js +4 -19
- package/src/style/style_layer/symbol_style_layer_properties.js +7 -1
- package/src/style-spec/expression/compound_expression.js +30 -16
- package/src/style-spec/expression/definitions/assertion.js +52 -5
- package/src/style-spec/expression/definitions/coercion.js +13 -0
- package/src/style-spec/expression/definitions/comparison.js +193 -0
- package/src/style-spec/expression/definitions/formatted.js +123 -0
- package/src/style-spec/expression/definitions/index.js +11 -62
- package/src/style-spec/expression/definitions/interpolate.js +17 -7
- package/src/style-spec/expression/definitions/literal.js +5 -0
- package/src/style-spec/expression/parsing_context.js +6 -7
- package/src/style-spec/expression/types.js +12 -1
- package/src/style-spec/feature_filter/convert.js +197 -0
- package/src/style-spec/feature_filter/index.js +5 -2
- package/src/style-spec/function/convert.js +78 -100
- package/src/style-spec/reference/v8.json +160 -52
- package/src/symbol/collision_index.js +0 -1
- package/src/symbol/cross_tile_symbol_index.js +12 -7
- package/src/symbol/get_anchors.js +11 -22
- package/src/symbol/mergelines.js +4 -1
- package/src/symbol/placement.js +58 -54
- package/src/symbol/quads.js +7 -6
- package/src/symbol/shaping.js +185 -40
- package/src/symbol/symbol_layout.js +40 -37
- package/src/symbol/transform_text.js +12 -1
- package/src/ui/map.js +8 -25
- package/src/style-spec/expression/definitions/array.js +0 -82
- package/src/style-spec/expression/definitions/equals.js +0 -93
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
const { isExpressionFilter } = require('./index');
|
|
2
|
+
|
|
3
|
+
module.exports = convertFilter;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Convert the given legacy filter to (the JSON representation of) an
|
|
7
|
+
* equivalent expression
|
|
8
|
+
* @private
|
|
9
|
+
*/
|
|
10
|
+
function convertFilter(filter) {
|
|
11
|
+
return _convertFilter(filter, {});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* Convert the given filter to an expression, storing the expected types for
|
|
16
|
+
* any feature properties referenced in expectedTypes.
|
|
17
|
+
*
|
|
18
|
+
* These expected types are needed in order to construct preflight type checks
|
|
19
|
+
* needed for handling 'any' filters. A preflight type check is necessary in
|
|
20
|
+
* order to mimic legacy filters' semantics around expected type mismatches.
|
|
21
|
+
* For example, consider the legacy filter:
|
|
22
|
+
*
|
|
23
|
+
* ["any", ["all", [">", "y", 0], [">", "y", 0]], [">", "x", 0]]
|
|
24
|
+
*
|
|
25
|
+
* Naively, we might convert this to the expression:
|
|
26
|
+
*
|
|
27
|
+
* ["any", ["all", [">", ["get", "y"], 0], [">", ["get", "z"], 0]], [">", ["get", "x"], 0]]
|
|
28
|
+
*
|
|
29
|
+
* But if we tried to evaluate this against, say `{x: 1, y: null, z: 0}`, the
|
|
30
|
+
* [">", ["get", "y"], 0] would cause an evaluation error, leading to the
|
|
31
|
+
* entire filter returning false. Legacy filter semantics, though, ask for
|
|
32
|
+
* [">", "y", 0] to simply return `false` when `y` is of the wrong type,
|
|
33
|
+
* allowing the subsequent terms of the outer "any" expression to be evaluated
|
|
34
|
+
* (resulting, in this case, in a `true` value, because x > 0).
|
|
35
|
+
*
|
|
36
|
+
* We account for this by inserting a preflight type-checking expression before
|
|
37
|
+
* each "any" term, allowing us to avoid evaluating the actual converted filter
|
|
38
|
+
* if any type mismatches would cause it to produce an evalaution error:
|
|
39
|
+
*
|
|
40
|
+
* ["any",
|
|
41
|
+
* ["case",
|
|
42
|
+
* ["all", ["==", ["typeof", ["get", "y"]], "number"], ["==", ["typeof", ["get", "z"], "number]],
|
|
43
|
+
* ["all", [">", ["get", "y"], 0], [">", ["get", "z"], 0]],
|
|
44
|
+
* false
|
|
45
|
+
* ],
|
|
46
|
+
* ["case",
|
|
47
|
+
* ["==", ["typeof", ["get", "x"], "number"]],
|
|
48
|
+
* [">", ["get", "x"], 0],
|
|
49
|
+
* false
|
|
50
|
+
* ]
|
|
51
|
+
* ]
|
|
52
|
+
*
|
|
53
|
+
* An alternative, possibly more direct approach would be to use type checks
|
|
54
|
+
* in the conversion of each comparison operator, so that the converted version
|
|
55
|
+
* of each individual ==, >=, etc. would mimic the legacy filter semantics. The
|
|
56
|
+
* downside of this approach is that it can lead to many more type checks than
|
|
57
|
+
* would otherwise be necessary: outside the context of an "any" expression,
|
|
58
|
+
* bailing out due to a runtime type error (expression semantics) and returning
|
|
59
|
+
* false (legacy filter semantics) are equivalent: they cause the filter to
|
|
60
|
+
* produce a `false` result.
|
|
61
|
+
*/
|
|
62
|
+
function _convertFilter(filter, expectedTypes) {
|
|
63
|
+
if (isExpressionFilter(filter)) {
|
|
64
|
+
return filter;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!filter) return true;
|
|
68
|
+
const op = filter[0];
|
|
69
|
+
if (filter.length <= 1) return op !== 'any';
|
|
70
|
+
|
|
71
|
+
let converted;
|
|
72
|
+
|
|
73
|
+
if (op === '==' || op === '!=' || op === '<' || op === '>' || op === '<=' || op === '>=') {
|
|
74
|
+
const [, property, value] = filter;
|
|
75
|
+
converted = convertComparisonOp(property, value, op, expectedTypes);
|
|
76
|
+
} else if (op === 'any') {
|
|
77
|
+
const children = filter.slice(1).map(f => {
|
|
78
|
+
const types = {};
|
|
79
|
+
const child = _convertFilter(f, types);
|
|
80
|
+
const typechecks = runtimeTypeChecks(types);
|
|
81
|
+
return typechecks === true ? child : ['case', typechecks, child, false];
|
|
82
|
+
});
|
|
83
|
+
return ['any'].concat(children);
|
|
84
|
+
} else if (op === 'all') {
|
|
85
|
+
const children = filter.slice(1).map(f => _convertFilter(f, expectedTypes));
|
|
86
|
+
return ['all'].concat(children);
|
|
87
|
+
} else if (op === 'none') {
|
|
88
|
+
return ['!', _convertFilter(['any'].concat(filter.slice(1)), {})];
|
|
89
|
+
} else if (op === 'in') {
|
|
90
|
+
converted = convertInOp(filter[1], filter.slice(2));
|
|
91
|
+
} else if (op === '!in') {
|
|
92
|
+
converted = convertInOp(filter[1], filter.slice(2), true);
|
|
93
|
+
} else if (op === 'has') {
|
|
94
|
+
converted = convertHasOp(filter[1]);
|
|
95
|
+
} else if (op === '!has') {
|
|
96
|
+
converted = ['!', convertHasOp(filter[1])];
|
|
97
|
+
} else {
|
|
98
|
+
converted = true;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return converted;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Given a set of feature properties and an expected type for each one,
|
|
105
|
+
// construct an boolean expression that tests whether each property has the
|
|
106
|
+
// right type.
|
|
107
|
+
// E.g.: for {name: 'string', population: 'number'}, return
|
|
108
|
+
// [ 'all',
|
|
109
|
+
// ['==', ['typeof', ['get', 'name'], 'string']],
|
|
110
|
+
// ['==', ['typeof', ['get', 'population'], 'number]]
|
|
111
|
+
// ]
|
|
112
|
+
function runtimeTypeChecks(expectedTypes) {
|
|
113
|
+
const conditions = [];
|
|
114
|
+
for (const property in expectedTypes) {
|
|
115
|
+
const get = property === '$id' ? ['id'] : ['get', property];
|
|
116
|
+
conditions.push(['==', ['typeof', get], expectedTypes[property]]);
|
|
117
|
+
}
|
|
118
|
+
if (conditions.length === 0) return true;
|
|
119
|
+
if (conditions.length === 1) return conditions[0];
|
|
120
|
+
return ['all'].concat(conditions);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function convertComparisonOp(property, value, op, expectedTypes) {
|
|
124
|
+
let get;
|
|
125
|
+
if (property === '$type') {
|
|
126
|
+
return [op, ['geometry-type'], value];
|
|
127
|
+
}
|
|
128
|
+
if (property === '$id') {
|
|
129
|
+
get = ['id'];
|
|
130
|
+
} else {
|
|
131
|
+
get = ['get', property];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (expectedTypes && value !== null) {
|
|
135
|
+
const type = typeof value;
|
|
136
|
+
expectedTypes[property] = type;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (op === '==' && property !== '$id' && value === null) {
|
|
140
|
+
return [
|
|
141
|
+
'all',
|
|
142
|
+
['has', property], // missing property != null for legacy filters
|
|
143
|
+
['==', get, null]
|
|
144
|
+
];
|
|
145
|
+
}
|
|
146
|
+
if (op === '!=' && property !== '$id' && value === null) {
|
|
147
|
+
return [
|
|
148
|
+
'any',
|
|
149
|
+
['!', ['has', property]], // missing property != null for legacy filters
|
|
150
|
+
['!=', get, null]
|
|
151
|
+
];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return [op, get, value];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function convertInOp(property, values, negate = false) {
|
|
158
|
+
if (values.length === 0) return negate;
|
|
159
|
+
|
|
160
|
+
let get;
|
|
161
|
+
if (property === '$type') {
|
|
162
|
+
get = ['geometry-type'];
|
|
163
|
+
} else if (property === '$id') {
|
|
164
|
+
get = ['id'];
|
|
165
|
+
} else {
|
|
166
|
+
get = ['get', property];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Determine if the list of values to be searched is homogenously typed.
|
|
170
|
+
// If so (and if the type is string or number), then we can use a
|
|
171
|
+
// [match, input, [...values], true, false] construction rather than a
|
|
172
|
+
// bunch of `==` tests.
|
|
173
|
+
let uniformTypes = true;
|
|
174
|
+
const type = typeof values[0];
|
|
175
|
+
for (const value of values) {
|
|
176
|
+
if (typeof value !== type) {
|
|
177
|
+
uniformTypes = false;
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (uniformTypes && (type === 'string' || type === 'number')) {
|
|
183
|
+
return ['match', get, values, !negate, negate];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return [negate ? 'all' : 'any'].concat(values.map(v => [negate ? '!=' : '==', get, v]));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function convertHasOp(property) {
|
|
190
|
+
if (property === '$type') {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
if (property === '$id') {
|
|
194
|
+
return ['!=', ['id'], null];
|
|
195
|
+
}
|
|
196
|
+
return ['has', property];
|
|
197
|
+
}
|
|
@@ -5,6 +5,9 @@ module.exports = createFilter;
|
|
|
5
5
|
createFilter.isExpressionFilter = isExpressionFilter;
|
|
6
6
|
|
|
7
7
|
function isExpressionFilter(filter) {
|
|
8
|
+
if (filter === true || filter === false) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
8
11
|
if (!Array.isArray(filter) || filter.length === 0) {
|
|
9
12
|
return false;
|
|
10
13
|
}
|
|
@@ -24,7 +27,7 @@ function isExpressionFilter(filter) {
|
|
|
24
27
|
case '>=':
|
|
25
28
|
case '<':
|
|
26
29
|
case '<=':
|
|
27
|
-
return filter.length
|
|
30
|
+
return filter.length !== 3 || Array.isArray(filter[1]) || Array.isArray(filter[2]);
|
|
28
31
|
|
|
29
32
|
case 'any':
|
|
30
33
|
case 'all':
|
|
@@ -61,7 +64,7 @@ const filterSpec = {
|
|
|
61
64
|
* @returns {Function} filter-evaluating function
|
|
62
65
|
*/
|
|
63
66
|
function createFilter(filter) {
|
|
64
|
-
if (
|
|
67
|
+
if (filter === null || filter === undefined) {
|
|
65
68
|
return () => true;
|
|
66
69
|
}
|
|
67
70
|
|
|
@@ -3,85 +3,64 @@ const assert = require('assert');
|
|
|
3
3
|
module.exports = convertFunction;
|
|
4
4
|
|
|
5
5
|
function convertFunction(parameters, propertySpec) {
|
|
6
|
-
let
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (typeof parameters.default !== 'undefined') {
|
|
11
|
-
defaultExpression = convertValue(parameters.default, propertySpec);
|
|
12
|
-
} else {
|
|
13
|
-
defaultExpression = convertValue(propertySpec.default, propertySpec);
|
|
14
|
-
if (defaultExpression === null) {
|
|
15
|
-
defaultExpression = ['error', 'No default property value available.'];
|
|
16
|
-
}
|
|
6
|
+
let stops = parameters.stops;
|
|
7
|
+
if (!stops) {
|
|
8
|
+
// identity function
|
|
9
|
+
return convertIdentityFunction(parameters, propertySpec);
|
|
17
10
|
}
|
|
18
11
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const zoomDependent = zoomAndFeatureDependent || !featureDependent;
|
|
23
|
-
|
|
24
|
-
const stops = parameters.stops.map(stop => {
|
|
25
|
-
if (!featureDependent && propertySpec.tokens && typeof stop[1] === 'string') {
|
|
26
|
-
return [stop[0], convertTokenString(stop[1])];
|
|
27
|
-
}
|
|
28
|
-
return [stop[0], convertValue(stop[1], propertySpec)];
|
|
29
|
-
});
|
|
12
|
+
const zoomAndFeatureDependent = stops && typeof stops[0][0] === 'object';
|
|
13
|
+
const featureDependent = zoomAndFeatureDependent || parameters.property !== undefined;
|
|
14
|
+
const zoomDependent = zoomAndFeatureDependent || !featureDependent;
|
|
30
15
|
|
|
31
|
-
|
|
32
|
-
|
|
16
|
+
stops = stops.map(stop => {
|
|
17
|
+
if (!featureDependent && propertySpec.tokens && typeof stop[1] === 'string') {
|
|
18
|
+
return [stop[0], convertTokenString(stop[1])];
|
|
33
19
|
}
|
|
20
|
+
return [stop[0], ['literal', stop[1]]];
|
|
21
|
+
});
|
|
34
22
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
} else if (zoomDependent) {
|
|
38
|
-
expression = convertZoomFunction(parameters, propertySpec, stops);
|
|
39
|
-
} else {
|
|
40
|
-
expression = convertPropertyFunction(parameters, propertySpec, stops, defaultExpression);
|
|
41
|
-
}
|
|
42
|
-
} else {
|
|
43
|
-
// identity function
|
|
44
|
-
expression = convertIdentityFunction(parameters, propertySpec, defaultExpression);
|
|
23
|
+
if (zoomAndFeatureDependent) {
|
|
24
|
+
return convertZoomAndPropertyFunction(parameters, propertySpec, stops);
|
|
45
25
|
}
|
|
46
|
-
|
|
47
|
-
|
|
26
|
+
if (zoomDependent) {
|
|
27
|
+
return convertZoomFunction(parameters, propertySpec, stops);
|
|
28
|
+
}
|
|
29
|
+
return convertPropertyFunction(parameters, propertySpec, stops);
|
|
48
30
|
}
|
|
49
31
|
|
|
50
|
-
function convertIdentityFunction(parameters, propertySpec
|
|
32
|
+
function convertIdentityFunction(parameters, propertySpec) {
|
|
51
33
|
const get = ['get', parameters.property];
|
|
52
34
|
|
|
53
|
-
if (
|
|
54
|
-
return
|
|
35
|
+
if (parameters.default === undefined) {
|
|
36
|
+
return get;
|
|
55
37
|
}
|
|
56
|
-
if (propertySpec.type === '
|
|
57
|
-
return ['
|
|
38
|
+
if (propertySpec.type === 'enum') {
|
|
39
|
+
return ['match', get, Object.keys(propertySpec.values), get, parameters.default];
|
|
58
40
|
}
|
|
41
|
+
const expression = [
|
|
42
|
+
propertySpec.type === 'color' ? 'to-color' : propertySpec.type,
|
|
43
|
+
get,
|
|
44
|
+
['literal', parameters.default]
|
|
45
|
+
];
|
|
59
46
|
if (propertySpec.type === 'array') {
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
if (propertySpec.type === 'enum') {
|
|
63
|
-
return [
|
|
64
|
-
'let',
|
|
65
|
-
'property_value',
|
|
66
|
-
['string', get],
|
|
67
|
-
['match', ['var', 'property_value'], propertySpec.values, ['var', 'property_value'], defaultExpression]
|
|
68
|
-
];
|
|
47
|
+
expression.splice(1, 0, propertySpec.value, propertySpec.length || null);
|
|
69
48
|
}
|
|
70
|
-
return
|
|
49
|
+
return expression;
|
|
71
50
|
}
|
|
72
51
|
|
|
73
|
-
function
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
52
|
+
function getInterpolateOperator(parameters) {
|
|
53
|
+
switch (parameters.colorSpace) {
|
|
54
|
+
case 'hcl':
|
|
55
|
+
return 'interpolate-hcl';
|
|
56
|
+
case 'lab':
|
|
57
|
+
return 'interpolate-lab';
|
|
58
|
+
default:
|
|
59
|
+
return 'interpolate';
|
|
80
60
|
}
|
|
81
|
-
return value;
|
|
82
61
|
}
|
|
83
62
|
|
|
84
|
-
function convertZoomAndPropertyFunction(parameters, propertySpec, stops
|
|
63
|
+
function convertZoomAndPropertyFunction(parameters, propertySpec, stops) {
|
|
85
64
|
const featureFunctionParameters = {};
|
|
86
65
|
const featureFunctionStops = {};
|
|
87
66
|
const zoomStops = [];
|
|
@@ -107,15 +86,10 @@ function convertZoomAndPropertyFunction(parameters, propertySpec, stops, default
|
|
|
107
86
|
// otherwise.
|
|
108
87
|
const functionType = getFunctionType({}, propertySpec);
|
|
109
88
|
if (functionType === 'exponential') {
|
|
110
|
-
const expression = [
|
|
89
|
+
const expression = [getInterpolateOperator(parameters), ['linear'], ['zoom']];
|
|
111
90
|
|
|
112
91
|
for (const z of zoomStops) {
|
|
113
|
-
const output = convertPropertyFunction(
|
|
114
|
-
featureFunctionParameters[z],
|
|
115
|
-
propertySpec,
|
|
116
|
-
featureFunctionStops[z],
|
|
117
|
-
defaultExpression
|
|
118
|
-
);
|
|
92
|
+
const output = convertPropertyFunction(featureFunctionParameters[z], propertySpec, featureFunctionStops[z]);
|
|
119
93
|
appendStopPair(expression, z, output, false);
|
|
120
94
|
}
|
|
121
95
|
|
|
@@ -124,12 +98,7 @@ function convertZoomAndPropertyFunction(parameters, propertySpec, stops, default
|
|
|
124
98
|
const expression = ['step', ['zoom']];
|
|
125
99
|
|
|
126
100
|
for (const z of zoomStops) {
|
|
127
|
-
const output = convertPropertyFunction(
|
|
128
|
-
featureFunctionParameters[z],
|
|
129
|
-
propertySpec,
|
|
130
|
-
featureFunctionStops[z],
|
|
131
|
-
defaultExpression
|
|
132
|
-
);
|
|
101
|
+
const output = convertPropertyFunction(featureFunctionParameters[z], propertySpec, featureFunctionStops[z]);
|
|
133
102
|
appendStopPair(expression, z, output, true);
|
|
134
103
|
}
|
|
135
104
|
|
|
@@ -138,43 +107,52 @@ function convertZoomAndPropertyFunction(parameters, propertySpec, stops, default
|
|
|
138
107
|
return expression;
|
|
139
108
|
}
|
|
140
109
|
|
|
141
|
-
function
|
|
142
|
-
|
|
110
|
+
function coalesce(a, b) {
|
|
111
|
+
if (a !== undefined) return a;
|
|
112
|
+
if (b !== undefined) return b;
|
|
113
|
+
}
|
|
143
114
|
|
|
144
|
-
|
|
145
|
-
|
|
115
|
+
function convertPropertyFunction(parameters, propertySpec, stops) {
|
|
116
|
+
const type = getFunctionType(parameters, propertySpec);
|
|
117
|
+
const get = ['get', parameters.property];
|
|
146
118
|
if (type === 'categorical' && typeof stops[0][0] === 'boolean') {
|
|
147
119
|
assert(parameters.stops.length > 0 && parameters.stops.length <= 2);
|
|
148
|
-
expression = ['case'];
|
|
120
|
+
const expression = ['case'];
|
|
149
121
|
for (const stop of stops) {
|
|
150
|
-
expression.push(['==',
|
|
122
|
+
expression.push(['==', get, stop[0]], stop[1]);
|
|
151
123
|
}
|
|
152
|
-
expression.push(
|
|
124
|
+
expression.push(['literal', coalesce(parameters.default, propertySpec.default)]);
|
|
153
125
|
return expression;
|
|
154
126
|
}
|
|
155
127
|
if (type === 'categorical') {
|
|
156
|
-
expression = ['match',
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
expression = ['interpolate', ['exponential', base], ['number', ['get', parameters.property]]];
|
|
163
|
-
} else {
|
|
164
|
-
throw new Error(`Unknown property function type ${type}`);
|
|
128
|
+
const expression = ['match', get];
|
|
129
|
+
for (const stop of stops) {
|
|
130
|
+
appendStopPair(expression, stop[0], stop[1], false);
|
|
131
|
+
}
|
|
132
|
+
expression.push(['literal', coalesce(parameters.default, propertySpec.default)]);
|
|
133
|
+
return expression;
|
|
165
134
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
135
|
+
if (type === 'interval') {
|
|
136
|
+
const expression = ['step', ['number', get]];
|
|
137
|
+
for (const stop of stops) {
|
|
138
|
+
appendStopPair(expression, stop[0], stop[1], true);
|
|
139
|
+
}
|
|
140
|
+
fixupDegenerateStepCurve(expression);
|
|
141
|
+
return parameters.default === undefined
|
|
142
|
+
? expression
|
|
143
|
+
: ['case', ['==', ['typeof', get], 'number'], expression, ['literal', parameters.default]];
|
|
169
144
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
expression
|
|
145
|
+
if (type === 'exponential') {
|
|
146
|
+
const base = parameters.base !== undefined ? parameters.base : 1;
|
|
147
|
+
const expression = [getInterpolateOperator(parameters), ['exponential', base], ['number', get]];
|
|
148
|
+
for (const stop of stops) {
|
|
149
|
+
appendStopPair(expression, stop[0], stop[1], false);
|
|
150
|
+
}
|
|
151
|
+
return parameters.default === undefined
|
|
152
|
+
? expression
|
|
153
|
+
: ['case', ['==', ['typeof', get], 'number'], expression, ['literal', parameters.default]];
|
|
173
154
|
}
|
|
174
|
-
|
|
175
|
-
fixupDegenerateStepCurve(expression);
|
|
176
|
-
|
|
177
|
-
return expression;
|
|
155
|
+
throw new Error(`Unknown property function type ${type}`);
|
|
178
156
|
}
|
|
179
157
|
|
|
180
158
|
function convertZoomFunction(parameters, propertySpec, stops, input = ['zoom']) {
|
|
@@ -186,7 +164,7 @@ function convertZoomFunction(parameters, propertySpec, stops, input = ['zoom'])
|
|
|
186
164
|
isStep = true;
|
|
187
165
|
} else if (type === 'exponential') {
|
|
188
166
|
const base = parameters.base !== undefined ? parameters.base : 1;
|
|
189
|
-
expression = [
|
|
167
|
+
expression = [getInterpolateOperator(parameters), ['exponential', base], input];
|
|
190
168
|
} else {
|
|
191
169
|
throw new Error(`Unknown zoom function type "${type}"`);
|
|
192
170
|
}
|