maplibre-gl 6.2.0 → 6.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.
- package/dist/maplibre-gl-dev.mjs +522 -223
- package/dist/maplibre-gl-dev.mjs.map +1 -1
- package/dist/maplibre-gl-shared-dev.mjs +103 -58
- package/dist/maplibre-gl-shared-dev.mjs.map +1 -1
- package/dist/maplibre-gl-shared.mjs +2 -2
- package/dist/maplibre-gl-shared.mjs.map +1 -1
- package/dist/maplibre-gl-worker-dev.mjs +23 -49
- package/dist/maplibre-gl-worker-dev.mjs.map +1 -1
- package/dist/maplibre-gl-worker.mjs +2 -2
- package/dist/maplibre-gl-worker.mjs.map +1 -1
- package/dist/maplibre-gl.css +1 -1
- package/dist/maplibre-gl.d.ts +214 -59
- package/dist/maplibre-gl.mjs +44 -44
- package/dist/maplibre-gl.mjs.map +1 -1
- package/package.json +10 -20
- package/src/data/feature_index.bench.ts +21 -0
- package/src/data/segment.test.ts +2 -2
- package/src/geo/edge_insets.test.ts +1 -1
- package/src/geo/lng_lat.test.ts +7 -7
- package/src/geo/lng_lat_bounds.test.ts +4 -4
- package/src/geo/mercator_coordinate.test.ts +2 -2
- package/src/geo/projection/camera_helper.ts +5 -0
- package/src/geo/projection/globe_transform.test.ts +25 -0
- package/src/geo/projection/globe_transform.ts +7 -3
- package/src/geo/projection/mercator_camera_helper.ts +1 -1
- package/src/geo/projection/mercator_transform.ts +21 -5
- package/src/geo/projection/vertical_perspective_camera_helper.ts +60 -31
- package/src/geo/projection/vertical_perspective_transform.ts +7 -1
- package/src/geo/transform_interface.ts +13 -1
- package/src/index.ts +7 -2
- package/src/render/image_atlas.test.ts +72 -0
- package/src/render/image_atlas.ts +17 -2
- package/src/render/image_manager.test.ts +46 -0
- package/src/render/image_manager.ts +9 -2
- package/src/render/painter.ts +1 -12
- package/src/render/update_pattern_positions_in_program.test.ts +1 -1
- package/src/shaders/glsl/_prelude.vertex.glsl +2 -3
- package/src/shaders/glsl/_prelude.vertex.glsl.g.ts +1 -1
- package/src/shaders/glsl/circle.vertex.glsl +4 -4
- package/src/shaders/glsl/circle.vertex.glsl.g.ts +1 -1
- package/src/shaders/glsl/fill_extrusion.vertex.glsl +3 -3
- package/src/shaders/glsl/fill_extrusion.vertex.glsl.g.ts +1 -1
- package/src/shaders/glsl/fill_extrusion_pattern.vertex.glsl +5 -5
- package/src/shaders/glsl/fill_extrusion_pattern.vertex.glsl.g.ts +1 -1
- package/src/shaders/glsl/heatmap.vertex.glsl +4 -4
- package/src/shaders/glsl/heatmap.vertex.glsl.g.ts +1 -1
- package/src/shaders/glsl/line.vertex.glsl +7 -7
- package/src/shaders/glsl/line.vertex.glsl.g.ts +1 -1
- package/src/shaders/glsl/line_gradient.vertex.glsl +6 -6
- package/src/shaders/glsl/line_gradient.vertex.glsl.g.ts +1 -1
- package/src/shaders/glsl/line_gradient_sdf.vertex.glsl +7 -7
- package/src/shaders/glsl/line_gradient_sdf.vertex.glsl.g.ts +1 -1
- package/src/shaders/glsl/line_pattern.vertex.glsl +7 -7
- package/src/shaders/glsl/line_pattern.vertex.glsl.g.ts +1 -1
- package/src/shaders/glsl/line_sdf.vertex.glsl +7 -7
- package/src/shaders/glsl/line_sdf.vertex.glsl.g.ts +1 -1
- package/src/shaders/glsl/raster.fragment.glsl +4 -4
- package/src/shaders/glsl/raster.fragment.glsl.g.ts +1 -1
- package/src/shaders/glsl/raster.vertex.glsl +11 -6
- package/src/shaders/glsl/raster.vertex.glsl.g.ts +1 -1
- package/src/shaders/glsl/symbol_icon.vertex.glsl +5 -5
- package/src/shaders/glsl/symbol_icon.vertex.glsl.g.ts +1 -1
- package/src/shaders/glsl/symbol_sdf.vertex.glsl +5 -5
- package/src/shaders/glsl/symbol_sdf.vertex.glsl.g.ts +1 -1
- package/src/shaders/glsl/symbol_text_and_icon.vertex.glsl +6 -6
- package/src/shaders/glsl/symbol_text_and_icon.vertex.glsl.g.ts +1 -1
- package/src/source/canvas_source.test.ts +31 -0
- package/src/source/canvas_source.ts +2 -1
- package/src/source/geojson_worker_source.test.ts +88 -0
- package/src/source/geojson_worker_source.ts +22 -39
- package/src/source/image_source.test.ts +205 -7
- package/src/source/image_source.ts +118 -4
- package/src/source/raster_dem_tile_worker_source.test.ts +1 -1
- package/src/source/vector_tile_worker_source.test.ts +94 -2
- package/src/source/vector_tile_worker_source.ts +18 -27
- package/src/source/video_source.test.ts +12 -8
- package/src/source/worker_tile.bench.ts +10 -0
- package/src/source/worker_tile.ts +0 -3
- package/src/style/create_style_layer.bench.ts +15 -0
- package/src/style/properties.bench.ts +81 -0
- package/src/style/style.test.ts +11 -10
- package/src/style/style_image.ts +67 -9
- package/src/style/style_layer.bench.ts +65 -0
- package/src/style/style_layer.test.ts +1 -1
- package/src/style/style_layer.ts +2 -2
- package/src/style/validate_style.bench.ts +11 -0
- package/src/style/validate_style.test.ts +2 -2
- package/src/symbol/anchor.test.ts +2 -2
- package/src/symbol/collision_index.bench.ts +116 -0
- package/src/symbol/cross_tile_symbol_index.bench.ts +49 -0
- package/src/symbol/shaping.test.ts +2 -1
- package/src/symbol/symbol_layout.bench.ts +30 -0
- package/src/tile/tile_id.test.ts +1 -1
- package/src/tile/tile_manager.ts +2 -2
- package/src/ui/control/fullscreen_control.test.ts +10 -10
- package/src/ui/control/geolocate_control.test.ts +3 -5
- package/src/ui/control/globe_control.test.ts +6 -6
- package/src/ui/events.ts +1 -1
- package/src/ui/handler/scroll_zoom.test.ts +50 -0
- package/src/ui/handler/two_fingers_touch.test.ts +3 -3
- package/src/ui/handler_manager.test.ts +243 -3
- package/src/ui/handler_manager.ts +79 -16
- package/src/ui/map.ts +17 -3
- package/src/ui/map_tests/map_cross_window.test.ts +2 -2
- package/src/ui/map_tests/map_events.test.ts +3 -3
- package/src/ui/map_tests/map_images.test.ts +29 -0
- package/src/ui/map_tests/map_style.test.ts +9 -8
- package/src/ui/map_tests/map_webgl.test.ts +29 -0
- package/src/ui/marker.test.ts +26 -42
- package/src/ui/popup.test.ts +14 -14
- package/src/util/evented.test.ts +33 -28
- package/src/util/evented.ts +69 -43
- package/src/util/test/null_gl.ts +10 -0
- package/src/util/test/util.ts +2 -1
- package/src/util/util.test.ts +1 -1
- package/src/util/web_worker_transfer.test.ts +5 -5
- package/src/webgl/context.ts +20 -0
- package/src/webgl/draw/draw_raster.ts +11 -6
- package/src/webgl/program/raster_program.ts +11 -0
- package/src/webgl/program.ts +31 -16
- package/src/webgl/texture.test.ts +16 -1
- package/src/webgl/texture.ts +3 -0
- package/src/webgl/vertex_buffer.test.ts +17 -2
- package/src/webgl/vertex_buffer.ts +24 -13
package/src/util/evented.test.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import {describe, test, expect, vi} from 'vitest';
|
|
2
2
|
import {Event, Evented} from './evented.ts';
|
|
3
3
|
|
|
4
|
+
class StubbedEvent extends Event<'a' | 'b'> {
|
|
5
|
+
foo?: string;
|
|
6
|
+
foz?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
4
9
|
// `Evented` is abstract, so use a minimal concrete subclass to exercise its behavior.
|
|
5
|
-
class StubbedEvented extends Evented {}
|
|
10
|
+
class StubbedEvented extends Evented<Record<StubbedEvent['type'], StubbedEvent>> {}
|
|
6
11
|
|
|
7
12
|
describe('Evented', () => {
|
|
8
13
|
|
|
@@ -10,8 +15,8 @@ describe('Evented', () => {
|
|
|
10
15
|
const evented = new StubbedEvented();
|
|
11
16
|
const listener = vi.fn();
|
|
12
17
|
evented.on('a', listener);
|
|
13
|
-
evented.fire(new
|
|
14
|
-
evented.fire(new
|
|
18
|
+
evented.fire(new StubbedEvent('a'));
|
|
19
|
+
evented.fire(new StubbedEvent('a'));
|
|
15
20
|
expect(listener).toHaveBeenCalledTimes(2);
|
|
16
21
|
});
|
|
17
22
|
|
|
@@ -19,8 +24,8 @@ describe('Evented', () => {
|
|
|
19
24
|
const evented = new StubbedEvented();
|
|
20
25
|
const listener = vi.fn();
|
|
21
26
|
evented.once('a', listener);
|
|
22
|
-
evented.fire(new
|
|
23
|
-
evented.fire(new
|
|
27
|
+
evented.fire(new StubbedEvent('a'));
|
|
28
|
+
evented.fire(new StubbedEvent('a'));
|
|
24
29
|
expect(listener).toHaveBeenCalledTimes(1);
|
|
25
30
|
expect(evented.listens('a')).toBeFalsy();
|
|
26
31
|
});
|
|
@@ -29,17 +34,17 @@ describe('Evented', () => {
|
|
|
29
34
|
const evented = new StubbedEvented();
|
|
30
35
|
const listener = vi.fn();
|
|
31
36
|
const subscription = evented.on('a', listener);
|
|
32
|
-
evented.fire(new
|
|
37
|
+
evented.fire(new StubbedEvent('a'));
|
|
33
38
|
subscription.unsubscribe();
|
|
34
|
-
evented.fire(new
|
|
39
|
+
evented.fire(new StubbedEvent('a'));
|
|
35
40
|
expect(listener).toHaveBeenCalledTimes(1);
|
|
36
41
|
});
|
|
37
42
|
|
|
38
43
|
test('returns a promise when no listener is provided to "once" method', async () => {
|
|
39
44
|
const evented = new StubbedEvented();
|
|
40
45
|
const promise = evented.once('a');
|
|
41
|
-
evented.fire(new
|
|
42
|
-
evented.fire(new
|
|
46
|
+
evented.fire(new StubbedEvent('a'));
|
|
47
|
+
evented.fire(new StubbedEvent('a'));
|
|
43
48
|
await promise;
|
|
44
49
|
expect(evented.listens('a')).toBeFalsy();
|
|
45
50
|
|
|
@@ -50,7 +55,7 @@ describe('Evented', () => {
|
|
|
50
55
|
evented.on('a', (data) => {
|
|
51
56
|
expect(data.foo).toBe('bar');
|
|
52
57
|
});
|
|
53
|
-
evented.fire(new
|
|
58
|
+
evented.fire(new StubbedEvent('a', {foo: 'bar'}));
|
|
54
59
|
|
|
55
60
|
});
|
|
56
61
|
|
|
@@ -59,7 +64,7 @@ describe('Evented', () => {
|
|
|
59
64
|
evented.on('a', (data) => {
|
|
60
65
|
expect(data.target).toBe(evented);
|
|
61
66
|
});
|
|
62
|
-
evented.fire(new
|
|
67
|
+
evented.fire(new StubbedEvent('a'));
|
|
63
68
|
|
|
64
69
|
});
|
|
65
70
|
|
|
@@ -68,7 +73,7 @@ describe('Evented', () => {
|
|
|
68
73
|
evented.on('a', (data) => {
|
|
69
74
|
expect(data.type).toBe('a');
|
|
70
75
|
});
|
|
71
|
-
evented.fire(new
|
|
76
|
+
evented.fire(new StubbedEvent('a'));
|
|
72
77
|
|
|
73
78
|
});
|
|
74
79
|
|
|
@@ -77,7 +82,7 @@ describe('Evented', () => {
|
|
|
77
82
|
const listener = vi.fn();
|
|
78
83
|
evented.on('a', listener);
|
|
79
84
|
evented.off('a', listener);
|
|
80
|
-
evented.fire(new
|
|
85
|
+
evented.fire(new StubbedEvent('a'));
|
|
81
86
|
expect(listener).not.toHaveBeenCalled();
|
|
82
87
|
});
|
|
83
88
|
|
|
@@ -86,7 +91,7 @@ describe('Evented', () => {
|
|
|
86
91
|
const listener = vi.fn();
|
|
87
92
|
evented.once('a', listener);
|
|
88
93
|
evented.off('a', listener);
|
|
89
|
-
evented.fire(new
|
|
94
|
+
evented.fire(new StubbedEvent('a'));
|
|
90
95
|
expect(listener).not.toHaveBeenCalled();
|
|
91
96
|
});
|
|
92
97
|
|
|
@@ -95,9 +100,9 @@ describe('Evented', () => {
|
|
|
95
100
|
const listener = vi.fn();
|
|
96
101
|
evented.once('a', () => {
|
|
97
102
|
listener();
|
|
98
|
-
evented.fire(new
|
|
103
|
+
evented.fire(new StubbedEvent('a'));
|
|
99
104
|
});
|
|
100
|
-
evented.fire(new
|
|
105
|
+
evented.fire(new StubbedEvent('a'));
|
|
101
106
|
expect(listener).toHaveBeenCalledTimes(1);
|
|
102
107
|
});
|
|
103
108
|
|
|
@@ -124,7 +129,7 @@ describe('Evented', () => {
|
|
|
124
129
|
evented.on('a', () => {
|
|
125
130
|
evented.on('a', nestedListener);
|
|
126
131
|
});
|
|
127
|
-
evented.fire(new
|
|
132
|
+
evented.fire(new StubbedEvent('a'));
|
|
128
133
|
|
|
129
134
|
expect(nestedListener).not.toHaveBeenCalled();
|
|
130
135
|
});
|
|
@@ -147,7 +152,7 @@ describe('Evented', () => {
|
|
|
147
152
|
evented.on('a', listenerA);
|
|
148
153
|
evented.on('a', listenerB);
|
|
149
154
|
evented.on('a', listenerA);
|
|
150
|
-
evented.fire(new
|
|
155
|
+
evented.fire(new StubbedEvent('a'));
|
|
151
156
|
expect(listenerA).toHaveBeenCalledTimes(1);
|
|
152
157
|
expect(order).toEqual(['A', 'B']);
|
|
153
158
|
|
|
@@ -162,8 +167,8 @@ describe('evented parents', () => {
|
|
|
162
167
|
const eventedSink = new StubbedEvented();
|
|
163
168
|
eventedSource.setEventedParent(eventedSink);
|
|
164
169
|
eventedSink.on('a', listener);
|
|
165
|
-
eventedSource.fire(new
|
|
166
|
-
eventedSource.fire(new
|
|
170
|
+
eventedSource.fire(new StubbedEvent('a'));
|
|
171
|
+
eventedSource.fire(new StubbedEvent('a'));
|
|
167
172
|
expect(listener).toHaveBeenCalledTimes(2);
|
|
168
173
|
});
|
|
169
174
|
|
|
@@ -174,7 +179,7 @@ describe('evented parents', () => {
|
|
|
174
179
|
eventedSink.on('a', (data) => {
|
|
175
180
|
expect(data.foo).toBe('bar');
|
|
176
181
|
});
|
|
177
|
-
eventedSource.fire(new
|
|
182
|
+
eventedSource.fire(new StubbedEvent('a', {foo: 'bar'}));
|
|
178
183
|
|
|
179
184
|
});
|
|
180
185
|
|
|
@@ -185,7 +190,7 @@ describe('evented parents', () => {
|
|
|
185
190
|
eventedSink.on('a', (data) => {
|
|
186
191
|
expect(data.foz).toBe('baz');
|
|
187
192
|
});
|
|
188
|
-
eventedSource.fire(new
|
|
193
|
+
eventedSource.fire(new StubbedEvent('a', {foo: 'bar'}));
|
|
189
194
|
|
|
190
195
|
});
|
|
191
196
|
|
|
@@ -196,7 +201,7 @@ describe('evented parents', () => {
|
|
|
196
201
|
eventedSink.on('a', (data) => {
|
|
197
202
|
expect(data.foz).toBe('baz');
|
|
198
203
|
});
|
|
199
|
-
eventedSource.fire(new
|
|
204
|
+
eventedSource.fire(new StubbedEvent('a', {foo: 'bar'}));
|
|
200
205
|
|
|
201
206
|
});
|
|
202
207
|
|
|
@@ -208,7 +213,7 @@ describe('evented parents', () => {
|
|
|
208
213
|
eventedSink.on('a', (data) => {
|
|
209
214
|
expect(data.target).toBe(eventedSource);
|
|
210
215
|
});
|
|
211
|
-
eventedSource.fire(new
|
|
216
|
+
eventedSource.fire(new StubbedEvent('a'));
|
|
212
217
|
|
|
213
218
|
});
|
|
214
219
|
|
|
@@ -219,7 +224,7 @@ describe('evented parents', () => {
|
|
|
219
224
|
eventedSink.on('a', listener);
|
|
220
225
|
eventedSource.setEventedParent(eventedSink);
|
|
221
226
|
eventedSource.setEventedParent(null);
|
|
222
|
-
eventedSource.fire(new
|
|
227
|
+
eventedSource.fire(new StubbedEvent('a'));
|
|
223
228
|
expect(listener).not.toHaveBeenCalled();
|
|
224
229
|
});
|
|
225
230
|
|
|
@@ -236,11 +241,11 @@ describe('evented parents', () => {
|
|
|
236
241
|
const eventedSource = new StubbedEvented();
|
|
237
242
|
const eventedParent = new StubbedEvented();
|
|
238
243
|
let i = 0;
|
|
239
|
-
eventedSource.setEventedParent(eventedParent, () => i++);
|
|
244
|
+
eventedSource.setEventedParent(eventedParent, () => ({counter: i++}));
|
|
240
245
|
eventedSource.on('a', () => {});
|
|
241
|
-
eventedSource.fire(new
|
|
246
|
+
eventedSource.fire(new StubbedEvent('a'));
|
|
242
247
|
expect(i).toBe(1);
|
|
243
|
-
eventedSource.fire(new
|
|
248
|
+
eventedSource.fire(new StubbedEvent('a'));
|
|
244
249
|
expect(i).toBe(2);
|
|
245
250
|
|
|
246
251
|
});
|
package/src/util/evented.ts
CHANGED
|
@@ -3,11 +3,26 @@ import {extend, type Subscription} from './util.ts';
|
|
|
3
3
|
/**
|
|
4
4
|
* A listener method used as a callback to events
|
|
5
5
|
*/
|
|
6
|
-
export type Listener = (
|
|
6
|
+
export type Listener<E extends Event = Event> = (event: E) => any;
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* A mapping between event names and the event each of them carries.
|
|
10
|
+
*/
|
|
11
|
+
export type EventTypeMap = Record<string, Event>;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The event names of an {@link EventTypeMap}.
|
|
15
|
+
*/
|
|
16
|
+
export type EventNames<EventType extends EventTypeMap> = Extract<keyof EventType, string>;
|
|
9
17
|
|
|
10
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Properties merged into every event bubbled up to an evented parent.
|
|
20
|
+
*/
|
|
21
|
+
export type EventedParentData = Record<string, unknown>;
|
|
22
|
+
|
|
23
|
+
type Listeners<EventType extends EventTypeMap> = {[K in keyof EventType]?: Array<Listener<EventType[K]>>};
|
|
24
|
+
|
|
25
|
+
function _addEventListener<T extends EventTypeMap, K extends EventNames<T>>(type: K, listener: Listener<T[K]>, listenerList: Listeners<T>) {
|
|
11
26
|
const listenerExists = listenerList[type]?.includes(listener);
|
|
12
27
|
if (!listenerExists) {
|
|
13
28
|
listenerList[type] ||= [];
|
|
@@ -15,7 +30,7 @@ function _addEventListener<T extends Record<string, any>>(type: keyof T, listene
|
|
|
15
30
|
}
|
|
16
31
|
}
|
|
17
32
|
|
|
18
|
-
function _removeEventListener<T extends
|
|
33
|
+
function _removeEventListener<T extends EventTypeMap, K extends EventNames<T>>(type: K, listener: Listener<T[K]>, listenerList: Listeners<T>) {
|
|
19
34
|
if (listenerList?.[type]) {
|
|
20
35
|
const index = listenerList[type].indexOf(listener);
|
|
21
36
|
if (index !== -1) {
|
|
@@ -27,15 +42,15 @@ function _removeEventListener<T extends Record<string, any>>(type: keyof T, list
|
|
|
27
42
|
/**
|
|
28
43
|
* The event class
|
|
29
44
|
*/
|
|
30
|
-
export class Event {
|
|
31
|
-
readonly type:
|
|
45
|
+
export class Event<TType extends string = string> {
|
|
46
|
+
readonly type: TType;
|
|
32
47
|
/**
|
|
33
48
|
* The object that fired the event. Set when the event is fired, and narrowed to a more
|
|
34
49
|
* specific type (e.g. `Map`, `Marker`) by the event subclasses.
|
|
35
50
|
*/
|
|
36
51
|
target?: unknown;
|
|
37
52
|
|
|
38
|
-
constructor(type:
|
|
53
|
+
constructor(type: TType, data: object = {}) {
|
|
39
54
|
extend(this, data);
|
|
40
55
|
this.type = type;
|
|
41
56
|
}
|
|
@@ -48,24 +63,31 @@ type ErrorLike = {
|
|
|
48
63
|
/**
|
|
49
64
|
* An error event
|
|
50
65
|
*/
|
|
51
|
-
export class ErrorEvent extends Event {
|
|
66
|
+
export class ErrorEvent extends Event<'error'> {
|
|
52
67
|
error: ErrorLike;
|
|
53
68
|
|
|
54
|
-
constructor(error: ErrorLike, data:
|
|
69
|
+
constructor(error: ErrorLike, data: object = {}) {
|
|
55
70
|
super('error', extend({error}, data));
|
|
56
71
|
}
|
|
57
72
|
}
|
|
58
73
|
|
|
74
|
+
/**
|
|
75
|
+
* The event map of an {@link Evented} that only reports errors.
|
|
76
|
+
*/
|
|
77
|
+
export type ErrorEventType = {
|
|
78
|
+
error: ErrorEvent;
|
|
79
|
+
};
|
|
80
|
+
|
|
59
81
|
/**
|
|
60
82
|
* Methods mixed in to other classes for event capabilities.
|
|
61
83
|
*
|
|
62
84
|
* @group Event Related
|
|
63
85
|
*/
|
|
64
|
-
export abstract class Evented<EventType extends
|
|
65
|
-
_listeners
|
|
66
|
-
_oneTimeListeners
|
|
67
|
-
_eventedParent
|
|
68
|
-
_eventedParentData
|
|
86
|
+
export abstract class Evented<EventType extends EventTypeMap = EventTypeMap> {
|
|
87
|
+
_listeners?: Listeners<EventType>;
|
|
88
|
+
_oneTimeListeners?: Listeners<EventType>;
|
|
89
|
+
_eventedParent?: Evented;
|
|
90
|
+
_eventedParentData?: EventedParentData | (() => EventedParentData);
|
|
69
91
|
|
|
70
92
|
/**
|
|
71
93
|
* Adds a listener to a specified event type.
|
|
@@ -75,7 +97,7 @@ export abstract class Evented<EventType extends Record<string, any> = Record<str
|
|
|
75
97
|
* The listener function is called with the data object passed to `fire`,
|
|
76
98
|
* extended with `target` and `type` properties.
|
|
77
99
|
*/
|
|
78
|
-
on<T extends
|
|
100
|
+
on<T extends EventNames<EventType>>(type: T, listener: (event: EventType[T]) => void): Subscription {
|
|
79
101
|
this._listeners ||= {};
|
|
80
102
|
_addEventListener(type, listener, this._listeners);
|
|
81
103
|
|
|
@@ -92,7 +114,7 @@ export abstract class Evented<EventType extends Record<string, any> = Record<str
|
|
|
92
114
|
* @param type - The event type to remove listeners for.
|
|
93
115
|
* @param listener - The listener function to remove.
|
|
94
116
|
*/
|
|
95
|
-
off<T extends
|
|
117
|
+
off<T extends EventNames<EventType>>(type: T, listener: (event: EventType[T]) => void): this {
|
|
96
118
|
_removeEventListener(type, listener, this._listeners);
|
|
97
119
|
_removeEventListener(type, listener, this._oneTimeListeners);
|
|
98
120
|
|
|
@@ -107,7 +129,7 @@ export abstract class Evented<EventType extends Record<string, any> = Record<str
|
|
|
107
129
|
* @param type - The event type to listen for.
|
|
108
130
|
* @returns a promise that resolves with the event
|
|
109
131
|
*/
|
|
110
|
-
once<T extends
|
|
132
|
+
once<T extends EventNames<EventType>>(type: T): Promise<EventType[T]>;
|
|
111
133
|
/**
|
|
112
134
|
* Adds a listener that will be called only once to a specified event type.
|
|
113
135
|
*
|
|
@@ -117,8 +139,8 @@ export abstract class Evented<EventType extends Record<string, any> = Record<str
|
|
|
117
139
|
* @param listener - The function to be called when the event is fired the first time.
|
|
118
140
|
* @returns `this` when a listener is provided
|
|
119
141
|
*/
|
|
120
|
-
once<T extends
|
|
121
|
-
once<T extends
|
|
142
|
+
once<T extends EventNames<EventType>>(type: T, listener: (event: EventType[T]) => void): this;
|
|
143
|
+
once<T extends EventNames<EventType>>(type: T, listener?: (event: EventType[T]) => void): this | Promise<EventType[T]> {
|
|
122
144
|
if (!listener) {
|
|
123
145
|
return new Promise((resolve) => this.once(type, resolve));
|
|
124
146
|
}
|
|
@@ -128,44 +150,48 @@ export abstract class Evented<EventType extends Record<string, any> = Record<str
|
|
|
128
150
|
return this;
|
|
129
151
|
}
|
|
130
152
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
153
|
+
/**
|
|
154
|
+
* Calls every listener registered for the event's type.
|
|
155
|
+
*/
|
|
156
|
+
fire(event: EventType[EventNames<EventType>]): this;
|
|
157
|
+
/**
|
|
158
|
+
* Compatibility with the (type: string, properties: Object) signature from previous versions.
|
|
159
|
+
* See https://github.com/mapbox/mapbox-gl-js/issues/6522,
|
|
160
|
+
* https://github.com/mapbox/mapbox-gl-draw/issues/766
|
|
161
|
+
*/
|
|
162
|
+
fire(type: EventNames<EventType>, properties?: object): this;
|
|
163
|
+
fire(event: EventType[EventNames<EventType>] | EventNames<EventType>, properties?: object): this {
|
|
164
|
+
const firedEvent: Event = typeof event === 'string' ? new Event(event, properties || {}) : event;
|
|
165
|
+
const type = firedEvent.type as EventNames<EventType>;
|
|
140
166
|
|
|
141
167
|
if (this.listens(type)) {
|
|
142
|
-
|
|
168
|
+
firedEvent.target = this;
|
|
143
169
|
|
|
144
170
|
// make sure adding or removing listeners inside other listeners won't cause an infinite loop
|
|
145
|
-
const listeners = this._listeners?.[type]
|
|
171
|
+
const listeners = this._listeners?.[type]?.slice() ?? [];
|
|
146
172
|
for (const listener of listeners) {
|
|
147
|
-
listener.call(this,
|
|
173
|
+
listener.call(this, firedEvent);
|
|
148
174
|
}
|
|
149
175
|
|
|
150
|
-
const oneTimeListeners = this._oneTimeListeners?.[type]
|
|
176
|
+
const oneTimeListeners = this._oneTimeListeners?.[type]?.slice() ?? [];
|
|
151
177
|
for (const listener of oneTimeListeners) {
|
|
152
178
|
_removeEventListener(type, listener, this._oneTimeListeners);
|
|
153
|
-
listener.call(this,
|
|
179
|
+
listener.call(this, firedEvent);
|
|
154
180
|
}
|
|
155
181
|
|
|
156
182
|
const parent = this._eventedParent;
|
|
157
183
|
if (parent) {
|
|
158
184
|
extend(
|
|
159
|
-
|
|
185
|
+
firedEvent,
|
|
160
186
|
typeof this._eventedParentData === 'function' ? this._eventedParentData() : this._eventedParentData
|
|
161
187
|
);
|
|
162
|
-
parent.fire(
|
|
188
|
+
parent.fire(firedEvent);
|
|
163
189
|
}
|
|
164
190
|
|
|
165
191
|
// To ensure that no error events are dropped, print them to the
|
|
166
192
|
// console if they have no listeners.
|
|
167
|
-
} else if (
|
|
168
|
-
console.error(
|
|
193
|
+
} else if (firedEvent instanceof ErrorEvent) {
|
|
194
|
+
console.error(firedEvent.error);
|
|
169
195
|
}
|
|
170
196
|
|
|
171
197
|
return this;
|
|
@@ -177,18 +203,18 @@ export abstract class Evented<EventType extends Record<string, any> = Record<str
|
|
|
177
203
|
* @param type - The event type
|
|
178
204
|
* @returns `true` if there is at least one registered listener for specified event type, `false` otherwise
|
|
179
205
|
*/
|
|
180
|
-
listens(type:
|
|
181
|
-
return (
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
206
|
+
listens(type: EventNames<EventType>): boolean {
|
|
207
|
+
return Boolean(
|
|
208
|
+
this._listeners?.[type]?.length ||
|
|
209
|
+
this._oneTimeListeners?.[type]?.length ||
|
|
210
|
+
this._eventedParent?.listens(type)
|
|
185
211
|
);
|
|
186
212
|
}
|
|
187
213
|
|
|
188
214
|
/**
|
|
189
215
|
* Bubble all events fired by this instance of Evented to this parent instance of Evented.
|
|
190
216
|
*/
|
|
191
|
-
setEventedParent(parent?: Evented | null, data?:
|
|
217
|
+
setEventedParent(parent?: Evented | null, data?: EventedParentData | (() => EventedParentData)): this {
|
|
192
218
|
this._eventedParent = parent;
|
|
193
219
|
this._eventedParentData = data;
|
|
194
220
|
|
package/src/util/test/null_gl.ts
CHANGED
|
@@ -70,6 +70,16 @@ export class NullWebGL2RenderingContext {
|
|
|
70
70
|
INT: number = 0x1404;
|
|
71
71
|
UNSIGNED_INT: number = 0x1405;
|
|
72
72
|
FLOAT: number = 0x1406;
|
|
73
|
+
FLOAT_VEC2: number = 0x8B50;
|
|
74
|
+
FLOAT_VEC3: number = 0x8B51;
|
|
75
|
+
FLOAT_VEC4: number = 0x8B52;
|
|
76
|
+
INT_VEC2: number = 0x8B53;
|
|
77
|
+
INT_VEC3: number = 0x8B54;
|
|
78
|
+
INT_VEC4: number = 0x8B55;
|
|
79
|
+
UNSIGNED_INT_VEC2: number = 0x8DC6;
|
|
80
|
+
UNSIGNED_INT_VEC3: number = 0x8DC7;
|
|
81
|
+
UNSIGNED_INT_VEC4: number = 0x8DC8;
|
|
82
|
+
ACTIVE_ATTRIBUTES: number = 0x8B89;
|
|
73
83
|
ALPHA: number = 0x1906;
|
|
74
84
|
RGB: number = 0x1907;
|
|
75
85
|
RGBA: number = 0x1908;
|
package/src/util/test/util.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {extend} from '../../util/util.ts';
|
|
|
5
5
|
import {type Dispatcher} from '../../util/dispatcher.ts';
|
|
6
6
|
import {type IActor} from '../actor.ts';
|
|
7
7
|
import {Evented} from '../evented.ts';
|
|
8
|
+
import {type SourceEventType} from '../../ui/events.ts';
|
|
8
9
|
import {type SourceSpecification, type StyleSpecification, type TerrainSpecification} from '@maplibre/maplibre-gl-style-spec';
|
|
9
10
|
import {MercatorTransform} from '../../geo/projection/mercator_transform.ts';
|
|
10
11
|
import {RequestManager} from '../request_manager.ts';
|
|
@@ -197,7 +198,7 @@ export const sleep: (milliseconds?: number) => Promise<void> = (milliseconds: nu
|
|
|
197
198
|
return new Promise<void>(resolve => setTimeout(resolve, milliseconds));
|
|
198
199
|
};
|
|
199
200
|
|
|
200
|
-
export function waitForMetadataEvent(source: Evented): Promise<void> {
|
|
201
|
+
export function waitForMetadataEvent(source: Evented<SourceEventType>): Promise<void> {
|
|
201
202
|
return new Promise((resolve) => {
|
|
202
203
|
source.on('data', (e) => {
|
|
203
204
|
if (e.sourceDataType === 'metadata') {
|
package/src/util/util.test.ts
CHANGED
|
@@ -78,7 +78,7 @@ describe('util', () => {
|
|
|
78
78
|
|
|
79
79
|
test('bezier', () => {
|
|
80
80
|
const curve = bezier(0, 0, 0.25, 1);
|
|
81
|
-
expect(curve
|
|
81
|
+
expect(curve).toBeInstanceOf(Function);
|
|
82
82
|
expect(curve(0)).toBe(0);
|
|
83
83
|
expect(curve(1)).toBe(1);
|
|
84
84
|
expect(curve(0.5)).toBe(0.8230854638965502);
|
|
@@ -39,8 +39,8 @@ describe('web worker transfer', () => {
|
|
|
39
39
|
const serializableMock = new SerializableMock(10);
|
|
40
40
|
const transferables = [];
|
|
41
41
|
const deserialized = deserialize(serialize(serializableMock, transferables)) as SerializableMock;
|
|
42
|
-
expect(deserialize(serialize(serializableMock, transferables))
|
|
43
|
-
expect(serializableMock.dataView
|
|
42
|
+
expect(deserialize(serialize(serializableMock, transferables))).toBeInstanceOf(SerializableMock);
|
|
43
|
+
expect(serializableMock.dataView).toBeInstanceOf(DataView);
|
|
44
44
|
|
|
45
45
|
expect(serializableMock !== deserialized).toBeTruthy();
|
|
46
46
|
expect(deserialized.constructor === SerializableMock).toBeTruthy();
|
|
@@ -51,7 +51,7 @@ describe('web worker transfer', () => {
|
|
|
51
51
|
expect(transferables[1] === serializableMock.dataView.buffer).toBeTruthy();
|
|
52
52
|
expect(deserialized._cached === undefined).toBeTruthy();
|
|
53
53
|
expect(deserialized.squared() === 100).toBeTruthy();
|
|
54
|
-
expect(deserialized.dataView
|
|
54
|
+
expect(deserialized.dataView).toBeInstanceOf(DataView);
|
|
55
55
|
expect(deserialized.array).toEqual(serializableMock.array);
|
|
56
56
|
});
|
|
57
57
|
|
|
@@ -61,7 +61,7 @@ describe('web worker transfer', () => {
|
|
|
61
61
|
register('Anon', Klass);
|
|
62
62
|
const x = new Klass();
|
|
63
63
|
const deserialized = deserialize(serialize(x));
|
|
64
|
-
expect(deserialized
|
|
64
|
+
expect(deserialized).toBeInstanceOf(Klass);
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
test('null', () => {
|
|
@@ -94,7 +94,7 @@ describe('web worker transfer', () => {
|
|
|
94
94
|
expect(!customSerialization._deserialized).toBeTruthy();
|
|
95
95
|
|
|
96
96
|
const deserialized = deserialize(serialize(customSerialization)) as CustomSerialization;
|
|
97
|
-
expect(deserialize(serialize(customSerialization))
|
|
97
|
+
expect(deserialize(serialize(customSerialization))).toBeInstanceOf(CustomSerialization);
|
|
98
98
|
expect(deserialized.id).toBe(customSerialization.id);
|
|
99
99
|
expect(deserialized._deserialized).toBeTruthy();
|
|
100
100
|
});
|
package/src/webgl/context.ts
CHANGED
|
@@ -177,6 +177,26 @@ export class Context {
|
|
|
177
177
|
this.pixelStoreUnpackFlipY.dirty = true;
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Reset some GL state to default values before handing users the raw context, as we do for
|
|
182
|
+
* custom layers and WebGL style images, to avoid hard-to-debug bugs in their code.
|
|
183
|
+
*
|
|
184
|
+
* MapLibre restores all of its own state afterwards, so the only state worth resetting first
|
|
185
|
+
* is state users would be surprised to find dirty: `CULL_FACE`, `TEXTURE0` and the three
|
|
186
|
+
* `UNPACK_` settings, whose defaults are meaningful enough that most code assumes them.
|
|
187
|
+
* The vertex array is unbound rather than reset, so that MapLibre never has to track it and
|
|
188
|
+
* a user's `vertexAttribPointer` calls cannot land on one of ours.
|
|
189
|
+
*/
|
|
190
|
+
setCustomLayerDefaults(): void {
|
|
191
|
+
this.unbindVAO();
|
|
192
|
+
|
|
193
|
+
this.cullFace.setDefault();
|
|
194
|
+
this.activeTexture.setDefault();
|
|
195
|
+
this.pixelStoreUnpack.setDefault();
|
|
196
|
+
this.pixelStoreUnpackPremultiplyAlpha.setDefault();
|
|
197
|
+
this.pixelStoreUnpackFlipY.setDefault();
|
|
198
|
+
}
|
|
199
|
+
|
|
180
200
|
createIndexBuffer(array: TriangleIndexArray | LineIndexArray | LineStripIndexArray, dynamicDraw?: boolean): IndexBuffer {
|
|
181
201
|
return new IndexBuffer(this, array, dynamicDraw);
|
|
182
202
|
}
|
|
@@ -5,7 +5,11 @@ import {now} from '../../util/time_control.ts';
|
|
|
5
5
|
import {StencilMode} from '../stencil_mode.ts';
|
|
6
6
|
import {DepthMode} from '../depth_mode.ts';
|
|
7
7
|
import {CullFaceMode} from '../cull_face_mode.ts';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
identityPerspectiveTransform,
|
|
10
|
+
rasterUniformValues,
|
|
11
|
+
type RasterPerspectiveTransform
|
|
12
|
+
} from '../program/raster_program.ts';
|
|
9
13
|
import {EXTENT} from '../../data/extent.ts';
|
|
10
14
|
import {FadingDirections} from '../../tile/tile.ts';
|
|
11
15
|
import Point from '@mapbox/point-geometry';
|
|
@@ -59,16 +63,16 @@ export function drawRaster(painter: Painter, tileManager: TileManager, layer: Ra
|
|
|
59
63
|
// Stencil mask and two-pass is not used for ImageSource sources regardless of projection.
|
|
60
64
|
if (source instanceof ImageSource) {
|
|
61
65
|
// Image source - no stencil is used
|
|
62
|
-
drawTiles(painter, tileManager, layer, tileIDs, null, false, false, source.tileCoords, source.flippedWindingOrder, isRenderingToTexture);
|
|
66
|
+
drawTiles(painter, tileManager, layer, tileIDs, null, false, false, source.tileCoords, source.perspectiveTransform, source.flippedWindingOrder, isRenderingToTexture);
|
|
63
67
|
} else if (useSubdivision) {
|
|
64
68
|
// Two-pass rendering
|
|
65
69
|
const [stencilBorderless, stencilBorders, coords] = painter.stencilConfigForOverlapTwoPass(tileIDs);
|
|
66
|
-
drawTiles(painter, tileManager, layer, coords, stencilBorderless, false, true, cornerCoords, false, isRenderingToTexture); // draw without borders
|
|
67
|
-
drawTiles(painter, tileManager, layer, coords, stencilBorders, true, true, cornerCoords, false, isRenderingToTexture); // draw with borders
|
|
70
|
+
drawTiles(painter, tileManager, layer, coords, stencilBorderless, false, true, cornerCoords, identityPerspectiveTransform, false, isRenderingToTexture); // draw without borders
|
|
71
|
+
drawTiles(painter, tileManager, layer, coords, stencilBorders, true, true, cornerCoords, identityPerspectiveTransform, false, isRenderingToTexture); // draw with borders
|
|
68
72
|
} else {
|
|
69
73
|
// Simple rendering
|
|
70
74
|
const [stencil, coords] = painter.getStencilConfigForOverlapAndUpdateStencilID(tileIDs);
|
|
71
|
-
drawTiles(painter, tileManager, layer, coords, stencil, false, true, cornerCoords, false, isRenderingToTexture);
|
|
75
|
+
drawTiles(painter, tileManager, layer, coords, stencil, false, true, cornerCoords, identityPerspectiveTransform, false, isRenderingToTexture);
|
|
72
76
|
}
|
|
73
77
|
}
|
|
74
78
|
|
|
@@ -81,6 +85,7 @@ function drawTiles(
|
|
|
81
85
|
useBorder: boolean,
|
|
82
86
|
allowPoles: boolean,
|
|
83
87
|
corners: Point[],
|
|
88
|
+
perspectiveTransform: RasterPerspectiveTransform,
|
|
84
89
|
flipCullfaceMode: boolean = false,
|
|
85
90
|
isRenderingToTexture: boolean = false) {
|
|
86
91
|
const minTileZ = coords[coords.length - 1].overscaledZ;
|
|
@@ -133,7 +138,7 @@ function drawTiles(
|
|
|
133
138
|
|
|
134
139
|
const terrainData = painter.getTerrainDataForTile(coord, isRenderingToTexture);
|
|
135
140
|
const projectionData = transform.getProjectionData({overscaledTileID: coord, aligned: align, applyGlobeMatrix: !isRenderingToTexture, applyTerrainMatrix: true});
|
|
136
|
-
const uniformValues = rasterUniformValues(parentTopLeft, parentScaleBy, fadeValues.fadeMix, layer, corners);
|
|
141
|
+
const uniformValues = rasterUniformValues(parentTopLeft, parentScaleBy, fadeValues.fadeMix, layer, corners, perspectiveTransform);
|
|
137
142
|
|
|
138
143
|
const mesh = projection.getMeshFromTileID(context, coord.canonical, useBorder, allowPoles, 'raster');
|
|
139
144
|
const stencilMode = stencilModes ? stencilModes[coord.overscaledZ] : StencilMode.disabled;
|
|
@@ -5,10 +5,18 @@ import type {UniformValues, UniformLocations} from '../uniform_binding.ts';
|
|
|
5
5
|
import type {RasterStyleLayer} from '../../style/style_layer/raster_style_layer.ts';
|
|
6
6
|
import type Point from '@mapbox/point-geometry';
|
|
7
7
|
|
|
8
|
+
export type RasterPerspectiveTransform = [number, number, number];
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Affine texture coordinates represented as a homogeneous transform.
|
|
12
|
+
*/
|
|
13
|
+
export const identityPerspectiveTransform: RasterPerspectiveTransform = [0, 0, 1];
|
|
14
|
+
|
|
8
15
|
export type RasterUniformsType = {
|
|
9
16
|
'u_tl_parent': Uniform2f;
|
|
10
17
|
'u_scale_parent': Uniform1f;
|
|
11
18
|
'u_buffer_scale': Uniform1f;
|
|
19
|
+
'u_perspective_transform': Uniform3f;
|
|
12
20
|
'u_fade_t': Uniform1f;
|
|
13
21
|
'u_opacity': Uniform1f;
|
|
14
22
|
'u_image0': Uniform1i;
|
|
@@ -26,6 +34,7 @@ const rasterUniforms = (context: Context, locations: UniformLocations): RasterUn
|
|
|
26
34
|
'u_tl_parent': new Uniform2f(context, locations.u_tl_parent),
|
|
27
35
|
'u_scale_parent': new Uniform1f(context, locations.u_scale_parent),
|
|
28
36
|
'u_buffer_scale': new Uniform1f(context, locations.u_buffer_scale),
|
|
37
|
+
'u_perspective_transform': new Uniform3f(context, locations.u_perspective_transform),
|
|
29
38
|
'u_fade_t': new Uniform1f(context, locations.u_fade_t),
|
|
30
39
|
'u_opacity': new Uniform1f(context, locations.u_opacity),
|
|
31
40
|
'u_image0': new Uniform1i(context, locations.u_image0),
|
|
@@ -48,6 +57,7 @@ const rasterUniformValues = (
|
|
|
48
57
|
},
|
|
49
58
|
layer: RasterStyleLayer,
|
|
50
59
|
cornerCoords: Point[],
|
|
60
|
+
perspectiveTransform: RasterPerspectiveTransform,
|
|
51
61
|
): UniformValues<RasterUniformsType> => ({
|
|
52
62
|
'u_tl_parent': parentTL,
|
|
53
63
|
'u_scale_parent': parentScaleBy,
|
|
@@ -56,6 +66,7 @@ const rasterUniformValues = (
|
|
|
56
66
|
// so that the texture coordinares for poles always lie beyond the edge of the texture.
|
|
57
67
|
// Right now the coordinates are placed right at the texture border.
|
|
58
68
|
'u_buffer_scale': 1,
|
|
69
|
+
'u_perspective_transform': perspectiveTransform,
|
|
59
70
|
'u_fade_t': fade.mix,
|
|
60
71
|
'u_opacity': fade.opacity * layer.paint.get('raster-opacity'),
|
|
61
72
|
'u_image0': 0,
|