@maptiler/sdk 5.0.0-rc.1 → 5.0.0-rc.3

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 CHANGED
@@ -1406,6 +1406,182 @@ When defining a new _ramp_, the colors can be an RGB array (`[number, number, nu
1406
1406
 
1407
1407
  Many methods are available on color ramps, such as getting the `<canvas>` element of it, rescaling it, flipping it or [resampling it in a non-linear way](colorramp.md). Read more on [our reference page](https://docs.maptiler.com/sdk-js/api/color-ramp/) and have a look at our [examples](https://docs.maptiler.com/sdk-js/examples/?q=colorramp) to see how they work.
1408
1408
 
1409
+ ### Markers
1410
+
1411
+ The SDK's `Marker` is designed for MapTiler maps. It is built on the MapLibre marker and adds built-in shapes and sizes, colours that follow the active MapTiler style, collision handling, interaction states, transitions and animations.
1412
+
1413
+ #### Adding markers
1414
+
1415
+ Create a marker, give it a position, and add it through the map. Markers added this way take part in collision handling and follow the style's colours:
1416
+
1417
+ ```ts
1418
+ import { Map, Marker } from "@maptiler/sdk";
1419
+
1420
+ const marker = new Marker({ lngLat: [8.54, 47.37], shape: "bubble-circle", size: "m", content: "A1" });
1421
+ map.addMarker(marker);
1422
+
1423
+ // or straight from options
1424
+ map.addMarker({ lngLat: [8.55, 47.38], shape: "circle" });
1425
+ map.addMarkers([
1426
+ { lngLat: [8.53, 47.36], shape: "square" },
1427
+ new Marker({ shape: "circle" }).setLngLat([8.56, 47.39]),
1428
+ ]);
1429
+
1430
+ map.getMarker(marker.id);
1431
+ map.getMarkers();
1432
+ map.removeMarker(marker.id);
1433
+ map.removeMarkers(); // all markers, or pass a list of ids
1434
+ ```
1435
+
1436
+ Removing a marker plays its exit animation first, if it has one (see [Animations](#animations)). Pass `{ immediate: true }` to `removeMarker()` or `removeMarkers()` to remove markers straight away.
1437
+
1438
+ > [!WARNING]
1439
+ > `marker.addTo(map)` is deprecated. It now delegates to `map.addMarker(marker)` and logs a one-time warning. Use `map.addMarker()` instead.
1440
+
1441
+ #### Appearance
1442
+
1443
+ ```ts
1444
+ const marker = new Marker({
1445
+ shape: "maptiler", // "circle" | "square" | "bubble-circle" | "bubble-square" | "maptiler" | "maptiler-full"
1446
+ size: "l", // "xs" | "s" | "m" | "l"
1447
+ shadow: "soft", // "none" | "soft" | "medium" | "strong"
1448
+ content: "42", // text shown inside the marker
1449
+ outline: true,
1450
+ scale: [1.2, 1.2],
1451
+ title: "Zurich", // native tooltip
1452
+ });
1453
+ ```
1454
+
1455
+ The appearance options have matching setters and getters, such as `setShape()`, `setSize()` or `getContent()`.
1456
+
1457
+ Unless you set them, the marker's colours (`innerColor`, `outerColor`, `contentColor` and `outlineColor`) are picked for the current MapTiler style and update when the style changes. A colour you set explicitly stays fixed, and setting it back to `undefined` returns it to the style's colour:
1458
+
1459
+ ```ts
1460
+ marker.setInnerColor("#ff5a1f");
1461
+ marker.setInnerColor(undefined); // back to the style's colour
1462
+ ```
1463
+
1464
+ Instead of text, a marker can show an image, or any HTML or SVG element, for example one managed by React:
1465
+
1466
+ ```ts
1467
+ new Marker({ url: "https://example.com/icon.svg" });
1468
+ new Marker({ element: myElement });
1469
+ ```
1470
+
1471
+ With `element`, the shape and size options do not apply. The colour and shadow options are set on the element as CSS custom properties, so its own styles can use them.
1472
+
1473
+ #### Collisions
1474
+
1475
+ By default, markers are always shown even when they overlap. To declutter the map, choose what happens when markers collide. Where markers overlap, the one with the higher `priority` wins:
1476
+
1477
+ ```ts
1478
+ // default for every marker on the map
1479
+ map.setMarkerCollisionOptions({ behaviour: "hide-by-priority" });
1480
+
1481
+ // or per marker
1482
+ new Marker({ priority: 10, collisionBehaviour: "minimize-by-priority" });
1483
+ ```
1484
+
1485
+ - `always-show`: never hidden (the default)
1486
+ - `hide-by-priority`: hidden behind a higher-priority marker
1487
+ - `minimize-by-priority`: shrinks to a small dot behind a higher-priority marker. `minimizedOptions` changes how the minimized marker looks.
1488
+
1489
+ `setMarkerCollisionOptions()` also sets the `proximityPadding` used for `markerproximity` events and the duration and easing of the hide and show fade. `marker.getCollisionDisplayState()` returns `"visible"`, `"hidden"` or `"minimized"`.
1490
+
1491
+ Markers fire `markeroverlap` and `markerproximity` when other markers start or stop colliding with them:
1492
+
1493
+ ```ts
1494
+ marker.on("markeroverlap", ({ entered, exited, current }) => {
1495
+ console.log(`${current.length} markers overlap this one`);
1496
+ });
1497
+ ```
1498
+
1499
+ #### Interaction states
1500
+
1501
+ Change a marker's look while it is hovered, focused, pressed or dragged. The marker returns to its own values when the state ends:
1502
+
1503
+ ```ts
1504
+ const marker = new Marker({
1505
+ draggable: true,
1506
+ states: {
1507
+ hover: { scale: [1.2, 1.2] },
1508
+ active: { shadow: "strong" },
1509
+ dragging: { opacity: 0.6 },
1510
+ },
1511
+ });
1512
+
1513
+ marker.setUIState("focus", { outline: 3 });
1514
+ ```
1515
+
1516
+ #### Transitions
1517
+
1518
+ Ease a property to its new value instead of jumping to it. `position`, `scale`, `rotation` and the four colours can be transitioned, each with `[duration, easing?, delay?]`:
1519
+
1520
+ ```ts
1521
+ const marker = new Marker({
1522
+ transitions: {
1523
+ position: [600, "QuadraticInOut"],
1524
+ innerColor: [300],
1525
+ },
1526
+ });
1527
+
1528
+ marker.setLngLat([8.6, 47.4]); // glides to the new position
1529
+ marker.setTransitionForProperty("scale", [200, "CubicOut"]);
1530
+ ```
1531
+
1532
+ The `transitionstart` and `transitionend` events report the property being transitioned.
1533
+
1534
+ #### Animations
1535
+
1536
+ Play an animation when a marker is added, loop one while it is on the map, and play another when it is removed:
1537
+
1538
+ ```ts
1539
+ const marker = new Marker({
1540
+ animations: {
1541
+ enter: { preset: "drop" }, // "grow" | "drop" | "pop" | "bounce" | "fade"
1542
+ idle: { preset: "pulsescale", iterations: 3 }, // "pulsescale" | "pulseopacity" | "ring" | "bounce"
1543
+ exit: { preset: "fade", duration: 300 }, // "shrink" | "fade" | "pop" | "explode"
1544
+ },
1545
+ });
1546
+
1547
+ map.addMarker(marker); // plays "drop"
1548
+ map.removeMarker(marker.id); // plays "fade", then removes the marker
1549
+ map.removeMarker(marker.id, { immediate: true }); // removes it without the exit animation
1550
+ ```
1551
+
1552
+ Each animation also accepts `duration`, `delay`, `easing` and `magnitude`. Instead of a preset, `custom` takes a function called every frame with the animation's progress (`0` to `1`) and the marker. Animations fire events such as `enteranimationstart`, `idleanimationiteration` and `exitanimationend`.
1553
+
1554
+ #### Altitude (experimental)
1555
+
1556
+ Raise a marker above the ground. The marker is placed in 3D, so it stays in the right place as the camera moves, with terrain and under globe projection:
1557
+
1558
+ ```ts
1559
+ marker.setAltitude(500); // 500 m above the terrain under the marker
1560
+ marker.setAltitude(1200, { relativeTo: "sea" }); // 1200 m above sea level
1561
+ marker.setAltitude(false); // back on the map surface
1562
+
1563
+ marker.setGroundLine(true); // dashed line from the marker down to the ground
1564
+ ```
1565
+
1566
+ Style the ground line with your own CSS on the `maptiler-marker-groundline` class, or add a class of your own with `setGroundLine(true, { className: "my-line" })`.
1567
+
1568
+ #### The MapLibre marker
1569
+
1570
+ Compared with the MapLibre marker:
1571
+ - The `color` option is removed. Use `innerColor`, `outerColor`, `contentColor` and `outlineColor`.
1572
+ - `scale` is a 2D vector, `[x, y]`.
1573
+ - `setRotation()` rotates the marker's shape rather than its container.
1574
+
1575
+ The plain MapLibre marker is still available as `MarkerMLGL`:
1576
+
1577
+ ```ts
1578
+ import { MarkerMLGL } from "@maptiler/sdk";
1579
+
1580
+ new MarkerMLGL({ color: "#f00" }).setLngLat([8.54, 47.37]).addTo(map);
1581
+ ```
1582
+
1583
+ See `demos/16-maptiler-markers.html` to `demos/20-marker-altitude.html` for examples.
1584
+
1409
1585
  ### Camera routes and animations
1410
1586
 
1411
1587
  The SDK comes with several classes to help with animations, particularly route animations.
@@ -1438,7 +1614,8 @@ const marker = new Marker().setLngLat(
1438
1614
  -7.449346225791231,
1439
1615
  39.399728941536836,
1440
1616
  )
1441
- ).addTo(map);
1617
+ );
1618
+ map.addMarker(marker);
1442
1619
 
1443
1620
  // TimeUpdate is fired every frame
1444
1621
  animation.addEventListener(AnimationEventTypes.TimeUpdate, (e) => {
@@ -1,4 +1,4 @@
1
- import { LngLat, Marker, Point, PositionAnchor, TransformConstrainFunction } from '../index';
1
+ import { LngLat, MarkerMLGL as Marker, Point, PositionAnchor, TransformConstrainFunction } from '../index';
2
2
  export declare function unprojectFromWorldCoordinates(worldSize: number, point: Point): LngLat;
3
3
  export declare const overpanningUnderzoomingTransformConstrain: TransformConstrainFunction;
4
4
  export declare const anchorTranslate: Record<PositionAnchor, string>;
package/dist/Map.d.ts CHANGED
@@ -8,6 +8,7 @@ import { Telemetry } from './Telemetry';
8
8
  import { CubemapDefinition, CubemapLayer, CubemapLayerConstructorOptions } from './custom-layers/CubemapLayer';
9
9
  import { GradientDefinition, RadialGradientLayer, RadialGradientLayerConstructorOptions } from './custom-layers/RadialGradientLayer';
10
10
  import { StyleSpecificationWithMetaData } from './custom-layers/extractCustomLayerStyle';
11
+ import { MapTilerMarkerOptions, Marker, MarkerCollisionOptions, RemoveMarkerOptions } from '.';
11
12
  export type LoadWithTerrainEvent = {
12
13
  type: "loadWithTerrain";
13
14
  target: Map;
@@ -64,6 +65,11 @@ export declare const GeolocationType: {
64
65
  * if falls back to the default Mercator
65
66
  */
66
67
  export type ProjectionTypes = "mercator" | "globe" | undefined;
68
+ /**
69
+ * Default zoom at/above which a `"globe"` projection request switches to flat mercator — see
70
+ * {@link MapOptions.globeMercatorSwitchZoom}.
71
+ */
72
+ export declare const DEFAULT_GLOBE_MERCATOR_SWITCH_ZOOM = 11;
67
73
  /**
68
74
  * The {@link AttributionControl} options object
69
75
  */
@@ -196,6 +202,26 @@ export type MapOptions = Omit<MapOptionsML, "style" | "maplibreLogo" | "attribut
196
202
  * If not provided, the style takes precedence. If provided, overwrite the style.
197
203
  */
198
204
  projection?: ProjectionTypes;
205
+ /**
206
+ * MapLibre's plain `type: "globe"` already resolves to
207
+ * `["interpolate", ["linear"], ["zoom"], 11, "vertical-perspective", 12, "mercator"]` —
208
+ * vertical-perspective below zoom 11, linearly blended into flat mercator between 11 and 12.
209
+ * That blend is a MapLibre bug for anything that places objects via its per-projection model
210
+ * matrix (marker altitude, `maptiler-3d-js`): the matrix isn't well-defined mid-blend, only
211
+ * once it's settled fully at one end, so objects placed while zooming through 11-12 jump
212
+ * around.
213
+ *
214
+ * Whenever a projection change resolves to `"globe"` (constructor option, `setProjection`, or
215
+ * the {@link MaptilerProjectionControl}), the SDK requests
216
+ * `{ type: ["step", ["zoom"], "vertical-perspective", globeMercatorSwitchZoom, "mercator"] }`
217
+ * instead of the literal string — spherical below this zoom, flat mercator at and above it,
218
+ * snapping instantly at the threshold instead of blending across that zoom band.
219
+ *
220
+ * Set to `false` to request MapLibre's own `"globe"` literally instead, blend bug and all.
221
+ *
222
+ * Default: `11`
223
+ */
224
+ globeMercatorSwitchZoom?: number | false;
199
225
  /**
200
226
  * Turn on/off spacebox.
201
227
  *
@@ -323,6 +349,7 @@ export declare class Map extends MapMLGL {
323
349
  private terrainAnimationDuration;
324
350
  private monitoredStyleUrls;
325
351
  private styleInProcess;
352
+ private currentStyleId?;
326
353
  private curentProjection;
327
354
  private originalLabelStyle;
328
355
  private isStyleLocalized;
@@ -372,6 +399,13 @@ export declare class Map extends MapMLGL {
372
399
  */
373
400
  setStyle(style: null | ReferenceMapStyle | MapStyleVariant | StyleSpecification | StyleSpecificationWithMetaData | string, options?: StyleSwapOptions & StyleOptions): this;
374
401
  private spaceboxLoadingState;
402
+ /**
403
+ * Returns the id of the current MapTiler style (e.g. `"streets-v4-dark"`),
404
+ * derived from the value passed to the constructor or `setStyle`.
405
+ * `undefined` when the style is a custom `StyleSpecification` or a URL that
406
+ * doesn't follow the MapTiler Cloud `/maps/<id>/style.json` shape.
407
+ */
408
+ getStyleId(): string | undefined;
375
409
  /**
376
410
  * Adds a [MapLibre style layer](https://maplibre.org/maplibre-style-spec/layers)
377
411
  * to the map's style.
@@ -423,6 +457,49 @@ export declare class Map extends MapMLGL {
423
457
  * ```
424
458
  */
425
459
  removeLayer(id: string): this;
460
+ /**
461
+ * Adds a marker to the map, registering it for collision handling and style-aware colours.
462
+ * Plays the marker's `enter` animation, if it has one.
463
+ * @param markerOrMarkerConfig - A `Marker`, or the options to create one from.
464
+ */
465
+ addMarker(markerOrMarkerConfig: Marker | MapTilerMarkerOptions): this;
466
+ /**
467
+ * Removes a marker from the map, playing its `exit` animation first, if it has one.
468
+ * @param id - Id of the marker to remove.
469
+ * @param options.immediate - Removes the marker straight away, without its `exit` animation.
470
+ */
471
+ removeMarker(id: string, options?: RemoveMarkerOptions): this;
472
+ /**
473
+ * Adds several markers to the map. See {@link Map.addMarker}.
474
+ * @param markers - `Marker`s, or the options to create them from.
475
+ */
476
+ addMarkers(markers: (Marker | MapTilerMarkerOptions)[]): this;
477
+ /**
478
+ * Removes several markers from the map, playing their `exit` animations first, if they have them.
479
+ * @param markerIds - Ids of the markers to remove. Removes every marker when omitted.
480
+ * @param options.immediate - Removes the markers straight away, without their `exit` animations.
481
+ */
482
+ removeMarkers(markerIds?: string[], options?: RemoveMarkerOptions): this;
483
+ /** Returns every marker added to the map. */
484
+ getMarkers(): Marker[];
485
+ /** Returns the marker with the given id, or `undefined` if it isn't on the map. */
486
+ getMarker(id: string): Marker | undefined;
487
+ /**
488
+ * Configures marker collision detection for this map.
489
+ * @param options.proximityPadding - Distance in CSS px within which two
490
+ * markers count as "in proximity". Overlap always uses 0.
491
+ * @param options.accuracy - `high` (default) tests rotated markers with
492
+ * their actual rotated box; `low` uses the upright box enclosing it,
493
+ * which is cheaper per pair but over-reports collisions for rotated
494
+ * markers (it never misses a real one).
495
+ * @param options.behaviour - Default collision behaviour applied to every
496
+ * marker on this map (`always-show` | `hide-by-priority` |
497
+ * `minimize-by-priority`). A marker's own `collisionBehaviour` option
498
+ * overrides it. Defaults to `always-show`.
499
+ * @param options.transitionDuration - Duration in ms of the hide/show/minimize fade. Defaults to `150`.
500
+ * @param options.transitionEasing - CSS easing function for the fade. Defaults to `"ease"`.
501
+ */
502
+ setMarkerCollisionOptions(options: MarkerCollisionOptions): this;
426
503
  /**
427
504
  * Sets the zoom extent for the specified style layer. The zoom extent includes the
428
505
  * [minimum zoom level](https://maplibre.org/maplibre-style-spec/layers/#minzoom)
@@ -571,7 +648,11 @@ export declare class Map extends MapMLGL {
571
648
  */
572
649
  getProjection(): ProjectionSpecification;
573
650
  /**
574
- * Returns whether a globe projection is currently being used
651
+ * Returns whether a globe-family projection is currently configured — `"globe"`,
652
+ * `"vertical-perspective"`, or the `globeMercatorSwitchZoom` step expression this class
653
+ * requests for `"globe"` (see {@link MapOptions.globeMercatorSwitchZoom}). This reflects the
654
+ * configured projection, not the instantaneous rendered state — under the step expression it
655
+ * stays `true` even after zooming past the switch threshold into flat mercator rendering.
575
656
  */
576
657
  isGlobeProjection(): boolean;
577
658
  /**