maplibre-gl 3.2.2 → 3.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +1 -1
- package/README.md +2 -1
- package/build/generate-dist-package.js +7 -2
- package/build/generate-struct-arrays.ts +3 -1
- package/build/generate-style-code.ts +7 -8
- package/build/generate-typings.ts +1 -1
- package/dist/LICENSE.txt +116 -0
- package/dist/maplibre-gl-csp-worker.js +1 -1
- package/dist/maplibre-gl-csp-worker.js.map +1 -1
- package/dist/maplibre-gl-csp.js +1 -1
- package/dist/maplibre-gl-csp.js.map +1 -1
- package/dist/maplibre-gl-dev.js +472 -195
- package/dist/maplibre-gl-dev.js.map +1 -1
- package/dist/maplibre-gl.d.ts +58 -16
- package/dist/maplibre-gl.js +3 -3
- package/dist/maplibre-gl.js.map +1 -1
- package/dist/package.json +1 -1
- package/package.json +24 -23
- package/src/data/array_types.g.ts +78 -14
- package/src/data/bucket/symbol_attributes.ts +7 -1
- package/src/data/bucket/symbol_bucket.ts +4 -1
- package/src/render/draw_symbol.ts +8 -9
- package/src/render/program.ts +15 -0
- package/src/source/vector_tile_source.ts +0 -1
- package/src/source/video_source.ts +4 -0
- package/src/style/properties.ts +4 -0
- package/src/style/style.ts +14 -8
- package/src/style/style_layer/background_style_layer_properties.g.ts +1 -6
- package/src/style/style_layer/circle_style_layer_properties.g.ts +1 -6
- package/src/style/style_layer/fill_extrusion_style_layer_properties.g.ts +1 -6
- package/src/style/style_layer/fill_style_layer_properties.g.ts +1 -6
- package/src/style/style_layer/heatmap_style_layer_properties.g.ts +1 -6
- package/src/style/style_layer/hillshade_style_layer_properties.g.ts +1 -6
- package/src/style/style_layer/line_style_layer_properties.g.ts +1 -6
- package/src/style/style_layer/raster_style_layer_properties.g.ts +1 -6
- package/src/style/style_layer/symbol_style_layer_properties.g.ts +4 -6
- package/src/style/style_layer/variable_text_anchor.test.ts +117 -0
- package/src/style/style_layer/variable_text_anchor.ts +163 -0
- package/src/symbol/placement.ts +52 -40
- package/src/symbol/symbol_layout.ts +42 -116
- package/src/ui/control/navigation_control.ts +0 -1
- package/src/ui/map.test.ts +37 -8
- package/src/ui/map.ts +14 -13
- package/src/ui/marker.ts +1 -1
- package/src/ui/popup.ts +1 -1
- package/src/util/throttle.ts +7 -3
|
@@ -19,7 +19,7 @@ import {SIZE_PACK_FACTOR, MAX_PACKED_SIZE, MAX_GLYPH_ICON_SIZE} from './symbol_s
|
|
|
19
19
|
import ONE_EM from './one_em';
|
|
20
20
|
import type {CanonicalTileID} from '../source/tile_id';
|
|
21
21
|
import type {Shaping, PositionedIcon, TextJustify} from './shaping';
|
|
22
|
-
import type {CollisionBoxArray} from '../data/array_types.g';
|
|
22
|
+
import type {CollisionBoxArray, TextAnchorOffsetArray} from '../data/array_types.g';
|
|
23
23
|
import type {SymbolFeature} from '../data/bucket/symbol_bucket';
|
|
24
24
|
import type {StyleImage} from '../style/style_image';
|
|
25
25
|
import type {StyleGlyph} from '../style/style_glyph';
|
|
@@ -31,6 +31,8 @@ import type {PossiblyEvaluatedPropertyValue} from '../style/properties';
|
|
|
31
31
|
import Point from '@mapbox/point-geometry';
|
|
32
32
|
import murmur3 from 'murmurhash-js';
|
|
33
33
|
import {getIconPadding, SymbolPadding} from '../style/style_layer/symbol_style_layer';
|
|
34
|
+
import {VariableAnchorOffsetCollection} from '@maplibre/maplibre-gl-style-spec';
|
|
35
|
+
import {getTextVariableAnchorOffset, evaluateVariableOffset, INVALID_TEXT_OFFSET, TextAnchor, TextAnchorEnum} from '../style/style_layer/variable_text_anchor';
|
|
34
36
|
|
|
35
37
|
// The symbol layout process needs `text-size` evaluated at up to five different zoom levels, and
|
|
36
38
|
// `icon-size` at up to three:
|
|
@@ -59,98 +61,6 @@ type ShapedTextOrientations = {
|
|
|
59
61
|
horizontal: Record<TextJustify, Shaping>;
|
|
60
62
|
};
|
|
61
63
|
|
|
62
|
-
export type TextAnchor = 'center' | 'left' | 'right' | 'top' | 'bottom' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
63
|
-
|
|
64
|
-
// The radial offset is to the edge of the text box
|
|
65
|
-
// In the horizontal direction, the edge of the text box is where glyphs start
|
|
66
|
-
// But in the vertical direction, the glyphs appear to "start" at the baseline
|
|
67
|
-
// We don't actually load baseline data, but we assume an offset of ONE_EM - 17
|
|
68
|
-
// (see "yOffset" in shaping.js)
|
|
69
|
-
const baselineOffset = 7;
|
|
70
|
-
const INVALID_TEXT_OFFSET = Number.POSITIVE_INFINITY;
|
|
71
|
-
|
|
72
|
-
export function evaluateVariableOffset(anchor: TextAnchor, offset: [number, number]) {
|
|
73
|
-
|
|
74
|
-
function fromRadialOffset(anchor: TextAnchor, radialOffset: number) {
|
|
75
|
-
let x = 0, y = 0;
|
|
76
|
-
if (radialOffset < 0) radialOffset = 0; // Ignore negative offset.
|
|
77
|
-
// solve for r where r^2 + r^2 = radialOffset^2
|
|
78
|
-
const hypotenuse = radialOffset / Math.sqrt(2);
|
|
79
|
-
switch (anchor) {
|
|
80
|
-
case 'top-right':
|
|
81
|
-
case 'top-left':
|
|
82
|
-
y = hypotenuse - baselineOffset;
|
|
83
|
-
break;
|
|
84
|
-
case 'bottom-right':
|
|
85
|
-
case 'bottom-left':
|
|
86
|
-
y = -hypotenuse + baselineOffset;
|
|
87
|
-
break;
|
|
88
|
-
case 'bottom':
|
|
89
|
-
y = -radialOffset + baselineOffset;
|
|
90
|
-
break;
|
|
91
|
-
case 'top':
|
|
92
|
-
y = radialOffset - baselineOffset;
|
|
93
|
-
break;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
switch (anchor) {
|
|
97
|
-
case 'top-right':
|
|
98
|
-
case 'bottom-right':
|
|
99
|
-
x = -hypotenuse;
|
|
100
|
-
break;
|
|
101
|
-
case 'top-left':
|
|
102
|
-
case 'bottom-left':
|
|
103
|
-
x = hypotenuse;
|
|
104
|
-
break;
|
|
105
|
-
case 'left':
|
|
106
|
-
x = radialOffset;
|
|
107
|
-
break;
|
|
108
|
-
case 'right':
|
|
109
|
-
x = -radialOffset;
|
|
110
|
-
break;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return [x, y];
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function fromTextOffset(anchor: TextAnchor, offsetX: number, offsetY: number) {
|
|
117
|
-
let x = 0, y = 0;
|
|
118
|
-
// Use absolute offset values.
|
|
119
|
-
offsetX = Math.abs(offsetX);
|
|
120
|
-
offsetY = Math.abs(offsetY);
|
|
121
|
-
|
|
122
|
-
switch (anchor) {
|
|
123
|
-
case 'top-right':
|
|
124
|
-
case 'top-left':
|
|
125
|
-
case 'top':
|
|
126
|
-
y = offsetY - baselineOffset;
|
|
127
|
-
break;
|
|
128
|
-
case 'bottom-right':
|
|
129
|
-
case 'bottom-left':
|
|
130
|
-
case 'bottom':
|
|
131
|
-
y = -offsetY + baselineOffset;
|
|
132
|
-
break;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
switch (anchor) {
|
|
136
|
-
case 'top-right':
|
|
137
|
-
case 'bottom-right':
|
|
138
|
-
case 'right':
|
|
139
|
-
x = -offsetX;
|
|
140
|
-
break;
|
|
141
|
-
case 'top-left':
|
|
142
|
-
case 'bottom-left':
|
|
143
|
-
case 'left':
|
|
144
|
-
x = offsetX;
|
|
145
|
-
break;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return [x, y];
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return (offset[1] !== INVALID_TEXT_OFFSET) ? fromTextOffset(anchor, offset[0], offset[1]) : fromRadialOffset(anchor, offset[0]);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
64
|
export function performSymbolLayout(args: {
|
|
155
65
|
bucket: SymbolBucket;
|
|
156
66
|
glyphMap: {
|
|
@@ -175,8 +85,9 @@ export function performSymbolLayout(args: {
|
|
|
175
85
|
args.bucket.compareText = {};
|
|
176
86
|
args.bucket.iconsNeedLinear = false;
|
|
177
87
|
|
|
178
|
-
const
|
|
179
|
-
const
|
|
88
|
+
const layer = args.bucket.layers[0];
|
|
89
|
+
const layout = layer.layout;
|
|
90
|
+
const unevaluatedLayoutValues = layer._unevaluatedLayout._values;
|
|
180
91
|
|
|
181
92
|
const sizes: Sizes = {
|
|
182
93
|
// Filled in below, if *SizeData.kind is 'composite'
|
|
@@ -226,16 +137,16 @@ export function performSymbolLayout(args: {
|
|
|
226
137
|
const spacingIfAllowed = allowsLetterSpacing(unformattedText) ? spacing : 0;
|
|
227
138
|
|
|
228
139
|
const textAnchor = layout.get('text-anchor').evaluate(feature, {}, args.canonical);
|
|
229
|
-
const
|
|
140
|
+
const variableAnchorOffset = getTextVariableAnchorOffset(layer, feature, args.canonical);
|
|
230
141
|
|
|
231
|
-
if (!
|
|
142
|
+
if (!variableAnchorOffset) {
|
|
232
143
|
const radialOffset = layout.get('text-radial-offset').evaluate(feature, {}, args.canonical);
|
|
233
144
|
// Layers with variable anchors use the `text-radial-offset` property and the [x, y] offset vector
|
|
234
145
|
// is calculated at placement time instead of layout time
|
|
235
146
|
if (radialOffset) {
|
|
236
147
|
// The style spec says don't use `text-offset` and `text-radial-offset` together
|
|
237
148
|
// but doesn't actually specify what happens if you use both. We go with the radial offset.
|
|
238
|
-
textOffset = evaluateVariableOffset(textAnchor, [radialOffset * ONE_EM, INVALID_TEXT_OFFSET])
|
|
149
|
+
textOffset = evaluateVariableOffset(textAnchor, [radialOffset * ONE_EM, INVALID_TEXT_OFFSET]);
|
|
239
150
|
} else {
|
|
240
151
|
textOffset = (layout.get('text-offset').evaluate(feature, {}, args.canonical).map(t => t * ONE_EM) as [number, number]);
|
|
241
152
|
}
|
|
@@ -261,14 +172,19 @@ export function performSymbolLayout(args: {
|
|
|
261
172
|
};
|
|
262
173
|
|
|
263
174
|
// If this layer uses text-variable-anchor, generate shapings for all justification possibilities.
|
|
264
|
-
if (!textAlongLine &&
|
|
265
|
-
const justifications =
|
|
266
|
-
|
|
267
|
-
|
|
175
|
+
if (!textAlongLine && variableAnchorOffset) {
|
|
176
|
+
const justifications = new Set<TextJustify>();
|
|
177
|
+
|
|
178
|
+
if (textJustify === 'auto') {
|
|
179
|
+
for (let i = 0; i < variableAnchorOffset.values.length; i += 2) {
|
|
180
|
+
justifications.add(getAnchorJustification(variableAnchorOffset.values[i] as TextAnchor));
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
justifications.add(textJustify);
|
|
184
|
+
}
|
|
268
185
|
|
|
269
186
|
let singleLine = false;
|
|
270
|
-
for (
|
|
271
|
-
const justification: TextJustify = justifications[i];
|
|
187
|
+
for (const justification of justifications) {
|
|
272
188
|
if (shapedTextOrientations.horizontal[justification]) continue;
|
|
273
189
|
if (singleLine) {
|
|
274
190
|
// If the shaping for the first justification was only a single line, we
|
|
@@ -486,6 +402,22 @@ function addFeature(bucket: SymbolBucket,
|
|
|
486
402
|
}
|
|
487
403
|
}
|
|
488
404
|
|
|
405
|
+
function addTextVariableAnchorOffsets(textAnchorOffsets: TextAnchorOffsetArray, variableAnchorOffset: VariableAnchorOffsetCollection): [number, number] {
|
|
406
|
+
const startIndex = textAnchorOffsets.length;
|
|
407
|
+
const values = variableAnchorOffset?.values;
|
|
408
|
+
|
|
409
|
+
if (values?.length > 0) {
|
|
410
|
+
for (let i = 0; i < values.length; i += 2) {
|
|
411
|
+
const anchor = TextAnchorEnum[values[i] as TextAnchor];
|
|
412
|
+
const offset = values[i + 1] as [number, number];
|
|
413
|
+
|
|
414
|
+
textAnchorOffsets.emplaceBack(anchor, offset[0], offset[1]);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return [startIndex, textAnchorOffsets.length];
|
|
419
|
+
}
|
|
420
|
+
|
|
489
421
|
function addTextVertices(bucket: SymbolBucket,
|
|
490
422
|
anchor: Point,
|
|
491
423
|
shapedText: Shaping,
|
|
@@ -602,15 +534,6 @@ function addSymbol(bucket: SymbolBucket,
|
|
|
602
534
|
const placedTextSymbolIndices: {[k: string]: number} = {};
|
|
603
535
|
let key = murmur3('');
|
|
604
536
|
|
|
605
|
-
let textOffset0 = 0;
|
|
606
|
-
let textOffset1 = 0;
|
|
607
|
-
if (layer._unevaluatedLayout.getValue('text-radial-offset') === undefined) {
|
|
608
|
-
[textOffset0, textOffset1] = (layer.layout.get('text-offset').evaluate(feature, {}, canonical).map(t => t * ONE_EM) as [number, number]);
|
|
609
|
-
} else {
|
|
610
|
-
textOffset0 = layer.layout.get('text-radial-offset').evaluate(feature, {}, canonical) * ONE_EM;
|
|
611
|
-
textOffset1 = INVALID_TEXT_OFFSET;
|
|
612
|
-
}
|
|
613
|
-
|
|
614
537
|
if (bucket.allowVerticalPlacement && shapedTextOrientations.vertical) {
|
|
615
538
|
const textRotation = layer.layout.get('text-rotate').evaluate(feature, {}, canonical);
|
|
616
539
|
const verticalTextRotation = textRotation + 90.0;
|
|
@@ -763,6 +686,9 @@ function addSymbol(bucket: SymbolBucket,
|
|
|
763
686
|
bucket.addToSortKeyRanges(bucket.symbolInstances.length, feature.sortKey as number);
|
|
764
687
|
}
|
|
765
688
|
|
|
689
|
+
const variableAnchorOffset = getTextVariableAnchorOffset(layer, feature, canonical);
|
|
690
|
+
const [textAnchorOffsetStartIndex, textAnchorOffsetEndIndex] = addTextVariableAnchorOffsets(bucket.textAnchorOffsets, variableAnchorOffset);
|
|
691
|
+
|
|
766
692
|
bucket.symbolInstances.emplaceBack(
|
|
767
693
|
anchor.x,
|
|
768
694
|
anchor.y,
|
|
@@ -789,9 +715,9 @@ function addSymbol(bucket: SymbolBucket,
|
|
|
789
715
|
useRuntimeCollisionCircles,
|
|
790
716
|
0,
|
|
791
717
|
textBoxScale,
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
718
|
+
collisionCircleDiameter,
|
|
719
|
+
textAnchorOffsetStartIndex,
|
|
720
|
+
textAnchorOffsetEndIndex);
|
|
795
721
|
}
|
|
796
722
|
|
|
797
723
|
function anchorIsTooClose(bucket: SymbolBucket, text: string, repeatDistance: number, anchor: Point) {
|
|
@@ -43,7 +43,6 @@ const defaultOptions: NavigationOptions = {
|
|
|
43
43
|
* map.addControl(nav, 'top-left');
|
|
44
44
|
* ```
|
|
45
45
|
* @see [Display map navigation controls](https://maplibre.org/maplibre-gl-js/docs/examples/navigation/)
|
|
46
|
-
* @see [Add a third party vector tile source](https://maplibre.org/maplibre-gl-js/docs/examples/third-party/)
|
|
47
46
|
*/
|
|
48
47
|
export class NavigationControl implements IControl {
|
|
49
48
|
_map: Map;
|
package/src/ui/map.test.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {OverscaledTileID} from '../source/tile_id';
|
|
|
6
6
|
import {Event, ErrorEvent} from '../util/evented';
|
|
7
7
|
import simulate from '../../test/unit/lib/simulate_interaction';
|
|
8
8
|
import {fixedLngLat, fixedNum} from '../../test/unit/lib/fixed';
|
|
9
|
-
import {LayerSpecification, SourceSpecification, StyleSpecification} from '@maplibre/maplibre-gl-style-spec';
|
|
9
|
+
import {GeoJSONSourceSpecification, LayerSpecification, SourceSpecification, StyleSpecification} from '@maplibre/maplibre-gl-style-spec';
|
|
10
10
|
import {RequestTransformFunction} from '../util/request_manager';
|
|
11
11
|
import {extend} from '../util/util';
|
|
12
12
|
import {LngLatBoundsLike} from '../geo/lng_lat_bounds';
|
|
@@ -675,6 +675,19 @@ describe('Map', () => {
|
|
|
675
675
|
map.addSource('fill', source);
|
|
676
676
|
});
|
|
677
677
|
|
|
678
|
+
test('a layer can be added with an embedded source specification', () => {
|
|
679
|
+
const map = createMap({deleteStyle: true});
|
|
680
|
+
const source: GeoJSONSourceSpecification = {
|
|
681
|
+
type: 'geojson',
|
|
682
|
+
data: {type: 'Point', coordinates: [0, 0]}
|
|
683
|
+
};
|
|
684
|
+
map.addLayer({
|
|
685
|
+
id: 'foo',
|
|
686
|
+
type: 'symbol',
|
|
687
|
+
source
|
|
688
|
+
});
|
|
689
|
+
});
|
|
690
|
+
|
|
678
691
|
test('returns the style with added source and layer', done => {
|
|
679
692
|
const style = createStyle();
|
|
680
693
|
const map = createMap({style});
|
|
@@ -848,21 +861,30 @@ describe('Map', () => {
|
|
|
848
861
|
|
|
849
862
|
const map = createMap();
|
|
850
863
|
|
|
851
|
-
const
|
|
852
|
-
const
|
|
864
|
+
const updateSpy = jest.spyOn(map, '_update');
|
|
865
|
+
const resizeSpy = jest.spyOn(map, 'resize');
|
|
853
866
|
|
|
854
867
|
// The initial "observe" event fired by ResizeObserver should be captured/muted
|
|
855
868
|
// in the map constructor
|
|
856
869
|
|
|
857
870
|
observerCallback();
|
|
858
|
-
expect(
|
|
859
|
-
expect(
|
|
871
|
+
expect(updateSpy).not.toHaveBeenCalled();
|
|
872
|
+
expect(resizeSpy).not.toHaveBeenCalled();
|
|
873
|
+
|
|
874
|
+
// The next "observe" event should fire a resize / _update
|
|
860
875
|
|
|
861
|
-
|
|
876
|
+
observerCallback();
|
|
877
|
+
expect(updateSpy).toHaveBeenCalled();
|
|
878
|
+
expect(resizeSpy).toHaveBeenCalledTimes(1);
|
|
862
879
|
|
|
880
|
+
// Additional "observe" events should be throttled
|
|
881
|
+
observerCallback();
|
|
882
|
+
observerCallback();
|
|
863
883
|
observerCallback();
|
|
864
|
-
|
|
865
|
-
expect(
|
|
884
|
+
observerCallback();
|
|
885
|
+
expect(resizeSpy).toHaveBeenCalledTimes(1);
|
|
886
|
+
await new Promise((resolve) => { setTimeout(resolve, 100); });
|
|
887
|
+
expect(resizeSpy).toHaveBeenCalledTimes(2);
|
|
866
888
|
});
|
|
867
889
|
|
|
868
890
|
test('width and height correctly rounded', () => {
|
|
@@ -2569,6 +2591,13 @@ describe('Map', () => {
|
|
|
2569
2591
|
});
|
|
2570
2592
|
});
|
|
2571
2593
|
|
|
2594
|
+
describe('#getTerrain', () => {
|
|
2595
|
+
test('returns null when not set', () => {
|
|
2596
|
+
const map = createMap();
|
|
2597
|
+
expect(map.getTerrain()).toBeNull();
|
|
2598
|
+
});
|
|
2599
|
+
});
|
|
2600
|
+
|
|
2572
2601
|
describe('#setCooperativeGestures', () => {
|
|
2573
2602
|
test('returns self', () => {
|
|
2574
2603
|
const map = createMap();
|
package/src/ui/map.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {RGBAImage} from '../util/image';
|
|
|
25
25
|
import {Event, ErrorEvent, Listener} from '../util/evented';
|
|
26
26
|
import {MapEventType, MapLayerEventType, MapMouseEvent, MapSourceDataEvent, MapStyleDataEvent} from './events';
|
|
27
27
|
import {TaskQueue} from '../util/task_queue';
|
|
28
|
+
import {throttle} from '../util/throttle';
|
|
28
29
|
import {webpSupported} from '../util/webp_supported';
|
|
29
30
|
import {PerformanceMarkers, PerformanceUtils} from '../util/performance';
|
|
30
31
|
import {Source, SourceClass} from '../source/source';
|
|
@@ -33,9 +34,8 @@ import {StyleLayer} from '../style/style_layer';
|
|
|
33
34
|
import type {RequestTransformFunction} from '../util/request_manager';
|
|
34
35
|
import type {LngLatLike} from '../geo/lng_lat';
|
|
35
36
|
import type {LngLatBoundsLike} from '../geo/lng_lat_bounds';
|
|
36
|
-
import type {FeatureIdentifier, StyleOptions, StyleSetterOptions} from '../style/style';
|
|
37
|
+
import type {AddLayerObject, FeatureIdentifier, StyleOptions, StyleSetterOptions} from '../style/style';
|
|
37
38
|
import type {MapDataEvent} from './events';
|
|
38
|
-
import type {CustomLayerInterface} from '../style/style_layer/custom_style_layer';
|
|
39
39
|
import type {StyleImage, StyleImageInterface, StyleImageMetadata} from '../style/style_image';
|
|
40
40
|
import type {PointLike} from './camera';
|
|
41
41
|
import type {ScrollZoomHandler} from './handler/scroll_zoom';
|
|
@@ -51,7 +51,6 @@ import {defaultLocale} from './default_locale';
|
|
|
51
51
|
import type {TaskID} from '../util/task_queue';
|
|
52
52
|
import type {Cancelable} from '../types/cancelable';
|
|
53
53
|
import type {
|
|
54
|
-
LayerSpecification,
|
|
55
54
|
FilterSpecification,
|
|
56
55
|
StyleSpecification,
|
|
57
56
|
LightSpecification,
|
|
@@ -640,15 +639,17 @@ export class Map extends Camera {
|
|
|
640
639
|
if (typeof window !== 'undefined') {
|
|
641
640
|
addEventListener('online', this._onWindowOnline, false);
|
|
642
641
|
let initialResizeEventCaptured = false;
|
|
642
|
+
const throttledResizeCallback = throttle((entries: ResizeObserverEntry[]) => {
|
|
643
|
+
if (this._trackResize && !this._removed) {
|
|
644
|
+
this.resize(entries)._update();
|
|
645
|
+
}
|
|
646
|
+
}, 50);
|
|
643
647
|
this._resizeObserver = new ResizeObserver((entries) => {
|
|
644
648
|
if (!initialResizeEventCaptured) {
|
|
645
649
|
initialResizeEventCaptured = true;
|
|
646
650
|
return;
|
|
647
651
|
}
|
|
648
|
-
|
|
649
|
-
if (this._trackResize) {
|
|
650
|
-
this.resize(entries)._update();
|
|
651
|
-
}
|
|
652
|
+
throttledResizeCallback(entries);
|
|
652
653
|
});
|
|
653
654
|
this._resizeObserver.observe(this._container);
|
|
654
655
|
}
|
|
@@ -1962,7 +1963,7 @@ export class Map extends Camera {
|
|
|
1962
1963
|
* map.setTerrain({ source: 'terrain' });
|
|
1963
1964
|
* ```
|
|
1964
1965
|
*/
|
|
1965
|
-
setTerrain(options: TerrainSpecification): this {
|
|
1966
|
+
setTerrain(options: TerrainSpecification | null): this {
|
|
1966
1967
|
this.style._checkLoaded();
|
|
1967
1968
|
|
|
1968
1969
|
// clear event handlers
|
|
@@ -2017,8 +2018,8 @@ export class Map extends Camera {
|
|
|
2017
2018
|
* map.getTerrain(); // { source: 'terrain' };
|
|
2018
2019
|
* ```
|
|
2019
2020
|
*/
|
|
2020
|
-
getTerrain(): TerrainSpecification {
|
|
2021
|
-
return this.terrain
|
|
2021
|
+
getTerrain(): TerrainSpecification | null {
|
|
2022
|
+
return this.terrain?.options ?? null;
|
|
2022
2023
|
}
|
|
2023
2024
|
|
|
2024
2025
|
/**
|
|
@@ -2346,7 +2347,7 @@ export class Map extends Camera {
|
|
|
2346
2347
|
*
|
|
2347
2348
|
* @param layer - The layer to add,
|
|
2348
2349
|
* conforming to either the MapLibre Style Specification's [layer definition](https://maplibre.org/maplibre-style-spec/layers) or,
|
|
2349
|
-
* less commonly, the {@link CustomLayerInterface} specification.
|
|
2350
|
+
* less commonly, the {@link CustomLayerInterface} specification. Can also be a layer definition with an embedded source definition.
|
|
2350
2351
|
* The MapLibre Style Specification's layer definition is appropriate for most layers.
|
|
2351
2352
|
*
|
|
2352
2353
|
* @param beforeId - The ID of an existing layer to insert the new layer before,
|
|
@@ -2418,7 +2419,7 @@ export class Map extends Camera {
|
|
|
2418
2419
|
* @see [Add a vector tile source](https://maplibre.org/maplibre-gl-js/docs/examples/vector-source/)
|
|
2419
2420
|
* @see [Add a WMS source](https://maplibre.org/maplibre-gl-js/docs/examples/wms/)
|
|
2420
2421
|
*/
|
|
2421
|
-
addLayer(layer:
|
|
2422
|
+
addLayer(layer: AddLayerObject, beforeId?: string) {
|
|
2422
2423
|
this._lazyInitEmptyStyle();
|
|
2423
2424
|
this.style.addLayer(layer, beforeId);
|
|
2424
2425
|
return this._update(true);
|
|
@@ -2475,7 +2476,7 @@ export class Map extends Camera {
|
|
|
2475
2476
|
* @see [Filter symbols by toggling a list](https://maplibre.org/maplibre-gl-js/docs/examples/filter-markers/)
|
|
2476
2477
|
* @see [Filter symbols by text input](https://maplibre.org/maplibre-gl-js/docs/examples/filter-markers-by-input/)
|
|
2477
2478
|
*/
|
|
2478
|
-
getLayer(id: string): StyleLayer {
|
|
2479
|
+
getLayer(id: string): StyleLayer | undefined {
|
|
2479
2480
|
return this.style.getLayer(id);
|
|
2480
2481
|
}
|
|
2481
2482
|
|
package/src/ui/marker.ts
CHANGED
|
@@ -419,7 +419,7 @@ export class Marker extends Evented {
|
|
|
419
419
|
if (!('offset' in popup.options)) {
|
|
420
420
|
const markerHeight = 41 - (5.8 / 2);
|
|
421
421
|
const markerRadius = 13.5;
|
|
422
|
-
const linearOffset = Math.
|
|
422
|
+
const linearOffset = Math.abs(markerRadius) / Math.SQRT2;
|
|
423
423
|
popup.options.offset = this._defaultMarker ? {
|
|
424
424
|
'top': [0, 0],
|
|
425
425
|
'top-left': [0, 0],
|
package/src/ui/popup.ts
CHANGED
|
@@ -627,7 +627,7 @@ function normalizeOffset(offset?: Offset | null) {
|
|
|
627
627
|
|
|
628
628
|
} else if (typeof offset === 'number') {
|
|
629
629
|
// input specifies a radius from which to calculate offsets at all positions
|
|
630
|
-
const cornerOffset = Math.round(Math.
|
|
630
|
+
const cornerOffset = Math.round(Math.abs(offset) / Math.SQRT2);
|
|
631
631
|
return {
|
|
632
632
|
'center': new Point(0, 0),
|
|
633
633
|
'top': new Point(0, offset),
|
package/src/util/throttle.ts
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Throttle the given function to run at most every `period` milliseconds.
|
|
3
3
|
*/
|
|
4
|
-
export function throttle(
|
|
4
|
+
export function throttle<T extends (...args: any) => void>(fn: T, time: number): (...args: Parameters<T>) => ReturnType<typeof setTimeout> {
|
|
5
5
|
let pending = false;
|
|
6
6
|
let timerId: ReturnType<typeof setTimeout> = null;
|
|
7
|
+
let lastCallContext = null;
|
|
8
|
+
let lastCallArgs: Parameters<T>;
|
|
7
9
|
|
|
8
10
|
const later = () => {
|
|
9
11
|
timerId = null;
|
|
10
12
|
if (pending) {
|
|
11
|
-
fn();
|
|
13
|
+
fn.apply(lastCallContext, lastCallArgs);
|
|
12
14
|
timerId = setTimeout(later, time);
|
|
13
15
|
pending = false;
|
|
14
16
|
}
|
|
15
17
|
};
|
|
16
18
|
|
|
17
|
-
return () => {
|
|
19
|
+
return (...args: Parameters<T>) => {
|
|
18
20
|
pending = true;
|
|
21
|
+
lastCallContext = this;
|
|
22
|
+
lastCallArgs = args;
|
|
19
23
|
if (!timerId) {
|
|
20
24
|
later();
|
|
21
25
|
}
|