@mapbox/mapbox-gl-style-spec 14.29.0 → 14.30.0-alpha.742b92e7a62

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mapbox/mapbox-gl-style-spec",
3
- "version": "14.29.0",
3
+ "version": "14.30.0-alpha.742b92e7a62",
4
4
  "description": "a specification for mapbox gl styles",
5
5
  "author": "Mapbox",
6
6
  "license": "SEE LICENSE IN LICENSE.txt",
package/reference/v8.json CHANGED
@@ -1647,6 +1647,14 @@
1647
1647
  }
1648
1648
  }
1649
1649
  },
1650
+ "placement-group": {
1651
+ "doc": "Marks a placement priority group relative to other layers, going from lower to higher priority. Symbols from groups with higher priorities will be placed first",
1652
+ "sdk-support": {
1653
+ "basic functionality": {}
1654
+ },
1655
+ "private": true,
1656
+ "experimental": true
1657
+ },
1650
1658
  "clip": {
1651
1659
  "doc": "Layer that removes 3D content from map.",
1652
1660
  "sdk-support": {
@@ -1667,7 +1675,7 @@
1667
1675
  },
1668
1676
  "source": {
1669
1677
  "type": "string",
1670
- "doc": "Name of a source description to be used for this layer. Required for all layer types except `background` and `slot`."
1678
+ "doc": "Name of a source description to be used for this layer. Required for all layer types except `background`, `slot`, and `placement-group`."
1671
1679
  },
1672
1680
  "source-layer": {
1673
1681
  "type": "string",
@@ -10316,6 +10324,56 @@
10316
10324
  ]
10317
10325
  },
10318
10326
  "property-type": "data-driven"
10327
+ },
10328
+ "placement-priority": {
10329
+ "type": "number",
10330
+ "doc": "In-group placement priority. Higher values are placed first within the symbol's placement group.",
10331
+ "default": 0,
10332
+ "minimum": 0,
10333
+ "transition": false,
10334
+ "appearance": true,
10335
+ "expression": {
10336
+ "interpolated": true,
10337
+ "parameters": [
10338
+ "zoom",
10339
+ "pitch",
10340
+ "feature",
10341
+ "feature-state",
10342
+ "measure-light",
10343
+ "distance-from-center"
10344
+ ]
10345
+ },
10346
+ "property-type": "data-driven",
10347
+ "sdk-support": {
10348
+ "basic functionality": {},
10349
+ "data-driven styling": {}
10350
+ },
10351
+ "private": true,
10352
+ "experimental": true
10353
+ },
10354
+ "placement-group": {
10355
+ "type": "string",
10356
+ "doc": "Assigns this symbol layer to the specified placement-group layer, placing its symbols as if they were drawn within that group. When unset, the layer's symbols use an implicitly created placement group located at the same position as the symbol layer.",
10357
+ "transition": false,
10358
+ "appearance": true,
10359
+ "expression": {
10360
+ "interpolated": false,
10361
+ "parameters": [
10362
+ "zoom",
10363
+ "pitch",
10364
+ "feature",
10365
+ "feature-state",
10366
+ "measure-light",
10367
+ "distance-from-center"
10368
+ ]
10369
+ },
10370
+ "property-type": "data-driven",
10371
+ "sdk-support": {
10372
+ "basic functionality": {},
10373
+ "data-driven styling": {}
10374
+ },
10375
+ "private": true,
10376
+ "experimental": true
10319
10377
  }
10320
10378
  },
10321
10379
  "paint_raster": {
@@ -10450,7 +10508,9 @@
10450
10508
  "experimental": true,
10451
10509
  "sdk-support": {
10452
10510
  "basic functionality": {
10453
- "js": "3.29.0"
10511
+ "js": "3.29.0",
10512
+ "android": "11.30.0",
10513
+ "ios": "11.30.0"
10454
10514
  }
10455
10515
  }
10456
10516
  },
package/types.ts CHANGED
@@ -904,7 +904,15 @@ export type SymbolLayerSpecification = {
904
904
  "icon-color-brightness-min"?: number | ExpressionSpecification,
905
905
  "icon-color-brightness-max"?: number | ExpressionSpecification,
906
906
  "symbol-z-offset"?: DataDrivenPropertyValueSpecification<number>,
907
- "symbol-z-offset-transition"?: TransitionSpecification
907
+ "symbol-z-offset-transition"?: TransitionSpecification,
908
+ /**
909
+ * @experimental This property is experimental and subject to change in future versions.
910
+ */
911
+ "placement-priority"?: DataDrivenPropertyValueSpecification<number>,
912
+ /**
913
+ * @experimental This property is experimental and subject to change in future versions.
914
+ */
915
+ "placement-group"?: DataDrivenPropertyValueSpecification<string>
908
916
  },
909
917
  "appearances"?: Array<AppearanceSpecification>
910
918
  };
@@ -1524,6 +1532,21 @@ export type SlotLayerSpecification = {
1524
1532
  "paint"?: never
1525
1533
  };
1526
1534
 
1535
+ export type PlacementGroupLayerSpecification = {
1536
+ "id": string,
1537
+ "type": "placement-group",
1538
+ "metadata"?: unknown,
1539
+ "source"?: never,
1540
+ "source-layer"?: never,
1541
+ "slot"?: string,
1542
+ "minzoom"?: never,
1543
+ "maxzoom"?: never,
1544
+ "filter"?: never,
1545
+ "appearances"?: Array<AppearanceSpecification>,
1546
+ "layout"?: never,
1547
+ "paint"?: never
1548
+ };
1549
+
1527
1550
  export type ClipLayerSpecification = {
1528
1551
  "id": string,
1529
1552
  "type": "clip",
@@ -1563,6 +1586,7 @@ export type LayerSpecification =
1563
1586
  | BackgroundLayerSpecification
1564
1587
  | SkyLayerSpecification
1565
1588
  | SlotLayerSpecification
1589
+ | PlacementGroupLayerSpecification
1566
1590
  | ClipLayerSpecification;
1567
1591
 
1568
1592
  export type LayoutSpecification = UnionToIntersection<NonNullable<LayerSpecification['layout']>>;
@@ -1668,6 +1692,11 @@ export type SkyLayer = SkyLayerSpecification;
1668
1692
  */
1669
1693
  export type SlotLayer = SlotLayerSpecification;
1670
1694
 
1695
+ /**
1696
+ * @deprecated Use `PlacementGroupLayerSpecification` instead.
1697
+ */
1698
+ export type PlacementGroupLayer = PlacementGroupLayerSpecification;
1699
+
1671
1700
  /**
1672
1701
  * @deprecated Use `ClipLayerSpecification` instead.
1673
1702
  */
@@ -25,19 +25,40 @@ function compareAreas(a: Ring, b: Ring): number {
25
25
  return (b.area!) - (a.area!);
26
26
  }
27
27
 
28
+ // Whether every point of the ring lies on a single line, i.e. the ring has no real area
29
+ // regardless of winding
30
+ function isCollinear(ring: Ring): boolean {
31
+ const len = ring.length;
32
+ if (len < 3) return true;
33
+
34
+ const p0 = ring[0]!;
35
+ let dx = 0, dy = 0, i = 1;
36
+ for (; i < len; i++) {
37
+ dx = ring[i]!.x - p0.x;
38
+ dy = ring[i]!.y - p0.y;
39
+ if (dx !== 0 || dy !== 0) break;
40
+ }
41
+ if (i === len) return true; // every point coincides with p0
42
+
43
+ for (; i < len; i++) {
44
+ const px = ring[i]!.x - p0.x;
45
+ const py = ring[i]!.y - p0.y;
46
+ if (dx * py - dy * px !== 0) return false;
47
+ }
48
+ return true;
49
+ }
50
+
28
51
  // classifies an array of rings into polygons with outer rings and holes
29
52
  export function classifyRings(rings: Array<Ring>, maxRings: number): Array<Array<Ring>> {
30
53
  const len = rings.length;
31
54
 
32
- if (len <= 1) return [rings];
33
-
34
55
  const polygons: Array<Array<Ring>> = [];
35
56
  let polygon: Array<Ring> | undefined,
36
57
  ccw: boolean | undefined;
37
58
 
38
59
  for (let i = 0; i < len; i++) {
39
60
  const area = calculateSignedArea(rings[i]!);
40
- if (area === 0) continue;
61
+ if (area === 0 && isCollinear(rings[i]!)) continue;
41
62
 
42
63
  (rings[i]!).area = Math.abs(area);
43
64
 
@@ -72,7 +72,7 @@ export default function validateLayer(options: LayerValidatorOptions): Validatio
72
72
  } else {
73
73
  type = unbundle(parent.type) as string;
74
74
  }
75
- } else if (!(type === 'background' || type === 'sky' || type === 'slot')) {
75
+ } else if (!(type === 'background' || type === 'sky' || type === 'slot' || type === 'placement-group')) {
76
76
  if (!layer.source) {
77
77
  errors.push(new ValidationError(key, layer, 'missing required property "source"'));
78
78
  } else if (!isString(layer.source)) {
@@ -79,7 +79,7 @@ export default function validateLights(options: LightsValidatorOptions): Validat
79
79
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
80
80
  if (useThemeMatch && lightPropertySpec[useThemeMatch[1]!]) {
81
81
  errors = errors.concat(validate({
82
- key,
82
+ key: propertyKey,
83
83
  value: properties[propertyKey],
84
84
  valueSpec: {type: 'string'},
85
85
  style,
@@ -88,8 +88,8 @@ export default function validateLights(options: LightsValidatorOptions): Validat
88
88
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
89
89
  } else if (transitionMatch && lightPropertySpec[transitionMatch[1]!] && lightPropertySpec[transitionMatch[1]!].transition) {
90
90
  errors = errors.concat(validate({
91
- key,
92
- value: light[key],
91
+ key: propertyKey,
92
+ value: properties[propertyKey],
93
93
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
94
94
  valueSpec: styleSpec.transition,
95
95
  style,
@@ -24,7 +24,8 @@ type MapboxStyleSpecification = StyleSpecification & {
24
24
  };
25
25
 
26
26
  const SUPPORTED_SPEC_VERSION = 8;
27
- const MAX_SOURCES_IN_STYLE = 15;
27
+ const MAX_SOURCES_IN_STYLE = 64;
28
+ const MAX_TILESETS_IN_SOURCE = 15;
28
29
 
29
30
  function isValid(value: string | null | undefined, regex: RegExp): boolean {
30
31
  if (!value || !isString(value)) return true;
@@ -78,11 +79,22 @@ function getSourceErrors(source: SourceSpecification, i: number): Array<Validati
78
79
  function getMaxSourcesErrors(sourcesCount: number): Array<ValidationError> {
79
80
  const errors: ValidationError[] = [];
80
81
  if (sourcesCount > MAX_SOURCES_IN_STYLE) {
81
- errors.push(new ValidationError('sources', null, `Styles must contain ${MAX_SOURCES_IN_STYLE} or fewer sources`));
82
+ errors.push(new ValidationError('sources', null, `Styles must contain ${MAX_SOURCES_IN_STYLE} or fewer tilesets`));
82
83
  }
83
84
  return errors;
84
85
  }
85
86
 
87
+ function getMaxTilesetsErrors(sources: SourcesSpecification): Array<ValidationError> {
88
+ const errors: ValidationError[] = [];
89
+ Object.keys(sources).forEach((s: string, i: number) => {
90
+ const source = sources[s]!;
91
+ if (getSourceCount(source) > MAX_TILESETS_IN_SOURCE) {
92
+ errors.push(new ValidationError(`sources[${i}].url`, (source as {url?: string}).url, `Sources must contain ${MAX_TILESETS_IN_SOURCE} or fewer tilesets`));
93
+ }
94
+ });
95
+ return errors;
96
+ }
97
+
86
98
  function getSourcesErrors(sources: SourcesSpecification): {
87
99
  errors: Array<ValidationError>;
88
100
  sourcesCount: number;
@@ -225,6 +237,7 @@ export default function validateMapboxApiSupported(style: MapboxStyleSpecificati
225
237
  const sourcesErrors = getSourcesErrors(s.sources);
226
238
  sourcesCount += sourcesErrors.sourcesCount;
227
239
  errors = errors.concat(sourcesErrors.errors);
240
+ errors = errors.concat(getMaxTilesetsErrors(s.sources));
228
241
  }
229
242
 
230
243
  if (s.imports) {