maplibre-gl 3.2.2 → 3.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.
Files changed (30) hide show
  1. package/build/generate-struct-arrays.ts +3 -1
  2. package/build/generate-style-code.ts +7 -8
  3. package/dist/maplibre-gl-csp-worker.js +1 -1
  4. package/dist/maplibre-gl-csp-worker.js.map +1 -1
  5. package/dist/maplibre-gl-csp.js +1 -1
  6. package/dist/maplibre-gl-csp.js.map +1 -1
  7. package/dist/maplibre-gl-dev.js +424 -168
  8. package/dist/maplibre-gl-dev.js.map +1 -1
  9. package/dist/maplibre-gl.d.ts +44 -7
  10. package/dist/maplibre-gl.js +3 -3
  11. package/dist/maplibre-gl.js.map +1 -1
  12. package/package.json +10 -10
  13. package/src/data/array_types.g.ts +78 -14
  14. package/src/data/bucket/symbol_attributes.ts +7 -1
  15. package/src/data/bucket/symbol_bucket.ts +4 -1
  16. package/src/render/draw_symbol.ts +8 -9
  17. package/src/style/properties.ts +4 -0
  18. package/src/style/style_layer/background_style_layer_properties.g.ts +1 -6
  19. package/src/style/style_layer/circle_style_layer_properties.g.ts +1 -6
  20. package/src/style/style_layer/fill_extrusion_style_layer_properties.g.ts +1 -6
  21. package/src/style/style_layer/fill_style_layer_properties.g.ts +1 -6
  22. package/src/style/style_layer/heatmap_style_layer_properties.g.ts +1 -6
  23. package/src/style/style_layer/hillshade_style_layer_properties.g.ts +1 -6
  24. package/src/style/style_layer/line_style_layer_properties.g.ts +1 -6
  25. package/src/style/style_layer/raster_style_layer_properties.g.ts +1 -6
  26. package/src/style/style_layer/symbol_style_layer_properties.g.ts +4 -6
  27. package/src/style/style_layer/variable_text_anchor.test.ts +117 -0
  28. package/src/style/style_layer/variable_text_anchor.ts +163 -0
  29. package/src/symbol/placement.ts +52 -40
  30. package/src/symbol/symbol_layout.ts +42 -116
@@ -1,4 +1,4 @@
1
- /* MapLibre GL JS is licensed under the 3-Clause BSD License. Full text of license: https://github.com/maplibre/maplibre-gl-js/blob/v3.2.2/LICENSE.txt */
1
+ /* MapLibre GL JS is licensed under the 3-Clause BSD License. Full text of license: https://github.com/maplibre/maplibre-gl-js/blob/v3.3.0/LICENSE.txt */
2
2
  (function (global, factory) {
3
3
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
4
4
  typeof define === 'function' && define.amd ? define(factory) :
@@ -2549,6 +2549,25 @@ var layout_symbol = {
2549
2549
  },
2550
2550
  "property-type": "data-constant"
2551
2551
  },
2552
+ "text-variable-anchor-offset": {
2553
+ type: "variableAnchorOffsetCollection",
2554
+ requires: [
2555
+ "text-field",
2556
+ {
2557
+ "symbol-placement": [
2558
+ "point"
2559
+ ]
2560
+ }
2561
+ ],
2562
+ expression: {
2563
+ interpolated: true,
2564
+ parameters: [
2565
+ "zoom",
2566
+ "feature"
2567
+ ]
2568
+ },
2569
+ "property-type": "data-driven"
2570
+ },
2552
2571
  "text-anchor": {
2553
2572
  type: "enum",
2554
2573
  values: {
@@ -4868,6 +4887,7 @@ const CollatorType = { kind: 'collator' };
4868
4887
  const FormattedType = { kind: 'formatted' };
4869
4888
  const PaddingType = { kind: 'padding' };
4870
4889
  const ResolvedImageType = { kind: 'resolvedImage' };
4890
+ const VariableAnchorOffsetCollectionType = { kind: 'variableAnchorOffsetCollection' };
4871
4891
  function array$1(itemType, N) {
4872
4892
  return {
4873
4893
  kind: 'array',
@@ -4896,7 +4916,8 @@ const valueMemberTypes = [
4896
4916
  ObjectType,
4897
4917
  array$1(ValueType),
4898
4918
  PaddingType,
4899
- ResolvedImageType
4919
+ ResolvedImageType,
4920
+ VariableAnchorOffsetCollectionType
4900
4921
  ];
4901
4922
  /**
4902
4923
  * Returns null if `t` is a subtype of `expected`; otherwise returns an
@@ -5592,6 +5613,44 @@ class Padding {
5592
5613
  }
5593
5614
  }
5594
5615
 
5616
+ /** Set of valid anchor positions, as a set for validation */
5617
+ const anchors = new Set(['center', 'left', 'right', 'top', 'bottom', 'top-left', 'top-right', 'bottom-left', 'bottom-right']);
5618
+ /**
5619
+ * Utility class to assist managing values for text-variable-anchor-offset property. Create instances from
5620
+ * bare arrays using the static method `VariableAnchorOffsetCollection.parse`.
5621
+ * @private
5622
+ */
5623
+ class VariableAnchorOffsetCollection {
5624
+ constructor(values) {
5625
+ this.values = values.slice();
5626
+ }
5627
+ static parse(input) {
5628
+ if (input instanceof VariableAnchorOffsetCollection) {
5629
+ return input;
5630
+ }
5631
+ if (!Array.isArray(input) ||
5632
+ input.length < 1 ||
5633
+ input.length % 2 !== 0) {
5634
+ return undefined;
5635
+ }
5636
+ for (let i = 0; i < input.length; i += 2) {
5637
+ // Elements in even positions should be anchor positions; Elements in odd positions should be offset values
5638
+ const anchorValue = input[i];
5639
+ const offsetValue = input[i + 1];
5640
+ if (typeof anchorValue !== 'string' || !anchors.has(anchorValue)) {
5641
+ return undefined;
5642
+ }
5643
+ if (!Array.isArray(offsetValue) || offsetValue.length !== 2 || typeof offsetValue[0] !== 'number' || typeof offsetValue[1] !== 'number') {
5644
+ return undefined;
5645
+ }
5646
+ }
5647
+ return new VariableAnchorOffsetCollection(input);
5648
+ }
5649
+ toString() {
5650
+ return JSON.stringify(this.values);
5651
+ }
5652
+ }
5653
+
5595
5654
  class ResolvedImage {
5596
5655
  constructor(options) {
5597
5656
  this.name = options.name;
@@ -5620,31 +5679,16 @@ function validateRGBA(r, g, b, a) {
5620
5679
  return null;
5621
5680
  }
5622
5681
  function isValue(mixed) {
5623
- if (mixed === null) {
5624
- return true;
5625
- }
5626
- else if (typeof mixed === 'string') {
5627
- return true;
5628
- }
5629
- else if (typeof mixed === 'boolean') {
5630
- return true;
5631
- }
5632
- else if (typeof mixed === 'number') {
5633
- return true;
5634
- }
5635
- else if (mixed instanceof Color) {
5636
- return true;
5637
- }
5638
- else if (mixed instanceof Collator) {
5639
- return true;
5640
- }
5641
- else if (mixed instanceof Formatted) {
5642
- return true;
5643
- }
5644
- else if (mixed instanceof Padding) {
5645
- return true;
5646
- }
5647
- else if (mixed instanceof ResolvedImage) {
5682
+ if (mixed === null ||
5683
+ typeof mixed === 'string' ||
5684
+ typeof mixed === 'boolean' ||
5685
+ typeof mixed === 'number' ||
5686
+ mixed instanceof Color ||
5687
+ mixed instanceof Collator ||
5688
+ mixed instanceof Formatted ||
5689
+ mixed instanceof Padding ||
5690
+ mixed instanceof VariableAnchorOffsetCollection ||
5691
+ mixed instanceof ResolvedImage) {
5648
5692
  return true;
5649
5693
  }
5650
5694
  else if (Array.isArray(mixed)) {
@@ -5692,6 +5736,9 @@ function typeOf(value) {
5692
5736
  else if (value instanceof Padding) {
5693
5737
  return PaddingType;
5694
5738
  }
5739
+ else if (value instanceof VariableAnchorOffsetCollection) {
5740
+ return VariableAnchorOffsetCollectionType;
5741
+ }
5695
5742
  else if (value instanceof ResolvedImage) {
5696
5743
  return ResolvedImageType;
5697
5744
  }
@@ -5725,7 +5772,7 @@ function toString(value) {
5725
5772
  else if (type === 'string' || type === 'number' || type === 'boolean') {
5726
5773
  return String(value);
5727
5774
  }
5728
- else if (value instanceof Color || value instanceof Formatted || value instanceof Padding || value instanceof ResolvedImage) {
5775
+ else if (value instanceof Color || value instanceof Formatted || value instanceof Padding || value instanceof VariableAnchorOffsetCollection || value instanceof ResolvedImage) {
5729
5776
  return value.toString();
5730
5777
  }
5731
5778
  else {
@@ -5889,71 +5936,80 @@ class Coercion {
5889
5936
  return new Coercion(type, parsed);
5890
5937
  }
5891
5938
  evaluate(ctx) {
5892
- if (this.type.kind === 'boolean') {
5893
- return Boolean(this.args[0].evaluate(ctx));
5894
- }
5895
- else if (this.type.kind === 'color') {
5896
- let input;
5897
- let error;
5898
- for (const arg of this.args) {
5899
- input = arg.evaluate(ctx);
5900
- error = null;
5901
- if (input instanceof Color) {
5902
- return input;
5903
- }
5904
- else if (typeof input === 'string') {
5905
- const c = ctx.parseColor(input);
5906
- if (c)
5907
- return c;
5908
- }
5909
- else if (Array.isArray(input)) {
5910
- if (input.length < 3 || input.length > 4) {
5911
- error = `Invalid rbga value ${JSON.stringify(input)}: expected an array containing either three or four numeric values.`;
5939
+ switch (this.type.kind) {
5940
+ case 'boolean':
5941
+ return Boolean(this.args[0].evaluate(ctx));
5942
+ case 'color': {
5943
+ let input;
5944
+ let error;
5945
+ for (const arg of this.args) {
5946
+ input = arg.evaluate(ctx);
5947
+ error = null;
5948
+ if (input instanceof Color) {
5949
+ return input;
5912
5950
  }
5913
- else {
5914
- error = validateRGBA(input[0], input[1], input[2], input[3]);
5951
+ else if (typeof input === 'string') {
5952
+ const c = ctx.parseColor(input);
5953
+ if (c)
5954
+ return c;
5915
5955
  }
5916
- if (!error) {
5917
- return new Color(input[0] / 255, input[1] / 255, input[2] / 255, input[3]);
5956
+ else if (Array.isArray(input)) {
5957
+ if (input.length < 3 || input.length > 4) {
5958
+ error = `Invalid rbga value ${JSON.stringify(input)}: expected an array containing either three or four numeric values.`;
5959
+ }
5960
+ else {
5961
+ error = validateRGBA(input[0], input[1], input[2], input[3]);
5962
+ }
5963
+ if (!error) {
5964
+ return new Color(input[0] / 255, input[1] / 255, input[2] / 255, input[3]);
5965
+ }
5918
5966
  }
5919
5967
  }
5968
+ throw new RuntimeError(error || `Could not parse color from value '${typeof input === 'string' ? input : JSON.stringify(input)}'`);
5920
5969
  }
5921
- throw new RuntimeError(error || `Could not parse color from value '${typeof input === 'string' ? input : JSON.stringify(input)}'`);
5922
- }
5923
- else if (this.type.kind === 'padding') {
5924
- let input;
5925
- for (const arg of this.args) {
5926
- input = arg.evaluate(ctx);
5927
- const pad = Padding.parse(input);
5928
- if (pad) {
5929
- return pad;
5970
+ case 'padding': {
5971
+ let input;
5972
+ for (const arg of this.args) {
5973
+ input = arg.evaluate(ctx);
5974
+ const pad = Padding.parse(input);
5975
+ if (pad) {
5976
+ return pad;
5977
+ }
5930
5978
  }
5979
+ throw new RuntimeError(`Could not parse padding from value '${typeof input === 'string' ? input : JSON.stringify(input)}'`);
5931
5980
  }
5932
- throw new RuntimeError(`Could not parse padding from value '${typeof input === 'string' ? input : JSON.stringify(input)}'`);
5933
- }
5934
- else if (this.type.kind === 'number') {
5935
- let value = null;
5936
- for (const arg of this.args) {
5937
- value = arg.evaluate(ctx);
5938
- if (value === null)
5939
- return 0;
5940
- const num = Number(value);
5941
- if (isNaN(num))
5942
- continue;
5943
- return num;
5981
+ case 'variableAnchorOffsetCollection': {
5982
+ let input;
5983
+ for (const arg of this.args) {
5984
+ input = arg.evaluate(ctx);
5985
+ const coll = VariableAnchorOffsetCollection.parse(input);
5986
+ if (coll) {
5987
+ return coll;
5988
+ }
5989
+ }
5990
+ throw new RuntimeError(`Could not parse variableAnchorOffsetCollection from value '${typeof input === 'string' ? input : JSON.stringify(input)}'`);
5944
5991
  }
5945
- throw new RuntimeError(`Could not convert ${JSON.stringify(value)} to number.`);
5946
- }
5947
- else if (this.type.kind === 'formatted') {
5948
- // There is no explicit 'to-formatted' but this coercion can be implicitly
5949
- // created by properties that expect the 'formatted' type.
5950
- return Formatted.fromString(toString(this.args[0].evaluate(ctx)));
5951
- }
5952
- else if (this.type.kind === 'resolvedImage') {
5953
- return ResolvedImage.fromString(toString(this.args[0].evaluate(ctx)));
5954
- }
5955
- else {
5956
- return toString(this.args[0].evaluate(ctx));
5992
+ case 'number': {
5993
+ let value = null;
5994
+ for (const arg of this.args) {
5995
+ value = arg.evaluate(ctx);
5996
+ if (value === null)
5997
+ return 0;
5998
+ const num = Number(value);
5999
+ if (isNaN(num))
6000
+ continue;
6001
+ return num;
6002
+ }
6003
+ throw new RuntimeError(`Could not convert ${JSON.stringify(value)} to number.`);
6004
+ }
6005
+ case 'formatted':
6006
+ // There is no explicit 'to-formatted' but this coercion can be implicitly
6007
+ // created by properties that expect the 'formatted' type.
6008
+ return Formatted.fromString(toString(this.args[0].evaluate(ctx)));
6009
+ case 'resolvedImage':
6010
+ return ResolvedImage.fromString(toString(this.args[0].evaluate(ctx)));
6011
+ default:
6012
+ return toString(this.args[0].evaluate(ctx));
5957
6013
  }
5958
6014
  }
5959
6015
  eachChild(fn) {
@@ -6075,6 +6131,9 @@ class ParsingContext {
6075
6131
  else if (expected.kind === 'padding' && (actual.kind === 'value' || actual.kind === 'number' || actual.kind === 'array')) {
6076
6132
  parsed = annotate(parsed, expected, options.typeAnnotation || 'coerce');
6077
6133
  }
6134
+ else if (expected.kind === 'variableAnchorOffsetCollection' && (actual.kind === 'value' || actual.kind === 'array')) {
6135
+ parsed = annotate(parsed, expected, options.typeAnnotation || 'coerce');
6136
+ }
6078
6137
  else if (this.checkSubtype(expected, actual)) {
6079
6138
  return null;
6080
6139
  }
@@ -6845,6 +6904,7 @@ const interpolateFactory = (interpolationType) => {
6845
6904
  case 'color': return color;
6846
6905
  case 'array': return array;
6847
6906
  case 'padding': return padding;
6907
+ case 'variableAnchorOffsetCollection': return variableAnchorOffsetCollection;
6848
6908
  }
6849
6909
  };
6850
6910
  function number(from, to, t) {
@@ -6906,11 +6966,32 @@ function array(from, to, t) {
6906
6966
  function padding(from, to, t) {
6907
6967
  return new Padding(array(from.values, to.values, t));
6908
6968
  }
6969
+ function variableAnchorOffsetCollection(from, to, t) {
6970
+ const fromValues = from.values;
6971
+ const toValues = to.values;
6972
+ if (fromValues.length !== toValues.length) {
6973
+ throw new RuntimeError(`Cannot interpolate values of different length. from: ${from.toString()}, to: ${to.toString()}`);
6974
+ }
6975
+ const output = [];
6976
+ for (let i = 0; i < fromValues.length; i += 2) {
6977
+ // Anchor entries must match
6978
+ if (fromValues[i] !== toValues[i]) {
6979
+ throw new RuntimeError(`Cannot interpolate values containing mismatched anchors. from[${i}]: ${fromValues[i]}, to[${i}]: ${toValues[i]}`);
6980
+ }
6981
+ output.push(fromValues[i]);
6982
+ // Interpolate the offset values for each anchor
6983
+ const [fx, fy] = fromValues[i + 1];
6984
+ const [tx, ty] = toValues[i + 1];
6985
+ output.push([number(fx, tx, t), number(fy, ty, t)]);
6986
+ }
6987
+ return new VariableAnchorOffsetCollection(output);
6988
+ }
6909
6989
  const interpolate = {
6910
6990
  number,
6911
6991
  color,
6912
6992
  array,
6913
6993
  padding,
6994
+ variableAnchorOffsetCollection
6914
6995
  };
6915
6996
 
6916
6997
  class Interpolate {
@@ -7009,6 +7090,7 @@ class Interpolate {
7009
7090
  if (!verifyType(outputType, NumberType) &&
7010
7091
  !verifyType(outputType, ColorType) &&
7011
7092
  !verifyType(outputType, PaddingType) &&
7093
+ !verifyType(outputType, VariableAnchorOffsetCollectionType) &&
7012
7094
  !verifyType(outputType, array$1(NumberType))) {
7013
7095
  return context.error(`Type ${toString$1(outputType)} is not interpolatable.`);
7014
7096
  }
@@ -8868,6 +8950,9 @@ function normalizePropertyExpression(value, specification) {
8868
8950
  else if (specification.type === 'padding' && (typeof value === 'number' || Array.isArray(value))) {
8869
8951
  constant = Padding.parse(value);
8870
8952
  }
8953
+ else if (specification.type === 'variableAnchorOffsetCollection' && Array.isArray(value)) {
8954
+ constant = VariableAnchorOffsetCollection.parse(value);
8955
+ }
8871
8956
  return {
8872
8957
  kind: 'constant',
8873
8958
  evaluate: () => constant
@@ -8921,7 +9006,8 @@ function getExpectedType(spec) {
8921
9006
  boolean: BooleanType,
8922
9007
  formatted: FormattedType,
8923
9008
  padding: PaddingType,
8924
- resolvedImage: ResolvedImageType
9009
+ resolvedImage: ResolvedImageType,
9010
+ variableAnchorOffsetCollection: VariableAnchorOffsetCollectionType
8925
9011
  };
8926
9012
  if (spec.type === 'array') {
8927
9013
  return array$1(types[spec.value] || ValueType, spec.length);
@@ -8941,6 +9027,9 @@ function getDefaultValue(spec) {
8941
9027
  else if (spec.type === 'padding') {
8942
9028
  return Padding.parse(spec.default) || null;
8943
9029
  }
9030
+ else if (spec.type === 'variableAnchorOffsetCollection') {
9031
+ return VariableAnchorOffsetCollection.parse(spec.default) || null;
9032
+ }
8944
9033
  else if (spec.default === undefined) {
8945
9034
  return null;
8946
9035
  }
@@ -10610,6 +10699,38 @@ function validatePadding(options) {
10610
10699
  }
10611
10700
  }
10612
10701
 
10702
+ function validateVariableAnchorOffsetCollection(options) {
10703
+ const key = options.key;
10704
+ const value = options.value;
10705
+ const type = getType(value);
10706
+ const styleSpec = options.styleSpec;
10707
+ if (type !== 'array' || value.length < 1 || value.length % 2 !== 0) {
10708
+ return [new ValidationError(key, value, 'variableAnchorOffsetCollection requires a non-empty array of even length')];
10709
+ }
10710
+ let errors = [];
10711
+ for (let i = 0; i < value.length; i += 2) {
10712
+ // Elements in even positions should be values from text-anchor enum
10713
+ errors = errors.concat(validateEnum({
10714
+ key: `${key}[${i}]`,
10715
+ value: value[i],
10716
+ valueSpec: styleSpec['layout_symbol']['text-anchor']
10717
+ }));
10718
+ // Elements in odd positions should be points (2-element numeric arrays)
10719
+ errors = errors.concat(validateArray({
10720
+ key: `${key}[${i + 1}]`,
10721
+ value: value[i + 1],
10722
+ valueSpec: {
10723
+ length: 2,
10724
+ value: 'number'
10725
+ },
10726
+ validateSpec: options.validateSpec,
10727
+ style: options.style,
10728
+ styleSpec
10729
+ }));
10730
+ }
10731
+ return errors;
10732
+ }
10733
+
10613
10734
  function validateSprite(options) {
10614
10735
  let errors = [];
10615
10736
  const sprite = options.value;
@@ -10672,6 +10793,7 @@ const VALIDATORS = {
10672
10793
  'formatted': validateFormatted,
10673
10794
  'resolvedImage': validateImage,
10674
10795
  'padding': validatePadding,
10796
+ 'variableAnchorOffsetCollection': validateVariableAnchorOffsetCollection,
10675
10797
  'sprite': validateSprite,
10676
10798
  };
10677
10799
  // Main recursive validation function. Tracks:
@@ -12246,6 +12368,9 @@ class Layout {
12246
12368
  this._properties = properties;
12247
12369
  this._values = Object.create(properties.defaultPropertyValues);
12248
12370
  }
12371
+ hasValue(name) {
12372
+ return this._values[name].value !== undefined;
12373
+ }
12249
12374
  getValue(name) {
12250
12375
  return clone$9(this._values[name].value);
12251
12376
  }
@@ -13371,10 +13496,11 @@ register('StructArrayLayout2i2ui3ul3ui2f3ub1ul1i48', StructArrayLayout2i2ui3ul3u
13371
13496
  * [0]: Int16[8]
13372
13497
  * [16]: Uint16[15]
13373
13498
  * [48]: Uint32[1]
13374
- * [52]: Float32[4]
13499
+ * [52]: Float32[2]
13500
+ * [60]: Uint16[2]
13375
13501
  *
13376
13502
  */
13377
- class StructArrayLayout8i15ui1ul4f68 extends StructArray {
13503
+ class StructArrayLayout8i15ui1ul2f2ui64 extends StructArray {
13378
13504
  _refreshViews() {
13379
13505
  this.uint8 = new Uint8Array(this.arrayBuffer);
13380
13506
  this.int16 = new Int16Array(this.arrayBuffer);
@@ -13388,8 +13514,8 @@ class StructArrayLayout8i15ui1ul4f68 extends StructArray {
13388
13514
  return this.emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27);
13389
13515
  }
13390
13516
  emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) {
13391
- const o2 = i * 34;
13392
- const o4 = i * 17;
13517
+ const o2 = i * 32;
13518
+ const o4 = i * 16;
13393
13519
  this.int16[o2 + 0] = v0;
13394
13520
  this.int16[o2 + 1] = v1;
13395
13521
  this.int16[o2 + 2] = v2;
@@ -13416,13 +13542,13 @@ class StructArrayLayout8i15ui1ul4f68 extends StructArray {
13416
13542
  this.uint32[o4 + 12] = v23;
13417
13543
  this.float32[o4 + 13] = v24;
13418
13544
  this.float32[o4 + 14] = v25;
13419
- this.float32[o4 + 15] = v26;
13420
- this.float32[o4 + 16] = v27;
13545
+ this.uint16[o2 + 30] = v26;
13546
+ this.uint16[o2 + 31] = v27;
13421
13547
  return i;
13422
13548
  }
13423
13549
  }
13424
- StructArrayLayout8i15ui1ul4f68.prototype.bytesPerElement = 68;
13425
- register('StructArrayLayout8i15ui1ul4f68', StructArrayLayout8i15ui1ul4f68);
13550
+ StructArrayLayout8i15ui1ul2f2ui64.prototype.bytesPerElement = 64;
13551
+ register('StructArrayLayout8i15ui1ul2f2ui64', StructArrayLayout8i15ui1ul2f2ui64);
13426
13552
  /**
13427
13553
  * @internal
13428
13554
  * Implementation of the StructArray layout:
@@ -13447,6 +13573,35 @@ class StructArrayLayout1f4 extends StructArray {
13447
13573
  }
13448
13574
  StructArrayLayout1f4.prototype.bytesPerElement = 4;
13449
13575
  register('StructArrayLayout1f4', StructArrayLayout1f4);
13576
+ /**
13577
+ * @internal
13578
+ * Implementation of the StructArray layout:
13579
+ * [0]: Uint16[1]
13580
+ * [4]: Float32[2]
13581
+ *
13582
+ */
13583
+ class StructArrayLayout1ui2f12 extends StructArray {
13584
+ _refreshViews() {
13585
+ this.uint8 = new Uint8Array(this.arrayBuffer);
13586
+ this.uint16 = new Uint16Array(this.arrayBuffer);
13587
+ this.float32 = new Float32Array(this.arrayBuffer);
13588
+ }
13589
+ emplaceBack(v0, v1, v2) {
13590
+ const i = this.length;
13591
+ this.resize(i + 1);
13592
+ return this.emplace(i, v0, v1, v2);
13593
+ }
13594
+ emplace(i, v0, v1, v2) {
13595
+ const o2 = i * 6;
13596
+ const o4 = i * 3;
13597
+ this.uint16[o2 + 0] = v0;
13598
+ this.float32[o4 + 1] = v1;
13599
+ this.float32[o4 + 2] = v2;
13600
+ return i;
13601
+ }
13602
+ }
13603
+ StructArrayLayout1ui2f12.prototype.bytesPerElement = 12;
13604
+ register('StructArrayLayout1ui2f12', StructArrayLayout1ui2f12);
13450
13605
  /**
13451
13606
  * @internal
13452
13607
  * Implementation of the StructArray layout:
@@ -13640,13 +13795,13 @@ class SymbolInstanceStruct extends Struct {
13640
13795
  get crossTileID() { return this._structArray.uint32[this._pos4 + 12]; }
13641
13796
  set crossTileID(x) { this._structArray.uint32[this._pos4 + 12] = x; }
13642
13797
  get textBoxScale() { return this._structArray.float32[this._pos4 + 13]; }
13643
- get textOffset0() { return this._structArray.float32[this._pos4 + 14]; }
13644
- get textOffset1() { return this._structArray.float32[this._pos4 + 15]; }
13645
- get collisionCircleDiameter() { return this._structArray.float32[this._pos4 + 16]; }
13798
+ get collisionCircleDiameter() { return this._structArray.float32[this._pos4 + 14]; }
13799
+ get textAnchorOffsetStartIndex() { return this._structArray.uint16[this._pos2 + 30]; }
13800
+ get textAnchorOffsetEndIndex() { return this._structArray.uint16[this._pos2 + 31]; }
13646
13801
  }
13647
- SymbolInstanceStruct.prototype.size = 68;
13802
+ SymbolInstanceStruct.prototype.size = 64;
13648
13803
  /** @internal */
13649
- class SymbolInstanceArray extends StructArrayLayout8i15ui1ul4f68 {
13804
+ class SymbolInstanceArray extends StructArrayLayout8i15ui1ul2f2ui64 {
13650
13805
  /**
13651
13806
  * Return the SymbolInstanceStruct at the given location in the array.
13652
13807
  * @param index The index of the element.
@@ -13669,6 +13824,24 @@ class SymbolLineVertexArray extends StructArrayLayout3i6 {
13669
13824
  }
13670
13825
  register('SymbolLineVertexArray', SymbolLineVertexArray);
13671
13826
  /** @internal */
13827
+ class TextAnchorOffsetStruct extends Struct {
13828
+ get textAnchor() { return this._structArray.uint16[this._pos2 + 0]; }
13829
+ get textOffset0() { return this._structArray.float32[this._pos4 + 1]; }
13830
+ get textOffset1() { return this._structArray.float32[this._pos4 + 2]; }
13831
+ }
13832
+ TextAnchorOffsetStruct.prototype.size = 12;
13833
+ /** @internal */
13834
+ class TextAnchorOffsetArray extends StructArrayLayout1ui2f12 {
13835
+ /**
13836
+ * Return the TextAnchorOffsetStruct at the given location in the array.
13837
+ * @param index The index of the element.
13838
+ */
13839
+ get(index) {
13840
+ return new TextAnchorOffsetStruct(this, index);
13841
+ }
13842
+ }
13843
+ register('TextAnchorOffsetArray', TextAnchorOffsetArray);
13844
+ /** @internal */
13672
13845
  class FeatureIndexStruct extends Struct {
13673
13846
  get featureIndex() { return this._structArray.uint32[this._pos4 + 0]; }
13674
13847
  get sourceLayerIndex() { return this._structArray.uint16[this._pos2 + 2]; }
@@ -25433,8 +25606,9 @@ const symbolInstance = createLayout([
25433
25606
  { type: 'Uint16', name: 'useRuntimeCollisionCircles' },
25434
25607
  { type: 'Uint32', name: 'crossTileID' },
25435
25608
  { type: 'Float32', name: 'textBoxScale' },
25436
- { type: 'Float32', components: 2, name: 'textOffset' },
25437
25609
  { type: 'Float32', name: 'collisionCircleDiameter' },
25610
+ { type: 'Uint16', name: 'textAnchorOffsetStartIndex' },
25611
+ { type: 'Uint16', name: 'textAnchorOffsetEndIndex' }
25438
25612
  ]);
25439
25613
  const glyphOffset = createLayout([
25440
25614
  { type: 'Float32', name: 'offsetX' }
@@ -25444,6 +25618,10 @@ const lineVertex = createLayout([
25444
25618
  { type: 'Int16', name: 'y' },
25445
25619
  { type: 'Int16', name: 'tileUnitDistanceFromAnchor' }
25446
25620
  ]);
25621
+ const textAnchorOffset = createLayout([
25622
+ { type: 'Uint16', name: 'textAnchor' },
25623
+ { type: 'Float32', components: 2, name: 'textOffset' }
25624
+ ]);
25447
25625
 
25448
25626
  function transformTextInternal(text, layer, feature) {
25449
25627
  const transform = layer.layout.get('text-transform').evaluate(feature, {});
@@ -27436,6 +27614,7 @@ class SymbolBucket {
27436
27614
  this.glyphOffsetArray = new GlyphOffsetArray();
27437
27615
  this.lineVertexArray = new SymbolLineVertexArray();
27438
27616
  this.symbolInstances = new SymbolInstanceArray();
27617
+ this.textAnchorOffsets = new TextAnchorOffsetArray();
27439
27618
  }
27440
27619
  calculateGlyphDependencies(text, stack, textAlongLine, allowVerticalPlacement, doesAllowVerticalWritingMode) {
27441
27620
  for (let i = 0; i < text.length; i++) {
@@ -27913,6 +28092,7 @@ const getLayout = () => layout = layout || new Properties({
27913
28092
  "text-justify": new DataDrivenProperty(v8Spec["layout_symbol"]["text-justify"]),
27914
28093
  "text-radial-offset": new DataDrivenProperty(v8Spec["layout_symbol"]["text-radial-offset"]),
27915
28094
  "text-variable-anchor": new DataConstantProperty(v8Spec["layout_symbol"]["text-variable-anchor"]),
28095
+ "text-variable-anchor-offset": new DataDrivenProperty(v8Spec["layout_symbol"]["text-variable-anchor-offset"]),
27916
28096
  "text-anchor": new DataDrivenProperty(v8Spec["layout_symbol"]["text-anchor"]),
27917
28097
  "text-max-angle": new DataConstantProperty(v8Spec["layout_symbol"]["text-max-angle"]),
27918
28098
  "text-writing-mode": new DataConstantProperty(v8Spec["layout_symbol"]["text-writing-mode"]),
@@ -30044,6 +30224,18 @@ function getCentroidCell(polygon) {
30044
30224
  return new Cell(x / area, y / area, 0, polygon);
30045
30225
  }
30046
30226
 
30227
+ exports.TextAnchorEnum = void 0;
30228
+ (function (TextAnchorEnum) {
30229
+ TextAnchorEnum[TextAnchorEnum["center"] = 1] = "center";
30230
+ TextAnchorEnum[TextAnchorEnum["left"] = 2] = "left";
30231
+ TextAnchorEnum[TextAnchorEnum["right"] = 3] = "right";
30232
+ TextAnchorEnum[TextAnchorEnum["top"] = 4] = "top";
30233
+ TextAnchorEnum[TextAnchorEnum["bottom"] = 5] = "bottom";
30234
+ TextAnchorEnum[TextAnchorEnum["top-left"] = 6] = "top-left";
30235
+ TextAnchorEnum[TextAnchorEnum["top-right"] = 7] = "top-right";
30236
+ TextAnchorEnum[TextAnchorEnum["bottom-left"] = 8] = "bottom-left";
30237
+ TextAnchorEnum[TextAnchorEnum["bottom-right"] = 9] = "bottom-right";
30238
+ })(exports.TextAnchorEnum || (exports.TextAnchorEnum = {}));
30047
30239
  // The radial offset is to the edge of the text box
30048
30240
  // In the horizontal direction, the edge of the text box is where glyphs start
30049
30241
  // But in the vertical direction, the glyphs appear to "start" at the baseline
@@ -30125,14 +30317,60 @@ function evaluateVariableOffset(anchor, offset) {
30125
30317
  }
30126
30318
  return (offset[1] !== INVALID_TEXT_OFFSET) ? fromTextOffset(anchor, offset[0], offset[1]) : fromRadialOffset(anchor, offset[0]);
30127
30319
  }
30320
+ // Helper to support both text-variable-anchor and text-variable-anchor-offset. Offset values converted from EMs to PXs
30321
+ function getTextVariableAnchorOffset(layer, feature, canonical) {
30322
+ var _a;
30323
+ const layout = layer.layout;
30324
+ // If style specifies text-variable-anchor-offset, just return it
30325
+ const variableAnchorOffset = (_a = layout.get('text-variable-anchor-offset')) === null || _a === void 0 ? void 0 : _a.evaluate(feature, {}, canonical);
30326
+ if (variableAnchorOffset) {
30327
+ const sourceValues = variableAnchorOffset.values;
30328
+ const destValues = [];
30329
+ // Convert offsets from EM to PX, and apply baseline shift
30330
+ for (let i = 0; i < sourceValues.length; i += 2) {
30331
+ const anchor = destValues[i] = sourceValues[i];
30332
+ const offset = sourceValues[i + 1].map(t => t * ONE_EM);
30333
+ if (anchor.startsWith('top')) {
30334
+ offset[1] -= baselineOffset;
30335
+ }
30336
+ else if (anchor.startsWith('bottom')) {
30337
+ offset[1] += baselineOffset;
30338
+ }
30339
+ destValues[i + 1] = offset;
30340
+ }
30341
+ return new VariableAnchorOffsetCollection(destValues);
30342
+ }
30343
+ // If style specifies text-variable-anchor, convert to the new format
30344
+ const variableAnchor = layout.get('text-variable-anchor');
30345
+ if (variableAnchor) {
30346
+ let textOffset;
30347
+ const unevaluatedLayout = layer._unevaluatedLayout;
30348
+ // The style spec says don't use `text-offset` and `text-radial-offset` together
30349
+ // but doesn't actually specify what happens if you use both. We go with the radial offset.
30350
+ if (unevaluatedLayout.getValue('text-radial-offset') !== undefined) {
30351
+ textOffset = [layout.get('text-radial-offset').evaluate(feature, {}, canonical) * ONE_EM, INVALID_TEXT_OFFSET];
30352
+ }
30353
+ else {
30354
+ textOffset = layout.get('text-offset').evaluate(feature, {}, canonical).map(t => t * ONE_EM);
30355
+ }
30356
+ const anchorOffsets = [];
30357
+ for (const anchor of variableAnchor) {
30358
+ anchorOffsets.push(anchor, evaluateVariableOffset(anchor, textOffset));
30359
+ }
30360
+ return new VariableAnchorOffsetCollection(anchorOffsets);
30361
+ }
30362
+ return null;
30363
+ }
30364
+
30128
30365
  function performSymbolLayout(args) {
30129
30366
  args.bucket.createArrays();
30130
30367
  const tileSize = 512 * args.bucket.overscaling;
30131
30368
  args.bucket.tilePixelRatio = EXTENT / tileSize;
30132
30369
  args.bucket.compareText = {};
30133
30370
  args.bucket.iconsNeedLinear = false;
30134
- const layout = args.bucket.layers[0].layout;
30135
- const unevaluatedLayoutValues = args.bucket.layers[0]._unevaluatedLayout._values;
30371
+ const layer = args.bucket.layers[0];
30372
+ const layout = layer.layout;
30373
+ const unevaluatedLayoutValues = layer._unevaluatedLayout._values;
30136
30374
  const sizes = {
30137
30375
  // Filled in below, if *SizeData.kind is 'composite'
30138
30376
  // compositeIconSizes: undefined,
@@ -30175,8 +30413,8 @@ function performSymbolLayout(args) {
30175
30413
  const spacing = layout.get('text-letter-spacing').evaluate(feature, {}, args.canonical) * ONE_EM;
30176
30414
  const spacingIfAllowed = allowsLetterSpacing(unformattedText) ? spacing : 0;
30177
30415
  const textAnchor = layout.get('text-anchor').evaluate(feature, {}, args.canonical);
30178
- const variableTextAnchor = layout.get('text-variable-anchor');
30179
- if (!variableTextAnchor) {
30416
+ const variableAnchorOffset = getTextVariableAnchorOffset(layer, feature, args.canonical);
30417
+ if (!variableAnchorOffset) {
30180
30418
  const radialOffset = layout.get('text-radial-offset').evaluate(feature, {}, args.canonical);
30181
30419
  // Layers with variable anchors use the `text-radial-offset` property and the [x, y] offset vector
30182
30420
  // is calculated at placement time instead of layout time
@@ -30205,13 +30443,18 @@ function performSymbolLayout(args) {
30205
30443
  }
30206
30444
  };
30207
30445
  // If this layer uses text-variable-anchor, generate shapings for all justification possibilities.
30208
- if (!textAlongLine && variableTextAnchor) {
30209
- const justifications = textJustify === 'auto' ?
30210
- variableTextAnchor.map(a => getAnchorJustification(a)) :
30211
- [textJustify];
30446
+ if (!textAlongLine && variableAnchorOffset) {
30447
+ const justifications = new Set();
30448
+ if (textJustify === 'auto') {
30449
+ for (let i = 0; i < variableAnchorOffset.values.length; i += 2) {
30450
+ justifications.add(getAnchorJustification(variableAnchorOffset.values[i]));
30451
+ }
30452
+ }
30453
+ else {
30454
+ justifications.add(textJustify);
30455
+ }
30212
30456
  let singleLine = false;
30213
- for (let i = 0; i < justifications.length; i++) {
30214
- const justification = justifications[i];
30457
+ for (const justification of justifications) {
30215
30458
  if (shapedTextOrientations.horizontal[justification])
30216
30459
  continue;
30217
30460
  if (singleLine) {
@@ -30376,6 +30619,18 @@ function addFeature(bucket, feature, shapedTextOrientations, shapedIcon, imageMa
30376
30619
  }
30377
30620
  }
30378
30621
  }
30622
+ function addTextVariableAnchorOffsets(textAnchorOffsets, variableAnchorOffset) {
30623
+ const startIndex = textAnchorOffsets.length;
30624
+ const values = variableAnchorOffset === null || variableAnchorOffset === void 0 ? void 0 : variableAnchorOffset.values;
30625
+ if ((values === null || values === void 0 ? void 0 : values.length) > 0) {
30626
+ for (let i = 0; i < values.length; i += 2) {
30627
+ const anchor = exports.TextAnchorEnum[values[i]];
30628
+ const offset = values[i + 1];
30629
+ textAnchorOffsets.emplaceBack(anchor, offset[0], offset[1]);
30630
+ }
30631
+ }
30632
+ return [startIndex, textAnchorOffsets.length];
30633
+ }
30379
30634
  function addTextVertices(bucket, anchor, shapedText, imageMap, layer, textAlongLine, feature, textOffset, lineArray, writingMode, placementTypes, placedTextSymbolIndices, placedIconIndex, sizes, canonical) {
30380
30635
  const glyphQuads = getGlyphQuads(anchor, shapedText, textOffset, layer, textAlongLine, feature, imageMap, bucket.allowVerticalPlacement);
30381
30636
  const sizeData = bucket.textSizeData;
@@ -30427,15 +30682,6 @@ function addSymbol(bucket, anchor, line, shapedTextOrientations, shapedIcon, ima
30427
30682
  let verticalPlacedIconSymbolIndex = -1;
30428
30683
  const placedTextSymbolIndices = {};
30429
30684
  let key = murmur3$1('');
30430
- let textOffset0 = 0;
30431
- let textOffset1 = 0;
30432
- if (layer._unevaluatedLayout.getValue('text-radial-offset') === undefined) {
30433
- [textOffset0, textOffset1] = layer.layout.get('text-offset').evaluate(feature, {}, canonical).map(t => t * ONE_EM);
30434
- }
30435
- else {
30436
- textOffset0 = layer.layout.get('text-radial-offset').evaluate(feature, {}, canonical) * ONE_EM;
30437
- textOffset1 = INVALID_TEXT_OFFSET;
30438
- }
30439
30685
  if (bucket.allowVerticalPlacement && shapedTextOrientations.vertical) {
30440
30686
  const textRotation = layer.layout.get('text-rotate').evaluate(feature, {}, canonical);
30441
30687
  const verticalTextRotation = textRotation + 90.0;
@@ -30536,7 +30782,9 @@ function addSymbol(bucket, anchor, line, shapedTextOrientations, shapedIcon, ima
30536
30782
  if (feature.sortKey !== undefined) {
30537
30783
  bucket.addToSortKeyRanges(bucket.symbolInstances.length, feature.sortKey);
30538
30784
  }
30539
- bucket.symbolInstances.emplaceBack(anchor.x, anchor.y, placedTextSymbolIndices.right >= 0 ? placedTextSymbolIndices.right : -1, placedTextSymbolIndices.center >= 0 ? placedTextSymbolIndices.center : -1, placedTextSymbolIndices.left >= 0 ? placedTextSymbolIndices.left : -1, placedTextSymbolIndices.vertical || -1, placedIconSymbolIndex, verticalPlacedIconSymbolIndex, key, textBoxStartIndex, textBoxEndIndex, verticalTextBoxStartIndex, verticalTextBoxEndIndex, iconBoxStartIndex, iconBoxEndIndex, verticalIconBoxStartIndex, verticalIconBoxEndIndex, featureIndex, numHorizontalGlyphVertices, numVerticalGlyphVertices, numIconVertices, numVerticalIconVertices, useRuntimeCollisionCircles, 0, textBoxScale, textOffset0, textOffset1, collisionCircleDiameter);
30785
+ const variableAnchorOffset = getTextVariableAnchorOffset(layer, feature, canonical);
30786
+ const [textAnchorOffsetStartIndex, textAnchorOffsetEndIndex] = addTextVariableAnchorOffsets(bucket.textAnchorOffsets, variableAnchorOffset);
30787
+ bucket.symbolInstances.emplaceBack(anchor.x, anchor.y, placedTextSymbolIndices.right >= 0 ? placedTextSymbolIndices.right : -1, placedTextSymbolIndices.center >= 0 ? placedTextSymbolIndices.center : -1, placedTextSymbolIndices.left >= 0 ? placedTextSymbolIndices.left : -1, placedTextSymbolIndices.vertical || -1, placedIconSymbolIndex, verticalPlacedIconSymbolIndex, key, textBoxStartIndex, textBoxEndIndex, verticalTextBoxStartIndex, verticalTextBoxEndIndex, iconBoxStartIndex, iconBoxEndIndex, verticalIconBoxStartIndex, verticalIconBoxEndIndex, featureIndex, numHorizontalGlyphVertices, numVerticalGlyphVertices, numIconVertices, numVerticalIconVertices, useRuntimeCollisionCircles, 0, textBoxScale, collisionCircleDiameter, textAnchorOffsetStartIndex, textAnchorOffsetEndIndex);
30540
30788
  }
30541
30789
  function anchorIsTooClose(bucket, text, repeatDistance, anchor) {
30542
30790
  const compareText = bucket.compareText;
@@ -31058,7 +31306,6 @@ exports.emptyStyle = emptyStyle;
31058
31306
  exports.equals = equals$6;
31059
31307
  exports.evaluateSizeForFeature = evaluateSizeForFeature;
31060
31308
  exports.evaluateSizeForZoom = evaluateSizeForZoom;
31061
- exports.evaluateVariableOffset = evaluateVariableOffset;
31062
31309
  exports.evented = evented;
31063
31310
  exports.extend = extend;
31064
31311
  exports.filterObject = filterObject;
@@ -33782,7 +34029,7 @@ define(['./shared'], (function (performance) { 'use strict';
33782
34029
 
33783
34030
  var name = "maplibre-gl";
33784
34031
  var description = "BSD licensed community fork of mapbox-gl, a WebGL interactive maps library";
33785
- var version$2 = "3.2.2";
34032
+ var version$2 = "3.3.0";
33786
34033
  var main = "dist/maplibre-gl.js";
33787
34034
  var style = "dist/maplibre-gl.css";
33788
34035
  var license = "BSD-3-Clause";
@@ -33801,7 +34048,7 @@ var dependencies = {
33801
34048
  "@mapbox/unitbezier": "^0.0.1",
33802
34049
  "@mapbox/vector-tile": "^1.3.1",
33803
34050
  "@mapbox/whoots-js": "^3.1.0",
33804
- "@maplibre/maplibre-gl-style-spec": "^19.2.2",
34051
+ "@maplibre/maplibre-gl-style-spec": "^19.3.0",
33805
34052
  "@types/geojson": "^7946.0.10",
33806
34053
  "@types/mapbox__point-geometry": "^0.1.2",
33807
34054
  "@types/mapbox__vector-tile": "^1.3.0",
@@ -33835,7 +34082,7 @@ var devDependencies = {
33835
34082
  "@types/d3": "^7.4.0",
33836
34083
  "@types/diff": "^5.0.3",
33837
34084
  "@types/earcut": "^2.1.1",
33838
- "@types/eslint": "^8.44.1",
34085
+ "@types/eslint": "^8.44.2",
33839
34086
  "@types/gl": "^6.0.2",
33840
34087
  "@types/glob": "^8.1.0",
33841
34088
  "@types/jest": "^29.5.3",
@@ -33843,24 +34090,24 @@ var devDependencies = {
33843
34090
  "@types/minimist": "^1.2.2",
33844
34091
  "@types/murmurhash-js": "^1.0.4",
33845
34092
  "@types/nise": "^1.4.1",
33846
- "@types/node": "^20.4.5",
34093
+ "@types/node": "^20.4.8",
33847
34094
  "@types/offscreencanvas": "^2019.7.0",
33848
34095
  "@types/pixelmatch": "^5.2.4",
33849
34096
  "@types/pngjs": "^6.0.1",
33850
- "@types/react": "^18.2.17",
34097
+ "@types/react": "^18.2.18",
33851
34098
  "@types/react-dom": "^18.2.7",
33852
34099
  "@types/request": "^2.48.8",
33853
34100
  "@types/shuffle-seed": "^1.1.0",
33854
34101
  "@types/window-or-global": "^1.0.4",
33855
- "@typescript-eslint/eslint-plugin": "^6.2.0",
33856
- "@typescript-eslint/parser": "^6.2.0",
34102
+ "@typescript-eslint/eslint-plugin": "^6.2.1",
34103
+ "@typescript-eslint/parser": "^6.2.1",
33857
34104
  address: "^1.2.2",
33858
34105
  benchmark: "^2.1.4",
33859
34106
  canvas: "^2.11.2",
33860
34107
  cssnano: "^6.0.1",
33861
34108
  d3: "^7.8.5",
33862
34109
  "d3-queue": "^3.0.7",
33863
- "devtools-protocol": "^0.0.1173815",
34110
+ "devtools-protocol": "^0.0.1179426",
33864
34111
  diff: "^5.1.0",
33865
34112
  "dts-bundle-generator": "^8.0.1",
33866
34113
  eslint: "^8.46.0",
@@ -33892,10 +34139,10 @@ var devDependencies = {
33892
34139
  "postcss-cli": "^10.1.0",
33893
34140
  "postcss-inline-svg": "^6.0.0",
33894
34141
  "pretty-bytes": "^6.1.1",
33895
- puppeteer: "^20.9.0",
34142
+ puppeteer: "^21.0.1",
33896
34143
  react: "^18.2.0",
33897
34144
  "react-dom": "^18.2.0",
33898
- rollup: "^3.27.0",
34145
+ rollup: "^3.27.2",
33899
34146
  "rollup-plugin-sourcemaps": "^0.6.3",
33900
34147
  rw: "^1.3.3",
33901
34148
  semver: "^7.5.4",
@@ -40127,8 +40374,7 @@ function calculateVariableLayoutShift(anchor, width, height, textOffset, textBox
40127
40374
  const { horizontalAlign, verticalAlign } = performance.getAnchorAlignment(anchor);
40128
40375
  const shiftX = -(horizontalAlign - 0.5) * width;
40129
40376
  const shiftY = -(verticalAlign - 0.5) * height;
40130
- const offset = performance.evaluateVariableOffset(anchor, textOffset);
40131
- return new performance.Point(shiftX + offset[0] * textBoxScale, shiftY + offset[1] * textBoxScale);
40377
+ return new performance.Point(shiftX + textOffset[0] * textBoxScale, shiftY + textOffset[1] * textBoxScale);
40132
40378
  }
40133
40379
  function shiftVariableCollisionBox(collisionBox, shiftX, shiftY, rotateWithMap, pitchWithMap, angle) {
40134
40380
  const { x1, x2, y1, y2, anchorPointX, anchorPointY } = collisionBox;
@@ -40215,8 +40461,9 @@ class Placement {
40215
40461
  });
40216
40462
  }
40217
40463
  }
40218
- attemptAnchorPlacement(anchor, textBox, width, height, textBoxScale, rotateWithMap, pitchWithMap, textPixelRatio, posMatrix, collisionGroup, textOverlapMode, symbolInstance, bucket, orientation, iconBox, getElevation) {
40219
- const textOffset = [symbolInstance.textOffset0, symbolInstance.textOffset1];
40464
+ attemptAnchorPlacement(textAnchorOffset, textBox, width, height, textBoxScale, rotateWithMap, pitchWithMap, textPixelRatio, posMatrix, collisionGroup, textOverlapMode, symbolInstance, bucket, orientation, iconBox, getElevation) {
40465
+ const anchor = performance.TextAnchorEnum[textAnchorOffset.textAnchor];
40466
+ const textOffset = [textAnchorOffset.textOffset0, textAnchorOffset.textOffset1];
40220
40467
  const shift = calculateVariableLayoutShift(anchor, width, height, textOffset, textBoxScale);
40221
40468
  const placedGlyphBoxes = this.collisionIndex.placeCollisionBox(shiftVariableCollisionBox(textBox, shift.x, shift.y, rotateWithMap, pitchWithMap, this.transform.angle), textOverlapMode, textPixelRatio, posMatrix, collisionGroup.predicate, getElevation);
40222
40469
  if (iconBox) {
@@ -40286,6 +40533,7 @@ class Placement {
40286
40533
  const tileID = this.retainedQueryData[bucket.bucketInstanceId].tileID;
40287
40534
  const getElevation = this.terrain ? (x, y) => this.terrain.getElevation(tileID, x, y) : null;
40288
40535
  const placeSymbol = (symbolInstance, collisionArrays) => {
40536
+ var _a, _b;
40289
40537
  if (seenCrossTileIDs[symbolInstance.crossTileID])
40290
40538
  return;
40291
40539
  if (holdingForFade) {
@@ -40347,7 +40595,10 @@ class Placement {
40347
40595
  placed = placeHorizontalFn();
40348
40596
  }
40349
40597
  };
40350
- if (!layout.get('text-variable-anchor')) {
40598
+ const textAnchorOffsetStart = symbolInstance.textAnchorOffsetStartIndex;
40599
+ const textAnchorOffsetEnd = symbolInstance.textAnchorOffsetEndIndex;
40600
+ // If start+end indices match, text-variable-anchor is not in play.
40601
+ if (textAnchorOffsetEnd === textAnchorOffsetStart) {
40351
40602
  const placeBox = (collisionTextBox, orientation) => {
40352
40603
  const placedFeature = this.collisionIndex.placeCollisionBox(collisionTextBox, textOverlapMode, textPixelRatio, posMatrix, collisionGroup.predicate, getElevation);
40353
40604
  if (placedFeature && placedFeature.box && placedFeature.box.length) {
@@ -40370,35 +40621,40 @@ class Placement {
40370
40621
  updatePreviousOrientationIfNotPlaced(placed && placed.box && placed.box.length);
40371
40622
  }
40372
40623
  else {
40373
- let anchors = layout.get('text-variable-anchor');
40374
- // If this symbol was in the last placement, shift the previously used
40375
- // anchor to the front of the anchor list, only if the previous anchor
40376
- // is still in the anchor list
40377
- if (this.prevPlacement && this.prevPlacement.variableOffsets[symbolInstance.crossTileID]) {
40378
- const prevOffsets = this.prevPlacement.variableOffsets[symbolInstance.crossTileID];
40379
- if (anchors.indexOf(prevOffsets.anchor) > 0) {
40380
- anchors = anchors.filter(anchor => anchor !== prevOffsets.anchor);
40381
- anchors.unshift(prevOffsets.anchor);
40382
- }
40383
- }
40624
+ // If this symbol was in the last placement, prefer placement using same anchor, if it's still available
40625
+ let prevAnchor = performance.TextAnchorEnum[(_b = (_a = this.prevPlacement) === null || _a === void 0 ? void 0 : _a.variableOffsets[symbolInstance.crossTileID]) === null || _b === void 0 ? void 0 : _b.anchor];
40384
40626
  const placeBoxForVariableAnchors = (collisionTextBox, collisionIconBox, orientation) => {
40385
40627
  const width = collisionTextBox.x2 - collisionTextBox.x1;
40386
40628
  const height = collisionTextBox.y2 - collisionTextBox.y1;
40387
40629
  const textBoxScale = symbolInstance.textBoxScale;
40388
40630
  const variableIconBox = hasIconTextFit && (iconOverlapMode === 'never') ? collisionIconBox : null;
40389
40631
  let placedBox = { box: [], offscreen: false };
40390
- const placementAttempts = (textOverlapMode !== 'never') ? anchors.length * 2 : anchors.length;
40391
- for (let i = 0; i < placementAttempts; ++i) {
40392
- const anchor = anchors[i % anchors.length];
40393
- const overlapMode = (i >= anchors.length) ? textOverlapMode : 'never';
40394
- const result = this.attemptAnchorPlacement(anchor, collisionTextBox, width, height, textBoxScale, rotateWithMap, pitchWithMap, textPixelRatio, posMatrix, collisionGroup, overlapMode, symbolInstance, bucket, orientation, variableIconBox, getElevation);
40395
- if (result) {
40396
- placedBox = result.placedGlyphBoxes;
40397
- if (placedBox && placedBox.box && placedBox.box.length) {
40398
- placeText = true;
40399
- shift = result.shift;
40400
- break;
40632
+ let placementPasses = (textOverlapMode === 'never') ? 1 : 2;
40633
+ let overlapMode = 'never';
40634
+ if (prevAnchor) {
40635
+ placementPasses++;
40636
+ }
40637
+ for (let pass = 0; pass < placementPasses; pass++) {
40638
+ for (let i = textAnchorOffsetStart; i < textAnchorOffsetEnd; i++) {
40639
+ const textAnchorOffset = bucket.textAnchorOffsets.get(i);
40640
+ if (prevAnchor && textAnchorOffset.textAnchor !== prevAnchor) {
40641
+ continue;
40401
40642
  }
40643
+ const result = this.attemptAnchorPlacement(textAnchorOffset, collisionTextBox, width, height, textBoxScale, rotateWithMap, pitchWithMap, textPixelRatio, posMatrix, collisionGroup, overlapMode, symbolInstance, bucket, orientation, variableIconBox, getElevation);
40644
+ if (result) {
40645
+ placedBox = result.placedGlyphBoxes;
40646
+ if (placedBox && placedBox.box && placedBox.box.length) {
40647
+ placeText = true;
40648
+ shift = result.shift;
40649
+ return placedBox;
40650
+ }
40651
+ }
40652
+ }
40653
+ if (prevAnchor) {
40654
+ prevAnchor = null;
40655
+ }
40656
+ else {
40657
+ overlapMode = textOverlapMode;
40402
40658
  }
40403
40659
  }
40404
40660
  return placedBox;
@@ -40670,11 +40926,12 @@ class Placement {
40670
40926
  bucket.iconCollisionBox.collisionVertexArray.clear();
40671
40927
  if (bucket.hasTextCollisionBoxData())
40672
40928
  bucket.textCollisionBox.collisionVertexArray.clear();
40673
- const layout = bucket.layers[0].layout;
40929
+ const layer = bucket.layers[0];
40930
+ const layout = layer.layout;
40674
40931
  const duplicateOpacityState = new JointOpacityState(null, 0, false, false, true);
40675
40932
  const textAllowOverlap = layout.get('text-allow-overlap');
40676
40933
  const iconAllowOverlap = layout.get('icon-allow-overlap');
40677
- const variablePlacement = layout.get('text-variable-anchor');
40934
+ const hasVariablePlacement = layer._unevaluatedLayout.hasValue('text-variable-anchor') || layer._unevaluatedLayout.hasValue('text-variable-anchor-offset');
40678
40935
  const rotateWithMap = layout.get('text-rotation-alignment') === 'map';
40679
40936
  const pitchWithMap = layout.get('text-pitch-alignment') === 'map';
40680
40937
  const hasIconTextFit = layout.get('icon-text-fit') !== 'none';
@@ -40768,7 +41025,7 @@ class Placement {
40768
41025
  let shift = new performance.Point(0, 0);
40769
41026
  if (collisionArrays.textBox || collisionArrays.verticalTextBox) {
40770
41027
  let used = true;
40771
- if (variablePlacement) {
41028
+ if (hasVariablePlacement) {
40772
41029
  const variableOffset = this.variableOffsets[crossTileID];
40773
41030
  if (variableOffset) {
40774
41031
  // This will show either the currently placed position or the last
@@ -44771,10 +45028,10 @@ function drawSymbols(painter, sourceCache, layer, coords, variableOffsets) {
44771
45028
  // Disable the stencil test so that labels aren't clipped to tile boundaries.
44772
45029
  const stencilMode = StencilMode.disabled;
44773
45030
  const colorMode = painter.colorModeForRenderPass();
44774
- const variablePlacement = layer.layout.get('text-variable-anchor');
45031
+ const hasVariablePlacement = layer._unevaluatedLayout.hasValue('text-variable-anchor') || layer._unevaluatedLayout.hasValue('text-variable-anchor-offset');
44775
45032
  //Compute variable-offsets before painting since icons and text data positioning
44776
45033
  //depend on each other in this case.
44777
- if (variablePlacement) {
45034
+ if (hasVariablePlacement) {
44778
45035
  updateVariableAnchors(coords, painter, layer, sourceCache, layer.layout.get('text-rotation-alignment'), layer.layout.get('text-pitch-alignment'), variableOffsets);
44779
45036
  }
44780
45037
  if (layer.paint.get('icon-opacity').constantOr(1) !== 0) {
@@ -44792,8 +45049,7 @@ function calculateVariableRenderShift(anchor, width, height, textOffset, textBox
44792
45049
  const { horizontalAlign, verticalAlign } = performance.getAnchorAlignment(anchor);
44793
45050
  const shiftX = -(horizontalAlign - 0.5) * width;
44794
45051
  const shiftY = -(verticalAlign - 0.5) * height;
44795
- const variableOffset = performance.evaluateVariableOffset(anchor, textOffset);
44796
- return new performance.Point((shiftX / textBoxScale + variableOffset[0]) * renderTextSize, (shiftY / textBoxScale + variableOffset[1]) * renderTextSize);
45052
+ return new performance.Point((shiftX / textBoxScale + textOffset[0]) * renderTextSize, (shiftY / textBoxScale + textOffset[1]) * renderTextSize);
44797
45053
  }
44798
45054
  function updateVariableAnchors(coords, painter, layer, sourceCache, rotationAlignment, pitchAlignment, variableOffsets) {
44799
45055
  const tr = painter.transform;
@@ -44909,7 +45165,7 @@ function drawLayerSymbols(painter, sourceCache, layer, coords, isText, translate
44909
45165
  const hasSortKey = !layer.layout.get('symbol-sort-key').isConstant();
44910
45166
  let sortFeaturesByKey = false;
44911
45167
  const depthMode = painter.depthModeForSublayer(0, DepthMode.ReadOnly);
44912
- const variablePlacement = layer.layout.get('text-variable-anchor');
45168
+ const hasVariablePlacement = layer._unevaluatedLayout.hasValue('text-variable-anchor') || layer._unevaluatedLayout.hasValue('text-variable-anchor-offset');
44913
45169
  const tileRenderState = [];
44914
45170
  for (const coord of coords) {
44915
45171
  const tile = sourceCache.getTile(coord);
@@ -44954,7 +45210,7 @@ function drawLayerSymbols(painter, sourceCache, layer, coords, isText, translate
44954
45210
  const s = pixelsToTileUnits(tile, 1, painter.transform.zoom);
44955
45211
  const labelPlaneMatrix = getLabelPlaneMatrix(coord.posMatrix, pitchWithMap, rotateWithMap, painter.transform, s);
44956
45212
  const glCoordMatrix = getGlCoordMatrix(coord.posMatrix, pitchWithMap, rotateWithMap, painter.transform, s);
44957
- const hasVariableAnchors = variablePlacement && bucket.hasTextData();
45213
+ const hasVariableAnchors = hasVariablePlacement && bucket.hasTextData();
44958
45214
  const updateTextFitIcon = layer.layout.get('icon-text-fit') !== 'none' &&
44959
45215
  hasVariableAnchors &&
44960
45216
  bucket.hasIconData();
@@ -44963,7 +45219,7 @@ function drawLayerSymbols(painter, sourceCache, layer, coords, isText, translate
44963
45219
  const rotateToLine = layer.layout.get('text-rotation-alignment') === 'map';
44964
45220
  updateLineLabels(bucket, coord.posMatrix, painter, isText, labelPlaneMatrix, glCoordMatrix, pitchWithMap, keepUpright, rotateToLine, getElevation);
44965
45221
  }
44966
- const matrix = painter.translatePosMatrix(coord.posMatrix, tile, translate, translateAnchor), uLabelPlaneMatrix = (alongLine || (isText && variablePlacement) || updateTextFitIcon) ? identityMat4 : labelPlaneMatrix, uglCoordMatrix = painter.translatePosMatrix(glCoordMatrix, tile, translate, translateAnchor, true);
45222
+ const matrix = painter.translatePosMatrix(coord.posMatrix, tile, translate, translateAnchor), uLabelPlaneMatrix = (alongLine || (isText && hasVariablePlacement) || updateTextFitIcon) ? identityMat4 : labelPlaneMatrix, uglCoordMatrix = painter.translatePosMatrix(glCoordMatrix, tile, translate, translateAnchor, true);
44967
45223
  const hasHalo = isSDF && layer.paint.get(isText ? 'text-halo-width' : 'icon-halo-width').constantOr(1) !== 0;
44968
45224
  let uniformValues;
44969
45225
  if (isSDF) {