maplibre-gl 6.11.0 → 6.11.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/README.md +1 -1
- package/dist/maplibre-gl-dev.mjs +203 -107
- package/dist/maplibre-gl-dev.mjs.map +1 -1
- package/dist/maplibre-gl-shared-dev.mjs +1 -3
- 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 +1 -1
- package/dist/maplibre-gl-worker.mjs +6 -2
- package/dist/maplibre-gl-worker.mjs.map +1 -1
- package/dist/maplibre-gl.d.ts +54 -5
- package/dist/maplibre-gl.mjs +13 -13
- package/dist/maplibre-gl.mjs.map +1 -1
- package/package.json +2 -2
- package/src/source/geojson_source.test.ts +32 -13
- package/src/source/geojson_source.ts +8 -3
- package/src/source/geojson_source_diff.test.ts +10 -0
- package/src/source/geojson_source_diff.ts +7 -44
- package/src/source/vector_tile_source.test.ts +25 -0
- package/src/source/vector_tile_source.ts +3 -0
- package/src/ui/camera.ts +34 -0
- package/src/ui/handler_manager.test.ts +30 -12
- package/src/ui/handler_manager.ts +50 -29
- package/src/ui/map.ts +4 -15
- package/src/ui/map_tests/map_terrain.test.ts +98 -0
- package/src/util/dom.test.ts +136 -2
- package/src/util/dom.ts +97 -35
package/README.md
CHANGED
|
@@ -104,7 +104,7 @@ Silver:
|
|
|
104
104
|
|
|
105
105
|
<a href="https://www.caltopo.com/"><img src="https://maplibre.org/img/caltopo-logo.svg" alt="Logo Caltopo" width="25%"/></a>
|
|
106
106
|
|
|
107
|
-
<a href="https://www.
|
|
107
|
+
<a href="https://www.smartmaps.net/"><img src="https://maplibre.org/img/smartmaps-logo.svg" alt="Logo SmartMaps" width="25%"/></a>
|
|
108
108
|
|
|
109
109
|
Backers and Supporters:
|
|
110
110
|
|
package/dist/maplibre-gl-dev.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MapLibre GL JS
|
|
3
|
-
* @license 3-Clause BSD. Full text of license: https://github.com/maplibre/maplibre-gl-js/blob/v6.11.
|
|
3
|
+
* @license 3-Clause BSD. Full text of license: https://github.com/maplibre/maplibre-gl-js/blob/v6.11.1/LICENSE.txt
|
|
4
4
|
*/
|
|
5
5
|
import { $ as projectToWorldCoordinates, $n as differenceOfAnglesDegrees, $r as add, $t as Transitionable, A as evaluateSizeForZoom, Ai as rotateX, An as addProtocol, Ar as scaleZoom, At as toEvaluationFeature, B as isCluster, Bi as rotate, Bn as arrayBufferToImage, Br as EXTENT, Bt as SegmentVector, C as addDynamicAttributes, Ci as exactEquals, Cn as GLOBAL_DISPATCHER_ID, Cr as pointPlaneSignedDistance, Ct as HEATMAP_FULL_RENDER_FBO_KEY, Di as multiply, Dn as getVideo, Dr as remapSaturate, Dt as RGBAImage, E as TextAnchorEnum, Ei as invert$1, En as getReferrer, Er as readImageUsingVideoFrame, Et as AlphaImage, F as potpack, Fi as create$4, Fn as isAbortError, Fr as uniqueId, Ft as Uniform4f, Gn as createIdentityMat4f32, Gr as zero, Gt as PosArray, Hi as offscreenCanvasSupported, Hn as bezier, Hr as length$1, Ht as CollisionCircleLayoutArray, I as isStyleImageWebGLData, Ii as fromRotation, In as throwIfAborted, Ir as warnOnce, It as UniformColor, J as cameraDirectionFromPitchBearing, Jn as createVec3f64, Jr as multiply$1, Jt as TriangleIndexArray, K as isFillExtrusionStyleLayer, Kn as createIdentityMat4f64, Kr as fromEuler, Kt as QuadTriangleArray, L as renderStyleImage, Li as create$2, Lr as wrap, Lt as UniformColorArray, M as getAnchorAlignment, Mi as rotateZ, Mn as removeProtocol, Mr as subscribe, Mt as Uniform1i, Ni as scale, Nn as config, Nr as threePlaneIntersection, Nt as Uniform2f, O as clipLine, Oi as ortho, On as makeRequest, Or as rollPitchBearingEqual, Ot as isCircleStyleLayer, P as ImagePosition, Pi as translate, Pn as AbortError, Pr as translatePosition, Pt as Uniform3f, Q as maxMercatorHorizonAngle, Qn as degreesToRadians, Qr as transformMat4, Qt as Properties, R as parseGlyphPbf, Ri as determinant, Rn as MAX_VALID_LATITUDE, Rr as zoomScale, Rt as UniformFloatArray, S as SymbolBucket, Si as equals, Sn as AJAXError, Sr as pick, St as isHillshadeStyleLayer, T as getAnchorJustification, Ti as identity, Tn as getJSON, Tr as rayPlaneIntersection, Tt as renderColorRamp, U as collisionCircleLayout, Ui as Point, Un as clamp, Ur as scale$3, Ut as LineStripIndexArray, V as codePointUsesLocalIdeographFontFamily, Vi as isOffscreenCanvasDistorted, Vn as arrayBufferToImageBitmap, Vr as create$3, Vt as CollisionBoxArray, W as isLineStyleLayer, Wn as clone$2, Wr as sqrLen, Wt as Pos3dArray, X as cameraMercatorCoordinateFromCenterAndRotation, Xn as deepEqual, Xr as mul, Xt as isRasterStyleLayer, Y as cameraMercatorCoordinate, Yn as createVec4f64, Yr as slerp, Yt as createLayout, Z as getMercatorHorizon, Zn as defaultEasing, Zr as scale$2, Zt as DataConstantProperty, _ as createStyleLayer, _i as transformQuat, _n as derefLayers, _r as lerp, _t as SubdivisionGranularityExpression, a as GeoJSONFeature, ai as length, an as validateAndEmit, ar as findLineIntersection, at as lngFromMercatorX, b as isBackgroundStyleLayer, bi as copy, bn as Event, br as nextPowerOfTwo, ci as rotateX$1, cn as emptyStyle, cr as getEdgeTiles, ct as mercatorZfromAltitude, d as OverscaledTileID, di as scale$1, dr as isImageBitmap, ei as clone, en as EvaluationParameters, er as distanceOfAnglesRadians, et as tileCoordinatesToMercatorCoordinates, f as UnwrappedTileID, fi as scaleAndAdd, fn as interpolateFactory, fr as isPointableEvent, ft as EXTENT_BOUNDS, g as Actor, gi as transformMat4$1, gn as diff, gr as isWorker, gt as SOUTH_POLE_Y, h as isInBoundsForZoomLngLat, hi as transformMat3, hn as ValidationError, hr as isTouchableOrPointableType, ht as NORTH_POLE_Y, ii as len, in as emitValidationErrors, ir as filterObject, it as latFromMercatorY, ji as rotateY$1, jn as getProtocol, jr as sphericalToCartesian, jt as Uniform1f, k as evaluateSizeForFeature, ki as perspective, kn as sameOrigin, kr as rollPitchBearingToQuat, kt as polygonIntersectsPolygon, li as rotateY, lt as LngLat, m as compareTileId, mi as subtract, mn as Color, mr as isTouchableEvent, mt as isFillStyleLayer, n as TileCache, ni as distance, nr as evaluateZoomSnap, nt as MercatorCoordinate, oi as negate, on as validateStyle, or as getAABB, ot as mercatorXfromLng, p as calculateTileKey, pi as sub, pn as ProjectionDefinition, pr as isSafari, pt as Bounds, q as calculateTileMatrix, qn as createMat4f64, qr as fromValues, qt as RasterBoundsArray, ri as dot, rn as SPEC_SOURCE_TYPES, rr as extend, rt as altitudeFromMercatorZ, s as GEOJSON_TILE_LAYER_NAME, si as normalize, sn as validateStyleAndEmit, sr as getAngleDelta, st as mercatorYfromLat, ti as cross, tn as ZoomHistory, tr as ensureError, tt as unprojectFromWorldCoordinates, u as CanonicalTileID, ui as rotateZ$1, un as featureFilter, ur as getRollPitchBearing, ut as earthRadius, v as isCustomStyleLayer, vi as zero$1, vn as latest, vr as mapObject, vt as SubdivisionGranularitySetting, w as getOverlapMode, wi as fromScaling, wn as getArrayBuffer, wr as radiansToDegrees, wt as isHeatmapStyleLayer, x as isSymbolStyleLayer, xi as create$1, xn as Evented, xr as parseCacheControl, xt as Texture, y as validateCustomStyleLayer, yi as clone$1, yn as ErrorEvent, yr as mod, yt as isColorReliefStyleLayer, zi as invert, zn as angleToRotateBetweenVectors2D, zr as pixelsToTileUnits, zt as UniformMatrix4f } from "./maplibre-gl-shared-dev.mjs";
|
|
6
6
|
//#region package.json
|
|
7
|
-
var version$2 = "6.11.
|
|
7
|
+
var version$2 = "6.11.1";
|
|
8
8
|
//#endregion
|
|
9
9
|
//#region src/util/browser.ts
|
|
10
10
|
let linkEl;
|
|
@@ -198,6 +198,92 @@ function isTimeFrozen() {
|
|
|
198
198
|
}
|
|
199
199
|
//#endregion
|
|
200
200
|
//#region src/util/dom.ts
|
|
201
|
+
const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
|
|
202
|
+
const ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
203
|
+
"a",
|
|
204
|
+
"abbr",
|
|
205
|
+
"b",
|
|
206
|
+
"bdi",
|
|
207
|
+
"bdo",
|
|
208
|
+
"br",
|
|
209
|
+
"cite",
|
|
210
|
+
"code",
|
|
211
|
+
"del",
|
|
212
|
+
"div",
|
|
213
|
+
"em",
|
|
214
|
+
"i",
|
|
215
|
+
"img",
|
|
216
|
+
"ins",
|
|
217
|
+
"kbd",
|
|
218
|
+
"li",
|
|
219
|
+
"mark",
|
|
220
|
+
"ol",
|
|
221
|
+
"p",
|
|
222
|
+
"q",
|
|
223
|
+
"s",
|
|
224
|
+
"samp",
|
|
225
|
+
"small",
|
|
226
|
+
"span",
|
|
227
|
+
"strong",
|
|
228
|
+
"sub",
|
|
229
|
+
"sup",
|
|
230
|
+
"time",
|
|
231
|
+
"u",
|
|
232
|
+
"ul",
|
|
233
|
+
"var",
|
|
234
|
+
"wbr"
|
|
235
|
+
]);
|
|
236
|
+
const ALLOWED_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
237
|
+
"alt",
|
|
238
|
+
"class",
|
|
239
|
+
"datetime",
|
|
240
|
+
"dir",
|
|
241
|
+
"height",
|
|
242
|
+
"href",
|
|
243
|
+
"hreflang",
|
|
244
|
+
"lang",
|
|
245
|
+
"referrerpolicy",
|
|
246
|
+
"rel",
|
|
247
|
+
"role",
|
|
248
|
+
"src",
|
|
249
|
+
"target",
|
|
250
|
+
"title",
|
|
251
|
+
"translate",
|
|
252
|
+
"type",
|
|
253
|
+
"width"
|
|
254
|
+
]);
|
|
255
|
+
const URL_ATTRIBUTES = /* @__PURE__ */ new Set(["href", "src"]);
|
|
256
|
+
const ALLOWED_PROTOCOLS = /* @__PURE__ */ new Set([
|
|
257
|
+
"http:",
|
|
258
|
+
"https:",
|
|
259
|
+
"mailto:"
|
|
260
|
+
]);
|
|
261
|
+
/**
|
|
262
|
+
* Relative URLs have to resolve against something before their protocol can be read. Only the protocol of the
|
|
263
|
+
* result is used, so the base never leaks into the sanitized markup.
|
|
264
|
+
*/
|
|
265
|
+
const RELATIVE_URL_BASE = "https://maplibre.invalid/";
|
|
266
|
+
let elementInternals;
|
|
267
|
+
/**
|
|
268
|
+
* The `Element` members the sanitizer uses, read off the prototype rather than off the element it is looking at.
|
|
269
|
+
* A form control named `children`, `remove` or `localName` shadows the same-named property of its own form element,
|
|
270
|
+
* which would otherwise let untrusted markup pick what the sanitizer walking that tree sees.
|
|
271
|
+
*
|
|
272
|
+
* They are read on first use rather than when this module is loaded, since the module is also imported where there
|
|
273
|
+
* is no DOM at all, such as during server side rendering.
|
|
274
|
+
*/
|
|
275
|
+
function getElementInternals() {
|
|
276
|
+
elementInternals ??= {
|
|
277
|
+
getAttribute: Element.prototype.getAttribute,
|
|
278
|
+
getAttributeNames: Element.prototype.getAttributeNames,
|
|
279
|
+
querySelectorAll: Element.prototype.querySelectorAll,
|
|
280
|
+
remove: Element.prototype.remove,
|
|
281
|
+
removeAttribute: Element.prototype.removeAttribute,
|
|
282
|
+
localName: Object.getOwnPropertyDescriptor(Element.prototype, "localName").get,
|
|
283
|
+
namespaceURI: Object.getOwnPropertyDescriptor(Element.prototype, "namespaceURI").get
|
|
284
|
+
};
|
|
285
|
+
return elementInternals;
|
|
286
|
+
}
|
|
201
287
|
var DOM = class DOM {
|
|
202
288
|
static {
|
|
203
289
|
this.docStyle = typeof window !== "undefined" && window.document?.documentElement.style;
|
|
@@ -257,55 +343,54 @@ var DOM = class DOM {
|
|
|
257
343
|
return points;
|
|
258
344
|
}
|
|
259
345
|
/**
|
|
260
|
-
* Sanitize an HTML string
|
|
261
|
-
*
|
|
262
|
-
*
|
|
346
|
+
* Sanitize an untrusted HTML string, such as the attribution a remote TileJSON asks the map to display.
|
|
347
|
+
*
|
|
348
|
+
* Only the elements in `ALLOWED_TAGS` and the attributes in `ALLOWED_ATTRIBUTES` survive; anything else is
|
|
349
|
+
* dropped along with its subtree. An allow list is used rather than a list of known-dangerous markup because
|
|
350
|
+
* the latter silently permits whatever it has not heard of yet, including markup added to HTML after it was
|
|
351
|
+
* written.
|
|
263
352
|
*
|
|
264
|
-
*
|
|
353
|
+
* The sanitized nodes are returned rather than a string: serializing and re-parsing is not a round trip, so
|
|
354
|
+
* a string result lets carefully nested markup mutate into a different - and no longer sanitized - tree.
|
|
265
355
|
*/
|
|
266
356
|
static sanitize(str) {
|
|
267
|
-
const
|
|
268
|
-
const
|
|
269
|
-
for (const element of
|
|
270
|
-
|
|
357
|
+
const body = new DOMParser().parseFromString(str, "text/html").body;
|
|
358
|
+
const { querySelectorAll, remove } = getElementInternals();
|
|
359
|
+
for (const element of Array.from(querySelectorAll.call(body, "*"))) if (DOM.isAllowedElement(element)) DOM.removeDisallowedAttributes(element);
|
|
360
|
+
else remove.call(element);
|
|
271
361
|
const fragment = document.createDocumentFragment();
|
|
272
|
-
fragment.append(...
|
|
362
|
+
fragment.append(...body.childNodes);
|
|
273
363
|
return fragment;
|
|
274
364
|
}
|
|
275
365
|
/**
|
|
276
|
-
*
|
|
366
|
+
* An element is allowed only when it is plain HTML markup on the allow list. Elements in the SVG and MathML
|
|
367
|
+
* namespaces are rejected even when their local name is allowed, since foreign content follows different
|
|
368
|
+
* parsing rules and is what makes most mutation attacks possible in the first place.
|
|
277
369
|
*/
|
|
278
|
-
static
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
"src",
|
|
282
|
-
"href",
|
|
283
|
-
"xlink:href"
|
|
284
|
-
].includes(name)) {
|
|
285
|
-
if (val.includes("javascript:") || val.includes("data:")) return true;
|
|
286
|
-
}
|
|
287
|
-
if (name === "srcdoc") return true;
|
|
288
|
-
if (name.startsWith("on")) return true;
|
|
370
|
+
static isAllowedElement(element) {
|
|
371
|
+
const { namespaceURI, localName } = getElementInternals();
|
|
372
|
+
return namespaceURI.call(element) === HTML_NAMESPACE && ALLOWED_TAGS.has(localName.call(element));
|
|
289
373
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
const nodes = html.children;
|
|
296
|
-
for (const node of nodes) {
|
|
297
|
-
DOM.removeAttributes(node);
|
|
298
|
-
DOM.clean(node);
|
|
374
|
+
static removeDisallowedAttributes(element) {
|
|
375
|
+
const { getAttributeNames, getAttribute, removeAttribute } = getElementInternals();
|
|
376
|
+
for (const name of getAttributeNames.call(element)) {
|
|
377
|
+
if (DOM.isAllowedAttribute(name, getAttribute.call(element, name))) continue;
|
|
378
|
+
removeAttribute.call(element, name);
|
|
299
379
|
}
|
|
300
380
|
}
|
|
301
381
|
/**
|
|
302
|
-
*
|
|
303
|
-
*
|
|
382
|
+
* `href` and `src` are further restricted to the protocols in `ALLOWED_PROTOCOLS`, so that `javascript:` and
|
|
383
|
+
* `data:` URLs cannot turn an otherwise harmless link or image into a script. The protocol is taken from a
|
|
384
|
+
* parsed URL rather than matched against the raw string, since the URL parser is what the browser will apply
|
|
385
|
+
* and it ignores tabs, newlines and leading control characters that a string comparison would trip over.
|
|
304
386
|
*/
|
|
305
|
-
static
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
387
|
+
static isAllowedAttribute(name, value) {
|
|
388
|
+
if (!ALLOWED_ATTRIBUTES.has(name) && !name.startsWith("aria-")) return false;
|
|
389
|
+
if (!URL_ATTRIBUTES.has(name)) return true;
|
|
390
|
+
try {
|
|
391
|
+
return ALLOWED_PROTOCOLS.has(new URL(value, RELATIVE_URL_BASE).protocol);
|
|
392
|
+
} catch {
|
|
393
|
+
return false;
|
|
309
394
|
}
|
|
310
395
|
}
|
|
311
396
|
};
|
|
@@ -2963,6 +3048,7 @@ var VectorTileSource = class extends Evented {
|
|
|
2963
3048
|
};
|
|
2964
3049
|
params.request.collectResourceTiming = this._collectResourceTiming;
|
|
2965
3050
|
await this.dispatcher.waitForInitComplete();
|
|
3051
|
+
if (tile.aborted) return;
|
|
2966
3052
|
let messageType = "RT";
|
|
2967
3053
|
if (!tile.actor || tile.state === "expired") {
|
|
2968
3054
|
tile.actor = this.dispatcher.getReadyActor();
|
|
@@ -3474,18 +3560,13 @@ function applySourceDiff(updateable, diff, promoteId) {
|
|
|
3474
3560
|
/**
|
|
3475
3561
|
* Merge two GeoJSONSourceDiffs, considering the order of operations as specified above (remove, add, update).
|
|
3476
3562
|
*
|
|
3477
|
-
*
|
|
3478
|
-
* the merge can be completed, then reverted to the original promoteId state after the merge.
|
|
3563
|
+
* `add` features of a promoteId source carry their id in a property, so `promoteId` is needed to key them.
|
|
3479
3564
|
*/
|
|
3480
3565
|
function mergeSourceDiffs(prevDiff, nextDiff, promoteId) {
|
|
3481
3566
|
if (!prevDiff) return nextDiff || {};
|
|
3482
3567
|
if (!nextDiff) return prevDiff || {};
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
promoteFeatureIds(nextDiff.add, promoteId);
|
|
3486
|
-
}
|
|
3487
|
-
const prev = diffToHashed(prevDiff);
|
|
3488
|
-
const next = diffToHashed(nextDiff);
|
|
3568
|
+
const prev = diffToHashed(prevDiff, promoteId);
|
|
3569
|
+
const next = diffToHashed(nextDiff, promoteId);
|
|
3489
3570
|
resolveMergeConflicts(prev, next);
|
|
3490
3571
|
const merged = {};
|
|
3491
3572
|
if (prev.removeAll || next.removeAll) merged.removeAll = true;
|
|
@@ -3493,9 +3574,7 @@ function mergeSourceDiffs(prevDiff, nextDiff, promoteId) {
|
|
|
3493
3574
|
merged.add = new Map([...prev.add, ...next.add]);
|
|
3494
3575
|
merged.update = new Map([...prev.update, ...next.update]);
|
|
3495
3576
|
if (merged.remove.size && merged.add.size) for (const id of merged.add.keys()) merged.remove.delete(id);
|
|
3496
|
-
|
|
3497
|
-
if (promoteId) demoteFeatureIds(mergedDiff.add, promoteId);
|
|
3498
|
-
return mergedDiff;
|
|
3577
|
+
return hashedToDiff(merged);
|
|
3499
3578
|
}
|
|
3500
3579
|
/**
|
|
3501
3580
|
* Resolve merge conflicts between two GeoJSONSourceDiffs considering the ordering above (remove/add/update).
|
|
@@ -3542,32 +3621,16 @@ function mergeFeatureDiffs(prev, next) {
|
|
|
3542
3621
|
return merged;
|
|
3543
3622
|
}
|
|
3544
3623
|
/**
|
|
3545
|
-
* Mutates diff.add and applies a feature id using the promoteId property
|
|
3546
|
-
*/
|
|
3547
|
-
function promoteFeatureIds(add, promoteId) {
|
|
3548
|
-
if (!add) return;
|
|
3549
|
-
for (const feature of add) {
|
|
3550
|
-
const id = getFeatureId(feature, promoteId);
|
|
3551
|
-
if (id != null) feature.id = id;
|
|
3552
|
-
}
|
|
3553
|
-
}
|
|
3554
|
-
/**
|
|
3555
|
-
* Mutates diff.add and removes the feature id if using the promoteId property
|
|
3556
|
-
*/
|
|
3557
|
-
function demoteFeatureIds(add, promoteId) {
|
|
3558
|
-
if (!add) return;
|
|
3559
|
-
for (const feature of add) if (getFeatureId(feature, promoteId) != null) delete feature.id;
|
|
3560
|
-
}
|
|
3561
|
-
/**
|
|
3562
3624
|
* @internal
|
|
3563
3625
|
* Convert a GeoJSONSourceDiff to an idempotent hashed representation using Sets and Maps
|
|
3626
|
+
* @param promoteId - If set, `add` features are keyed by that property instead of by `id`.
|
|
3564
3627
|
*/
|
|
3565
|
-
function diffToHashed(diff) {
|
|
3628
|
+
function diffToHashed(diff, promoteId) {
|
|
3566
3629
|
if (!diff) return {};
|
|
3567
3630
|
const hashed = {};
|
|
3568
3631
|
hashed.removeAll = diff.removeAll;
|
|
3569
3632
|
hashed.remove = new Set(diff.remove || []);
|
|
3570
|
-
hashed.add = new Map(diff.add?.map((feature) => [feature
|
|
3633
|
+
hashed.add = new Map(diff.add?.map((feature) => [getFeatureId(feature, promoteId), feature]));
|
|
3571
3634
|
hashed.update = new Map(diff.update?.map((update) => [update.id, update]));
|
|
3572
3635
|
return hashed;
|
|
3573
3636
|
}
|
|
@@ -3718,7 +3781,7 @@ var GeoJSONSource = class extends Evented {
|
|
|
3718
3781
|
maxZoom: this.maxzoom,
|
|
3719
3782
|
lineMetrics: options.lineMetrics || false,
|
|
3720
3783
|
generateId: options.generateId || false,
|
|
3721
|
-
promoteId:
|
|
3784
|
+
promoteId: this._promoteIdKey,
|
|
3722
3785
|
cluster: options.cluster || false,
|
|
3723
3786
|
clusterOptions: {
|
|
3724
3787
|
maxZoom: this._getClusterMaxZoom(options.clusterMaxZoom),
|
|
@@ -3733,6 +3796,10 @@ var GeoJSONSource = class extends Evented {
|
|
|
3733
3796
|
filter: options.filter
|
|
3734
3797
|
}, options.workerOptions);
|
|
3735
3798
|
}
|
|
3799
|
+
/** The `promoteId` property name, when it is a plain string. */
|
|
3800
|
+
get _promoteIdKey() {
|
|
3801
|
+
return typeof this.promoteId === "string" ? this.promoteId : void 0;
|
|
3802
|
+
}
|
|
3736
3803
|
_hasPendingWorkerUpdate() {
|
|
3737
3804
|
return this._pendingWorkerUpdate.data !== void 0 || this._pendingWorkerUpdate.diff !== void 0 || this._pendingWorkerUpdate.updateCluster;
|
|
3738
3805
|
}
|
|
@@ -3779,7 +3846,7 @@ var GeoJSONSource = class extends Evented {
|
|
|
3779
3846
|
* @param diff - The changes that need to be applied.
|
|
3780
3847
|
*/
|
|
3781
3848
|
updateData(diff) {
|
|
3782
|
-
this._pendingWorkerUpdate.diff = mergeSourceDiffs(this._pendingWorkerUpdate.diff, diff);
|
|
3849
|
+
this._pendingWorkerUpdate.diff = mergeSourceDiffs(this._pendingWorkerUpdate.diff, diff, this._promoteIdKey);
|
|
3783
3850
|
return this._updateWorkerData();
|
|
3784
3851
|
}
|
|
3785
3852
|
/**
|
|
@@ -4011,7 +4078,7 @@ var GeoJSONSource = class extends Evented {
|
|
|
4011
4078
|
*/
|
|
4012
4079
|
_applyDiffToSource(diff) {
|
|
4013
4080
|
if (!diff) return;
|
|
4014
|
-
const promoteId =
|
|
4081
|
+
const promoteId = this._promoteIdKey;
|
|
4015
4082
|
if (!this._data.url && !this._data.updateable) {
|
|
4016
4083
|
const updateable = toUpdateable(this._data.geojson, promoteId);
|
|
4017
4084
|
if (!updateable) throw new Error(`GeoJSONSource "${this.id}": GeoJSON data is not compatible with updateData`);
|
|
@@ -22544,7 +22611,10 @@ var HandlerManager = class {
|
|
|
22544
22611
|
return this._el?.ownerDocument?.defaultView || window;
|
|
22545
22612
|
}
|
|
22546
22613
|
constructor(map, camera, options) {
|
|
22547
|
-
this.
|
|
22614
|
+
this._terrainGesture = {
|
|
22615
|
+
inFlight: false,
|
|
22616
|
+
anchorElevation: null
|
|
22617
|
+
};
|
|
22548
22618
|
this.handleWindowEvent = (e) => {
|
|
22549
22619
|
this.handleEvent(e, `${e.type}Window`);
|
|
22550
22620
|
};
|
|
@@ -22729,7 +22799,7 @@ var HandlerManager = class {
|
|
|
22729
22799
|
const touchPitch = map.touchPitch = new TwoFingersTouchPitchHandler(map);
|
|
22730
22800
|
this._add("touchPitch", touchPitch);
|
|
22731
22801
|
if (options.interactive && options.touchPitch) map.touchPitch.enable(options.touchPitch);
|
|
22732
|
-
const getCenter = () =>
|
|
22802
|
+
const getCenter = () => this._camera.transform.centerPoint;
|
|
22733
22803
|
const mouseRotate = generateMouseRotationHandler(options, getCenter);
|
|
22734
22804
|
const mousePitch = generateMousePitchHandler(options);
|
|
22735
22805
|
const mouseRoll = generateMouseRollHandler(options, getCenter);
|
|
@@ -22833,14 +22903,18 @@ var HandlerManager = class {
|
|
|
22833
22903
|
this._updateMapTransform(combined, combinedEventsInProgress, combinedDeactivatedHandlers);
|
|
22834
22904
|
this._changes = [];
|
|
22835
22905
|
}
|
|
22906
|
+
/**
|
|
22907
|
+
* Applies a frame's combined handler deltas to the requested camera state and fires the movement
|
|
22908
|
+
* events. A frame without a change only fires the events and takes no requested camera state, so a
|
|
22909
|
+
* trailing frame that merely ends a handler leaves none behind for the next gesture to start from.
|
|
22910
|
+
*/
|
|
22836
22911
|
_updateMapTransform(combinedResult, combinedEventsInProgress, deactivatedHandlers) {
|
|
22837
|
-
const
|
|
22838
|
-
|
|
22839
|
-
const terrain = map.terrain;
|
|
22840
|
-
if (!hasChange(combinedResult) && !(terrain && this._terrainMovement)) {
|
|
22912
|
+
const terrain = this._map.terrain;
|
|
22913
|
+
if (!hasChange(combinedResult)) {
|
|
22841
22914
|
this._fireEvents(combinedEventsInProgress, deactivatedHandlers, true);
|
|
22842
22915
|
return;
|
|
22843
22916
|
}
|
|
22917
|
+
const tr = this._camera.getTransformForUpdate();
|
|
22844
22918
|
this._camera.stop(true);
|
|
22845
22919
|
const { panDelta, zoomDelta, bearingDelta, pitchDelta, rollDelta } = combinedResult;
|
|
22846
22920
|
let { around, aroundOnSurface } = this._resolveAround(combinedResult, terrain, tr);
|
|
@@ -22895,12 +22969,12 @@ var HandlerManager = class {
|
|
|
22895
22969
|
*/
|
|
22896
22970
|
_terrainGestureElevation(terrain, around, aroundOnSurface, tr, combinedEventsInProgress) {
|
|
22897
22971
|
if (!aroundOnSurface) return;
|
|
22898
|
-
if (
|
|
22972
|
+
if (this._terrainGesture.anchorElevation === null && (combinedEventsInProgress.drag || combinedEventsInProgress.zoom)) {
|
|
22899
22973
|
const anchor = tr.screenTerrainPointToMercatorCoordinate(around, terrain);
|
|
22900
|
-
this.
|
|
22974
|
+
this._terrainGesture.anchorElevation = anchor ? anchor.z : void 0;
|
|
22901
22975
|
}
|
|
22902
|
-
|
|
22903
|
-
|
|
22976
|
+
const elevation = this._terrainGesture.anchorElevation;
|
|
22977
|
+
if (elevation === null || elevation === void 0) return;
|
|
22904
22978
|
if (around.distSqr(tr.centerPoint) < .01) return;
|
|
22905
22979
|
if (elevation - tr.elevation >= TERRAIN_ANCHOR_MAX_CAMERA_ALTITUDE_FRACTION * (tr.getCameraAltitude() - tr.elevation)) return;
|
|
22906
22980
|
return elevation;
|
|
@@ -22924,21 +22998,13 @@ var HandlerManager = class {
|
|
|
22924
22998
|
cameraHelper.handleMapControlsPan(deltasForHelper, tr, preZoomAroundLoc);
|
|
22925
22999
|
return;
|
|
22926
23000
|
}
|
|
22927
|
-
if (
|
|
22928
|
-
|
|
22929
|
-
this._terrainMovement = true;
|
|
22930
|
-
this._camera.elevationFreeze = true;
|
|
22931
|
-
}
|
|
22932
|
-
cameraHelper.handleMapControlsPan(deltasForHelper, tr, preZoomAroundLoc);
|
|
22933
|
-
return;
|
|
22934
|
-
}
|
|
22935
|
-
if (!this._terrainMovement && (combinedEventsInProgress.drag || combinedEventsInProgress.zoom)) {
|
|
22936
|
-
this._terrainMovement = true;
|
|
23001
|
+
if (!this._terrainGesture.inFlight) {
|
|
23002
|
+
this._terrainGesture.inFlight = true;
|
|
22937
23003
|
this._camera.elevationFreeze = true;
|
|
22938
23004
|
cameraHelper.handleMapControlsPan(deltasForHelper, tr, preZoomAroundLoc);
|
|
22939
23005
|
return;
|
|
22940
23006
|
}
|
|
22941
|
-
if (deltasForHelper.aroundElevation === void 0 && combinedEventsInProgress.drag &&
|
|
23007
|
+
if (!cameraHelper.useGlobeControls && deltasForHelper.aroundElevation === void 0 && combinedEventsInProgress.drag && panDelta) {
|
|
22942
23008
|
tr.setCenter(tr.screenPointToLocation(tr.centerPoint.sub(panDelta)));
|
|
22943
23009
|
return;
|
|
22944
23010
|
}
|
|
@@ -22973,10 +23039,12 @@ var HandlerManager = class {
|
|
|
22973
23039
|
for (const name in endEvents) this._fireEvent(name, endEvents[name]);
|
|
22974
23040
|
const stillMoving = isMoving(this._eventsInProgress);
|
|
22975
23041
|
const finishedMoving = (wasMoving || nowMoving) && !stillMoving;
|
|
22976
|
-
if (finishedMoving && this.
|
|
23042
|
+
if (finishedMoving && this._terrainGesture.inFlight) {
|
|
22977
23043
|
this._camera.elevationFreeze = false;
|
|
22978
|
-
this.
|
|
22979
|
-
|
|
23044
|
+
this._terrainGesture = {
|
|
23045
|
+
inFlight: false,
|
|
23046
|
+
anchorElevation: null
|
|
23047
|
+
};
|
|
22980
23048
|
const tr = this._camera.getTransformForUpdate();
|
|
22981
23049
|
if (this._map.getCenterClampedToGround()) tr.recalculateZoomAndCenter(this._map.terrain);
|
|
22982
23050
|
this._camera.applyUpdatedTransform(tr);
|
|
@@ -22990,14 +23058,19 @@ var HandlerManager = class {
|
|
|
22990
23058
|
inertialEase.freezeElevation = true;
|
|
22991
23059
|
this._map.easeTo(inertialEase, { originalEvent: originalEndEvent });
|
|
22992
23060
|
} else {
|
|
22993
|
-
this.
|
|
23061
|
+
this._fireEvent("moveend", originalEndEvent);
|
|
22994
23062
|
if (shouldSnapToNorth(this._map.getBearing())) this._map.resetNorth();
|
|
22995
23063
|
}
|
|
22996
23064
|
this._updatingCamera = false;
|
|
22997
23065
|
}
|
|
22998
23066
|
}
|
|
23067
|
+
/**
|
|
23068
|
+
* Fires a movement event through the camera, whose evented parent is the map: the map's listeners
|
|
23069
|
+
* see the event as before, and the camera's own `moveend` listener drops the requested camera state,
|
|
23070
|
+
* so the next gesture starts from the rendered transform instead of the state this one ended in.
|
|
23071
|
+
*/
|
|
22999
23072
|
_fireEvent(type, e) {
|
|
23000
|
-
this.
|
|
23073
|
+
this._camera.fire(new MapMovementEvent(type, e ? { originalEvent: e } : {}));
|
|
23001
23074
|
}
|
|
23002
23075
|
_requestFrame() {
|
|
23003
23076
|
this._map.triggerRepaint();
|
|
@@ -23044,6 +23117,15 @@ var Camera = class extends Evented {
|
|
|
23044
23117
|
delete this._requestedCameraState;
|
|
23045
23118
|
});
|
|
23046
23119
|
}
|
|
23120
|
+
/**
|
|
23121
|
+
* @internal
|
|
23122
|
+
* Hands the camera the map's terrain, or null when the map has none, and brings the center
|
|
23123
|
+
* elevation up to date with it, see {@link Camera.applyTerrainChange}.
|
|
23124
|
+
*/
|
|
23125
|
+
setTerrain(terrain) {
|
|
23126
|
+
this.terrain = terrain;
|
|
23127
|
+
this.applyTerrainChange();
|
|
23128
|
+
}
|
|
23047
23129
|
migrateProjection(newTransform, newCameraHelper) {
|
|
23048
23130
|
newTransform.apply(this.transform, true);
|
|
23049
23131
|
this.transform = newTransform;
|
|
@@ -23348,6 +23430,7 @@ var Camera = class extends Evented {
|
|
|
23348
23430
|
this._fireMoveEvents(eventData);
|
|
23349
23431
|
}, (interruptingEaseId) => {
|
|
23350
23432
|
if (this.terrain && options.freezeElevation) this._finalizeElevation();
|
|
23433
|
+
else this.elevationFreeze = false;
|
|
23351
23434
|
this._afterEase(eventData, interruptingEaseId);
|
|
23352
23435
|
}, options);
|
|
23353
23436
|
return this;
|
|
@@ -23384,6 +23467,23 @@ var Camera = class extends Evented {
|
|
|
23384
23467
|
}
|
|
23385
23468
|
/**
|
|
23386
23469
|
* @internal
|
|
23470
|
+
* Applies a change of the terrain under the center to the transform: the terrain was set or
|
|
23471
|
+
* removed, or a DEM tile landed. The center keeps its place and the camera moves with the
|
|
23472
|
+
* center's elevation, as it does on every rendered frame while nothing holds the elevation.
|
|
23473
|
+
* While a gesture or an ease holds it this does nothing: the camera stays where the user put
|
|
23474
|
+
* it and the hold's end re-solves zoom and center onto the new terrain without moving it.
|
|
23475
|
+
* Nothing is in flight when this writes, so it writes the rendered transform, like the
|
|
23476
|
+
* per-frame clamp; a requested camera state created here would outlive the call and the
|
|
23477
|
+
* next gesture would start from it.
|
|
23478
|
+
*/
|
|
23479
|
+
applyTerrainChange() {
|
|
23480
|
+
if (this.elevationFreeze) return;
|
|
23481
|
+
const tr = this.transform;
|
|
23482
|
+
tr.setMinElevationForCurrentTile(this.terrain ? this.terrain.getMinTileElevationForLngLatZoom(tr.center, tr.tileZoom) : 0);
|
|
23483
|
+
if (this.getCenterClampedToGround()) tr.setElevation(this.terrain ? this.terrain.getElevationForLngLat(tr.center, tr) : 0);
|
|
23484
|
+
}
|
|
23485
|
+
/**
|
|
23486
|
+
* @internal
|
|
23387
23487
|
* Called when the camera is about to be manipulated.
|
|
23388
23488
|
* If `transformCameraUpdate` is specified or terrain is enabled, a copy of
|
|
23389
23489
|
* the current transform is created to track the accumulated changes.
|
|
@@ -23583,6 +23683,7 @@ var Camera = class extends Evented {
|
|
|
23583
23683
|
this._fireMoveEvents(eventData);
|
|
23584
23684
|
}, () => {
|
|
23585
23685
|
if (this.terrain && options.freezeElevation) this._finalizeElevation();
|
|
23686
|
+
else this.elevationFreeze = false;
|
|
23586
23687
|
this._afterEase(eventData);
|
|
23587
23688
|
}, options);
|
|
23588
23689
|
return this;
|
|
@@ -26155,9 +26256,7 @@ var Map$1 = class extends Evented {
|
|
|
26155
26256
|
this.terrain = null;
|
|
26156
26257
|
this.painter.renderToTexture = null;
|
|
26157
26258
|
this.painter.destroyRTTResources();
|
|
26158
|
-
this._camera.
|
|
26159
|
-
this._camera.transform.setMinElevationForCurrentTile(0);
|
|
26160
|
-
if (this.getCenterClampedToGround()) this._camera.transform.setElevation(0);
|
|
26259
|
+
this._camera.setTerrain(null);
|
|
26161
26260
|
} else {
|
|
26162
26261
|
const tileManager = this.style.tileManagers[options.source];
|
|
26163
26262
|
if (!tileManager) throw new Error(`cannot load terrain, because there exists no source with ID: ${options.source}`);
|
|
@@ -26170,9 +26269,7 @@ var Map$1 = class extends Evented {
|
|
|
26170
26269
|
if (this.terrain) this.terrain.destroy();
|
|
26171
26270
|
this.terrain = new Terrain(this.painter, tileManager, options, this._terrainSkirtLength);
|
|
26172
26271
|
this.painter.renderToTexture = new RenderToTexture(this.painter, this.terrain);
|
|
26173
|
-
this._camera.
|
|
26174
|
-
this._camera.transform.setMinElevationForCurrentTile(this.terrain.getMinTileElevationForLngLatZoom(this._camera.transform.center, this._camera.transform.tileZoom));
|
|
26175
|
-
this._camera.transform.setElevation(this.terrain.getElevationForLngLat(this._camera.transform.center, this._camera.transform));
|
|
26272
|
+
this._camera.setTerrain(this.terrain);
|
|
26176
26273
|
this._terrainDataCallback = (e) => this._handleTerrainDataEvent(e, options.source);
|
|
26177
26274
|
this.style.on("data", this._terrainDataCallback);
|
|
26178
26275
|
}
|
|
@@ -26190,10 +26287,9 @@ var Map$1 = class extends Evented {
|
|
|
26190
26287
|
this.terrain.resetElevationCache();
|
|
26191
26288
|
this.style.triggerSymbolPlacement();
|
|
26192
26289
|
}
|
|
26193
|
-
if (isTerrainSourceEvent && event.tile)
|
|
26194
|
-
|
|
26195
|
-
this._camera.
|
|
26196
|
-
if (this.getCenterClampedToGround()) this._camera.transform.setElevation(this.terrain.getElevationForLngLat(this._camera.transform.center, this._camera.transform));
|
|
26290
|
+
if (isTerrainSourceEvent && event.tile) {
|
|
26291
|
+
this.painter.markTerrainDepthDirty();
|
|
26292
|
+
this._camera.applyTerrainChange();
|
|
26197
26293
|
}
|
|
26198
26294
|
if (!event.tile) return;
|
|
26199
26295
|
if (event.source?.type === "image") {
|