maplibre-gl 2.3.1-pre.2 → 2.4.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.
@@ -104,6 +104,7 @@ export class MapEventHandler implements Handler {
104
104
  export class BlockableMapEventHandler {
105
105
  _map: Map;
106
106
  _delayContextMenu: boolean;
107
+ _ignoreContextMenu: boolean;
107
108
  _contextMenuEvent: MouseEvent;
108
109
 
109
110
  constructor(map: Map) {
@@ -112,6 +113,7 @@ export class BlockableMapEventHandler {
112
113
 
113
114
  reset() {
114
115
  this._delayContextMenu = false;
116
+ this._ignoreContextMenu = true;
115
117
  delete this._contextMenuEvent;
116
118
  }
117
119
 
@@ -122,6 +124,7 @@ export class BlockableMapEventHandler {
122
124
 
123
125
  mousedown() {
124
126
  this._delayContextMenu = true;
127
+ this._ignoreContextMenu = false;
125
128
  }
126
129
 
127
130
  mouseup() {
@@ -135,7 +138,7 @@ export class BlockableMapEventHandler {
135
138
  if (this._delayContextMenu) {
136
139
  // Mac: contextmenu fired on mousedown; we save it until mouseup for consistency's sake
137
140
  this._contextMenuEvent = e;
138
- } else {
141
+ } else if (!this._ignoreContextMenu) {
139
142
  // Windows: contextmenu fired on mouseup, so fire event now
140
143
  this._map.fire(new MapMouseEvent(e.type, this._map, e));
141
144
  }
@@ -13,6 +13,9 @@ import {LngLatBoundsLike} from '../geo/lng_lat_bounds';
13
13
  import {IControl} from './control/control';
14
14
  import EvaluationParameters from '../style/evaluation_parameters';
15
15
  import {fakeServer, FakeServer} from 'nise';
16
+ import {CameraOptions} from './camera';
17
+ import Terrain, {} from '../render/terrain';
18
+ import {mercatorZfromAltitude} from '../geo/mercator_coordinate';
16
19
 
17
20
  function createStyleSource() {
18
21
  return {
@@ -2132,6 +2135,108 @@ describe('Map', () => {
2132
2135
  map.fire(new Event('dataabort'));
2133
2136
  });
2134
2137
 
2138
+ describe('#calculateCameraOptionsFromTo', () => {
2139
+ // Choose initial zoom to avoid center being constrained by mercator latitude limits.
2140
+ test('pitch 90 with terrain', () => {
2141
+ const map = createMap();
2142
+
2143
+ const mockedGetElevation = jest.fn((_tileID: OverscaledTileID, _x: number, _y: number, _extent?: number) => 111200);
2144
+
2145
+ const terrainStub = {} as Terrain;
2146
+ terrainStub.getElevation = mockedGetElevation;
2147
+ map.style.terrain = terrainStub;
2148
+
2149
+ // distance between lng x and lng x+1 is 111.2km at same lat
2150
+ // altitude same as center elevation => 90° pitch
2151
+ const cameraOptions: CameraOptions = map.calculateCameraOptionsFromTo(new LngLat(1, 0), 111200, new LngLat(0, 0));
2152
+ expect(cameraOptions).toBeDefined();
2153
+ expect(cameraOptions.pitch).toBeCloseTo(90);
2154
+ expect(mockedGetElevation.mock.calls).toHaveLength(1);
2155
+ });
2156
+
2157
+ test('pitch 153.435 with terrain', () => {
2158
+ const map = createMap();
2159
+
2160
+ const mockedGetElevation = jest.fn((_tileID: OverscaledTileID, _x: number, _y: number, _extent?: number) => 111200 * 3);
2161
+
2162
+ const terrainStub = {} as Terrain;
2163
+ terrainStub.getElevation = mockedGetElevation;
2164
+ map.style.terrain = terrainStub;
2165
+ // distance between lng x and lng x+1 is 111.2km at same lat
2166
+ // (elevation difference of cam and center) / 2 = grounddistance =>
2167
+ // acos(111.2 / sqrt(111.2² + (111.2 * 2)²)) = acos(1/sqrt(5)) => 63.435 + 90 = 153.435
2168
+ const cameraOptions: CameraOptions = map.calculateCameraOptionsFromTo(new LngLat(1, 0), 111200, new LngLat(0, 0));
2169
+ expect(cameraOptions).toBeDefined();
2170
+ expect(cameraOptions.pitch).toBeCloseTo(153.435);
2171
+ expect(mockedGetElevation.mock.calls).toHaveLength(1);
2172
+ });
2173
+
2174
+ test('pitch 63 with terrain', () => {
2175
+ const map = createMap();
2176
+
2177
+ const mockedGetElevation = jest.fn((_tileID: OverscaledTileID, _x: number, _y: number, _extent?: number) => 111200 / 2);
2178
+
2179
+ const terrainStub = {} as Terrain;
2180
+ terrainStub.getElevation = mockedGetElevation;
2181
+ map.style.terrain = terrainStub;
2182
+
2183
+ // distance between lng x and lng x+1 is 111.2km at same lat
2184
+ // (elevation difference of cam and center) * 2 = grounddistance =>
2185
+ // acos(111.2 / sqrt(111.2² + (111.2 * 0.5)²)) = acos(1/sqrt(1.25)) => 90 (looking down) - 26.565 = 63.435
2186
+ const cameraOptions: CameraOptions = map.calculateCameraOptionsFromTo(new LngLat(0, 0), 111200, new LngLat(1, 0));
2187
+ expect(cameraOptions).toBeDefined();
2188
+ expect(cameraOptions.pitch).toBeCloseTo(63.435);
2189
+ expect(mockedGetElevation.mock.calls).toHaveLength(1);
2190
+ });
2191
+
2192
+ test('zoom distance 1000', () => {
2193
+ const map = createMap();
2194
+
2195
+ const mockedGetElevation = jest.fn((_tileID: OverscaledTileID, _x: number, _y: number, _extent?: number) => 1000);
2196
+
2197
+ const terrainStub = {} as Terrain;
2198
+ terrainStub.getElevation = mockedGetElevation;
2199
+ map.style.terrain = terrainStub;
2200
+
2201
+ const expectedZoom = Math.log2(map.transform.cameraToCenterDistance / mercatorZfromAltitude(1000, 0) / map.transform.tileSize);
2202
+ const cameraOptions = map.calculateCameraOptionsFromTo(new LngLat(0, 0), 0, new LngLat(0, 0));
2203
+
2204
+ expect(cameraOptions).toBeDefined();
2205
+ expect(cameraOptions.zoom).toBeCloseTo(expectedZoom);
2206
+ expect(mockedGetElevation.mock.calls).toHaveLength(1);
2207
+ });
2208
+
2209
+ test('don\'t call getElevation when altitude supplied', () => {
2210
+ const map = createMap();
2211
+
2212
+ const mockedGetElevation = jest.fn((_tileID: OverscaledTileID, _x: number, _y: number, _extent?: number) => 0);
2213
+
2214
+ const terrainStub = {} as Terrain;
2215
+ terrainStub.getElevation = mockedGetElevation;
2216
+ map.style.terrain = terrainStub;
2217
+
2218
+ const cameraOptions = map.calculateCameraOptionsFromTo(new LngLat(0, 0), 0, new LngLat(0, 0), 1000);
2219
+
2220
+ expect(cameraOptions).toBeDefined();
2221
+ expect(mockedGetElevation.mock.calls).toHaveLength(0);
2222
+ });
2223
+
2224
+ test('don\'t call getElevation when altitude 0 supplied', () => {
2225
+ const map = createMap();
2226
+
2227
+ const mockedGetElevation = jest.fn((_tileID: OverscaledTileID, _x: number, _y: number, _extent?: number) => 0);
2228
+
2229
+ const terrainStub = {} as Terrain;
2230
+ terrainStub.getElevation = mockedGetElevation;
2231
+ map.style.terrain = terrainStub;
2232
+
2233
+ const cameraOptions = map.calculateCameraOptionsFromTo(new LngLat(0, 0), 0, new LngLat(1, 0), 0);
2234
+
2235
+ expect(cameraOptions).toBeDefined();
2236
+ expect(mockedGetElevation.mock.calls).toHaveLength(0);
2237
+ });
2238
+ });
2239
+
2135
2240
  });
2136
2241
 
2137
2242
  function createStyle() {
package/src/ui/map.ts CHANGED
@@ -10,7 +10,7 @@ import Painter from '../render/painter';
10
10
  import Transform from '../geo/transform';
11
11
  import Hash from './hash';
12
12
  import HandlerManager from './handler_manager';
13
- import Camera from './camera';
13
+ import Camera, {CameraOptions} from './camera';
14
14
  import LngLat from '../geo/lng_lat';
15
15
  import LngLatBounds from '../geo/lng_lat_bounds';
16
16
  import Point from '@mapbox/point-geometry';
@@ -603,6 +603,13 @@ class Map extends Camera {
603
603
  return this._controls.indexOf(control) > -1;
604
604
  }
605
605
 
606
+ calculateCameraOptionsFromTo(from: LngLat, altitudeFrom: number, to: LngLat, altitudeTo?: number) : CameraOptions {
607
+ if (altitudeTo == null && this.style.terrain) {
608
+ altitudeTo = this.transform.getElevation(to, this.style.terrain);
609
+ }
610
+ return super.calculateCameraOptionsFromTo(from, altitudeFrom, to, altitudeTo);
611
+ }
612
+
606
613
  /**
607
614
  * Resizes the map according to the dimensions of its
608
615
  * `container` element.