@mapmap/maps 0.4.0 → 0.5.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 +119 -9
- package/dist/chunk-CH53LJR7.js +156 -0
- package/dist/chunk-CH53LJR7.js.map +1 -0
- package/dist/direction-icons.d.ts +21 -1
- package/dist/direction-icons.js +1 -149
- package/dist/direction-icons.js.map +1 -1
- package/dist/index.d.ts +584 -12
- package/dist/index.js +551 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -372,6 +372,102 @@ puck.setLocation({ lat: 51.5074, lon: -0.1278 }, 45); // heading in degrees
|
|
|
372
372
|
pitch/zoom as its option defaults when built from a `MapMapMap`; explicit
|
|
373
373
|
options still win (option > design > built-in). Themes saved without the
|
|
374
374
|
block load unchanged and stay `"version": 1`.
|
|
375
|
+
- `extra.nav.alerts` (optional since v1) holds the safety-camera alert
|
|
376
|
+
design: chip tokens (`background`, `textColor`, `outlineColor`,
|
|
377
|
+
`cornerRadius` 0-24, `outlineWidth` 0-4), the always-present escalated
|
|
378
|
+
pair (`escalatedBackground`, `escalatedTextColor`), `iconSet`
|
|
379
|
+
(`european` / `us` / `minimal` / `brand`) with optional per-kind
|
|
380
|
+
`iconUrlOverrides`, `alertSound` and `escalatedSound` from the built-in
|
|
381
|
+
earcon library (`cameraCalm`, `cameraUrgent`, `overspeedSoft`,
|
|
382
|
+
`zoneEnter`, `zoneClear`) with optional `alertSoundUrl` /
|
|
383
|
+
`escalatedSoundUrl` overrides, `mapIconSize` (0.75-1.5) and
|
|
384
|
+
`mapMinZoom` (9-14),
|
|
385
|
+
`corridorColor` / `corridorOpacity` for the average-speed corridor,
|
|
386
|
+
`leadDistance` (`short` / `standard` / `long` = 150 m / 250 m / 400 m
|
|
387
|
+
floors), `chipPosition` (`aboveSpeed` / `topLeading` / `topTrailing`)
|
|
388
|
+
and a `kinds` entry per camera kind (`fixed`, `average`, `red_light`,
|
|
389
|
+
`mobile_site`, `unknown`) carrying `showOnMap` (browse-mode map
|
|
390
|
+
display), `showOnMapWhileNavigating` (map display during guidance,
|
|
391
|
+
default true), `alertWhileDriving`, `showInRoutePreview`, `alertMode`
|
|
392
|
+
(`always` / `whenSpeeding` / `never`) and `audioMode` (`off` /
|
|
393
|
+
`earcon` / `earcon_and_speech`).
|
|
394
|
+
|
|
395
|
+
```ts
|
|
396
|
+
import { CameraAlertChip, alertPresentation, navCameraKind } from "@mapmap/maps";
|
|
397
|
+
|
|
398
|
+
const chip = new CameraAlertChip(document.body, map.navDesign?.alerts);
|
|
399
|
+
// Visual is unconditional and calm; audio is the escalation channel.
|
|
400
|
+
chip.update({ kind: "fixed", limitKph: 30, distanceM: 240 }, { speeding: false });
|
|
401
|
+
|
|
402
|
+
// Average-speed corridors tint the route line itself.
|
|
403
|
+
routes.setAlertCorridors([corridorGeometry]);
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
`alertPresentation(design, alert, { speeding })` is the pure rule behind
|
|
407
|
+
the chip: it returns whether to show it, whether to escalate, whether
|
|
408
|
+
audio fires and the lead-distance floor in metres. `alertChipContent`
|
|
409
|
+
returns just the title, subtitle and icon URL, which is what CarPlay's
|
|
410
|
+
`CPNavigationAlert` and Android Auto's `Alert` accept - colours, radius
|
|
411
|
+
and position do not survive a head-unit template, so styling degrades to
|
|
412
|
+
the platform look there rather than being assumed to render.
|
|
413
|
+
`alertContrastIssues(design)` runs a WCAG contrast check over both chip
|
|
414
|
+
colour pairs (floor 4.5:1); Studio surfaces the same warnings as you
|
|
415
|
+
pick colours.
|
|
416
|
+
|
|
417
|
+
**Sound.** `alertPresentation(...).soundUrl` is the earcon to play for
|
|
418
|
+
the state it just resolved - the calm sound, or its escalated variant
|
|
419
|
+
when the driver is over the limit - so a host never picks the file
|
|
420
|
+
itself. `alertSoundUrl(design, escalated)` is the same rule standalone.
|
|
421
|
+
The SDK bundles no audio: the built-ins resolve to
|
|
422
|
+
`https://mapmap.ai/earcons/*.mp3` (public and unmetered), and
|
|
423
|
+
`navAlertSoundUrl(sound, baseUrl)` re-points them at your own host.
|
|
424
|
+
|
|
425
|
+
```ts
|
|
426
|
+
const p = alertPresentation(design, alert, { speeding });
|
|
427
|
+
if (p.audible) {
|
|
428
|
+
const audio = new Audio(p.soundUrl);
|
|
429
|
+
audio.volume = 1; // the app owns the in-car level, not the theme
|
|
430
|
+
void audio.play()?.catch?.(() => {});
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
There are exactly two sounds, and that is deliberate. Which camera it is
|
|
435
|
+
travels in the icon and in the spoken line; how urgent it is travels in
|
|
436
|
+
the timbre. Per-kind chimes would ask a driver to learn five sounds at
|
|
437
|
+
motorway speed, which no shipping product does.
|
|
438
|
+
|
|
439
|
+
**Camera POIs on the map.** Cameras are not in the vector tiles - they
|
|
440
|
+
come from the gateway's `POST /v1/cameras/along`, behind the same
|
|
441
|
+
server-side jurisdiction policy - so a style draws them over a GeoJSON
|
|
442
|
+
source you add. `cameraSymbolLayer(design, sourceId, mode, variant)`
|
|
443
|
+
builds that layer: sprite icons per kind, the design's `mapIconSize` and
|
|
444
|
+
`mapMinZoom`, and a filter holding only the kinds that mode shows.
|
|
445
|
+
|
|
446
|
+
```ts
|
|
447
|
+
map.addSource("cameras", { type: "geojson", data: camerasGeoJson });
|
|
448
|
+
map.addLayer(cameraSymbolLayer(design, "cameras", "navigating", "light"));
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
The icons ship in the published sprite sheet
|
|
452
|
+
(`https://api.mapmap.ai/sprite/sprite`), generated from the same glyphs
|
|
453
|
+
the chip draws, so the pin and the chip are never two different cameras.
|
|
454
|
+
Image ids come from `cameraSpriteName(kind, variant)` -
|
|
455
|
+
`camera-fixed-dark`, `camera-redlight-light` and so on, `-dark` for
|
|
456
|
+
light basemaps and `-light` for dark ones. Your style must carry a
|
|
457
|
+
`sprite` URL for them to render; the skeleton ships none by default.
|
|
458
|
+
|
|
459
|
+
`cameraShownOnMap(design, kind, mode)` is the underlying rule.
|
|
460
|
+
`"browse"` reads `showOnMap` and `"navigating"` reads
|
|
461
|
+
`showOnMapWhileNavigating`, because showing a camera while planning and
|
|
462
|
+
showing it while driving are separate decisions - the market warns with
|
|
463
|
+
or without a planned route, so map display is not gated behind
|
|
464
|
+
guidance.
|
|
465
|
+
|
|
466
|
+
**Jurisdiction policy is server side and is not styleable.** Whether a
|
|
467
|
+
camera may be returned at all is decided per country by the gateway
|
|
468
|
+
before the response leaves it. This block styles what policy already
|
|
469
|
+
permits; it cannot widen it.
|
|
470
|
+
|
|
375
471
|
- The nav block travels with the **theme document**, never the compiled
|
|
376
472
|
style: `extra` round-trips through `POST /styles` and
|
|
377
473
|
`GET /styles/{id}/theme` (bounded at 256 KB serialised), but a compiled
|
|
@@ -501,37 +597,51 @@ const route = await routes.route(from, to, {
|
|
|
501
597
|
|
|
502
598
|
const steps = extractGuidance(route);
|
|
503
599
|
const banner = new GuidanceBanner(document.body, map.navDesign?.banner);
|
|
504
|
-
|
|
600
|
+
// Pass the step as the second argument so ferry legs get the ferry glyph
|
|
601
|
+
// and u-turns point the right way in left-hand-traffic regions.
|
|
602
|
+
banner.update(steps[0].banners[0] ?? null, steps[0]);
|
|
505
603
|
// As the driver advances, fire each voice prompt once when its
|
|
506
604
|
// distanceAlongGeometry trigger is crossed:
|
|
507
605
|
speak(steps[0].voice[0]);
|
|
508
606
|
```
|
|
509
607
|
|
|
510
|
-
Voice prompts arrive plain and as SSML
|
|
511
|
-
|
|
512
|
-
|
|
608
|
+
Voice prompts arrive plain and as SSML. The banner renders the manoeuvre
|
|
609
|
+
glyph from the platform's direction-icon set (roundabouts, forks, ramps,
|
|
610
|
+
ferries — see below) sized to the design's font, and, where OSM has
|
|
611
|
+
`turn:lanes` data, a lane diagram (sprite icons `lane-left`,
|
|
612
|
+
`lane-straight`, … ship with the map assets). The glyph's secondary shapes
|
|
613
|
+
retheme via the `--mm-icon-secondary` CSS custom property.
|
|
513
614
|
|
|
514
615
|
### Direction icons (`@mapmap/maps/direction-icons`)
|
|
515
616
|
|
|
516
|
-
|
|
517
|
-
|
|
617
|
+
The platform's 90-icon manoeuvre set as inline SVG, plus the OSRM maneuver
|
|
618
|
+
mapping. Available from the main entry and as a separate
|
|
619
|
+
`@mapmap/maps/direction-icons` entry point; apps that use neither
|
|
620
|
+
`GuidanceBanner` nor the icons tree-shake the set away entirely:
|
|
518
621
|
|
|
519
622
|
```ts
|
|
520
623
|
import {
|
|
521
624
|
directionIcons, // { turn_left: "<svg…>", roundabout_right: …, ferry: … }
|
|
625
|
+
iconNameForStep, // (step) => DirectionIconName — preferred
|
|
522
626
|
iconNameForManeuver, // (type?, modifier?, drivingSide?) => DirectionIconName
|
|
523
627
|
directionIconSvg, // shorthand: the SVG for a maneuver
|
|
524
628
|
} from "@mapmap/maps/direction-icons";
|
|
525
629
|
|
|
526
|
-
el.innerHTML =
|
|
630
|
+
el.innerHTML = directionIcons[iconNameForStep(step)];
|
|
527
631
|
```
|
|
528
632
|
|
|
529
633
|
Icons are 20×20 `viewBox` SVGs. The arrow inherits `currentColor`; secondary
|
|
530
634
|
road furniture (other lanes, the rest of a roundabout ring, ferry water) is
|
|
531
635
|
filled with `var(--mm-icon-secondary, #C9CDD2)` — set that CSS custom
|
|
532
636
|
property to retheme it. Unknown maneuvers degrade to the plain turn family,
|
|
533
|
-
never a missing icon
|
|
534
|
-
|
|
637
|
+
never a missing icon.
|
|
638
|
+
|
|
639
|
+
Prefer `iconNameForStep(step)`: it reads everything off the OSRM step
|
|
640
|
+
itself — ferry legs from `step.mode`, and the u-turn direction from
|
|
641
|
+
`step.driving_side` (the MapMap gateway emits it on u-turn steps), so
|
|
642
|
+
left-hand-traffic markets render `uturn_right` with no configuration.
|
|
643
|
+
The lower-level `iconNameForManeuver` remains for callers without a step
|
|
644
|
+
object; it defaults to right-hand traffic.
|
|
535
645
|
|
|
536
646
|
## Navigation camera
|
|
537
647
|
|