maplibre-gl 2.2.0-pre.2 → 2.2.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 (169) hide show
  1. package/README.md +73 -8
  2. package/build/generate-debug-index-file.ts +19 -0
  3. package/build/generate-style-code.ts +6 -1
  4. package/build/generate-style-spec.ts +151 -35
  5. package/build/rollup_plugins.ts +4 -1
  6. package/dist/maplibre-gl-csp-worker.js +1 -1
  7. package/dist/maplibre-gl-csp-worker.js.map +1 -1
  8. package/dist/maplibre-gl-csp.js +1 -1
  9. package/dist/maplibre-gl-csp.js.map +1 -1
  10. package/dist/maplibre-gl-dev.js +1317 -4304
  11. package/dist/maplibre-gl.css +1 -1
  12. package/dist/maplibre-gl.d.ts +443 -145
  13. package/dist/maplibre-gl.js +4 -4
  14. package/dist/maplibre-gl.js.map +1 -1
  15. package/package.json +70 -67
  16. package/src/css/maplibre-gl.css +48 -32
  17. package/src/data/bucket/fill_bucket.test.ts +1 -0
  18. package/src/data/bucket/symbol_bucket.test.ts +2 -0
  19. package/src/data/bucket/symbol_bucket.ts +1 -1
  20. package/src/data/evaluation_feature.ts +1 -1
  21. package/src/data/program_configuration.ts +2 -2
  22. package/src/geo/transform.test.ts +34 -1
  23. package/src/geo/transform.ts +25 -15
  24. package/src/gl/vertex_buffer.ts +4 -4
  25. package/src/index.ts +1 -1
  26. package/src/render/draw_debug.ts +1 -1
  27. package/src/render/draw_symbol.test.ts +2 -23
  28. package/src/render/draw_terrain.ts +1 -1
  29. package/src/render/image_atlas.ts +1 -0
  30. package/src/render/image_manager.ts +1 -0
  31. package/src/render/program/debug_program.ts +1 -1
  32. package/src/render/render_to_texture.ts +3 -0
  33. package/src/render/terrain.test.ts +119 -17
  34. package/src/render/terrain.ts +39 -21
  35. package/src/shaders/README.md +2 -2
  36. package/src/shaders/shaders.ts +3 -1
  37. package/src/source/geojson_worker_source.test.ts +2 -2
  38. package/src/source/geojson_wrapper.test.ts +1 -1
  39. package/src/source/image_source.test.ts +8 -8
  40. package/src/source/image_source.ts +1 -1
  41. package/src/source/load_tilejson.ts +6 -1
  42. package/src/source/pixels_to_tile_units.ts +1 -1
  43. package/src/source/raster_tile_source.test.ts +1 -1
  44. package/src/source/source_cache.test.ts +12 -12
  45. package/src/source/source_cache.ts +1 -1
  46. package/src/source/terrain_source_cache.test.ts +17 -2
  47. package/src/source/terrain_source_cache.ts +16 -12
  48. package/src/source/vector_tile_source.test.ts +1 -1
  49. package/src/source/vector_tile_worker_source.test.ts +1 -1
  50. package/src/source/video_source.test.ts +2 -2
  51. package/src/style/light.test.ts +1 -1
  52. package/src/style/load_sprite.ts +1 -1
  53. package/src/style/parse_glyph_pbf.ts +1 -1
  54. package/src/style/style.test.ts +3 -3
  55. package/src/style/style.ts +2 -2
  56. package/src/style/style_layer/background_style_layer_properties.g.ts +1 -0
  57. package/src/style/style_layer/circle_style_layer_properties.g.ts +1 -0
  58. package/src/style/style_layer/fill_extrusion_style_layer_properties.g.ts +1 -0
  59. package/src/style/style_layer/fill_style_layer_properties.g.ts +1 -0
  60. package/src/style/style_layer/heatmap_style_layer_properties.g.ts +1 -0
  61. package/src/style/style_layer/hillshade_style_layer_properties.g.ts +1 -0
  62. package/src/style/style_layer/line_style_layer_properties.g.ts +1 -0
  63. package/src/style/style_layer/raster_style_layer_properties.g.ts +1 -0
  64. package/src/style/style_layer/symbol_style_layer.ts +16 -1
  65. package/src/style/style_layer/symbol_style_layer_properties.g.ts +4 -3
  66. package/src/style-spec/CHANGELOG.md +5 -0
  67. package/src/style-spec/composite.test.ts +2 -0
  68. package/src/style-spec/composite.ts +3 -2
  69. package/src/style-spec/diff.test.ts +3 -3
  70. package/src/style-spec/empty.ts +3 -2
  71. package/src/style-spec/expression/compound_expression.ts +0 -4
  72. package/src/style-spec/expression/definitions/assertion.ts +0 -18
  73. package/src/style-spec/expression/definitions/at.ts +0 -4
  74. package/src/style-spec/expression/definitions/case.ts +0 -6
  75. package/src/style-spec/expression/definitions/coalesce.ts +0 -6
  76. package/src/style-spec/expression/definitions/coercion.ts +13 -18
  77. package/src/style-spec/expression/definitions/collator.ts +0 -10
  78. package/src/style-spec/expression/definitions/comparison.ts +0 -6
  79. package/src/style-spec/expression/definitions/format.ts +0 -19
  80. package/src/style-spec/expression/definitions/image.ts +0 -4
  81. package/src/style-spec/expression/definitions/in.ts +0 -4
  82. package/src/style-spec/expression/definitions/index_of.ts +0 -8
  83. package/src/style-spec/expression/definitions/interpolate.ts +1 -25
  84. package/src/style-spec/expression/definitions/length.ts +0 -6
  85. package/src/style-spec/expression/definitions/let.ts +0 -9
  86. package/src/style-spec/expression/definitions/literal.ts +1 -23
  87. package/src/style-spec/expression/definitions/match.ts +0 -41
  88. package/src/style-spec/expression/definitions/number_format.ts +0 -17
  89. package/src/style-spec/expression/definitions/slice.ts +0 -8
  90. package/src/style-spec/expression/definitions/step.ts +0 -11
  91. package/src/style-spec/expression/definitions/var.ts +0 -4
  92. package/src/style-spec/expression/definitions/within.ts +0 -5
  93. package/src/style-spec/expression/expression.test.ts +1 -1
  94. package/src/style-spec/expression/expression.ts +3 -3
  95. package/src/style-spec/expression/index.ts +8 -2
  96. package/src/style-spec/expression/parsing_context.ts +2 -0
  97. package/src/style-spec/expression/types/formatted.ts +0 -23
  98. package/src/style-spec/expression/types/resolved_image.ts +0 -4
  99. package/src/style-spec/expression/types.ts +6 -1
  100. package/src/style-spec/expression/values.ts +9 -4
  101. package/src/style-spec/feature_filter/convert.ts +65 -65
  102. package/src/style-spec/feature_filter/feature_filter.test.ts +45 -4
  103. package/src/style-spec/feature_filter/index.ts +2 -1
  104. package/src/style-spec/function/index.test.ts +117 -1
  105. package/src/style-spec/function/index.ts +24 -12
  106. package/src/style-spec/migrate/expressions.ts +2 -2
  107. package/src/style-spec/migrate/v8.test.ts +2 -0
  108. package/src/style-spec/migrate/v8.ts +8 -7
  109. package/src/style-spec/migrate/v9.test.ts +6 -4
  110. package/src/style-spec/migrate/v9.ts +3 -2
  111. package/src/style-spec/migrate.test.ts +3 -1
  112. package/src/style-spec/migrate.ts +5 -4
  113. package/src/style-spec/package.json +1 -1
  114. package/src/style-spec/read_style.ts +2 -1
  115. package/src/style-spec/reference/latest.ts +1 -1
  116. package/src/style-spec/reference/v8.json +9 -6
  117. package/src/style-spec/style-spec.test.ts +2 -1
  118. package/src/style-spec/style-spec.ts +8 -0
  119. package/src/style-spec/types.g.ts +152 -36
  120. package/src/style-spec/util/extend.ts +1 -1
  121. package/src/style-spec/util/interpolate.test.ts +5 -0
  122. package/src/style-spec/util/interpolate.ts +12 -0
  123. package/src/style-spec/util/padding.test.ts +27 -0
  124. package/src/style-spec/util/padding.ts +64 -0
  125. package/src/style-spec/util/ref_properties.ts +2 -1
  126. package/src/style-spec/validate/validate.ts +3 -1
  127. package/src/style-spec/validate/validate_expression.ts +2 -1
  128. package/src/style-spec/validate/validate_function.ts +2 -2
  129. package/src/style-spec/validate/validate_glyphs_url.ts +1 -1
  130. package/src/style-spec/validate/validate_object.ts +2 -2
  131. package/src/style-spec/validate/validate_padding.test.ts +82 -0
  132. package/src/style-spec/validate/validate_padding.ts +36 -0
  133. package/src/style-spec/validate_style.min.ts +4 -3
  134. package/src/style-spec/validate_style.ts +4 -3
  135. package/src/symbol/check_max_angle.test.ts +5 -5
  136. package/src/symbol/collision_feature.test.ts +22 -5
  137. package/src/symbol/collision_feature.ts +7 -5
  138. package/src/symbol/collision_index.ts +1 -1
  139. package/src/symbol/get_anchors.test.ts +4 -4
  140. package/src/symbol/{mergelines.test.ts → merge_lines.test.ts} +1 -1
  141. package/src/symbol/{mergelines.ts → merge_lines.ts} +1 -1
  142. package/src/symbol/projection.ts +1 -1
  143. package/src/symbol/quads.test.ts +1 -1
  144. package/src/symbol/shaping.ts +10 -10
  145. package/src/symbol/symbol_layout.ts +5 -4
  146. package/src/symbol/symbol_style_layer.test.ts +1 -1
  147. package/src/symbol/transform_text.ts +3 -3
  148. package/src/ui/camera.test.ts +11 -11
  149. package/src/ui/control/geolocate_control.ts +1 -1
  150. package/src/ui/control/terrain_control.ts +4 -4
  151. package/src/ui/handler/cooperative_gestures.test.ts +167 -0
  152. package/src/ui/handler/drag_pan.test.ts +2 -1
  153. package/src/ui/handler/scroll_zoom.ts +7 -0
  154. package/src/ui/handler/touch_pan.ts +22 -2
  155. package/src/ui/handler/touch_zoom_rotate.ts +18 -1
  156. package/src/ui/handler_manager.ts +2 -2
  157. package/src/ui/map.test.ts +17 -17
  158. package/src/ui/map.ts +76 -8
  159. package/src/ui/map_events.test.ts +33 -32
  160. package/src/ui/popup.test.ts +2 -2
  161. package/src/util/ajax.test.ts +5 -5
  162. package/src/util/ajax.ts +1 -1
  163. package/src/util/classify_rings.test.ts +27 -27
  164. package/src/util/find_pole_of_inaccessibility.ts +1 -1
  165. package/src/util/primitives.ts +4 -4
  166. package/src/util/resolve_tokens.test.ts +1 -1
  167. package/src/util/smart_wrap.ts +1 -1
  168. package/src/util/tile_request_cache.test.ts +5 -5
  169. package/src/util/util.test.ts +5 -5
@@ -4,14 +4,14 @@ import Anchor from './anchor';
4
4
 
5
5
  describe('checkMaxAngle', () => {
6
6
  test('line with no sharp angles', () => {
7
- const line = [ new Point(0, 0), new Point(20, -1), new Point(40, 1), new Point(60, 0) ];
7
+ const line = [new Point(0, 0), new Point(20, -1), new Point(40, 1), new Point(60, 0)];
8
8
  const anchor = new Anchor(30, 0, 0, 1);
9
9
  expect(checkMaxAngle(line, anchor, 25, 20, Math.PI / 8)).toBeTruthy();
10
10
  expect(checkMaxAngle(line, anchor, 25, 20, 0)).toBeFalsy();
11
11
  });
12
12
 
13
13
  test('one sharp corner', () => {
14
- const line = [ new Point(0, 0), new Point(0, 10), new Point(10, 10) ];
14
+ const line = [new Point(0, 0), new Point(0, 10), new Point(10, 10)];
15
15
  const anchor = new Anchor(0, 10, 0, 1);
16
16
  expect(checkMaxAngle(line, anchor, 10, 5, Math.PI / 2)).toBeTruthy();
17
17
  expect(checkMaxAngle(line, anchor, 10, 5, Math.PI / 2 - 0.01)).toBeFalsy();
@@ -27,20 +27,20 @@ describe('checkMaxAngle', () => {
27
27
  });
28
28
 
29
29
  test('label appears on the first line segment', () => {
30
- const line = [ new Point(0, 0), new Point(100, 0) ];
30
+ const line = [new Point(0, 0), new Point(100, 0)];
31
31
  const anchor = new Anchor(50, 0, 0, 0);
32
32
  expect(checkMaxAngle(line, anchor, 30, 5, Math.PI / 2)).toBeTruthy();
33
33
  });
34
34
 
35
35
  test('not enough space before the end of the line', () => {
36
- const line = [ new Point(0, 0), new Point(10, 0), new Point(20, 0), new Point(30, 0) ];
36
+ const line = [new Point(0, 0), new Point(10, 0), new Point(20, 0), new Point(30, 0)];
37
37
  const anchor = new Anchor(5, 0, 0, 0);
38
38
  expect(checkMaxAngle(line, anchor, 11, 5, Math.PI)).toBeFalsy();
39
39
  expect(checkMaxAngle(line, anchor, 10, 5, Math.PI)).toBeTruthy();
40
40
  });
41
41
 
42
42
  test('not enough space after the beginning of the line', () => {
43
- const line = [ new Point(0, 0), new Point(10, 0), new Point(20, 0), new Point(30, 0) ];
43
+ const line = [new Point(0, 0), new Point(10, 0), new Point(20, 0), new Point(30, 0)];
44
44
  const anchor = new Anchor(25, 0, 0, 2);
45
45
  expect(checkMaxAngle(line, anchor, 11, 5, Math.PI)).toBeFalsy();
46
46
  expect(checkMaxAngle(line, anchor, 10, 5, Math.PI)).toBeTruthy();
@@ -2,6 +2,7 @@ import CollisionFeature from './collision_feature';
2
2
  import Anchor from './anchor';
3
3
  import Point from '@mapbox/point-geometry';
4
4
  import {CollisionBoxArray} from '../data/array_types.g';
5
+ import {SymbolPadding} from '../style/style_layer/symbol_style_layer';
5
6
 
6
7
  describe('CollisionFeature', () => {
7
8
 
@@ -14,11 +15,13 @@ describe('CollisionFeature', () => {
14
15
  bottom: 10
15
16
  };
16
17
 
18
+ const padding: SymbolPadding = [0, 0, 0, 0];
19
+
17
20
  test('point label', () => {
18
21
  const point = new Point(500, 0);
19
22
  const anchor = new Anchor(point.x, point.y, 0, undefined);
20
23
 
21
- const cf = new CollisionFeature(collisionBoxArray, anchor, 0, 0, 0, shapedText, 1, 0, false, 0);
24
+ const cf = new CollisionFeature(collisionBoxArray, anchor, 0, 0, 0, shapedText, 1, padding, false, 0);
22
25
  expect(cf.circleDiameter).toBeFalsy();
23
26
  expect(cf.boxEndIndex - cf.boxStartIndex).toBe(1);
24
27
 
@@ -29,9 +32,23 @@ describe('CollisionFeature', () => {
29
32
  expect(box.y2).toBe(10);
30
33
  });
31
34
 
35
+ test('point label with padding', () => {
36
+ const point = new Point(500, 0);
37
+ const anchor = new Anchor(point.x, point.y, 0, undefined);
38
+ const pointPadding: SymbolPadding = [10, 20, -5, -10]; // top, right, bottom, left
39
+ const cf = new CollisionFeature(collisionBoxArray, anchor, 0, 0, 0, shapedText, 1, pointPadding, false, 0);
40
+
41
+ expect(cf.boxEndIndex - cf.boxStartIndex).toBe(1);
42
+ const box = collisionBoxArray.get(cf.boxStartIndex);
43
+ expect(box.x1).toBe(-40);
44
+ expect(box.x2).toBe(70);
45
+ expect(box.y1).toBe(-20);
46
+ expect(box.y2).toBe(5);
47
+ });
48
+
32
49
  test('Compute line height for runtime collision circles (line label)', () => {
33
50
  const anchor = new Anchor(505, 95, 0, 1);
34
- const cf = new CollisionFeature(collisionBoxArray, anchor, 0, 0, 0, shapedText, 1, 0, true, 0);
51
+ const cf = new CollisionFeature(collisionBoxArray, anchor, 0, 0, 0, shapedText, 1, padding, true, 0);
35
52
  expect(cf.circleDiameter).toBeTruthy();
36
53
  expect(cf.circleDiameter).toBe(shapedText.bottom - shapedText.top);
37
54
  expect(cf.boxEndIndex - cf.boxStartIndex).toBe(0);
@@ -46,7 +63,7 @@ describe('CollisionFeature', () => {
46
63
  };
47
64
 
48
65
  const anchor = new Anchor(505, 95, 0, 1);
49
- const cf = new CollisionFeature(collisionBoxArray, anchor, 0, 0, 0, shapedText, 1, 0, true, 0);
66
+ const cf = new CollisionFeature(collisionBoxArray, anchor, 0, 0, 0, shapedText, 1, padding, true, 0);
50
67
  expect(cf.boxEndIndex - cf.boxStartIndex).toBe(0);
51
68
  expect(cf.circleDiameter).toBeFalsy();
52
69
  });
@@ -60,7 +77,7 @@ describe('CollisionFeature', () => {
60
77
  };
61
78
 
62
79
  const anchor = new Anchor(505, 95, 0, 1);
63
- const cf = new CollisionFeature(collisionBoxArray, anchor, 0, 0, 0, shapedText, 1, 0, true, 0);
80
+ const cf = new CollisionFeature(collisionBoxArray, anchor, 0, 0, 0, shapedText, 1, padding, true, 0);
64
81
  expect(cf.boxEndIndex - cf.boxStartIndex).toBe(0);
65
82
  expect(cf.circleDiameter).toBeFalsy();
66
83
  });
@@ -74,7 +91,7 @@ describe('CollisionFeature', () => {
74
91
  };
75
92
 
76
93
  const anchor = new Anchor(505, 95, 0, 1);
77
- const cf = new CollisionFeature(collisionBoxArray, anchor, 0, 0, 0, shapedText, 1, 0, true, 0);
94
+ const cf = new CollisionFeature(collisionBoxArray, anchor, 0, 0, 0, shapedText, 1, padding, true, 0);
78
95
  expect(cf.boxEndIndex - cf.boxStartIndex).toBe(0);
79
96
  expect(cf.circleDiameter).toBe(10);
80
97
  });
@@ -1,6 +1,7 @@
1
1
  import type {CollisionBoxArray} from '../data/array_types.g';
2
2
  import Point from '@mapbox/point-geometry';
3
3
  import type Anchor from './anchor';
4
+ import {SymbolPadding} from '../style/style_layer/symbol_style_layer';
4
5
 
5
6
  /**
6
7
  * A CollisionFeature represents the area of the tile covered by a single label.
@@ -33,7 +34,7 @@ class CollisionFeature {
33
34
  bucketIndex: number,
34
35
  shaped: any,
35
36
  boxScale: number,
36
- padding: number,
37
+ padding: SymbolPadding,
37
38
  alignLine: boolean,
38
39
  rotate: number) {
39
40
 
@@ -59,10 +60,11 @@ class CollisionFeature {
59
60
  this.circleDiameter = height;
60
61
  }
61
62
  } else {
62
- let y1 = shaped.top * boxScale - padding;
63
- let y2 = shaped.bottom * boxScale + padding;
64
- let x1 = shaped.left * boxScale - padding;
65
- let x2 = shaped.right * boxScale + padding;
63
+ // margin is in CSS order: [top, right, bottom, left]
64
+ let y1 = shaped.top * boxScale - padding[0];
65
+ let y2 = shaped.bottom * boxScale + padding[2];
66
+ let x1 = shaped.left * boxScale - padding[3];
67
+ let x2 = shaped.right * boxScale + padding[1];
66
68
 
67
69
  const collisionPadding = shaped.collisionPadding;
68
70
  if (collisionPadding) {
@@ -364,7 +364,7 @@ class CollisionIndex {
364
364
  }
365
365
  }
366
366
 
367
- projectAndGetPerspectiveRatio(posMatrix: mat4, x: number, y: number, getElevation: (x: number, y: number) => number) {
367
+ projectAndGetPerspectiveRatio(posMatrix: mat4, x: number, y: number, getElevation?: (x: number, y: number) => number) {
368
368
  let p;
369
369
  if (getElevation) { // slow because of handle z-index
370
370
  p = [x, y, getElevation(x, y), 1] as vec4;
@@ -32,7 +32,7 @@ describe('getAnchors', () => {
32
32
  expect(anchors).toEqual([
33
33
  {x: 1, y: 2, angle: 1.5707963267948966, segment: 1},
34
34
  {x: 1, y: 5, angle: 1.5707963267948966, segment: 4},
35
- {x: 1, y: 8, angle: 1.5707963267948966, segment: 7} ]);
35
+ {x: 1, y: 8, angle: 1.5707963267948966, segment: 7}]);
36
36
 
37
37
  expect(
38
38
  labelLength / 2 + 1 <= anchors[0].y && anchors[0].y < labelLength / 2 + 3 * glyphSize + 1
@@ -46,7 +46,7 @@ describe('getAnchors', () => {
46
46
  expect(anchors).toEqual([
47
47
  {x: 1, y: 2, angle: 1.5707963267948966, segment: 1},
48
48
  {x: 1, y: 5, angle: 1.5707963267948966, segment: 3},
49
- {x: 1, y: 7, angle: 1.5707963267948966, segment: 6} ]);
49
+ {x: 1, y: 7, angle: 1.5707963267948966, segment: 6}]);
50
50
 
51
51
  });
52
52
 
@@ -56,7 +56,7 @@ describe('getAnchors', () => {
56
56
  expect(anchors).toEqual([
57
57
  {x: 1, y: 2, angle: 1.5707963267948966, segment: 1},
58
58
  {x: 1, y: 5, angle: 1.5707963267948966, segment: 4},
59
- {x: 1, y: 8, angle: 1.5707963267948966, segment: 7} ]);
59
+ {x: 1, y: 8, angle: 1.5707963267948966, segment: 7}]);
60
60
 
61
61
  });
62
62
 
@@ -66,7 +66,7 @@ describe('getAnchors', () => {
66
66
  expect(anchors).toEqual([
67
67
  {x: 1, y: 1, angle: 1.5707963267948966, segment: 1},
68
68
  {x: 1, y: 4, angle: 1.5707963267948966, segment: 3},
69
- {x: 1, y: 6, angle: 1.5707963267948966, segment: 6} ]);
69
+ {x: 1, y: 6, angle: 1.5707963267948966, segment: 6}]);
70
70
 
71
71
  });
72
72
 
@@ -1,4 +1,4 @@
1
- import mergeLines from './mergelines';
1
+ import mergeLines from './merge_lines';
2
2
  import Point from '@mapbox/point-geometry';
3
3
 
4
4
  function makeFeatures(lines) {
@@ -1,6 +1,6 @@
1
1
  import type {SymbolFeature} from '../data/bucket/symbol_bucket';
2
2
 
3
- export default function(features: Array<SymbolFeature>): Array<SymbolFeature> {
3
+ export default function mergeLines(features: Array<SymbolFeature>): Array<SymbolFeature> {
4
4
  const leftIndex: {[_: string]: number} = {};
5
5
  const rightIndex: {[_: string]: number} = {};
6
6
  const mergedFeatures = [];
@@ -101,7 +101,7 @@ function getGlCoordMatrix(posMatrix: mat4,
101
101
  }
102
102
  }
103
103
 
104
- function project(point: Point, matrix: mat4, getElevation: (x: number, y: number) => number) {
104
+ function project(point: Point, matrix: mat4, getElevation?: (x: number, y: number) => number) {
105
105
  let pos;
106
106
  if (getElevation) { // slow because of handle z-index
107
107
  pos = [point.x, point.y, getElevation(point.x, point.y), 1] as vec4;
@@ -4,7 +4,7 @@ import {getIconQuads} from './quads';
4
4
  describe('getIconQuads', () => {
5
5
  const image = Object.freeze({
6
6
  pixelRatio: 1,
7
- displaySize: Object.freeze([ 15, 11 ]),
7
+ displaySize: Object.freeze([15, 11]),
8
8
  paddedRect: Object.freeze({x: 0, y: 0, w: 17, h: 13})
9
9
  }) as ImagePosition;
10
10
 
@@ -340,16 +340,16 @@ const whitespace: {
340
340
  const breakable: {
341
341
  [_: number]: boolean;
342
342
  } = {
343
- [0x0a]: true, // newline
344
- [0x20]: true, // space
345
- [0x26]: true, // ampersand
346
- [0x28]: true, // left parenthesis
347
- [0x29]: true, // right parenthesis
348
- [0x2b]: true, // plus sign
349
- [0x2d]: true, // hyphen-minus
350
- [0x2f]: true, // solidus
351
- [0xad]: true, // soft hyphen
352
- [0xb7]: true, // middle dot
343
+ [0x0a]: true, // newline
344
+ [0x20]: true, // space
345
+ [0x26]: true, // ampersand
346
+ [0x28]: true, // left parenthesis
347
+ [0x29]: true, // right parenthesis
348
+ [0x2b]: true, // plus sign
349
+ [0x2d]: true, // hyphen-minus
350
+ [0x2f]: true, // solidus
351
+ [0xad]: true, // soft hyphen
352
+ [0xb7]: true, // middle dot
353
353
  [0x200b]: true, // zero-width space
354
354
  [0x2010]: true, // hyphen
355
355
  [0x2013]: true, // en dash
@@ -30,6 +30,7 @@ import type {PossiblyEvaluatedPropertyValue} from '../style/properties';
30
30
 
31
31
  import Point from '@mapbox/point-geometry';
32
32
  import murmur3 from 'murmurhash-js';
33
+ import {getIconPadding, SymbolPadding} from '../style/style_layer/symbol_style_layer';
33
34
 
34
35
  // The symbol layout process needs `text-size` evaluated at up to five different zoom levels, and
35
36
  // `icon-size` at up to three:
@@ -393,7 +394,7 @@ function addFeature(bucket: SymbolBucket,
393
394
  iconBoxScale = bucket.tilePixelRatio * layoutIconSize,
394
395
  symbolMinDistance = bucket.tilePixelRatio * layout.get('symbol-spacing'),
395
396
  textPadding = layout.get('text-padding') * bucket.tilePixelRatio,
396
- iconPadding = layout.get('icon-padding') * bucket.tilePixelRatio,
397
+ iconPadding = getIconPadding(layout, feature, canonical, bucket.tilePixelRatio),
397
398
  textMaxAngle = layout.get('text-max-angle') / 180 * Math.PI,
398
399
  textAlongLine = layout.get('text-rotation-alignment') !== 'viewport' && layout.get('symbol-placement') !== 'point',
399
400
  iconAlongLine = layout.get('icon-rotation-alignment') === 'map' && layout.get('symbol-placement') !== 'point',
@@ -424,7 +425,7 @@ function addFeature(bucket: SymbolBucket,
424
425
 
425
426
  addSymbol(bucket, anchor, line, shapedTextOrientations, shapedIcon, imageMap, verticallyShapedIcon, bucket.layers[0],
426
427
  bucket.collisionBoxArray, feature.index, feature.sourceLayerIndex, bucket.index,
427
- textBoxScale, textPadding, textAlongLine, textOffset,
428
+ textBoxScale, [textPadding, textPadding, textPadding, textPadding], textAlongLine, textOffset,
428
429
  iconBoxScale, iconPadding, iconAlongLine, iconOffset,
429
430
  feature, sizes, isSDFIcon, canonical, layoutTextSize);
430
431
  };
@@ -583,11 +584,11 @@ function addSymbol(bucket: SymbolBucket,
583
584
  sourceLayerIndex: number,
584
585
  bucketIndex: number,
585
586
  textBoxScale: number,
586
- textPadding: number,
587
+ textPadding: SymbolPadding,
587
588
  textAlongLine: boolean,
588
589
  textOffset: [number, number],
589
590
  iconBoxScale: number,
590
- iconPadding: number,
591
+ iconPadding: SymbolPadding,
591
592
  iconAlongLine: boolean,
592
593
  iconOffset: [number, number],
593
594
  feature: SymbolFeature,
@@ -67,7 +67,7 @@ describe('hasPaintOverrides', () => {
67
67
  });
68
68
 
69
69
  test('format expression, overriden text-color', () => {
70
- const props = {layout: {'text-field': ['format', ['get', 'name'], {'text-color':'red'}]}};
70
+ const props = {layout: {'text-field': ['format', ['get', 'name'], {'text-color': 'red'}]}};
71
71
  const layer = createSymbolLayer(props);
72
72
  expect(SymbolStyleLayer.hasPaintOverride(layer.layout, 'text-color')).toBe(true);
73
73
 
@@ -4,7 +4,7 @@ import type SymbolStyleLayer from '../style/style_layer/symbol_style_layer';
4
4
  import type {Feature} from '../style-spec/expression';
5
5
  import Formatted from '../style-spec/expression/types/formatted';
6
6
 
7
- function transformText(text: string, layer: SymbolStyleLayer, feature: Feature) {
7
+ function transformTextInternal(text: string, layer: SymbolStyleLayer, feature: Feature) {
8
8
  const transform = layer.layout.get('text-transform').evaluate(feature, {});
9
9
  if (transform === 'uppercase') {
10
10
  text = text.toLocaleUpperCase();
@@ -19,9 +19,9 @@ function transformText(text: string, layer: SymbolStyleLayer, feature: Feature)
19
19
  return text;
20
20
  }
21
21
 
22
- export default function(text: Formatted, layer: SymbolStyleLayer, feature: Feature): Formatted {
22
+ export default function transformText(text: Formatted, layer: SymbolStyleLayer, feature: Feature): Formatted {
23
23
  text.sections.forEach(section => {
24
- section.text = transformText(section.text, layer, feature);
24
+ section.text = transformTextInternal(section.text, layer, feature);
25
25
  });
26
26
  return text;
27
27
  }
@@ -926,17 +926,17 @@ describe('#flyTo', () => {
926
926
  });
927
927
 
928
928
  test('does not throw when cameras current zoom is sufficiently greater than passed zoom option', () => {
929
- const camera = createCamera({zoom: 22, center:[0, 0]});
930
- expect(() => camera.flyTo({zoom:10, center:[0, 0]})).not.toThrow();
929
+ const camera = createCamera({zoom: 22, center: [0, 0]});
930
+ expect(() => camera.flyTo({zoom: 10, center: [0, 0]})).not.toThrow();
931
931
  });
932
932
 
933
933
  test('does not throw when cameras current zoom is above maxzoom and an offset creates infinite zoom out factor', () => {
934
934
  const transform = new Transform(0, 20.9999, 0, 60, true);
935
935
  transform.resize(512, 512);
936
936
  const camera = attachSimulateFrame(new CameraMock(transform, {} as any))
937
- .jumpTo({zoom: 21, center:[0, 0]});
937
+ .jumpTo({zoom: 21, center: [0, 0]});
938
938
  camera._update = () => {};
939
- expect(() => camera.flyTo({zoom:7.5, center:[0, 0], offset:[0, 70]})).not.toThrow();
939
+ expect(() => camera.flyTo({zoom: 7.5, center: [0, 0], offset: [0, 70]})).not.toThrow();
940
940
  });
941
941
 
942
942
  test('zooms to specified level', () => {
@@ -1798,7 +1798,7 @@ describe('#fitBounds', () => {
1798
1798
  test('no padding passed', () => {
1799
1799
  const camera = createCamera();
1800
1800
  const bb = [[-133, 16], [-68, 50]];
1801
- camera.fitBounds(bb, {duration:0});
1801
+ camera.fitBounds(bb, {duration: 0});
1802
1802
 
1803
1803
  expect(fixedLngLat(camera.getCenter(), 4)).toEqual({lng: -100.5, lat: 34.7171});
1804
1804
  expect(fixedNum(camera.getZoom(), 3)).toBe(2.469);
@@ -1807,7 +1807,7 @@ describe('#fitBounds', () => {
1807
1807
  test('padding number', () => {
1808
1808
  const camera = createCamera();
1809
1809
  const bb = [[-133, 16], [-68, 50]];
1810
- camera.fitBounds(bb, {padding: 15, duration:0});
1810
+ camera.fitBounds(bb, {padding: 15, duration: 0});
1811
1811
 
1812
1812
  expect(fixedLngLat(camera.getCenter(), 4)).toEqual({lng: -100.5, lat: 34.7171});
1813
1813
  expect(fixedNum(camera.getZoom(), 3)).toBe(2.382);
@@ -1816,7 +1816,7 @@ describe('#fitBounds', () => {
1816
1816
  test('padding object', () => {
1817
1817
  const camera = createCamera();
1818
1818
  const bb = [[-133, 16], [-68, 50]];
1819
- camera.fitBounds(bb, {padding: {top: 10, right: 75, bottom: 50, left: 25}, duration:0});
1819
+ camera.fitBounds(bb, {padding: {top: 10, right: 75, bottom: 50, left: 25}, duration: 0});
1820
1820
 
1821
1821
  expect(fixedLngLat(camera.getCenter(), 4)).toEqual({lng: -96.5558, lat: 32.0833});
1822
1822
  });
@@ -1824,7 +1824,7 @@ describe('#fitBounds', () => {
1824
1824
  test('padding does not get propagated to transform.padding', () => {
1825
1825
  const camera = createCamera();
1826
1826
  const bb = [[-133, 16], [-68, 50]];
1827
- camera.fitBounds(bb, {padding: {top: 10, right: 75, bottom: 50, left: 25}, duration:0});
1827
+ camera.fitBounds(bb, {padding: {top: 10, right: 75, bottom: 50, left: 25}, duration: 0});
1828
1828
  const padding = camera.transform.padding;
1829
1829
 
1830
1830
  expect(padding).toEqual({
@@ -1842,7 +1842,7 @@ describe('#fitScreenCoordinates', () => {
1842
1842
  const p0 = [128, 128];
1843
1843
  const p1 = [256, 256];
1844
1844
  const bearing = 225;
1845
- camera.fitScreenCoordinates(p0, p1, bearing, {duration:0});
1845
+ camera.fitScreenCoordinates(p0, p1, bearing, {duration: 0});
1846
1846
 
1847
1847
  expect(fixedLngLat(camera.getCenter(), 4)).toEqual({lng: -45, lat: 40.9799});
1848
1848
  expect(fixedNum(camera.getZoom(), 3)).toBe(1.5);
@@ -1854,7 +1854,7 @@ describe('#fitScreenCoordinates', () => {
1854
1854
  const p0 = [128, 128];
1855
1855
  const p1 = [256, 256];
1856
1856
  const bearing = 0;
1857
- camera.fitScreenCoordinates(p0, p1, bearing, {duration:0});
1857
+ camera.fitScreenCoordinates(p0, p1, bearing, {duration: 0});
1858
1858
 
1859
1859
  expect(fixedLngLat(camera.getCenter(), 4)).toEqual({lng: -45, lat: 40.9799});
1860
1860
  expect(fixedNum(camera.getZoom(), 3)).toBe(2);
@@ -1866,7 +1866,7 @@ describe('#fitScreenCoordinates', () => {
1866
1866
  const p1 = [128, 128];
1867
1867
  const p0 = [256, 256];
1868
1868
  const bearing = 0;
1869
- camera.fitScreenCoordinates(p0, p1, bearing, {duration:0});
1869
+ camera.fitScreenCoordinates(p0, p1, bearing, {duration: 0});
1870
1870
 
1871
1871
  expect(fixedLngLat(camera.getCenter(), 4)).toEqual({lng: -45, lat: 40.9799});
1872
1872
  expect(fixedNum(camera.getZoom(), 3)).toBe(2);
@@ -516,7 +516,7 @@ class GeolocateControl extends Evented implements IControl {
516
516
  numberOfWatches++;
517
517
  let positionOptions;
518
518
  if (numberOfWatches > 1) {
519
- positionOptions = {maximumAge:600000, timeout:0};
519
+ positionOptions = {maximumAge: 600000, timeout: 0};
520
520
  noTimeout = true;
521
521
  } else {
522
522
  positionOptions = this.options.positionOptions;
@@ -11,14 +11,16 @@ import type {TerrainSpecification} from '../../style-spec/types.g';
11
11
  * @implements {IControl}
12
12
  * @param {Object} [options]
13
13
  * @param {string} [options.id] The ID of the raster-dem source to use.
14
- * @param {exaggeration: number; elevationOffset: number} [options.options] Allowed options are exaggeration: number; elevationOffset: number
14
+ * @param {Object} [options.options]
15
+ * @param {number} [options.options.elevationOffset]
16
+ * @param {number} [options.options.exaggeration]
15
17
  * @example
16
18
  * var map = new maplibregl.Map({TerrainControl: false})
17
19
  * .addControl(new maplibregl.TerrainControl({
18
20
  * source: "terrain"
19
21
  * }));
20
22
  */
21
- class TerrainControl implements IControl {
23
+ export default class TerrainControl implements IControl {
22
24
  options: TerrainSpecification;
23
25
  _map: Map;
24
26
  _container: HTMLElement;
@@ -73,5 +75,3 @@ class TerrainControl implements IControl {
73
75
  }
74
76
  }
75
77
  }
76
-
77
- export default TerrainControl;
@@ -0,0 +1,167 @@
1
+ import browser from '../../util/browser';
2
+ import Map from '../map';
3
+ import DOM from '../../util/dom';
4
+ import simulate from '../../../test/unit/lib/simulate_interaction';
5
+ import {setMatchMedia, setPerformance, setWebGlContext} from '../../util/test/util';
6
+
7
+ function createMap() {
8
+ return new Map({
9
+ container: DOM.create('div', '', window.document.body),
10
+ style: {
11
+ 'version': 8,
12
+ 'sources': {},
13
+ 'layers': []
14
+ },
15
+ cooperativeGestures: true
16
+ });
17
+ }
18
+
19
+ beforeEach(() => {
20
+ setPerformance();
21
+ setWebGlContext();
22
+ setMatchMedia();
23
+ });
24
+
25
+ describe('CoopGesturesHandler', () => {
26
+
27
+ test('Does not zoom on wheel if no key is down', () => {
28
+ const browserNow = jest.spyOn(browser, 'now');
29
+ let now = 1555555555555;
30
+ browserNow.mockReturnValue(now);
31
+
32
+ const map = createMap();
33
+ map._renderTaskQueue.run();
34
+
35
+ const startZoom = map.getZoom();
36
+ // simulate a single 'wheel' event
37
+ simulate.wheel(map.getCanvas(), {type: 'wheel', deltaY: -simulate.magicWheelZoomDelta});
38
+ map._renderTaskQueue.run();
39
+
40
+ now += 400;
41
+ browserNow.mockReturnValue(now);
42
+ map._renderTaskQueue.run();
43
+
44
+ const endZoom = map.getZoom();
45
+ expect(endZoom).toBeCloseTo(startZoom);
46
+
47
+ map.remove();
48
+ });
49
+
50
+ test('Zooms on wheel if control key is down', () => {
51
+ // NOTE: This should pass regardless of whether cooperativeGestures is enabled or not
52
+ const browserNow = jest.spyOn(browser, 'now');
53
+ let now = 1555555555555;
54
+ browserNow.mockReturnValue(now);
55
+
56
+ const map = createMap();
57
+ map._renderTaskQueue.run();
58
+
59
+ simulate.keydown(document, {type: 'keydown', key: 'Control'});
60
+ map._renderTaskQueue.run();
61
+
62
+ const startZoom = map.getZoom();
63
+ // simulate a single 'wheel' event
64
+ simulate.wheel(map.getCanvas(), {type: 'wheel', deltaY: -simulate.magicWheelZoomDelta});
65
+ map._renderTaskQueue.run();
66
+
67
+ now += 400;
68
+ browserNow.mockReturnValue(now);
69
+ map._renderTaskQueue.run();
70
+
71
+ const endZoom = map.getZoom();
72
+ expect(endZoom - startZoom).toBeCloseTo(0.0285, 3);
73
+
74
+ map.remove();
75
+ });
76
+
77
+ test('Does not pan on touchmove with a single touch', () => {
78
+ const map = createMap();
79
+ const target = map.getCanvas();
80
+ const startCenter = map.getCenter();
81
+ map._renderTaskQueue.run();
82
+
83
+ const dragstart = jest.fn();
84
+ const drag = jest.fn();
85
+ const dragend = jest.fn();
86
+
87
+ map.on('dragstart', dragstart);
88
+ map.on('drag', drag);
89
+ map.on('dragend', dragend);
90
+
91
+ simulate.touchstart(target, {touches: [{target, clientX: 0, clientY: 0}]});
92
+ map._renderTaskQueue.run();
93
+
94
+ simulate.touchmove(target, {touches: [{target, clientX: 10, clientY: 10}]});
95
+ map._renderTaskQueue.run();
96
+
97
+ simulate.touchend(target);
98
+ map._renderTaskQueue.run();
99
+
100
+ const endCenter = map.getCenter();
101
+ expect(endCenter.lng).toEqual(startCenter.lng);
102
+ expect(endCenter.lat).toEqual(startCenter.lat);
103
+
104
+ map.remove();
105
+ });
106
+
107
+ test('Does pan on touchmove with a double touch', () => {
108
+ // NOTE: This should pass regardless of whether cooperativeGestures is enabled or not
109
+ const map = createMap();
110
+ const target = map.getCanvas();
111
+ const startCenter = map.getCenter();
112
+ map._renderTaskQueue.run();
113
+
114
+ const dragstart = jest.fn();
115
+ const drag = jest.fn();
116
+ const dragend = jest.fn();
117
+
118
+ map.on('dragstart', dragstart);
119
+ map.on('drag', drag);
120
+ map.on('dragend', dragend);
121
+
122
+ simulate.touchstart(target, {touches: [{target, clientX: 0, clientY: 0}, {target, clientX: 1, clientY: 1}]});
123
+ map._renderTaskQueue.run();
124
+
125
+ simulate.touchmove(target, {touches: [{target, clientX: 10, clientY: 10}, {target, clientX: 11, clientY: 11}]});
126
+ map._renderTaskQueue.run();
127
+
128
+ simulate.touchend(target);
129
+ map._renderTaskQueue.run();
130
+
131
+ const endCenter = map.getCenter();
132
+ expect(endCenter.lng).toBeGreaterThan(startCenter.lng);
133
+ expect(endCenter.lat).toBeGreaterThan(startCenter.lat);
134
+
135
+ map.remove();
136
+ });
137
+
138
+ test('Drag pitch works with 3 fingers', () => {
139
+ // NOTE: This should pass regardless of whether cooperativeGestures is enabled or not
140
+ const map = createMap();
141
+ const target = map.getCanvas();
142
+ const startPitch = map.getPitch();
143
+ map._renderTaskQueue.run();
144
+
145
+ const dragstart = jest.fn();
146
+ const drag = jest.fn();
147
+ const dragend = jest.fn();
148
+
149
+ map.on('dragstart', dragstart);
150
+ map.on('drag', drag);
151
+ map.on('dragend', dragend);
152
+
153
+ simulate.touchstart(target, {touches: [{target, clientX: 0, clientY: 0}, {target, clientX: 1, clientY: 1}, {target, clientX: 2, clientY: 2}]});
154
+ map._renderTaskQueue.run();
155
+
156
+ simulate.touchmove(target, {touches: [{target, clientX: 0, clientY: -10}, {target, clientX: 1, clientY: -11}, {target, clientX: 2, clientY: -12}]});
157
+ map._renderTaskQueue.run();
158
+
159
+ simulate.touchend(target);
160
+ map._renderTaskQueue.run();
161
+
162
+ const endPitch = map.getPitch();
163
+ expect(endPitch).toBeGreaterThan(startPitch);
164
+
165
+ map.remove();
166
+ });
167
+ });
@@ -2,6 +2,7 @@ import DOM from '../../util/dom';
2
2
  import simulate from '../../../test/unit/lib/simulate_interaction';
3
3
  import {setMatchMedia, setPerformance, setWebGlContext} from '../../util/test/util';
4
4
  import Map, {MapOptions} from '../map';
5
+ import type {MapGeoJSONFeature} from '../../util/vectortile_to_geojson';
5
6
 
6
7
  function createMap(clickTolerance?, dragPan?) {
7
8
  return new Map({
@@ -456,7 +457,7 @@ describe('drag_pan', () => {
456
457
  const target = map.getCanvas();
457
458
 
458
459
  jest.spyOn(map, 'getLayer').mockReturnValue(true as any);
459
- jest.spyOn(map, 'queryRenderedFeatures').mockReturnValue([{}]);
460
+ jest.spyOn(map, 'queryRenderedFeatures').mockReturnValue([{} as MapGeoJSONFeature]);
460
461
 
461
462
  map.on('touchstart', 'point', (e) => {
462
463
  e.preventDefault();
@@ -148,6 +148,13 @@ class ScrollZoomHandler {
148
148
 
149
149
  wheel(e: WheelEvent) {
150
150
  if (!this.isEnabled()) return;
151
+ if (this._map._cooperativeGestures) {
152
+ if (this._map._metaPress) {
153
+ e.preventDefault();
154
+ } else {
155
+ return;
156
+ }
157
+ }
151
158
  let value = e.deltaMode === WheelEvent.DOM_DELTA_LINE ? e.deltaY * 40 : e.deltaY;
152
159
  const now = browser.now(),
153
160
  timeDelta = now - (this._lastWheelEventTime || 0);