@mapbox/mapbox-gl-style-spec 14.2.0 → 14.3.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.
@@ -0,0 +1,142 @@
1
+ // @flow
2
+
3
+ import {
4
+ type Type,
5
+ ValueType
6
+ } from '../types.js';
7
+ import {Color, typeOf, toString as valueToString} from '../values.js';
8
+ import Formatted from '../types/formatted.js';
9
+ import ResolvedImage from '../types/resolved_image.js';
10
+ import Literal from './literal.js';
11
+
12
+ import type {Expression, SerializedExpression} from '../expression.js';
13
+ import type ParsingContext from '../parsing_context.js';
14
+ import type EvaluationContext from '../evaluation_context.js';
15
+
16
+ function coerceValue(type: string, value: any): any {
17
+ switch (type) {
18
+ case 'string': return valueToString(value);
19
+ case 'number': return +value;
20
+ case 'boolean': return !!value;
21
+ case 'color': return Color.parse(value);
22
+ case 'formatted': {
23
+ return Formatted.fromString(valueToString(value));
24
+ }
25
+ case 'resolvedImage': {
26
+ return ResolvedImage.fromString(valueToString(value));
27
+ }
28
+ }
29
+ return value;
30
+ }
31
+
32
+ function clampToAllowedNumber(value: number, min: number | void, max: number | void, step: number | void): number {
33
+ if (step !== undefined) {
34
+ value = step * Math.round(value / step);
35
+ }
36
+ if (min !== undefined && value < min) {
37
+ value = min;
38
+ }
39
+ if (max !== undefined && value > max) {
40
+ value = max;
41
+ }
42
+ return value;
43
+ }
44
+
45
+ class Config implements Expression {
46
+ type: Type;
47
+ key: string;
48
+ scope: ?string;
49
+
50
+ constructor(type: Type, key: string, scope?: string) {
51
+ this.type = type;
52
+ this.key = key;
53
+ this.scope = scope;
54
+ }
55
+
56
+ static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Config {
57
+ let type = context.expectedType;
58
+ if (type === null || type === undefined) {
59
+ type = ValueType;
60
+ }
61
+ if (args.length < 2 || args.length > 3) {
62
+ return context.error(`Invalid number of arguments for 'config' expression.`);
63
+ }
64
+
65
+ const configKey = context.parse(args[1], 1);
66
+ if (!(configKey instanceof Literal)) {
67
+ return context.error(`Key name of 'config' expression must be a string literal.`);
68
+ }
69
+
70
+ if (args.length >= 3) {
71
+ const configScope = context.parse(args[2], 2);
72
+ if (!(configScope instanceof Literal)) {
73
+ return context.error(`Scope of 'config' expression must be a string literal.`);
74
+ }
75
+ return new Config(type, valueToString(configKey.value), valueToString(configScope.value));
76
+ }
77
+
78
+ return new Config(type, valueToString(configKey.value));
79
+ }
80
+
81
+ evaluate(ctx: EvaluationContext): any {
82
+ const FQIDSeparator = '\u001F';
83
+ const configKey = [this.key, this.scope, ctx.scope].filter(Boolean).join(FQIDSeparator);
84
+
85
+ const config = ctx.getConfig(configKey);
86
+ if (!config) return null;
87
+
88
+ const {type, value, values, minValue, maxValue, stepValue} = config;
89
+
90
+ const defaultValue = config.default.evaluate(ctx);
91
+
92
+ let result = defaultValue;
93
+ if (value) {
94
+ // temporarily override scope to parent to evaluate config expressions passed from the parent
95
+ const originalScope = ctx.scope;
96
+ ctx.scope = (originalScope || '').split(FQIDSeparator).slice(1).join(FQIDSeparator);
97
+ result = value.evaluate(ctx);
98
+ ctx.scope = originalScope;
99
+ }
100
+ if (type) {
101
+ result = coerceValue(type, result);
102
+ }
103
+
104
+ if (result !== undefined && (minValue !== undefined || maxValue !== undefined || stepValue !== undefined)) {
105
+ if (typeof result === 'number') {
106
+ result = clampToAllowedNumber(result, minValue, maxValue, stepValue);
107
+ } else if (Array.isArray(result)) {
108
+ result = result.map((item) => typeof item === 'number' ? clampToAllowedNumber(item, minValue, maxValue, stepValue) : item);
109
+ }
110
+ }
111
+
112
+ if (value !== undefined && result !== undefined && values && !values.includes(result)) {
113
+ // The result is not among the allowed values. Instead, use the default value from the option.
114
+ result = defaultValue;
115
+ if (type) {
116
+ result = coerceValue(type, result);
117
+ }
118
+ }
119
+
120
+ if ((type && type !== this.type) || (result !== undefined && typeOf(result) !== this.type)) {
121
+ result = coerceValue(this.type.kind, result);
122
+ }
123
+
124
+ return result;
125
+ }
126
+
127
+ eachChild() { }
128
+
129
+ outputDefined(): boolean {
130
+ return false;
131
+ }
132
+
133
+ serialize(): SerializedExpression {
134
+ const res = ["config", this.key];
135
+ if (this.scope) {
136
+ res.concat(this.key);
137
+ }
138
+ return res;
139
+ }
140
+ }
141
+
142
+ export default Config;
@@ -45,6 +45,7 @@ import FormatExpression from './format.js';
45
45
  import ImageExpression from './image.js';
46
46
  import Length from './length.js';
47
47
  import Within from './within.js';
48
+ import Config from './config.js';
48
49
  import Distance from './distance.js';
49
50
  import {mulberry32} from '../../util/random.js';
50
51
 
@@ -110,7 +111,9 @@ const expressions: ExpressionRegistry = {
110
111
  // $FlowFixMe[method-unbinding]
111
112
  'within': Within,
112
113
  // $FlowFixMe[method-unbinding]
113
- 'distance': Distance
114
+ 'distance': Distance,
115
+ // $FlowFixMe[method-unbinding]
116
+ 'config': Config
114
117
  };
115
118
 
116
119
  function rgba(ctx: EvaluationContext, [r, g, b, a]: Array<Expression>) {
@@ -145,70 +148,6 @@ function get(key: string, obj: {[string]: any}) {
145
148
  return typeof v === 'undefined' ? null : v;
146
149
  }
147
150
 
148
- function coerceValue(type: 'string' | 'number' | 'boolean' | 'color', value: any): any {
149
- switch (type) {
150
- case 'string': return String(value);
151
- case 'number': return +value;
152
- case 'boolean': return !!value;
153
- case 'color': return Color.parse(value);
154
- }
155
- return value;
156
- }
157
-
158
- function clampToAllowedNumber(value: number, min: number | void, max: number | void, step: number | void): number {
159
- if (step !== undefined) {
160
- value = step * Math.round(value / step);
161
- }
162
- if (min !== undefined && value < min) {
163
- value = min;
164
- }
165
- if (max !== undefined && value > max) {
166
- value = max;
167
- }
168
- return value;
169
- }
170
-
171
- const FQIDSeparator = '\u001F';
172
-
173
- function getConfig(ctx: EvaluationContext, key: string, scope: ?string) {
174
- // Create a fully qualified key from the requested scope
175
- // and the scope from the current evaluation context
176
- key = [key, scope, ctx.scope].filter(Boolean).join(FQIDSeparator);
177
-
178
- const config = ctx.getConfig(key);
179
- if (!config) return null;
180
-
181
- const {type, value, values, minValue, maxValue, stepValue} = config;
182
-
183
- const defaultValue = config.default.evaluate(ctx);
184
-
185
- let result = defaultValue;
186
- if (value) {
187
- // temporarily override scope to parent to evaluate config expressions passed from the parent
188
- const originalScope = ctx.scope;
189
- ctx.scope = (originalScope || '').split(FQIDSeparator).slice(1).join(FQIDSeparator);
190
- result = value.evaluate(ctx);
191
- ctx.scope = originalScope;
192
- }
193
-
194
- if (type) result = coerceValue(type, result);
195
-
196
- if (value !== undefined && result !== undefined && values && !values.includes(result)) {
197
- result = defaultValue;
198
- if (type) result = coerceValue(type, result);
199
- }
200
-
201
- if (result !== undefined && (minValue !== undefined || maxValue !== undefined || stepValue !== undefined)) {
202
- if (typeof result === 'number') {
203
- result = clampToAllowedNumber(result, minValue, maxValue, stepValue);
204
- } else if (Array.isArray(result)) {
205
- result = result.map((item) => typeof item === 'number' ? clampToAllowedNumber(item, minValue, maxValue, stepValue) : item);
206
- }
207
- }
208
-
209
- return result;
210
- }
211
-
212
151
  function binarySearch(v: any, a: {[number]: any}, i: number, j: number) {
213
152
  while (i <= j) {
214
153
  const m = (i + j) >> 1;
@@ -301,18 +240,6 @@ CompoundExpression.register(expressions, {
301
240
  ]
302
241
  ]
303
242
  },
304
- 'config': {
305
- type: ValueType,
306
- overloads: [
307
- [
308
- [StringType],
309
- (ctx, [key]) => getConfig(ctx, key.evaluate(ctx))
310
- ], [
311
- [StringType, StringType],
312
- (ctx, [key, scope]) => getConfig(ctx, key.evaluate(ctx), scope.evaluate(ctx))
313
- ]
314
- ]
315
- },
316
243
  'feature-state': [
317
244
  ValueType,
318
245
  [StringType],
@@ -368,6 +295,11 @@ CompoundExpression.register(expressions, {
368
295
  [],
369
296
  (ctx) => ctx.globals.rasterValue || 0
370
297
  ],
298
+ 'raster-particle-speed': [
299
+ NumberType,
300
+ [],
301
+ (ctx) => ctx.globals.rasterParticleSpeed || 0
302
+ ],
371
303
  'sky-radial-progress': [
372
304
  NumberType,
373
305
  [],
@@ -51,6 +51,7 @@ export interface GlobalProperties {
51
51
  heatmapDensity?: number,
52
52
  lineProgress?: number,
53
53
  rasterValue?: number,
54
+ rasterParticleSpeed?: number,
54
55
  skyRadialProgress?: number,
55
56
  +isSupportedScript?: (_: string) => boolean,
56
57
  accumulated?: Value,
@@ -3,6 +3,7 @@
3
3
  import CompoundExpression from './compound_expression.js';
4
4
  import Within from './definitions/within.js';
5
5
  import Distance from './definitions/distance.js';
6
+ import Config from './definitions/config.js';
6
7
  import type {Expression} from './expression.js';
7
8
 
8
9
  function isFeatureConstant(e: Expression): boolean {
@@ -53,11 +54,10 @@ function isStateConstant(e: Expression): boolean {
53
54
  }
54
55
 
55
56
  function isConfigConstant(e: Expression): boolean {
56
- if (e instanceof CompoundExpression) {
57
- if (e.name === 'config') {
58
- return false;
59
- }
57
+ if (e instanceof Config) {
58
+ return false;
60
59
  }
60
+
61
61
  let result = true;
62
62
  e.eachChild(arg => {
63
63
  if (result && !isConfigConstant(arg)) { result = false; }
@@ -11,6 +11,7 @@ import CompoundExpression from './compound_expression.js';
11
11
  import CollatorExpression from './definitions/collator.js';
12
12
  import Within from './definitions/within.js';
13
13
  import Distance from './definitions/distance.js';
14
+ import Config from './definitions/config.js';
14
15
  import {isGlobalPropertyConstant, isFeatureConstant} from './is_constant.js';
15
16
  import Var from './definitions/var.js';
16
17
 
@@ -202,17 +203,17 @@ function isConstant(expression: Expression) {
202
203
  return isConstant(expression.boundExpression);
203
204
  } else if (expression instanceof CompoundExpression && expression.name === 'error') {
204
205
  return false;
205
- } else if (expression instanceof CompoundExpression && expression.name === 'config') {
206
- return false;
207
206
  } else if (expression instanceof CollatorExpression) {
208
207
  // Although the results of a Collator expression with fixed arguments
209
208
  // generally shouldn't change between executions, we can't serialize them
210
209
  // as constant expressions because results change based on environment.
211
210
  return false;
212
- } else if (expression instanceof Within) {
211
+ } else if (expression instanceof Within) {
213
212
  return false;
214
213
  } else if (expression instanceof Distance) {
215
214
  return false;
215
+ } else if (expression instanceof Config) {
216
+ return false;
216
217
  }
217
218
 
218
219
  const isTypeAnnotation = expression instanceof Coercion ||
@@ -238,5 +239,5 @@ function isConstant(expression: Expression) {
238
239
  }
239
240
 
240
241
  return isFeatureConstant(expression) &&
241
- isGlobalPropertyConstant(expression, ['zoom', 'heatmap-density', 'line-progress', 'raster-value', 'sky-radial-progress', 'accumulated', 'is-supported-script', 'pitch', 'distance-from-center', 'measure-light']);
242
+ isGlobalPropertyConstant(expression, ['zoom', 'heatmap-density', 'line-progress', 'raster-value', 'sky-radial-progress', 'accumulated', 'is-supported-script', 'pitch', 'distance-from-center', 'measure-light', 'raster-particle-speed']);
242
243
  }
@@ -24,6 +24,8 @@ declare class WebGL2RenderingContext extends WebGLRenderingContext {
24
24
  QUERY_RESULT: 0x8866;
25
25
  MIN: 0x8007;
26
26
  MAX: 0x8008;
27
+ INTERLEAVED_ATTRIBS: 0x8C8C;
28
+ SEPARATE_ATTRIBS: 0x8C8D;
27
29
 
28
30
  createVertexArray: () => WebGLVertexArrayObject | null;
29
31
  deleteVertexArray: (vertexArray: WebGLVertexArrayObject | null) => void;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mapbox/mapbox-gl-style-spec",
3
3
  "description": "a specification for mapbox gl styles",
4
- "version": "14.2.0",
4
+ "version": "14.3.0",
5
5
  "author": "Mapbox",
6
6
  "keywords": [
7
7
  "mapbox",
package/reference/v8.json CHANGED
@@ -912,6 +912,17 @@
912
912
  "type": "*",
913
913
  "doc": "Contains the description of the raster data layers and the bands contained within the tiles."
914
914
  },
915
+ "volatile": {
916
+ "type": "boolean",
917
+ "default": false,
918
+ "doc": "A setting to determine whether a source's tiles are cached locally.",
919
+ "sdk-support": {
920
+ "basic functionality": {
921
+ "android": "9.3.0",
922
+ "ios": "5.10.0"
923
+ }
924
+ }
925
+ },
915
926
  "*": {
916
927
  "type": "*",
917
928
  "doc": "Other keys to configure the data source."
@@ -1163,6 +1174,17 @@
1163
1174
  }
1164
1175
  }
1165
1176
  },
1177
+ "raster-particle": {
1178
+ "doc": "Particle animation driven by textures such as wind maps.",
1179
+ "sdk-support": {
1180
+ "basic functionality": {
1181
+ "js": "0.10.0",
1182
+ "android": "2.0.1",
1183
+ "ios": "2.0.0",
1184
+ "macos": "0.1.0"
1185
+ }
1186
+ }
1187
+ },
1166
1188
  "hillshade": {
1167
1189
  "doc": "Client-side hillshading visualization based on DEM data. Currently, the implementation only supports Mapbox Terrain RGB and Mapzen Terrarium tiles.",
1168
1190
  "sdk-support": {
@@ -1273,6 +1295,7 @@
1273
1295
  "layout_fill-extrusion",
1274
1296
  "layout_symbol",
1275
1297
  "layout_raster",
1298
+ "layout_raster-particle",
1276
1299
  "layout_hillshade",
1277
1300
  "layout_background",
1278
1301
  "layout_sky",
@@ -3191,6 +3214,37 @@
3191
3214
  "property-type": "constant"
3192
3215
  }
3193
3216
  },
3217
+ "layout_raster-particle": {
3218
+ "visibility": {
3219
+ "type": "enum",
3220
+ "values": {
3221
+ "visible": {
3222
+ "doc": "The layer is shown."
3223
+ },
3224
+ "none": {
3225
+ "doc": "The layer is not shown."
3226
+ }
3227
+ },
3228
+ "default": "visible",
3229
+ "doc": "Whether this layer is displayed.",
3230
+ "sdk-support": {
3231
+ "basic functionality": {
3232
+ "js": "0.10.0",
3233
+ "android": "2.0.1",
3234
+ "ios": "2.0.0"
3235
+ },
3236
+ "expressions support": {
3237
+ "js": "3.0.0",
3238
+ "android": "11.0.0",
3239
+ "ios": "11.0.0"
3240
+ }
3241
+ },
3242
+ "expression": {
3243
+ "interpolated": false
3244
+ },
3245
+ "property-type": "constant"
3246
+ }
3247
+ },
3194
3248
  "layout_hillshade": {
3195
3249
  "visibility": {
3196
3250
  "type": "enum",
@@ -3739,7 +3793,7 @@
3739
3793
  }
3740
3794
  },
3741
3795
  "image": {
3742
- "doc": "Returns a [`ResolvedImage`](/mapbox-gl-js/style-spec/types/#resolvedimage) for use in [`icon-image`](/mapbox-gl-js/style-spec/layers/#layout-symbol-icon-image), `*-pattern` entries, and as a section in the [`'format'`](#types-format) expression. A [`'coalesce'`](#coalesce) expression containing `image` expressions will evaluate to the first listed image that is currently in the style. This validation process is synchronous and requires the image to have been added to the style before requesting it in the `'image'` argument.",
3796
+ "doc": "Returns a [`ResolvedImage`](/mapbox-gl-js/style-spec/types/#resolvedimage) for use in [`icon-image`](/mapbox-gl-js/style-spec/layers/#layout-symbol-icon-image), `*-pattern` entries, and as a section in the [`'format'`](#types-format) expression. A [`'coalesce'`](#coalesce) expression containing `image` expressions will evaluate to the first listed image that is currently in the style. This validation process is synchronous and requires the image to have been added to the style before requesting it in the `'image'` argument. To implement crossfading between two images within a symbol layer using the [`icon-image-cross-fade`](/mapbox-gl-js/style-spec/layers/#paint-symbol-icon-image-cross-fade) attribute, include a second image as the second argument in the `'image'` expression.",
3743
3797
  "group": "Types",
3744
3798
  "sdk-support": {
3745
3799
  "basic functionality": {
@@ -4483,6 +4537,17 @@
4483
4537
  }
4484
4538
  }
4485
4539
  },
4540
+ "raster-particle-speed": {
4541
+ "doc": "Returns the length of the particle velocity vector. Can only be used in the `raster-particle-color` property.",
4542
+ "group": "Raster Particle Animation",
4543
+ "sdk-support": {
4544
+ "basic functionality": {
4545
+ "js": "3.3.0",
4546
+ "android": "",
4547
+ "ios": ""
4548
+ }
4549
+ }
4550
+ },
4486
4551
  "random": {
4487
4552
  "doc": "Returns a random value in the specified range (first two input numbers) based on a supplied seed (third input). The seed can be an expression or a constant number or string value.",
4488
4553
  "group": "Math",
@@ -7022,6 +7087,9 @@
7022
7087
  "measure-light"
7023
7088
  ]
7024
7089
  },
7090
+ "requires": [
7091
+ "icon-image"
7092
+ ],
7025
7093
  "sdk-support": {
7026
7094
  "basic functionality": {
7027
7095
  "js": "3.0.0",
@@ -7361,10 +7429,6 @@
7361
7429
  },
7362
7430
  "raster-color-range": {
7363
7431
  "type": "array",
7364
- "default": [
7365
- 0,
7366
- 1
7367
- ],
7368
7432
  "length": 2,
7369
7433
  "value": "number",
7370
7434
  "property-type": "data-constant",
@@ -7378,7 +7442,7 @@
7378
7442
  "zoom"
7379
7443
  ]
7380
7444
  },
7381
- "doc": "When `raster-color` is active, specifies the range over which `raster-color` is tabulated. Units correspond to the computed raster value via `raster-color-mix`.",
7445
+ "doc": "When `raster-color` is active, specifies the range over which `raster-color` is tabulated. Units correspond to the computed raster value via `raster-color-mix`. For `rasterarray` sources, if `raster-color-range` is unspecified, the source's stated data range is used.",
7382
7446
  "example": [
7383
7447
  0.5,
7384
7448
  10
@@ -7575,7 +7639,7 @@
7575
7639
  ]
7576
7640
  },
7577
7641
  "property-type": "data-constant"
7578
- },
7642
+ },
7579
7643
  "raster-array-band": {
7580
7644
  "type": "string",
7581
7645
  "required": false,
@@ -7598,7 +7662,7 @@
7598
7662
  },
7599
7663
  "raster-elevation": {
7600
7664
  "type": "number",
7601
- "doc": "Specifies an uniform elevation from the ground, in meters. Only supported with image sources.",
7665
+ "doc": "Specifies an uniform elevation from the ground, in meters.",
7602
7666
  "default": 0,
7603
7667
  "minimum": 0,
7604
7668
  "transition": true,
@@ -7618,6 +7682,133 @@
7618
7682
  "property-type": "data-constant"
7619
7683
  }
7620
7684
  },
7685
+ "paint_raster-particle": {
7686
+ "raster-particle-array-band": {
7687
+ "type": "string",
7688
+ "required": false,
7689
+ "property-type": "data-constant",
7690
+ "transition": false,
7691
+ "doc": "Displayed band of raster array source layer",
7692
+ "example": "band-name",
7693
+ "sdk-support": {
7694
+ "basic functionality": {
7695
+ "js": "",
7696
+ "android": "",
7697
+ "ios": ""
7698
+ }
7699
+ }
7700
+ },
7701
+ "raster-particle-count": {
7702
+ "type": "number",
7703
+ "doc": "Defines the amount of particles per tile.",
7704
+ "default": 512,
7705
+ "minimum": 1,
7706
+ "transition": false,
7707
+ "sdk-support": {
7708
+ "basic functionality": {
7709
+ "js": "",
7710
+ "android": "",
7711
+ "ios": ""
7712
+ }
7713
+ },
7714
+ "property-type": "data-constant"
7715
+ },
7716
+ "raster-particle-color": {
7717
+ "type": "color",
7718
+ "doc": "Defines a color map by which to colorize a raster particle layer, parameterized by the `[\"raster-particle-speed\"]` expression and evaluated at 256 uniformly spaced steps over the range specified by `raster-particle-max-speed`.",
7719
+ "transition": false,
7720
+ "sdk-support": {
7721
+ "basic functionality": {
7722
+ "js": "",
7723
+ "android": "",
7724
+ "ios": ""
7725
+ },
7726
+ "data-driven styling": {}
7727
+ },
7728
+ "expression": {
7729
+ "interpolated": true,
7730
+ "parameters": [
7731
+ "raster-particle-speed"
7732
+ ]
7733
+ },
7734
+ "property-type": "color-ramp"
7735
+ },
7736
+ "raster-particle-max-speed": {
7737
+ "type": "number",
7738
+ "doc": "Defines the maximum speed for particles. Velocities with magnitudes equal to or exceeding this value are clamped to the max value.",
7739
+ "default": 1,
7740
+ "minimum": 1,
7741
+ "transition": false,
7742
+ "sdk-support": {
7743
+ "basic functionality": {
7744
+ "js": "",
7745
+ "android": "",
7746
+ "ios": ""
7747
+ }
7748
+ },
7749
+ "property-type": "data-constant"
7750
+ },
7751
+ "raster-particle-speed-factor": {
7752
+ "type": "number",
7753
+ "doc": "Defines a coefficient for the speed of particles’ motion.",
7754
+ "default": 0.2,
7755
+ "minimum": 0,
7756
+ "maximum": 1,
7757
+ "transition": true,
7758
+ "sdk-support": {
7759
+ "basic functionality": {
7760
+ "js": "",
7761
+ "android": "",
7762
+ "ios": ""
7763
+ }
7764
+ },
7765
+ "expression": {
7766
+ "interpolated": true,
7767
+ "parameters": [
7768
+ "zoom"
7769
+ ]
7770
+ },
7771
+ "property-type": "data-constant"
7772
+ },
7773
+ "raster-particle-fade-opacity-factor": {
7774
+ "type": "number",
7775
+ "doc": "Defines defines the opacity coefficient applied to the faded particles in each frame. In practice, this property controls the length of the particle tail.",
7776
+ "default": 0.98,
7777
+ "minimum": 0,
7778
+ "maximum": 1,
7779
+ "transition": true,
7780
+ "sdk-support": {
7781
+ "basic functionality": {
7782
+ "js": "",
7783
+ "android": "",
7784
+ "ios": ""
7785
+ }
7786
+ },
7787
+ "expression": {
7788
+ "interpolated": true,
7789
+ "parameters": [
7790
+ "zoom"
7791
+ ]
7792
+ },
7793
+ "property-type": "data-constant"
7794
+ },
7795
+ "raster-particle-reset-rate-factor": {
7796
+ "type": "number",
7797
+ "doc": "Defines a coefficient for a time period at which particles will restart at a random position, to avoid degeneration (empty areas without particles).",
7798
+ "default": 0.8,
7799
+ "minimum": 0,
7800
+ "maximum": 1,
7801
+ "transition": false,
7802
+ "sdk-support": {
7803
+ "basic functionality": {
7804
+ "js": "",
7805
+ "android": "",
7806
+ "ios": ""
7807
+ }
7808
+ },
7809
+ "property-type": "data-constant"
7810
+ }
7811
+ },
7621
7812
  "paint_hillshade": {
7622
7813
  "hillshade-illumination-direction": {
7623
7814
  "type": "number",
package/style-spec.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // @flow
2
2
 
3
3
  type ExpressionType = 'data-driven' | 'color-ramp' | 'data-constant' | 'constant';
4
- type ExpressionParameters = Array<'zoom' | 'feature' | 'feature-state' | 'heatmap-density' | 'line-progress' | 'raster-value' | 'sky-radial-progress' | 'pitch' | 'distance-from-center' | 'measure-light'>;
4
+ type ExpressionParameters = Array<'zoom' | 'feature' | 'feature-state' | 'heatmap-density' | 'line-progress' | 'raster-value' | 'sky-radial-progress' | 'pitch' | 'distance-from-center' | 'measure-light' | 'raster-particle-speed'>;
5
5
 
6
6
  export type ExpressionSpecification = {
7
7
  interpolated: boolean,