@antv/l7-map 2.25.7 → 2.25.9

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 (159) hide show
  1. package/es/index.d.ts +5 -0
  2. package/es/index.js +4 -0
  3. package/es/map/camera.d.ts +690 -0
  4. package/es/map/camera.js +1138 -0
  5. package/es/map/css/l7.css +171 -0
  6. package/es/map/events.d.ts +384 -0
  7. package/es/map/events.js +231 -0
  8. package/es/map/geo/edge_insets.d.ts +97 -0
  9. package/es/map/geo/edge_insets.js +115 -0
  10. package/es/map/geo/lng_lat.d.ts +116 -0
  11. package/es/map/geo/lng_lat.js +159 -0
  12. package/es/map/geo/lng_lat_bounds.d.ts +217 -0
  13. package/es/map/geo/lng_lat_bounds.js +334 -0
  14. package/es/map/geo/mercator_coordinate.d.ts +113 -0
  15. package/es/map/geo/mercator_coordinate.js +142 -0
  16. package/es/map/geo/transform.d.ts +262 -0
  17. package/es/map/geo/transform.js +736 -0
  18. package/es/map/handler/box_zoom.d.ts +65 -0
  19. package/es/map/handler/box_zoom.js +145 -0
  20. package/es/map/handler/click_zoom.d.ts +24 -0
  21. package/es/map/handler/click_zoom.js +47 -0
  22. package/es/map/handler/cooperative_gestures.d.ts +40 -0
  23. package/es/map/handler/cooperative_gestures.js +94 -0
  24. package/es/map/handler/drag_handler.d.ts +88 -0
  25. package/es/map/handler/drag_handler.js +89 -0
  26. package/es/map/handler/drag_move_state_manager.d.ts +30 -0
  27. package/es/map/handler/drag_move_state_manager.js +94 -0
  28. package/es/map/handler/handler_util.d.ts +3 -0
  29. package/es/map/handler/handler_util.js +8 -0
  30. package/es/map/handler/keyboard.d.ts +88 -0
  31. package/es/map/handler/keyboard.js +197 -0
  32. package/es/map/handler/map_event.d.ts +46 -0
  33. package/es/map/handler/map_event.js +131 -0
  34. package/es/map/handler/mouse.d.ts +30 -0
  35. package/es/map/handler/mouse.js +85 -0
  36. package/es/map/handler/one_finger_touch_drag.d.ts +15 -0
  37. package/es/map/handler/one_finger_touch_drag.js +39 -0
  38. package/es/map/handler/scroll_zoom.d.ts +102 -0
  39. package/es/map/handler/scroll_zoom.js +312 -0
  40. package/es/map/handler/shim/dblclick_zoom.d.ts +44 -0
  41. package/es/map/handler/shim/dblclick_zoom.js +60 -0
  42. package/es/map/handler/shim/drag_pan.d.ts +79 -0
  43. package/es/map/handler/shim/drag_pan.js +77 -0
  44. package/es/map/handler/shim/drag_rotate.d.ts +54 -0
  45. package/es/map/handler/shim/drag_rotate.js +66 -0
  46. package/es/map/handler/shim/two_fingers_touch.d.ts +74 -0
  47. package/es/map/handler/shim/two_fingers_touch.js +106 -0
  48. package/es/map/handler/tap_drag_zoom.d.ts +28 -0
  49. package/es/map/handler/tap_drag_zoom.js +92 -0
  50. package/es/map/handler/tap_recognizer.d.ts +35 -0
  51. package/es/map/handler/tap_recognizer.js +107 -0
  52. package/es/map/handler/tap_zoom.d.ts +28 -0
  53. package/es/map/handler/tap_zoom.js +87 -0
  54. package/es/map/handler/touch_pan.d.ts +40 -0
  55. package/es/map/handler/touch_pan.js +85 -0
  56. package/es/map/handler/transform-provider.d.ts +23 -0
  57. package/es/map/handler/transform-provider.js +35 -0
  58. package/es/map/handler/two_fingers_touch.d.ts +107 -0
  59. package/es/map/handler/two_fingers_touch.js +289 -0
  60. package/es/map/handler_inertia.d.ts +20 -0
  61. package/es/map/handler_inertia.js +128 -0
  62. package/es/map/handler_manager.d.ts +154 -0
  63. package/es/map/handler_manager.js +466 -0
  64. package/es/map/map.d.ts +637 -0
  65. package/es/map/map.js +984 -0
  66. package/es/map/util/abort_error.d.ts +15 -0
  67. package/es/map/util/abort_error.js +21 -0
  68. package/es/map/util/browser.d.ts +10 -0
  69. package/es/map/util/browser.js +30 -0
  70. package/es/map/util/dom.d.ts +30 -0
  71. package/es/map/util/dom.js +105 -0
  72. package/es/map/util/evented.d.ts +75 -0
  73. package/es/map/util/evented.js +158 -0
  74. package/es/map/util/simpleMapCoord.d.ts +31 -0
  75. package/es/map/util/simpleMapCoord.js +54 -0
  76. package/es/map/util/task_queue.d.ts +18 -0
  77. package/es/map/util/task_queue.js +54 -0
  78. package/es/map/util/util.d.ts +104 -0
  79. package/es/map/util/util.js +155 -0
  80. package/lib/index.d.ts +5 -0
  81. package/lib/index.js +33 -0
  82. package/lib/map/camera.d.ts +690 -0
  83. package/lib/map/camera.js +1145 -0
  84. package/lib/map/css/l7.css +171 -0
  85. package/lib/map/events.d.ts +384 -0
  86. package/lib/map/events.js +240 -0
  87. package/lib/map/geo/edge_insets.d.ts +97 -0
  88. package/lib/map/geo/edge_insets.js +122 -0
  89. package/lib/map/geo/lng_lat.d.ts +116 -0
  90. package/lib/map/geo/lng_lat.js +166 -0
  91. package/lib/map/geo/lng_lat_bounds.d.ts +217 -0
  92. package/lib/map/geo/lng_lat_bounds.js +341 -0
  93. package/lib/map/geo/mercator_coordinate.d.ts +113 -0
  94. package/lib/map/geo/mercator_coordinate.js +157 -0
  95. package/lib/map/geo/transform.d.ts +262 -0
  96. package/lib/map/geo/transform.js +744 -0
  97. package/lib/map/handler/box_zoom.d.ts +65 -0
  98. package/lib/map/handler/box_zoom.js +153 -0
  99. package/lib/map/handler/click_zoom.d.ts +24 -0
  100. package/lib/map/handler/click_zoom.js +54 -0
  101. package/lib/map/handler/cooperative_gestures.d.ts +40 -0
  102. package/lib/map/handler/cooperative_gestures.js +101 -0
  103. package/lib/map/handler/drag_handler.d.ts +88 -0
  104. package/lib/map/handler/drag_handler.js +97 -0
  105. package/lib/map/handler/drag_move_state_manager.d.ts +30 -0
  106. package/lib/map/handler/drag_move_state_manager.js +103 -0
  107. package/lib/map/handler/handler_util.d.ts +3 -0
  108. package/lib/map/handler/handler_util.js +14 -0
  109. package/lib/map/handler/keyboard.d.ts +88 -0
  110. package/lib/map/handler/keyboard.js +205 -0
  111. package/lib/map/handler/map_event.d.ts +46 -0
  112. package/lib/map/handler/map_event.js +140 -0
  113. package/lib/map/handler/mouse.d.ts +30 -0
  114. package/lib/map/handler/mouse.js +93 -0
  115. package/lib/map/handler/one_finger_touch_drag.d.ts +15 -0
  116. package/lib/map/handler/one_finger_touch_drag.js +47 -0
  117. package/lib/map/handler/scroll_zoom.d.ts +102 -0
  118. package/lib/map/handler/scroll_zoom.js +320 -0
  119. package/lib/map/handler/shim/dblclick_zoom.d.ts +44 -0
  120. package/lib/map/handler/shim/dblclick_zoom.js +68 -0
  121. package/lib/map/handler/shim/drag_pan.d.ts +79 -0
  122. package/lib/map/handler/shim/drag_pan.js +85 -0
  123. package/lib/map/handler/shim/drag_rotate.d.ts +54 -0
  124. package/lib/map/handler/shim/drag_rotate.js +74 -0
  125. package/lib/map/handler/shim/two_fingers_touch.d.ts +74 -0
  126. package/lib/map/handler/shim/two_fingers_touch.js +114 -0
  127. package/lib/map/handler/tap_drag_zoom.d.ts +28 -0
  128. package/lib/map/handler/tap_drag_zoom.js +99 -0
  129. package/lib/map/handler/tap_recognizer.d.ts +35 -0
  130. package/lib/map/handler/tap_recognizer.js +116 -0
  131. package/lib/map/handler/tap_zoom.d.ts +28 -0
  132. package/lib/map/handler/tap_zoom.js +94 -0
  133. package/lib/map/handler/touch_pan.d.ts +40 -0
  134. package/lib/map/handler/touch_pan.js +92 -0
  135. package/lib/map/handler/transform-provider.d.ts +23 -0
  136. package/lib/map/handler/transform-provider.js +43 -0
  137. package/lib/map/handler/two_fingers_touch.d.ts +107 -0
  138. package/lib/map/handler/two_fingers_touch.js +296 -0
  139. package/lib/map/handler_inertia.d.ts +20 -0
  140. package/lib/map/handler_inertia.js +136 -0
  141. package/lib/map/handler_manager.d.ts +154 -0
  142. package/lib/map/handler_manager.js +474 -0
  143. package/lib/map/map.d.ts +637 -0
  144. package/lib/map/map.js +991 -0
  145. package/lib/map/util/abort_error.d.ts +15 -0
  146. package/lib/map/util/abort_error.js +29 -0
  147. package/lib/map/util/browser.d.ts +10 -0
  148. package/lib/map/util/browser.js +36 -0
  149. package/lib/map/util/dom.d.ts +30 -0
  150. package/lib/map/util/dom.js +113 -0
  151. package/lib/map/util/evented.d.ts +75 -0
  152. package/lib/map/util/evented.js +167 -0
  153. package/lib/map/util/simpleMapCoord.d.ts +31 -0
  154. package/lib/map/util/simpleMapCoord.js +62 -0
  155. package/lib/map/util/task_queue.d.ts +18 -0
  156. package/lib/map/util/task_queue.js +62 -0
  157. package/lib/map/util/util.d.ts +104 -0
  158. package/lib/map/util/util.js +171 -0
  159. package/package.json +2 -2
@@ -0,0 +1,736 @@
1
+ import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
2
+ import Point from '@mapbox/point-geometry';
3
+ import { mat2, mat4, vec4 } from 'gl-matrix';
4
+ import { clamp, interpolates, wrap } from "../util/util";
5
+ import { EdgeInsets } from "./edge_insets";
6
+ import { LngLat } from "./lng_lat";
7
+ import { LngLatBounds } from "./lng_lat_bounds";
8
+ import { MercatorCoordinate, mercatorXfromLng, mercatorYfromLat, mercatorZfromAltitude } from "./mercator_coordinate";
9
+ export const MAX_VALID_LATITUDE = 85.051129;
10
+
11
+ /**
12
+ * @internal
13
+ * A single transform, generally used for a single tile to be
14
+ * scaled, rotated, and zoomed.
15
+ */
16
+ export class Transform {
17
+ constructor(minZoom, maxZoom, minPitch, maxPitch, renderWorldCopies) {
18
+ _defineProperty(this, "tileSize", void 0);
19
+ _defineProperty(this, "tileZoom", void 0);
20
+ _defineProperty(this, "lngRange", void 0);
21
+ _defineProperty(this, "latRange", void 0);
22
+ _defineProperty(this, "scale", void 0);
23
+ _defineProperty(this, "width", void 0);
24
+ _defineProperty(this, "height", void 0);
25
+ _defineProperty(this, "angle", void 0);
26
+ _defineProperty(this, "rotationMatrix", void 0);
27
+ _defineProperty(this, "pixelsToGLUnits", void 0);
28
+ _defineProperty(this, "cameraToCenterDistance", void 0);
29
+ _defineProperty(this, "mercatorMatrix", void 0);
30
+ _defineProperty(this, "projMatrix", void 0);
31
+ _defineProperty(this, "invProjMatrix", void 0);
32
+ _defineProperty(this, "alignedProjMatrix", void 0);
33
+ _defineProperty(this, "pixelMatrix", void 0);
34
+ _defineProperty(this, "pixelMatrix3D", void 0);
35
+ _defineProperty(this, "pixelMatrixInverse", void 0);
36
+ _defineProperty(this, "glCoordMatrix", void 0);
37
+ _defineProperty(this, "labelPlaneMatrix", void 0);
38
+ _defineProperty(this, "minElevationForCurrentTile", void 0);
39
+ _defineProperty(this, "_fov", void 0);
40
+ _defineProperty(this, "_pitch", void 0);
41
+ _defineProperty(this, "_zoom", void 0);
42
+ _defineProperty(this, "_unmodified", void 0);
43
+ _defineProperty(this, "_renderWorldCopies", void 0);
44
+ _defineProperty(this, "_minZoom", void 0);
45
+ _defineProperty(this, "_maxZoom", void 0);
46
+ _defineProperty(this, "_minPitch", void 0);
47
+ _defineProperty(this, "_maxPitch", void 0);
48
+ _defineProperty(this, "_center", void 0);
49
+ _defineProperty(this, "_elevation", void 0);
50
+ _defineProperty(this, "_pixelPerMeter", void 0);
51
+ _defineProperty(this, "_edgeInsets", void 0);
52
+ _defineProperty(this, "_constraining", void 0);
53
+ _defineProperty(this, "_posMatrixCache", void 0);
54
+ _defineProperty(this, "_alignedPosMatrixCache", void 0);
55
+ this.tileSize = 512; // constant
56
+
57
+ this._renderWorldCopies = renderWorldCopies === undefined ? true : !!renderWorldCopies;
58
+ this._minZoom = minZoom || 0;
59
+ this._maxZoom = maxZoom || 22;
60
+ this._minPitch = minPitch === undefined || minPitch === null ? 0 : minPitch;
61
+ this._maxPitch = maxPitch === undefined || maxPitch === null ? 60 : maxPitch;
62
+ this.setMaxBounds();
63
+ this.width = 0;
64
+ this.height = 0;
65
+ this._center = new LngLat(0, 0);
66
+ this._elevation = 0;
67
+ this.zoom = 0;
68
+ this.angle = 0;
69
+ this._fov = 0.6435011087932844;
70
+ this._pitch = 0;
71
+ this._unmodified = true;
72
+ this._edgeInsets = new EdgeInsets();
73
+ this._posMatrixCache = {};
74
+ this._alignedPosMatrixCache = {};
75
+ this.minElevationForCurrentTile = 0;
76
+ }
77
+ clone() {
78
+ const clone = new Transform(this._minZoom, this._maxZoom, this._minPitch, this.maxPitch, this._renderWorldCopies);
79
+ clone.apply(this);
80
+ return clone;
81
+ }
82
+ apply(that) {
83
+ this.tileSize = that.tileSize;
84
+ this.latRange = that.latRange;
85
+ this.width = that.width;
86
+ this.height = that.height;
87
+ this._center = that._center;
88
+ this._elevation = that._elevation;
89
+ this.minElevationForCurrentTile = that.minElevationForCurrentTile;
90
+ this.zoom = that.zoom;
91
+ this.angle = that.angle;
92
+ this._fov = that._fov;
93
+ this._pitch = that._pitch;
94
+ this._unmodified = that._unmodified;
95
+ this._edgeInsets = that._edgeInsets.clone();
96
+ this._calcMatrices();
97
+ }
98
+ get minZoom() {
99
+ return this._minZoom;
100
+ }
101
+ set minZoom(zoom) {
102
+ if (this._minZoom === zoom) return;
103
+ this._minZoom = zoom;
104
+ this.zoom = Math.max(this.zoom, zoom);
105
+ }
106
+ get maxZoom() {
107
+ return this._maxZoom;
108
+ }
109
+ set maxZoom(zoom) {
110
+ if (this._maxZoom === zoom) return;
111
+ this._maxZoom = zoom;
112
+ this.zoom = Math.min(this.zoom, zoom);
113
+ }
114
+ get minPitch() {
115
+ return this._minPitch;
116
+ }
117
+ set minPitch(pitch) {
118
+ if (this._minPitch === pitch) return;
119
+ this._minPitch = pitch;
120
+ this.pitch = Math.max(this.pitch, pitch);
121
+ }
122
+ get maxPitch() {
123
+ return this._maxPitch;
124
+ }
125
+ set maxPitch(pitch) {
126
+ if (this._maxPitch === pitch) return;
127
+ this._maxPitch = pitch;
128
+ this.pitch = Math.min(this.pitch, pitch);
129
+ }
130
+ get renderWorldCopies() {
131
+ return this._renderWorldCopies;
132
+ }
133
+ set renderWorldCopies(renderWorldCopies) {
134
+ if (renderWorldCopies === undefined) {
135
+ renderWorldCopies = true;
136
+ } else if (renderWorldCopies === null) {
137
+ renderWorldCopies = false;
138
+ }
139
+ this._renderWorldCopies = renderWorldCopies;
140
+ }
141
+ get worldSize() {
142
+ return this.tileSize * this.scale;
143
+ }
144
+ get centerOffset() {
145
+ return this.centerPoint._sub(this.size._div(2));
146
+ }
147
+ get size() {
148
+ return new Point(this.width, this.height);
149
+ }
150
+ get bearing() {
151
+ return -this.angle / Math.PI * 180;
152
+ }
153
+ set bearing(bearing) {
154
+ const b = -wrap(bearing, -180, 180) * Math.PI / 180;
155
+ if (this.angle === b) return;
156
+ this._unmodified = false;
157
+ this.angle = b;
158
+ this._calcMatrices();
159
+
160
+ // 2x2 matrix for rotating points
161
+ this.rotationMatrix = mat2.create();
162
+ mat2.rotate(this.rotationMatrix, this.rotationMatrix, this.angle);
163
+ }
164
+ get pitch() {
165
+ return this._pitch / Math.PI * 180;
166
+ }
167
+ set pitch(pitch) {
168
+ const p = clamp(pitch, this.minPitch, this.maxPitch) / 180 * Math.PI;
169
+ if (this._pitch === p) return;
170
+ this._unmodified = false;
171
+ this._pitch = p;
172
+ this._calcMatrices();
173
+ }
174
+ get fov() {
175
+ return this._fov / Math.PI * 180;
176
+ }
177
+ set fov(fov) {
178
+ fov = Math.max(0.01, Math.min(60, fov));
179
+ if (this._fov === fov) return;
180
+ this._unmodified = false;
181
+ this._fov = fov / 180 * Math.PI;
182
+ this._calcMatrices();
183
+ }
184
+ get zoom() {
185
+ return this._zoom;
186
+ }
187
+ set zoom(zoom) {
188
+ const constrainedZoom = Math.min(Math.max(zoom, this.minZoom), this.maxZoom);
189
+ if (this._zoom === constrainedZoom) return;
190
+ this._unmodified = false;
191
+ this._zoom = constrainedZoom;
192
+ this.tileZoom = Math.max(0, Math.floor(constrainedZoom));
193
+ this.scale = this.zoomScale(constrainedZoom);
194
+ this._constrain();
195
+ this._calcMatrices();
196
+ }
197
+ get center() {
198
+ return this._center;
199
+ }
200
+ set center(center) {
201
+ if (center.lat === this._center.lat && center.lng === this._center.lng) return;
202
+ this._unmodified = false;
203
+ this._center = center;
204
+ this._constrain();
205
+ this._calcMatrices();
206
+ }
207
+
208
+ /**
209
+ * Elevation at current center point, meters above sea level
210
+ */
211
+ get elevation() {
212
+ return this._elevation;
213
+ }
214
+ set elevation(elevation) {
215
+ if (elevation === this._elevation) return;
216
+ this._elevation = elevation;
217
+ this._constrain();
218
+ this._calcMatrices();
219
+ }
220
+ get padding() {
221
+ return this._edgeInsets.toJSON();
222
+ }
223
+ set padding(padding) {
224
+ if (this._edgeInsets.equals(padding)) return;
225
+ this._unmodified = false;
226
+ //Update edge-insets inplace
227
+ this._edgeInsets.interpolate(this._edgeInsets, padding, 1);
228
+ this._calcMatrices();
229
+ }
230
+
231
+ /**
232
+ * The center of the screen in pixels with the top-left corner being (0,0)
233
+ * and +y axis pointing downwards. This accounts for padding.
234
+ */
235
+ get centerPoint() {
236
+ return this._edgeInsets.getCenter(this.width, this.height);
237
+ }
238
+
239
+ /**
240
+ * Returns if the padding params match
241
+ *
242
+ * @param padding - the padding to check against
243
+ * @returns true if they are equal, false otherwise
244
+ */
245
+ isPaddingEqual(padding) {
246
+ return this._edgeInsets.equals(padding);
247
+ }
248
+
249
+ /**
250
+ * Helper method to update edge-insets in place
251
+ *
252
+ * @param start - the starting padding
253
+ * @param target - the target padding
254
+ * @param t - the step/weight
255
+ */
256
+ interpolatePadding(start, target, t) {
257
+ this._unmodified = false;
258
+ this._edgeInsets.interpolate(start, target, t);
259
+ this._constrain();
260
+ this._calcMatrices();
261
+ }
262
+
263
+ /**
264
+ * Return a zoom level that will cover all tiles the transform
265
+ * @param options - the options
266
+ * @returns zoom level An integer zoom level at which all tiles will be visible.
267
+ */
268
+ coveringZoomLevel(options) {
269
+ const z = (options.roundZoom ? Math.round : Math.floor)(this.zoom + this.scaleZoom(this.tileSize / options.tileSize));
270
+ // At negative zoom levels load tiles from z0 because negative tile zoom levels don't exist.
271
+ return Math.max(0, z);
272
+ }
273
+ resize(width, height) {
274
+ this.width = width;
275
+ this.height = height;
276
+ this.pixelsToGLUnits = [2 / width, -2 / height];
277
+ this._constrain();
278
+ this._calcMatrices();
279
+ }
280
+ get unmodified() {
281
+ return this._unmodified;
282
+ }
283
+ zoomScale(zoom) {
284
+ return Math.pow(2, zoom);
285
+ }
286
+ scaleZoom(scale) {
287
+ return Math.log(scale) / Math.LN2;
288
+ }
289
+
290
+ /**
291
+ * Convert from LngLat to world coordinates (Mercator coordinates scaled by 512)
292
+ * @param lnglat - the lngLat
293
+ * @returns Point
294
+ */
295
+ project(lnglat) {
296
+ const lat = clamp(lnglat.lat, -MAX_VALID_LATITUDE, MAX_VALID_LATITUDE);
297
+ return new Point(mercatorXfromLng(lnglat.lng) * this.worldSize, mercatorYfromLat(lat) * this.worldSize);
298
+ }
299
+
300
+ /**
301
+ * Convert from world coordinates ([0, 512],[0, 512]) to LngLat ([-180, 180], [-90, 90])
302
+ * @param point - world coordinate
303
+ * @returns LngLat
304
+ */
305
+ unproject(point) {
306
+ return new MercatorCoordinate(point.x / this.worldSize, point.y / this.worldSize).toLngLat();
307
+ }
308
+ get point() {
309
+ return this.project(this.center);
310
+ }
311
+
312
+ /**
313
+ * get the camera position in LngLat and altitudes in meter
314
+ * @returns An object with lngLat & altitude.
315
+ */
316
+ getCameraPosition() {
317
+ const lngLat = this.pointLocation(this.getCameraPoint());
318
+ const altitude = Math.cos(this._pitch) * this.cameraToCenterDistance / this._pixelPerMeter;
319
+ return {
320
+ lngLat,
321
+ altitude: altitude + this.elevation
322
+ };
323
+ }
324
+ setLocationAtPoint(lnglat, point) {
325
+ const a = this.pointCoordinate(point);
326
+ const b = this.pointCoordinate(this.centerPoint);
327
+ const loc = this.locationCoordinate(lnglat);
328
+ const newCenter = new MercatorCoordinate(loc.x - (a.x - b.x), loc.y - (a.y - b.y));
329
+ this.center = this.coordinateLocation(newCenter);
330
+ if (this._renderWorldCopies) {
331
+ this.center = this.center.wrap();
332
+ }
333
+ }
334
+
335
+ /**
336
+ * Given a LngLat location, return the screen point that corresponds to it
337
+ * @param lnglat - location
338
+ * @param terrain - optional terrain
339
+ * @returns screen point
340
+ */
341
+ locationPoint(lnglat) {
342
+ return this.coordinatePoint(this.locationCoordinate(lnglat));
343
+ }
344
+
345
+ /**
346
+ * Given a point on screen, return its lnglat
347
+ * @param p - screen point
348
+ * @param terrain - optional terrain
349
+ * @returns lnglat location
350
+ */
351
+ pointLocation(p) {
352
+ return this.coordinateLocation(this.pointCoordinate(p));
353
+ }
354
+
355
+ /**
356
+ * Given a geographical lnglat, return an unrounded
357
+ * coordinate that represents it at low zoom level.
358
+ * @param lnglat - the location
359
+ * @returns The mercator coordinate
360
+ */
361
+ locationCoordinate(lnglat) {
362
+ return MercatorCoordinate.fromLngLat(lnglat);
363
+ }
364
+
365
+ /**
366
+ * Given a Coordinate, return its geographical position.
367
+ * @param coord - mercator coordinates
368
+ * @returns lng and lat
369
+ */
370
+ coordinateLocation(coord) {
371
+ return coord && coord.toLngLat();
372
+ }
373
+
374
+ /**
375
+ * Given a Point, return its mercator coordinate.
376
+ * @param p - the point
377
+ * @param terrain - optional terrain
378
+ * @returns lnglat
379
+ */
380
+ pointCoordinate(p) {
381
+ // calculate point-coordinate on flat earth
382
+ const targetZ = 0;
383
+ // since we don't know the correct projected z value for the point,
384
+ // unproject two points to get a line and then find the point on that
385
+ // line with z=0
386
+
387
+ const coord0 = [p.x, p.y, 0, 1];
388
+ const coord1 = [p.x, p.y, 1, 1];
389
+ vec4.transformMat4(coord0, coord0, this.pixelMatrixInverse);
390
+ vec4.transformMat4(coord1, coord1, this.pixelMatrixInverse);
391
+ const w0 = coord0[3];
392
+ const w1 = coord1[3];
393
+ const x0 = coord0[0] / w0;
394
+ const x1 = coord1[0] / w1;
395
+ const y0 = coord0[1] / w0;
396
+ const y1 = coord1[1] / w1;
397
+ const z0 = coord0[2] / w0;
398
+ const z1 = coord1[2] / w1;
399
+ const t = z0 === z1 ? 0 : (targetZ - z0) / (z1 - z0);
400
+ return new MercatorCoordinate(interpolates.number(x0, x1, t) / this.worldSize, interpolates.number(y0, y1, t) / this.worldSize);
401
+ }
402
+
403
+ /**
404
+ * Given a coordinate, return the screen point that corresponds to it
405
+ * @param coord - the coordinates
406
+ * @param elevation - the elevation
407
+ * @param pixelMatrix - the pixel matrix
408
+ * @returns screen point
409
+ */
410
+ coordinatePoint(coord, elevation = 0, pixelMatrix = this.pixelMatrix) {
411
+ const p = [coord.x * this.worldSize, coord.y * this.worldSize, elevation, 1];
412
+ vec4.transformMat4(p, p, pixelMatrix);
413
+ return new Point(p[0] / p[3], p[1] / p[3]);
414
+ }
415
+
416
+ /**
417
+ * Returns the map's geographical bounds. When the bearing or pitch is non-zero, the visible region is not
418
+ * an axis-aligned rectangle, and the result is the smallest bounds that encompasses the visible region.
419
+ * @returns Returns a {@link LngLatBounds} object describing the map's geographical bounds.
420
+ */
421
+ getBounds() {
422
+ const top = Math.max(0, this.height / 2 - this.getHorizon());
423
+ return new LngLatBounds().extend(this.pointLocation(new Point(0, top))).extend(this.pointLocation(new Point(this.width, top))).extend(this.pointLocation(new Point(this.width, this.height))).extend(this.pointLocation(new Point(0, this.height)));
424
+ }
425
+
426
+ /**
427
+ * Returns the maximum geographical bounds the map is constrained to, or `null` if none set.
428
+ * @returns max bounds
429
+ */
430
+ getMaxBounds() {
431
+ if (!this.latRange || this.latRange.length !== 2 || !this.lngRange || this.lngRange.length !== 2) return null;
432
+ return new LngLatBounds([this.lngRange[0], this.latRange[0]], [this.lngRange[1], this.latRange[1]]);
433
+ }
434
+
435
+ /**
436
+ * Calculate pixel height of the visible horizon in relation to map-center (e.g. height/2),
437
+ * multiplied by a static factor to simulate the earth-radius.
438
+ * The calculated value is the horizontal line from the camera-height to sea-level.
439
+ * @returns Horizon above center in pixels.
440
+ */
441
+ getHorizon() {
442
+ return Math.tan(Math.PI / 2 - this._pitch) * this.cameraToCenterDistance * 0.85;
443
+ }
444
+
445
+ /**
446
+ * Sets or clears the map's geographical constraints.
447
+ * @param bounds - A {@link LngLatBounds} object describing the new geographic boundaries of the map.
448
+ */
449
+ setMaxBounds(bounds) {
450
+ if (bounds) {
451
+ this.lngRange = [bounds.getWest(), bounds.getEast()];
452
+ this.latRange = [bounds.getSouth(), bounds.getNorth()];
453
+ this._constrain();
454
+ } else {
455
+ this.lngRange = null;
456
+ this.latRange = [-MAX_VALID_LATITUDE, MAX_VALID_LATITUDE];
457
+ }
458
+ }
459
+ customLayerMatrix() {
460
+ return mat4.clone(this.mercatorMatrix);
461
+ }
462
+
463
+ /**
464
+ * Get center lngLat and zoom to ensure that
465
+ * 1) everything beyond the bounds is excluded
466
+ * 2) a given lngLat is as near the center as possible
467
+ * Bounds are those set by maxBounds or North & South "Poles" and, if only 1 globe is displayed, antimeridian.
468
+ */
469
+ getConstrained(lngLat, zoom) {
470
+ zoom = clamp(+zoom, this.minZoom, this.maxZoom);
471
+ const result = {
472
+ center: new LngLat(lngLat.lng, lngLat.lat),
473
+ zoom
474
+ };
475
+ let lngRange = this.lngRange;
476
+ if (!this._renderWorldCopies && lngRange === null) {
477
+ const almost180 = 180 - 1e-10;
478
+ lngRange = [-almost180, almost180];
479
+ }
480
+ const worldSize = this.tileSize * this.zoomScale(result.zoom); // A world size for the requested zoom level, not the current world size
481
+ let minY = 0;
482
+ let maxY = worldSize;
483
+ let minX = 0;
484
+ let maxX = worldSize;
485
+ let scaleY = 0;
486
+ let scaleX = 0;
487
+ const {
488
+ x: screenWidth,
489
+ y: screenHeight
490
+ } = this.size;
491
+ if (this.latRange) {
492
+ const latRange = this.latRange;
493
+ minY = mercatorYfromLat(latRange[1]) * worldSize;
494
+ maxY = mercatorYfromLat(latRange[0]) * worldSize;
495
+ const shouldZoomIn = maxY - minY < screenHeight;
496
+ if (shouldZoomIn) scaleY = screenHeight / (maxY - minY);
497
+ }
498
+ if (lngRange) {
499
+ minX = wrap(mercatorXfromLng(lngRange[0]) * worldSize, 0, worldSize);
500
+ maxX = wrap(mercatorXfromLng(lngRange[1]) * worldSize, 0, worldSize);
501
+ if (maxX < minX) maxX += worldSize;
502
+ const shouldZoomIn = maxX - minX < screenWidth;
503
+ if (shouldZoomIn) scaleX = screenWidth / (maxX - minX);
504
+ }
505
+ const {
506
+ x: originalX,
507
+ y: originalY
508
+ } = this.project.call({
509
+ worldSize
510
+ }, lngLat);
511
+ let modifiedX, modifiedY;
512
+ const scale = Math.max(scaleX || 0, scaleY || 0);
513
+ if (scale) {
514
+ // zoom in to exclude all beyond the given lng/lat ranges
515
+ const newPoint = new Point(scaleX ? (maxX + minX) / 2 : originalX, scaleY ? (maxY + minY) / 2 : originalY);
516
+ result.center = this.unproject.call({
517
+ worldSize
518
+ }, newPoint).wrap();
519
+ result.zoom += this.scaleZoom(scale);
520
+ return result;
521
+ }
522
+ if (this.latRange) {
523
+ const h2 = screenHeight / 2;
524
+ if (originalY - h2 < minY) modifiedY = minY + h2;
525
+ if (originalY + h2 > maxY) modifiedY = maxY - h2;
526
+ }
527
+ if (lngRange) {
528
+ const centerX = (minX + maxX) / 2;
529
+ let wrappedX = originalX;
530
+ if (this._renderWorldCopies) {
531
+ wrappedX = wrap(originalX, centerX - worldSize / 2, centerX + worldSize / 2);
532
+ }
533
+ const w2 = screenWidth / 2;
534
+ if (wrappedX - w2 < minX) modifiedX = minX + w2;
535
+ if (wrappedX + w2 > maxX) modifiedX = maxX - w2;
536
+ }
537
+
538
+ // pan the map if the screen goes off the range
539
+ if (modifiedX !== undefined || modifiedY !== undefined) {
540
+ var _modifiedX, _modifiedY;
541
+ const newPoint = new Point((_modifiedX = modifiedX) !== null && _modifiedX !== void 0 ? _modifiedX : originalX, (_modifiedY = modifiedY) !== null && _modifiedY !== void 0 ? _modifiedY : originalY);
542
+ result.center = this.unproject.call({
543
+ worldSize
544
+ }, newPoint).wrap();
545
+ }
546
+ return result;
547
+ }
548
+ _constrain() {
549
+ if (!this.center || !this.width || !this.height || this._constraining) return;
550
+ this._constraining = true;
551
+ const unmodified = this._unmodified;
552
+ const {
553
+ center,
554
+ zoom
555
+ } = this.getConstrained(this.center, this.zoom);
556
+ this.center = center;
557
+ this.zoom = zoom;
558
+ this._unmodified = unmodified;
559
+ this._constraining = false;
560
+ }
561
+ _calcMatrices() {
562
+ if (!this.height) return;
563
+ const halfFov = this._fov / 2;
564
+ const offset = this.centerOffset;
565
+ const x = this.point.x,
566
+ y = this.point.y;
567
+ this.cameraToCenterDistance = 0.5 / Math.tan(halfFov) * this.height;
568
+ this._pixelPerMeter = mercatorZfromAltitude(1, this.center.lat) * this.worldSize;
569
+ let m = mat4.identity(new Float64Array(16));
570
+ mat4.scale(m, m, [this.width / 2, -this.height / 2, 1]);
571
+ mat4.translate(m, m, [1, -1, 0]);
572
+ this.labelPlaneMatrix = m;
573
+ m = mat4.identity(new Float64Array(16));
574
+ mat4.scale(m, m, [1, -1, 1]);
575
+ mat4.translate(m, m, [-1, -1, 0]);
576
+ mat4.scale(m, m, [2 / this.width, 2 / this.height, 1]);
577
+ this.glCoordMatrix = m;
578
+
579
+ // Calculate the camera to sea-level distance in pixel in respect of terrain
580
+ const cameraToSeaLevelDistance = this.cameraToCenterDistance + this._elevation * this._pixelPerMeter / Math.cos(this._pitch);
581
+ // In case of negative minimum elevation (e.g. the dead see, under the sea maps) use a lower plane for calculation
582
+ const minElevation = Math.min(this.elevation, this.minElevationForCurrentTile);
583
+ const cameraToLowestPointDistance = cameraToSeaLevelDistance - minElevation * this._pixelPerMeter / Math.cos(this._pitch);
584
+ const lowestPlane = minElevation < 0 ? cameraToLowestPointDistance : cameraToSeaLevelDistance;
585
+
586
+ // Find the distance from the center point [width/2 + offset.x, height/2 + offset.y] to the
587
+ // center top point [width/2 + offset.x, 0] in Z units, using the law of sines.
588
+ // 1 Z unit is equivalent to 1 horizontal px at the center of the map
589
+ // (the distance between[width/2, height/2] and [width/2 + 1, height/2])
590
+ const groundAngle = Math.PI / 2 + this._pitch;
591
+ const fovAboveCenter = this._fov * (0.5 + offset.y / this.height);
592
+ const topHalfSurfaceDistance = Math.sin(fovAboveCenter) * lowestPlane / Math.sin(clamp(Math.PI - groundAngle - fovAboveCenter, 0.01, Math.PI - 0.01));
593
+
594
+ // Find the distance from the center point to the horizon
595
+ const horizon = this.getHorizon();
596
+ const horizonAngle = Math.atan(horizon / this.cameraToCenterDistance);
597
+ const fovCenterToHorizon = 2 * horizonAngle * (0.5 + offset.y / (horizon * 2));
598
+ const topHalfSurfaceDistanceHorizon = Math.sin(fovCenterToHorizon) * lowestPlane / Math.sin(clamp(Math.PI - groundAngle - fovCenterToHorizon, 0.01, Math.PI - 0.01));
599
+
600
+ // Calculate z distance of the farthest fragment that should be rendered.
601
+ // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance`
602
+ const topHalfMinDistance = Math.min(topHalfSurfaceDistance, topHalfSurfaceDistanceHorizon);
603
+ const farZ = (Math.cos(Math.PI / 2 - this._pitch) * topHalfMinDistance + lowestPlane) * 1.01;
604
+
605
+ // The larger the value of nearZ is
606
+ // - the more depth precision is available for features (good)
607
+ // - clipping starts appearing sooner when the camera is close to 3d features (bad)
608
+ //
609
+ // Other values work for mapbox-gl-js but deckgl was encountering precision issues
610
+ // when rendering custom layers. This value was experimentally chosen and
611
+ // seems to solve z-fighting issues in deckgl while not clipping buildings too close to the camera.
612
+ const nearZ = this.height / 50;
613
+
614
+ // matrix for conversion from location to clip space(-1 .. 1)
615
+ m = new Float64Array(16);
616
+ mat4.perspective(m, this._fov, this.width / this.height, nearZ, farZ);
617
+
618
+ // Apply center of perspective offset
619
+ m[8] = -offset.x * 2 / this.width;
620
+ m[9] = offset.y * 2 / this.height;
621
+ mat4.scale(m, m, [1, -1, 1]);
622
+ mat4.translate(m, m, [0, 0, -this.cameraToCenterDistance]);
623
+ mat4.rotateX(m, m, this._pitch);
624
+ mat4.rotateZ(m, m, this.angle);
625
+ mat4.translate(m, m, [-x, -y, 0]);
626
+
627
+ // The mercatorMatrix can be used to transform points from mercator coordinates
628
+ // ([0, 0] nw, [1, 1] se) to clip space.
629
+ this.mercatorMatrix = mat4.scale([], m, [this.worldSize, this.worldSize, this.worldSize]);
630
+
631
+ // scale vertically to meters per pixel (inverse of ground resolution):
632
+ mat4.scale(m, m, [1, 1, this._pixelPerMeter]);
633
+
634
+ // matrix for conversion from world space to screen coordinates in 2D
635
+ this.pixelMatrix = mat4.multiply(new Float64Array(16), this.labelPlaneMatrix, m);
636
+
637
+ // matrix for conversion from world space to clip space (-1 .. 1)
638
+ mat4.translate(m, m, [0, 0, -this.elevation]); // elevate camera over terrain
639
+ this.projMatrix = m;
640
+ this.invProjMatrix = mat4.invert([], m);
641
+
642
+ // matrix for conversion from world space to screen coordinates in 3D
643
+ this.pixelMatrix3D = mat4.multiply(new Float64Array(16), this.labelPlaneMatrix, m);
644
+
645
+ // Make a second projection matrix that is aligned to a pixel grid for rendering raster tiles.
646
+ // We're rounding the (floating point) x/y values to achieve to avoid rendering raster images to fractional
647
+ // coordinates. Additionally, we adjust by half a pixel in either direction in case that viewport dimension
648
+ // is an odd integer to preserve rendering to the pixel grid. We're rotating this shift based on the angle
649
+ // of the transformation so that 0°, 90°, 180°, and 270° rasters are crisp, and adjust the shift so that
650
+ // it is always <= 0.5 pixels.
651
+ const xShift = this.width % 2 / 2,
652
+ yShift = this.height % 2 / 2,
653
+ angleCos = Math.cos(this.angle),
654
+ angleSin = Math.sin(this.angle),
655
+ dx = x - Math.round(x) + angleCos * xShift + angleSin * yShift,
656
+ dy = y - Math.round(y) + angleCos * yShift + angleSin * xShift;
657
+ const alignedM = new Float64Array(m);
658
+ mat4.translate(alignedM, alignedM, [dx > 0.5 ? dx - 1 : dx, dy > 0.5 ? dy - 1 : dy, 0]);
659
+ this.alignedProjMatrix = alignedM;
660
+
661
+ // inverse matrix for conversion from screen coordinates to location
662
+ m = mat4.invert(new Float64Array(16), this.pixelMatrix);
663
+ if (!m) throw new Error('failed to invert matrix');
664
+ this.pixelMatrixInverse = m;
665
+ this._posMatrixCache = {};
666
+ this._alignedPosMatrixCache = {};
667
+ }
668
+ maxPitchScaleFactor() {
669
+ // calcMatrices hasn't run yet
670
+ if (!this.pixelMatrixInverse) return 1;
671
+ const coord = this.pointCoordinate(new Point(0, 0));
672
+ const p = [coord.x * this.worldSize, coord.y * this.worldSize, 0, 1];
673
+ const topPoint = vec4.transformMat4(p, p, this.pixelMatrix);
674
+ return topPoint[3] / this.cameraToCenterDistance;
675
+ }
676
+
677
+ /**
678
+ * The camera looks at the map from a 3D (lng, lat, altitude) location. Let's use `cameraLocation`
679
+ * as the name for the location under the camera and on the surface of the earth (lng, lat, 0).
680
+ * `cameraPoint` is the projected position of the `cameraLocation`.
681
+ *
682
+ * This point is useful to us because only fill-extrusions that are between `cameraPoint` and
683
+ * the query point on the surface of the earth can extend and intersect the query.
684
+ *
685
+ * When the map is not pitched the `cameraPoint` is equivalent to the center of the map because
686
+ * the camera is right above the center of the map.
687
+ */
688
+ getCameraPoint() {
689
+ const pitch = this._pitch;
690
+ const yOffset = Math.tan(pitch) * (this.cameraToCenterDistance || 1);
691
+ return this.centerPoint.add(new Point(0, yOffset));
692
+ }
693
+
694
+ /**
695
+ * When the map is pitched, some of the 3D features that intersect a query will not intersect
696
+ * the query at the surface of the earth. Instead the feature may be closer and only intersect
697
+ * the query because it extrudes into the air.
698
+ * @param queryGeometry - For point queries, the line from the query point to the "camera point",
699
+ * for other geometries, the envelope of the query geometry and the "camera point"
700
+ * @returns a geometry that includes all of the original query as well as all possible ares of the
701
+ * screen where the *base* of a visible extrusion could be.
702
+ *
703
+ */
704
+ getCameraQueryGeometry(queryGeometry) {
705
+ const c = this.getCameraPoint();
706
+ if (queryGeometry.length === 1) {
707
+ return [queryGeometry[0], c];
708
+ } else {
709
+ let minX = c.x;
710
+ let minY = c.y;
711
+ let maxX = c.x;
712
+ let maxY = c.y;
713
+ for (const p of queryGeometry) {
714
+ minX = Math.min(minX, p.x);
715
+ minY = Math.min(minY, p.y);
716
+ maxX = Math.max(maxX, p.x);
717
+ maxY = Math.max(maxY, p.y);
718
+ }
719
+ return [new Point(minX, minY), new Point(maxX, minY), new Point(maxX, maxY), new Point(minX, maxY), new Point(minX, minY)];
720
+ }
721
+ }
722
+ /**
723
+ * Return the distance to the camera in clip space from a LngLat.
724
+ * This can be compared to the value from the depth buffer (terrain.depthAtPoint)
725
+ * to determine whether a point is occluded.
726
+ * @param lngLat - the point
727
+ * @param elevation - the point's elevation
728
+ * @returns depth value in clip space (between 0 and 1)
729
+ */
730
+ lngLatToCameraDepth(lngLat, elevation) {
731
+ const coord = this.locationCoordinate(lngLat);
732
+ const p = [coord.x * this.worldSize, coord.y * this.worldSize, elevation, 1];
733
+ vec4.transformMat4(p, p, this.projMatrix);
734
+ return p[2] / p[3];
735
+ }
736
+ }