@mapbox/mapbox-gl-style-spec 14.8.0 → 14.9.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/diff.ts +16 -0
- package/dist/index.cjs +807 -130
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +162 -11
- package/dist/index.es.js +807 -130
- package/dist/index.es.js.map +1 -1
- package/expression/definitions/coercion.ts +1 -1
- package/expression/definitions/config.ts +1 -1
- package/expression/definitions/image.ts +184 -14
- package/expression/definitions/index.ts +7 -0
- package/expression/definitions/interpolate.ts +54 -13
- package/expression/expression.ts +1 -0
- package/expression/index.ts +12 -6
- package/expression/types/formatted.ts +1 -1
- package/expression/types/image_id_with_options.ts +54 -0
- package/expression/types/resolved_image.ts +49 -7
- package/expression/values.ts +9 -7
- package/feature_filter/index.ts +1 -0
- package/function/index.ts +1 -1
- package/group_by_layout.ts +35 -3
- package/package.json +1 -1
- package/reference/v8.json +357 -70
- package/types.ts +118 -9
- package/util/color.ts +62 -1
- package/validate/validate_fog.ts +10 -1
- package/validate/validate_function.ts +1 -1
- package/validate/validate_light.ts +10 -1
- package/validate/validate_lights.ts +11 -1
- package/validate/validate_property.ts +11 -0
- package/validate/validate_rain.ts +47 -0
- package/validate/validate_snow.ts +47 -0
- package/validate/validate_terrain.ts +11 -2
- package/validate_style.min.ts +4 -0
|
@@ -138,7 +138,7 @@ class Coercion implements Expression {
|
|
|
138
138
|
// created by properties that expect the 'formatted' type.
|
|
139
139
|
return Formatted.fromString(valueToString(this.args[0].evaluate(ctx)));
|
|
140
140
|
} else if (this.type.kind === 'resolvedImage') {
|
|
141
|
-
return ResolvedImage.
|
|
141
|
+
return ResolvedImage.build(valueToString(this.args[0].evaluate(ctx)));
|
|
142
142
|
} else if (this.type.kind === 'array') {
|
|
143
143
|
return this.args.map(arg => { return arg.evaluate(ctx); });
|
|
144
144
|
} else {
|
|
@@ -19,7 +19,7 @@ function coerceValue(type: string, value: any): any {
|
|
|
19
19
|
return Formatted.fromString(valueToString(value));
|
|
20
20
|
}
|
|
21
21
|
case 'resolvedImage': {
|
|
22
|
-
return ResolvedImage.
|
|
22
|
+
return ResolvedImage.build(valueToString(value));
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
return value;
|
|
@@ -1,20 +1,47 @@
|
|
|
1
|
-
import {ResolvedImageType, StringType} from '../types';
|
|
1
|
+
import {ColorType, ResolvedImageType, StringType} from '../types';
|
|
2
2
|
import ResolvedImage from '../types/resolved_image';
|
|
3
|
+
import {isExpression} from '..';
|
|
3
4
|
|
|
5
|
+
import type Color from '../../util/color';
|
|
4
6
|
import type {Expression, SerializedExpression} from '../expression';
|
|
5
7
|
import type EvaluationContext from '../evaluation_context';
|
|
6
8
|
import type ParsingContext from '../parsing_context';
|
|
7
9
|
import type {Type} from '../types';
|
|
8
10
|
|
|
11
|
+
export type ImageParams = Record<string, Expression>;
|
|
12
|
+
|
|
13
|
+
export type ImageOptions = {
|
|
14
|
+
params: ImageParams;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function isImageOptions(value: unknown) {
|
|
18
|
+
if (typeof value !== 'string' && !isExpression(value)) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
9
25
|
export default class ImageExpression implements Expression {
|
|
10
26
|
type: Type;
|
|
11
27
|
inputPrimary: Expression;
|
|
28
|
+
inputPrimaryParams: Record<string, Expression> | undefined;
|
|
12
29
|
inputSecondary: Expression | null | undefined;
|
|
30
|
+
inputSecondaryParams: Record<string, Expression> | undefined;
|
|
13
31
|
|
|
14
|
-
|
|
32
|
+
_imageWarnHistory: Record<string, boolean> = {};
|
|
33
|
+
|
|
34
|
+
constructor(
|
|
35
|
+
inputPrimary: Expression,
|
|
36
|
+
inputSecondary?: Expression | null,
|
|
37
|
+
inputPrimaryParams?: Record<string, Expression>,
|
|
38
|
+
inputSecondaryParams?: Record<string, Expression>
|
|
39
|
+
) {
|
|
15
40
|
this.type = ResolvedImageType;
|
|
16
41
|
this.inputPrimary = inputPrimary;
|
|
17
42
|
this.inputSecondary = inputSecondary;
|
|
43
|
+
this.inputPrimaryParams = inputPrimaryParams;
|
|
44
|
+
this.inputSecondaryParams = inputSecondaryParams;
|
|
18
45
|
}
|
|
19
46
|
|
|
20
47
|
static parse(args: ReadonlyArray<unknown>, context: ParsingContext): Expression | null | undefined {
|
|
@@ -23,23 +50,126 @@ export default class ImageExpression implements Expression {
|
|
|
23
50
|
return context.error(`Expected two or more arguments.`);
|
|
24
51
|
}
|
|
25
52
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
53
|
+
let nextArgId = 1;
|
|
54
|
+
const imageExpression: Array<{image: Expression, options: Record<string, Expression>}> = [];
|
|
55
|
+
|
|
56
|
+
function tryParseImage() {
|
|
57
|
+
if (nextArgId < args.length) {
|
|
58
|
+
const imageName = context.parse(args[nextArgId], nextArgId++, StringType);
|
|
59
|
+
if (!imageName) {
|
|
60
|
+
context.error(imageExpression.length ? `Secondary image variant is not a string.` : `No image name provided.`);
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
imageExpression.push({image: imageName, options: undefined});
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function tryParseOptions() {
|
|
72
|
+
if (nextArgId < args.length) {
|
|
73
|
+
if (!isImageOptions(args[nextArgId])) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const params = (args[nextArgId] as ImageOptions).params;
|
|
78
|
+
|
|
79
|
+
const optionsContext = context.concat(nextArgId);
|
|
80
|
+
|
|
81
|
+
if (!params) {
|
|
82
|
+
nextArgId++;
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (typeof params !== 'object' || params.constructor !== Object) {
|
|
87
|
+
optionsContext.error(`Image options \"params\" should be an object`);
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const parsed = {};
|
|
92
|
+
|
|
93
|
+
const childContext = optionsContext.concat(undefined, 'params');
|
|
94
|
+
|
|
95
|
+
for (const key in params) {
|
|
96
|
+
if (!key) {
|
|
97
|
+
childContext.error(`Image parameter name should be non-empty`);
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const value = childContext.concat(undefined, key).parse(params[key], undefined, ColorType, undefined, {typeAnnotation: 'coerce'});
|
|
102
|
+
if (!value) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
parsed[key] = value;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
imageExpression[imageExpression.length - 1].options = parsed;
|
|
110
|
+
nextArgId++;
|
|
111
|
+
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Parse the primary and secondary image expressions
|
|
119
|
+
for (let i = 0; i < 2; i++) {
|
|
120
|
+
if (!tryParseImage() || !tryParseOptions()) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
29
124
|
|
|
30
|
-
|
|
31
|
-
|
|
125
|
+
return new ImageExpression(
|
|
126
|
+
imageExpression[0].image,
|
|
127
|
+
imageExpression[1] ? imageExpression[1].image : undefined,
|
|
128
|
+
imageExpression[0].options,
|
|
129
|
+
imageExpression[1] ? imageExpression[1].options : undefined
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
evaluateParams(ctx: EvaluationContext, params: Record<string, Expression> | undefined): {params: Record<string, Color>} {
|
|
134
|
+
const result: Record<string, Color> = {};
|
|
135
|
+
if (params) {
|
|
136
|
+
for (const key in params) {
|
|
137
|
+
if (params[key]) {
|
|
138
|
+
try {
|
|
139
|
+
const color = params[key].evaluate(ctx);
|
|
140
|
+
const msg = `Ignoring image parameter "${key}" with semi-transparent color ${color.toString()}`;
|
|
141
|
+
|
|
142
|
+
if (color.a !== 1) {
|
|
143
|
+
if (!this._imageWarnHistory[msg]) {
|
|
144
|
+
console.warn(msg);
|
|
145
|
+
this._imageWarnHistory[msg] = true;
|
|
146
|
+
}
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
result[key] = color;
|
|
150
|
+
} catch (err) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
return undefined;
|
|
32
157
|
}
|
|
33
158
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
159
|
+
if (Object.keys(result).length === 0) {
|
|
160
|
+
return undefined;
|
|
161
|
+
}
|
|
37
162
|
|
|
38
|
-
return
|
|
163
|
+
return {params: result};
|
|
39
164
|
}
|
|
40
165
|
|
|
41
166
|
evaluate(ctx: EvaluationContext): null | ResolvedImage {
|
|
42
|
-
const value = ResolvedImage.
|
|
167
|
+
const value = ResolvedImage.build(
|
|
168
|
+
this.inputPrimary.evaluate(ctx),
|
|
169
|
+
this.inputSecondary ? this.inputSecondary.evaluate(ctx) : undefined,
|
|
170
|
+
this.inputPrimaryParams ? this.evaluateParams(ctx, this.inputPrimaryParams) : undefined,
|
|
171
|
+
this.inputSecondaryParams ? this.evaluateParams(ctx, this.inputSecondaryParams) : undefined
|
|
172
|
+
);
|
|
43
173
|
if (value && ctx.availableImages) {
|
|
44
174
|
value.available = ctx.availableImages.indexOf(value.namePrimary) > -1;
|
|
45
175
|
// If there's a secondary variant, only mark it available if both are present
|
|
@@ -53,8 +183,22 @@ export default class ImageExpression implements Expression {
|
|
|
53
183
|
|
|
54
184
|
eachChild(fn: (_: Expression) => void) {
|
|
55
185
|
fn(this.inputPrimary);
|
|
186
|
+
if (this.inputPrimaryParams) {
|
|
187
|
+
for (const key in this.inputPrimaryParams) {
|
|
188
|
+
if (this.inputPrimaryParams[key]) {
|
|
189
|
+
fn(this.inputPrimaryParams[key]);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
56
193
|
if (this.inputSecondary) {
|
|
57
194
|
fn(this.inputSecondary);
|
|
195
|
+
if (this.inputSecondaryParams) {
|
|
196
|
+
for (const key in this.inputSecondaryParams) {
|
|
197
|
+
if (this.inputSecondaryParams[key]) {
|
|
198
|
+
fn(this.inputSecondaryParams[key]);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
58
202
|
}
|
|
59
203
|
}
|
|
60
204
|
|
|
@@ -63,10 +207,36 @@ export default class ImageExpression implements Expression {
|
|
|
63
207
|
return false;
|
|
64
208
|
}
|
|
65
209
|
|
|
210
|
+
serializeParams(params: Record<string, Expression> | undefined): {params: Record<string, SerializedExpression>} {
|
|
211
|
+
const result: Record<string, SerializedExpression> = {};
|
|
212
|
+
if (params) {
|
|
213
|
+
for (const key in params) {
|
|
214
|
+
if (params[key]) {
|
|
215
|
+
result[key] = params[key].serialize();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
} else {
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return {params: result};
|
|
223
|
+
}
|
|
224
|
+
|
|
66
225
|
serialize(): SerializedExpression {
|
|
226
|
+
const serialized: SerializedExpression = ["image", this.inputPrimary.serialize()];
|
|
227
|
+
|
|
228
|
+
if (this.inputPrimaryParams) {
|
|
229
|
+
serialized.push(this.serializeParams(this.inputPrimaryParams));
|
|
230
|
+
}
|
|
231
|
+
|
|
67
232
|
if (this.inputSecondary) {
|
|
68
|
-
|
|
233
|
+
serialized.push(this.inputSecondary.serialize());
|
|
234
|
+
|
|
235
|
+
if (this.inputSecondaryParams) {
|
|
236
|
+
serialized.push(this.serializeParams(this.inputSecondaryParams));
|
|
237
|
+
}
|
|
69
238
|
}
|
|
70
|
-
|
|
239
|
+
|
|
240
|
+
return serialized;
|
|
71
241
|
}
|
|
72
242
|
}
|
|
@@ -182,6 +182,13 @@ CompoundExpression.register(expressions, {
|
|
|
182
182
|
return v.evaluate(ctx).toRenderColor(null).toArray();
|
|
183
183
|
}
|
|
184
184
|
],
|
|
185
|
+
'to-hsla': [
|
|
186
|
+
array(NumberType, 4),
|
|
187
|
+
[ColorType],
|
|
188
|
+
(ctx, [v]) => {
|
|
189
|
+
return v.evaluate(ctx).toRenderColor(null).toHslaArray();
|
|
190
|
+
}
|
|
191
|
+
],
|
|
185
192
|
'rgb': [
|
|
186
193
|
ColorType,
|
|
187
194
|
[NumberType, NumberType, NumberType],
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import UnitBezier from '@mapbox/unitbezier';
|
|
2
2
|
import * as interpolate from '../../util/interpolate';
|
|
3
|
-
import {toString, NumberType, ColorType} from '../types';
|
|
3
|
+
import {toString, NumberType, ColorType, ValueType} from '../types';
|
|
4
4
|
import {findStopLessThanOrEqualTo} from '../stops';
|
|
5
5
|
import {hcl, lab} from '../../util/color_spaces';
|
|
6
|
+
import Literal from './literal';
|
|
7
|
+
import RuntimeError from '../runtime_error';
|
|
6
8
|
|
|
7
9
|
import type Color from '../../util/color';
|
|
8
10
|
import type {Stops} from '../stops';
|
|
@@ -27,14 +29,16 @@ class Interpolate implements Expression {
|
|
|
27
29
|
operator: 'interpolate' | 'interpolate-hcl' | 'interpolate-lab';
|
|
28
30
|
interpolation: InterpolationType;
|
|
29
31
|
input: Expression;
|
|
32
|
+
dynamicStops: Expression | null;
|
|
30
33
|
labels: Array<number>;
|
|
31
34
|
outputs: Array<Expression>;
|
|
32
35
|
|
|
33
|
-
constructor(type: Type, operator: 'interpolate' | 'interpolate-hcl' | 'interpolate-lab', interpolation: InterpolationType, input: Expression, stops: Stops) {
|
|
36
|
+
constructor(type: Type, operator: 'interpolate' | 'interpolate-hcl' | 'interpolate-lab', interpolation: InterpolationType, input: Expression, dynamicStops: Expression | null, stops: Stops) {
|
|
34
37
|
this.type = type;
|
|
35
38
|
this.operator = operator;
|
|
36
39
|
this.interpolation = interpolation;
|
|
37
40
|
this.input = input;
|
|
41
|
+
this.dynamicStops = dynamicStops;
|
|
38
42
|
|
|
39
43
|
this.labels = [];
|
|
40
44
|
this.outputs = [];
|
|
@@ -101,12 +105,12 @@ class Interpolate implements Expression {
|
|
|
101
105
|
return context.error(`Unknown interpolation type ${String(interpolation[0])}`, 1, 0);
|
|
102
106
|
}
|
|
103
107
|
|
|
104
|
-
if (args.length - 1 <
|
|
108
|
+
if (args.length - 1 < 3) {
|
|
105
109
|
// @ts-expect-error - TS2322 - Type 'void' is not assignable to type 'Interpolate'.
|
|
106
|
-
return context.error(`Expected at least
|
|
110
|
+
return context.error(`Expected at least 3 arguments, but found only ${args.length - 1}.`);
|
|
107
111
|
}
|
|
108
112
|
|
|
109
|
-
if ((args.length - 1) % 2 !== 0) {
|
|
113
|
+
if (args.length - 1 > 3 && (args.length - 1) % 2 !== 0) {
|
|
110
114
|
// @ts-expect-error - TS2322 - Type 'void' is not assignable to type 'Interpolate'.
|
|
111
115
|
return context.error(`Expected an even number of arguments.`);
|
|
112
116
|
}
|
|
@@ -123,6 +127,15 @@ class Interpolate implements Expression {
|
|
|
123
127
|
outputType = context.expectedType;
|
|
124
128
|
}
|
|
125
129
|
|
|
130
|
+
// Exactly 3 arguments means that the steps are created by an expression
|
|
131
|
+
if (args.length - 1 === 3) {
|
|
132
|
+
const dynamicStops = context.parse(rest[0], 3, ValueType);
|
|
133
|
+
if (!dynamicStops) return null;
|
|
134
|
+
|
|
135
|
+
// @ts-expect-error - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'InterpolationType'.
|
|
136
|
+
return new Interpolate(outputType, (operator as any), interpolation, input, dynamicStops, stops);
|
|
137
|
+
}
|
|
138
|
+
|
|
126
139
|
for (let i = 0; i < rest.length; i += 2) {
|
|
127
140
|
const label = rest[i];
|
|
128
141
|
const value = rest[i + 1];
|
|
@@ -159,12 +172,36 @@ class Interpolate implements Expression {
|
|
|
159
172
|
}
|
|
160
173
|
|
|
161
174
|
// @ts-expect-error - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'InterpolationType'.
|
|
162
|
-
return new Interpolate(outputType, (operator as any), interpolation, input, stops);
|
|
175
|
+
return new Interpolate(outputType, (operator as any), interpolation, input, null, stops);
|
|
163
176
|
}
|
|
164
177
|
|
|
165
178
|
evaluate(ctx: EvaluationContext): Color {
|
|
166
|
-
|
|
167
|
-
|
|
179
|
+
let labels = this.labels;
|
|
180
|
+
let outputs = this.outputs;
|
|
181
|
+
|
|
182
|
+
if (this.dynamicStops) {
|
|
183
|
+
const dynamicStopsValue = (this.dynamicStops.evaluate(ctx) as [number]);
|
|
184
|
+
if (dynamicStopsValue.length % 2 !== 0) {
|
|
185
|
+
throw new RuntimeError('Expected an even number of arguments.');
|
|
186
|
+
}
|
|
187
|
+
labels = [];
|
|
188
|
+
outputs = [];
|
|
189
|
+
for (let i = 0; i < dynamicStopsValue.length; i += 2) {
|
|
190
|
+
const label = dynamicStopsValue[i];
|
|
191
|
+
const output = new Literal(NumberType, dynamicStopsValue[i + 1]);
|
|
192
|
+
if (typeof label !== 'number') {
|
|
193
|
+
throw new RuntimeError('Input/output pairs for "interpolate" expressions must be defined using literal numeric values (not computed expressions) for the input values.');
|
|
194
|
+
}
|
|
195
|
+
if (labels.length && labels[labels.length - 1] >= label) {
|
|
196
|
+
throw new RuntimeError('Input/output pairs for "interpolate" expressions must be arranged with input values in strictly ascending order.');
|
|
197
|
+
}
|
|
198
|
+
labels.push(label);
|
|
199
|
+
outputs.push(output);
|
|
200
|
+
}
|
|
201
|
+
if (labels.length === 0) {
|
|
202
|
+
throw new RuntimeError('Expected at least one input/output pair.');
|
|
203
|
+
}
|
|
204
|
+
}
|
|
168
205
|
|
|
169
206
|
if (labels.length === 1) {
|
|
170
207
|
return outputs[0].evaluate(ctx);
|
|
@@ -225,11 +262,15 @@ class Interpolate implements Expression {
|
|
|
225
262
|
|
|
226
263
|
const serialized = [this.operator, interpolation, this.input.serialize()];
|
|
227
264
|
|
|
228
|
-
|
|
229
|
-
serialized.push(
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
265
|
+
if (this.dynamicStops) {
|
|
266
|
+
serialized.push(this.dynamicStops.serialize());
|
|
267
|
+
} else {
|
|
268
|
+
for (let i = 0; i < this.labels.length; i++) {
|
|
269
|
+
serialized.push(
|
|
270
|
+
this.labels[i],
|
|
271
|
+
this.outputs[i].serialize()
|
|
272
|
+
);
|
|
273
|
+
}
|
|
233
274
|
}
|
|
234
275
|
return serialized;
|
|
235
276
|
}
|
package/expression/expression.ts
CHANGED
|
@@ -22,6 +22,7 @@ export type ExpressionParser = (args: ReadonlyArray<unknown>, context: ParsingCo
|
|
|
22
22
|
export type ExpressionRegistration = {
|
|
23
23
|
new(...args: any[]): Expression;
|
|
24
24
|
readonly parse: ExpressionParser;
|
|
25
|
+
_classRegistryKey?: string;
|
|
25
26
|
};
|
|
26
27
|
|
|
27
28
|
export type ExpressionRegistry = {
|
package/expression/index.ts
CHANGED
|
@@ -186,11 +186,13 @@ export class ZoomConstantExpression<Kind extends EvaluationKind> {
|
|
|
186
186
|
configDependencies: Set<string>;
|
|
187
187
|
_styleExpression: StyleExpression;
|
|
188
188
|
isLightConstant: boolean | null | undefined;
|
|
189
|
+
isLineProgressConstant: boolean | null | undefined;
|
|
189
190
|
|
|
190
|
-
constructor(kind: Kind, expression: StyleExpression, isLightConstant?: boolean | null) {
|
|
191
|
+
constructor(kind: Kind, expression: StyleExpression, isLightConstant?: boolean | null, isLineProgressConstant?: boolean | null) {
|
|
191
192
|
this.kind = kind;
|
|
192
193
|
this._styleExpression = expression;
|
|
193
194
|
this.isLightConstant = isLightConstant;
|
|
195
|
+
this.isLineProgressConstant = isLineProgressConstant;
|
|
194
196
|
this.isStateDependent = kind !== ('constant' as EvaluationKind) && !isConstant.isStateConstant(expression.expression);
|
|
195
197
|
this.configDependencies = isConstant.getConfigDependencies(expression.expression);
|
|
196
198
|
}
|
|
@@ -223,17 +225,19 @@ export class ZoomDependentExpression<Kind extends EvaluationKind> {
|
|
|
223
225
|
zoomStops: Array<number>;
|
|
224
226
|
isStateDependent: boolean;
|
|
225
227
|
isLightConstant: boolean | null | undefined;
|
|
228
|
+
isLineProgressConstant: boolean | null | undefined;
|
|
226
229
|
configDependencies: Set<string>;
|
|
227
230
|
|
|
228
231
|
_styleExpression: StyleExpression;
|
|
229
232
|
interpolationType: InterpolationType | null | undefined;
|
|
230
233
|
|
|
231
|
-
constructor(kind: Kind, expression: StyleExpression, zoomStops: Array<number>, interpolationType?: InterpolationType, isLightConstant?: boolean | null) {
|
|
234
|
+
constructor(kind: Kind, expression: StyleExpression, zoomStops: Array<number>, interpolationType?: InterpolationType, isLightConstant?: boolean | null, isLineProgressConstant?: boolean | null) {
|
|
232
235
|
this.kind = kind;
|
|
233
236
|
this.zoomStops = zoomStops;
|
|
234
237
|
this._styleExpression = expression;
|
|
235
238
|
this.isStateDependent = kind !== ('camera' as EvaluationKind) && !isConstant.isStateConstant(expression.expression);
|
|
236
239
|
this.isLightConstant = isLightConstant;
|
|
240
|
+
this.isLineProgressConstant = isLineProgressConstant;
|
|
237
241
|
this.configDependencies = isConstant.getConfigDependencies(expression.expression);
|
|
238
242
|
this.interpolationType = interpolationType;
|
|
239
243
|
}
|
|
@@ -285,6 +289,7 @@ export type SourceExpression = {
|
|
|
285
289
|
kind: 'source';
|
|
286
290
|
isStateDependent: boolean;
|
|
287
291
|
isLightConstant: boolean | null | undefined;
|
|
292
|
+
isLineProgressConstant: boolean | null | undefined;
|
|
288
293
|
configDependencies: Set<string>;
|
|
289
294
|
readonly evaluate: (
|
|
290
295
|
globals: GlobalProperties,
|
|
@@ -316,6 +321,7 @@ export interface CompositeExpression {
|
|
|
316
321
|
kind: 'composite';
|
|
317
322
|
isStateDependent: boolean;
|
|
318
323
|
isLightConstant: boolean | null | undefined;
|
|
324
|
+
isLineProgressConstant: boolean | null | undefined;
|
|
319
325
|
configDependencies: Set<string>;
|
|
320
326
|
readonly evaluate: (
|
|
321
327
|
globals: GlobalProperties,
|
|
@@ -381,18 +387,18 @@ export function createPropertyExpression(
|
|
|
381
387
|
if (!zoomCurve) {
|
|
382
388
|
return success((isFeatureConstant && isLineProgressConstant) ?
|
|
383
389
|
// @ts-expect-error - TS2339 - Property 'value' does not exist on type 'unknown'.
|
|
384
|
-
(new ZoomConstantExpression('constant', expression.value, isLightConstant) as ConstantExpression) :
|
|
390
|
+
(new ZoomConstantExpression('constant', expression.value, isLightConstant, isLineProgressConstant) as ConstantExpression) :
|
|
385
391
|
// @ts-expect-error - TS2339 - Property 'value' does not exist on type 'unknown'.
|
|
386
|
-
(new ZoomConstantExpression('source', expression.value, isLightConstant) as SourceExpression));
|
|
392
|
+
(new ZoomConstantExpression('source', expression.value, isLightConstant, isLineProgressConstant) as SourceExpression));
|
|
387
393
|
}
|
|
388
394
|
|
|
389
395
|
const interpolationType = zoomCurve instanceof Interpolate ? zoomCurve.interpolation : undefined;
|
|
390
396
|
|
|
391
397
|
return success((isFeatureConstant && isLineProgressConstant) ?
|
|
392
398
|
// @ts-expect-error - TS2339 - Property 'value' does not exist on type 'unknown'.
|
|
393
|
-
(new ZoomDependentExpression('camera', expression.value, zoomCurve.labels, interpolationType, isLightConstant) as CameraExpression) :
|
|
399
|
+
(new ZoomDependentExpression('camera', expression.value, zoomCurve.labels, interpolationType, isLightConstant, isLineProgressConstant) as CameraExpression) :
|
|
394
400
|
// @ts-expect-error - TS2339 - Property 'value' does not exist on type 'unknown'.
|
|
395
|
-
(new ZoomDependentExpression('composite', expression.value, zoomCurve.labels, interpolationType, isLightConstant) as CompositeExpression));
|
|
401
|
+
(new ZoomDependentExpression('composite', expression.value, zoomCurve.labels, interpolationType, isLightConstant, isLineProgressConstant) as CompositeExpression));
|
|
396
402
|
}
|
|
397
403
|
|
|
398
404
|
// serialization wrapper for old-style stop functions normalized to the
|
|
@@ -32,7 +32,7 @@ export default class Formatted {
|
|
|
32
32
|
isEmpty(): boolean {
|
|
33
33
|
if (this.sections.length === 0) return true;
|
|
34
34
|
return !this.sections.some(section => section.text.length !== 0 ||
|
|
35
|
-
(section.image && section.image.namePrimary
|
|
35
|
+
(section.image && section.image.namePrimary));
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
static factory(text: Formatted | string): Formatted {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type {RasterizationOptions} from "./resolved_image";
|
|
2
|
+
|
|
3
|
+
export class ImageIdWithOptions {
|
|
4
|
+
id: string;
|
|
5
|
+
options: RasterizationOptions;
|
|
6
|
+
|
|
7
|
+
constructor(id: string, options?: RasterizationOptions) {
|
|
8
|
+
this.id = id;
|
|
9
|
+
this.options = options || {params: {}};
|
|
10
|
+
|
|
11
|
+
if (!this.options.transform) {
|
|
12
|
+
this.options.transform = new DOMMatrix([1, 0, 0, 1, 0, 0]);
|
|
13
|
+
} else {
|
|
14
|
+
const {a, b, c, d, e, f} = this.options.transform;
|
|
15
|
+
this.options.transform = new DOMMatrix([a, b, c, d, e, f]);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static deserializeFromString(serialized: string): ImageIdWithOptions {
|
|
20
|
+
const deserializedObject = JSON.parse(serialized);
|
|
21
|
+
const options: RasterizationOptions = {params: deserializedObject.options.params};
|
|
22
|
+
|
|
23
|
+
const {a, b, c, d, e, f} = deserializedObject.options.transform;
|
|
24
|
+
|
|
25
|
+
options.transform = new DOMMatrix([a, b, c, d, e, f]);
|
|
26
|
+
|
|
27
|
+
return new ImageIdWithOptions(deserializedObject.id, deserializedObject.options);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
scaleSelf(factor: number): this {
|
|
31
|
+
this.options.transform = this.options.transform.scale(factor);
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
serialize(): string {
|
|
36
|
+
const serialisedObject: Record<string, any> = {
|
|
37
|
+
id: this.id,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
if (this.options) {
|
|
41
|
+
serialisedObject.options = this.options;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const {
|
|
45
|
+
a, b, c, d, e, f,
|
|
46
|
+
} = this.options.transform;
|
|
47
|
+
|
|
48
|
+
serialisedObject.options.transform = {
|
|
49
|
+
a, b, c, d, e, f,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return JSON.stringify(serialisedObject);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,12 +1,25 @@
|
|
|
1
|
+
import {ImageIdWithOptions} from "./image_id_with_options";
|
|
2
|
+
|
|
3
|
+
import type Color from "../../util/color";
|
|
4
|
+
|
|
5
|
+
export type RasterizationOptions = {
|
|
6
|
+
params: Record<string, Color>;
|
|
7
|
+
transform?: DOMMatrix;
|
|
8
|
+
}
|
|
9
|
+
|
|
1
10
|
export type ResolvedImageOptions = {
|
|
2
11
|
namePrimary: string;
|
|
12
|
+
optionsPrimary: RasterizationOptions | null | undefined;
|
|
3
13
|
nameSecondary: string | null | undefined;
|
|
14
|
+
optionsSecondary: RasterizationOptions | null | undefined;
|
|
4
15
|
available: boolean;
|
|
5
16
|
};
|
|
6
17
|
|
|
7
18
|
export default class ResolvedImage {
|
|
8
19
|
namePrimary: string;
|
|
20
|
+
optionsPrimary: RasterizationOptions | null | undefined;
|
|
9
21
|
nameSecondary: string | null | undefined;
|
|
22
|
+
optionsSecondary: RasterizationOptions | null | undefined;
|
|
10
23
|
available: boolean;
|
|
11
24
|
|
|
12
25
|
constructor(options: ResolvedImageOptions) {
|
|
@@ -14,25 +27,54 @@ export default class ResolvedImage {
|
|
|
14
27
|
if (options.nameSecondary) {
|
|
15
28
|
this.nameSecondary = options.nameSecondary;
|
|
16
29
|
}
|
|
30
|
+
if (options.optionsPrimary) {
|
|
31
|
+
this.optionsPrimary = options.optionsPrimary;
|
|
32
|
+
}
|
|
33
|
+
if (options.optionsSecondary) {
|
|
34
|
+
this.optionsSecondary = options.optionsSecondary;
|
|
35
|
+
}
|
|
17
36
|
this.available = options.available;
|
|
18
37
|
}
|
|
19
38
|
|
|
20
39
|
toString(): string {
|
|
21
|
-
if (this.nameSecondary) {
|
|
40
|
+
if (this.namePrimary && this.nameSecondary) {
|
|
22
41
|
return `[${this.namePrimary},${this.nameSecondary}]`;
|
|
23
42
|
}
|
|
43
|
+
|
|
24
44
|
return this.namePrimary;
|
|
25
45
|
}
|
|
26
46
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
47
|
+
getPrimary(): ImageIdWithOptions {
|
|
48
|
+
return new ImageIdWithOptions(this.namePrimary, {
|
|
49
|
+
params: this.optionsPrimary ? (this.optionsPrimary.params || {}) : {},
|
|
50
|
+
});
|
|
30
51
|
}
|
|
31
52
|
|
|
32
|
-
|
|
53
|
+
getSerializedPrimary(): string {
|
|
54
|
+
return this.getPrimary().serialize();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
getSecondary(): ImageIdWithOptions | null {
|
|
33
58
|
if (this.nameSecondary) {
|
|
34
|
-
return
|
|
59
|
+
return new ImageIdWithOptions(this.nameSecondary, {
|
|
60
|
+
params: this.optionsSecondary ? (this.optionsSecondary.params || {}) : {},
|
|
61
|
+
});
|
|
35
62
|
}
|
|
36
|
-
|
|
63
|
+
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static from(image: string | ResolvedImage): ResolvedImage {
|
|
68
|
+
return typeof image === 'string' ? ResolvedImage.build(image) : image;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
static build(
|
|
72
|
+
namePrimary: string,
|
|
73
|
+
nameSecondary?: string | null,
|
|
74
|
+
optionsPrimary?: RasterizationOptions | null,
|
|
75
|
+
optionsSecondary?: RasterizationOptions | null
|
|
76
|
+
): ResolvedImage | null {
|
|
77
|
+
if (!namePrimary) return null; // treat empty values as no image
|
|
78
|
+
return new ResolvedImage({namePrimary, nameSecondary, optionsPrimary, optionsSecondary, available: false});
|
|
37
79
|
}
|
|
38
80
|
}
|