@mapvx/web-js 3.5.1 → 3.6.0-dev.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/dist/umd/index.js CHANGED
@@ -11181,7 +11181,7 @@ const extractSafariExtensionDetails = (func, filename) => {
11181
11181
  // exists only for the type-checker, so in the ES/CJS builds the identifier is
11182
11182
  // genuinely absent and a direct comparison throws ReferenceError at module load.
11183
11183
  // `typeof` is the only safe way to probe a possibly-undeclared global.
11184
- var sentry_SDK_VERSION = false ? 0 : "3.5.1";
11184
+ var sentry_SDK_VERSION = false ? 0 : "3.6.0-dev.1";
11185
11185
  var DSN = false ? 0 : "https://872f598f020e3cd73a0933b562d24c81@sentry.mapvx.app/5";
11186
11186
 
11187
11187
  /**
@@ -21864,10 +21864,13 @@ function fitCamera_arrayLikeToArray(r, a) { (null == a || a > r.length) && (a =
21864
21864
  */
21865
21865
 
21866
21866
  /**
21867
- * Minimal structural view of a maplibre transform clone (`map.transform.clone()`).
21867
+ * Minimal camera simulator: the projection surface {@link refineCameraForPitch} needs to try a
21868
+ * candidate camera without the map being in that state.
21868
21869
  *
21869
- * We depend on the shape rather than the (non-exported) `ITransform` interface so
21870
- * the coupling stays explicit and version changes surface as type errors here.
21870
+ * Structural on purpose. It began as the shape of `map.transform.clone()`, and depending on the
21871
+ * shape rather than maplibre's non-exported `ITransform` is what made the v6 removal of
21872
+ * `map.transform` a local change: see `LiveMapFitTransform`, which satisfies this interface
21873
+ * through the map's public API instead.
21871
21874
  */
21872
21875
 
21873
21876
  /** maplibre world size (px) at zoom 0: tileSize (512) * 2^0. */
@@ -21961,7 +21964,7 @@ function computeOrientedCamera(coordinates, params) {
21961
21964
  * If any point falls behind the horizon during refinement, it bails out and
21962
21965
  * returns the best camera computed so far (never worse than the flat input).
21963
21966
  *
21964
- * @param transform A `map.transform.clone()` used purely for projection.
21967
+ * @param transform Camera simulator used purely for projection; the caller owns its lifecycle.
21965
21968
  * @param coordinates Points to fit.
21966
21969
  * @param initial The orthographic camera to refine.
21967
21970
  * @param params Bearing, pitch, padding and viewport constraints.
@@ -22036,6 +22039,203 @@ function refineCameraForPitch(transform, coordinates, initial, params) {
22036
22039
  }
22037
22040
  return best;
22038
22041
  }
22042
+ ;// ./src/map/liveMapFitTransform.ts
22043
+ function liveMapFitTransform_typeof(o) { "@babel/helpers - typeof"; return liveMapFitTransform_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, liveMapFitTransform_typeof(o); }
22044
+ function liveMapFitTransform_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
22045
+ function liveMapFitTransform_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? liveMapFitTransform_ownKeys(Object(t), !0).forEach(function (r) { liveMapFitTransform_defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : liveMapFitTransform_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
22046
+ function liveMapFitTransform_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
22047
+ function liveMapFitTransform_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, liveMapFitTransform_toPropertyKey(o.key), o); } }
22048
+ function liveMapFitTransform_createClass(e, r, t) { return r && liveMapFitTransform_defineProperties(e.prototype, r), t && liveMapFitTransform_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
22049
+ function liveMapFitTransform_defineProperty(e, r, t) { return (r = liveMapFitTransform_toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
22050
+ function liveMapFitTransform_toPropertyKey(t) { var i = liveMapFitTransform_toPrimitive(t, "string"); return "symbol" == liveMapFitTransform_typeof(i) ? i : i + ""; }
22051
+ function liveMapFitTransform_toPrimitive(t, r) { if ("object" != liveMapFitTransform_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != liveMapFitTransform_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
22052
+ /**
22053
+ * Screen-space tolerance, in pixels, for the horizon round-trip test.
22054
+ *
22055
+ * `project` and `unproject` are not exact inverses — they run through a 4x4 matrix and its
22056
+ * inverse, so a well-behaved point still drifts by a fraction of a pixel. Half a pixel is far
22057
+ * below that drift's ceiling and far above the millions-of-pixels divergence a point behind the
22058
+ * horizon produces, so the threshold is not sensitive to its exact value.
22059
+ */
22060
+ var SURFACE_ROUND_TRIP_EPSILON_PX = 0.5;
22061
+
22062
+ /**
22063
+ * A {@link FitTransform} backed by a live MapLibre map and its public API.
22064
+ *
22065
+ * ## Why this exists
22066
+ *
22067
+ * {@link refineCameraForPitch} needs to project points through MapLibre's real perspective
22068
+ * projection for camera states the map is not actually in — it tries a candidate camera, measures
22069
+ * where the geometry lands, adjusts, and repeats. Until MapLibre v6 that was done on
22070
+ * `map.transform.clone()`, a detached copy of the internal transform.
22071
+ *
22072
+ * v6 removed `map.transform` and exposes no replacement: there is no exported `Camera`,
22073
+ * `Transform` or `MercatorTransform`, and the migration guide says only "use `Map`'s public API
22074
+ * instead". So the simulation moves onto the map itself.
22075
+ *
22076
+ * ## How it stays invisible
22077
+ *
22078
+ * The map is genuinely moved, but never painted mid-simulation: MapLibre renders on
22079
+ * `requestAnimationFrame`, and every mutation here happens inside one synchronous block that ends
22080
+ * with {@link restore}. No intermediate frame exists to be seen.
22081
+ *
22082
+ * Camera writes are also batched. Setters only record intent; the map is moved at most once per
22083
+ * refinement iteration, lazily, the first time a projection actually needs the new camera.
22084
+ *
22085
+ * ## What it costs
22086
+ *
22087
+ * `jumpTo` fires camera events, so listeners observe movement that no user caused. At the only
22088
+ * call site this is bounded — the refinement is immediately followed by a real `easeTo`, so the
22089
+ * map was going to move regardless, and the `moveend` handler that reports completion is attached
22090
+ * *after* refinement and so cannot see the simulation's events.
22091
+ *
22092
+ * @example
22093
+ * ```typescript
22094
+ * const transform = new LiveMapFitTransform(map)
22095
+ * try {
22096
+ * camera = refineCameraForPitch(transform, coordinates, camera, params)
22097
+ * } finally {
22098
+ * transform.restore()
22099
+ * }
22100
+ * ```
22101
+ *
22102
+ * @group Map
22103
+ */
22104
+ var LiveMapFitTransform = /*#__PURE__*/function () {
22105
+ /**
22106
+ * Capture the map's current camera so it can be restored, and seed the simulation with it.
22107
+ *
22108
+ * @param map The live map to simulate on.
22109
+ */
22110
+ function LiveMapFitTransform(map) {
22111
+ var _this = this,
22112
+ _padding$top,
22113
+ _padding$bottom,
22114
+ _padding$left,
22115
+ _padding$right;
22116
+ liveMapFitTransform_classCallCheck(this, LiveMapFitTransform);
22117
+ /** Camera state to put back in {@link restore}. */
22118
+ /** Pending camera state; written by the setters, flushed by {@link sync}. */
22119
+ /** Whether {@link pending} has diverged from what the map is currently showing. */
22120
+ liveMapFitTransform_defineProperty(this, "dirty", false);
22121
+ /**
22122
+ * Whether the map was ever actually moved.
22123
+ *
22124
+ * Tracked separately from {@link dirty}, which {@link sync} clears the moment it flushes: keying
22125
+ * {@link restore} off `dirty` alone would make it a no-op right after a flush and strand the map
22126
+ * on a candidate camera.
22127
+ */
22128
+ liveMapFitTransform_defineProperty(this, "moved", false);
22129
+ liveMapFitTransform_defineProperty(this, "setCenter", function (center) {
22130
+ _this.pending.center = center;
22131
+ _this.dirty = true;
22132
+ });
22133
+ liveMapFitTransform_defineProperty(this, "setZoom", function (zoom) {
22134
+ _this.pending.zoom = zoom;
22135
+ _this.dirty = true;
22136
+ });
22137
+ liveMapFitTransform_defineProperty(this, "setBearing", function (bearing) {
22138
+ _this.pending.bearing = bearing;
22139
+ _this.dirty = true;
22140
+ });
22141
+ liveMapFitTransform_defineProperty(this, "setPitch", function (pitch) {
22142
+ _this.pending.pitch = pitch;
22143
+ _this.dirty = true;
22144
+ });
22145
+ liveMapFitTransform_defineProperty(this, "setPadding", function (padding) {
22146
+ _this.pending.padding = padding;
22147
+ _this.dirty = true;
22148
+ });
22149
+ liveMapFitTransform_defineProperty(this, "locationToScreenPoint", function (lnglat) {
22150
+ _this.sync();
22151
+ return _this.map.project(lnglat);
22152
+ });
22153
+ liveMapFitTransform_defineProperty(this, "screenPointToLocation", function (p) {
22154
+ _this.sync();
22155
+ return _this.map.unproject(p);
22156
+ });
22157
+ /**
22158
+ * Whether a projected point lies on the visible map surface rather than beyond the horizon.
22159
+ *
22160
+ * MapLibre exposes no public horizon test, so this uses a round-trip: unprojecting a screen
22161
+ * point casts a ray onto the map plane, and re-projecting that location lands back where it
22162
+ * started only if the ray actually met the plane in front of the camera. Past the horizon the
22163
+ * ray diverges and the round-trip misses by an enormous margin.
22164
+ *
22165
+ * @param p Screen point, as returned by {@link locationToScreenPoint}.
22166
+ * @returns `true` when the point is on the map surface.
22167
+ */
22168
+ liveMapFitTransform_defineProperty(this, "isPointOnMapSurface", function (p) {
22169
+ _this.sync();
22170
+ var roundTripped = _this.map.project(_this.map.unproject(p));
22171
+ return Number.isFinite(roundTripped.x) && Number.isFinite(roundTripped.y) && Math.abs(roundTripped.x - p.x) < SURFACE_ROUND_TRIP_EPSILON_PX && Math.abs(roundTripped.y - p.y) < SURFACE_ROUND_TRIP_EPSILON_PX;
22172
+ });
22173
+ /**
22174
+ * Put the camera back exactly as it was when this instance was constructed.
22175
+ *
22176
+ * Safe to call more than once, and safe to call when nothing was ever changed. Always call it
22177
+ * from a `finally` block so a throw mid-refinement cannot strand the map on a candidate camera.
22178
+ */
22179
+ liveMapFitTransform_defineProperty(this, "restore", function () {
22180
+ if (!_this.moved) {
22181
+ return;
22182
+ }
22183
+ _this.map.jumpTo({
22184
+ center: _this.snapshot.center,
22185
+ zoom: _this.snapshot.zoom,
22186
+ bearing: _this.snapshot.bearing,
22187
+ pitch: _this.snapshot.pitch,
22188
+ padding: _this.snapshot.padding
22189
+ });
22190
+ _this.pending = liveMapFitTransform_objectSpread({}, _this.snapshot);
22191
+ _this.dirty = false;
22192
+ _this.moved = false;
22193
+ });
22194
+ this.map = map;
22195
+ var _padding = map.getPadding();
22196
+ this.snapshot = {
22197
+ center: map.getCenter(),
22198
+ zoom: map.getZoom(),
22199
+ bearing: map.getBearing(),
22200
+ pitch: map.getPitch(),
22201
+ padding: {
22202
+ top: (_padding$top = _padding.top) !== null && _padding$top !== void 0 ? _padding$top : 0,
22203
+ bottom: (_padding$bottom = _padding.bottom) !== null && _padding$bottom !== void 0 ? _padding$bottom : 0,
22204
+ left: (_padding$left = _padding.left) !== null && _padding$left !== void 0 ? _padding$left : 0,
22205
+ right: (_padding$right = _padding.right) !== null && _padding$right !== void 0 ? _padding$right : 0
22206
+ }
22207
+ };
22208
+ this.pending = liveMapFitTransform_objectSpread({}, this.snapshot);
22209
+ }
22210
+ return liveMapFitTransform_createClass(LiveMapFitTransform, [{
22211
+ key: "center",
22212
+ get: function get() {
22213
+ return this.pending.center;
22214
+ }
22215
+ }, {
22216
+ key: "zoom",
22217
+ get: function get() {
22218
+ return this.pending.zoom;
22219
+ }
22220
+ }, {
22221
+ key: "sync",
22222
+ value: /** Flush {@link pending} onto the map, but only when a projection actually needs it. */
22223
+ function sync() {
22224
+ if (!this.dirty) {
22225
+ return;
22226
+ }
22227
+ this.map.jumpTo({
22228
+ center: this.pending.center,
22229
+ zoom: this.pending.zoom,
22230
+ bearing: this.pending.bearing,
22231
+ pitch: this.pending.pitch,
22232
+ padding: this.pending.padding
22233
+ });
22234
+ this.dirty = false;
22235
+ this.moved = true;
22236
+ }
22237
+ }]);
22238
+ }();
22039
22239
  ;// ./src/map/mapInteractionOptions.ts
22040
22240
  /**
22041
22241
  * Highest pitch MapLibre accepts for `minPitch`/`maxPitch` (it rejects anything
@@ -22350,6 +22550,7 @@ function convertPaddingToPixels(padding, containerWidth, containerHeight) {
22350
22550
 
22351
22551
 
22352
22552
 
22553
+
22353
22554
  /**
22354
22555
  * @group Map
22355
22556
  */
@@ -24357,9 +24558,18 @@ var InternalMapVXMap = /*#__PURE__*/function (_Loggeable) {
24357
24558
  // With a tilted camera the orthographic zoom is off due to perspective, so
24358
24559
  // refine it against maplibre's real projection on a cloned transform.
24359
24560
  if (pitch > 0) {
24360
- camera = refineCameraForPitch(this.map.transform.clone(), coordinates, camera, map_objectSpread(map_objectSpread({}, cameraParams), {}, {
24361
- pitch: pitch
24362
- }));
24561
+ // Simulated on the live map through its public API rather than on `map.transform.clone()`:
24562
+ // MapLibre v6 removes the internal transform and exposes no replacement. The whole loop is
24563
+ // synchronous and ends in `restore()`, so no intermediate frame is ever painted.
24564
+ // See DEVELOPER_DOCS/MAPLIBRE_V6_MIGRATION.md.
24565
+ var fitTransform = new LiveMapFitTransform(this.map);
24566
+ try {
24567
+ camera = refineCameraForPitch(fitTransform, coordinates, camera, map_objectSpread(map_objectSpread({}, cameraParams), {}, {
24568
+ pitch: pitch
24569
+ }));
24570
+ } finally {
24571
+ fitTransform.restore();
24572
+ }
24363
24573
  }
24364
24574
  if (onComplete) {
24365
24575
  void this.map.once("moveend", onComplete);