@12-apps/routing 1.1.0 → 1.2.0

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
@@ -83,6 +83,8 @@ const { RouteMap } = createWebRouting({
83
83
  />;
84
84
  ```
85
85
 
86
+ - `travelledParts` draws the solid line as separate strokes (a track with a
87
+ gap that must not be bridged by a straight line); it wins over `travelled`.
86
88
  - `maplibre-gl` is an optional peer dependency: install it in the web host.
87
89
  It is imported the first time a map mounts, so a page without a map never
88
90
  downloads it.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@12-apps/routing",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Road routes through an ordered list of stops, with the routing service chosen by host configuration (openrouteservice, OSRM, Google Routes, or your own adapter) and a straight-line fallback when none answers, plus a MapLibre route map for web hosts that draws markers, stops, a planned and a travelled line.",
@@ -19,7 +19,8 @@ export interface OpenRouteServiceOptions {
19
19
  baseUrl?: string;
20
20
  }
21
21
 
22
- const DEFAULT_BASE_URL = "https://api.openrouteservice.org";
22
+ /** `api.openrouteservice.org` is deprecated in favour of this host. */
23
+ const DEFAULT_BASE_URL = "https://api.heigit.org/openrouteservice";
23
24
 
24
25
  interface OrsSegment {
25
26
  distance?: unknown;
@@ -80,3 +80,20 @@ export function addLines(map: MapLike, theme: RouteMapTheme): void {
80
80
  export function setLine(map: MapLike, id: string, positions: readonly Position[] | undefined): void {
81
81
  map.getSource(id)?.setData(lineFeature(positions ?? []));
82
82
  }
83
+
84
+ /** Several strokes as one MultiLineString; a part under two points is dropped. */
85
+ function partsFeature(parts: readonly (readonly Position[])[]) {
86
+ const coordinates = parts.filter((part) => part.length > 1).map((part) => part.map((p) => [p[0], p[1]]));
87
+ return { type: "Feature" as const, properties: {}, geometry: { type: "MultiLineString" as const, coordinates } };
88
+ }
89
+
90
+ /** The travelled line: its parts when given, else the one line. */
91
+ export function setTravelled(
92
+ map: MapLike,
93
+ id: string,
94
+ line: readonly Position[] | undefined,
95
+ parts: readonly (readonly Position[])[] | undefined,
96
+ ): void {
97
+ if (parts) map.getSource(id)?.setData(partsFeature(parts));
98
+ else setLine(map, id, line);
99
+ }
@@ -66,6 +66,12 @@ export interface RouteMapProps {
66
66
  planned?: readonly Position[];
67
67
  /** The solid line, `[lng, lat][]`. */
68
68
  travelled?: readonly Position[];
69
+ /**
70
+ * The solid line in separate strokes, each `[lng, lat][]` — for a track with
71
+ * a gap that must not be bridged by a straight line. Wins over `travelled`
72
+ * when set; a part with fewer than two points draws nothing.
73
+ */
74
+ travelledParts?: readonly (readonly Position[])[];
69
75
  /** Overrides `theme.travelled` (a status colour). */
70
76
  travelledColor?: string;
71
77
  /** Change it to refit the viewport to everything drawn. */
@@ -29,7 +29,7 @@ import type { LngLat } from "../core/types";
29
29
 
30
30
  import type { RouteMapCopy } from "./copy";
31
31
  import { groupElement, markerElement, PLACE_LIFT, placeElement, stopElement } from "./map-elements";
32
- import { boundsOf, groupMarkers, PLANNED_LAYER, pointsOf, setLine, TRAVELLED_LAYER } from "./map-geometry";
32
+ import { boundsOf, groupMarkers, PLANNED_LAYER, pointsOf, setLine, setTravelled, TRAVELLED_LAYER } from "./map-geometry";
33
33
  import type { MarkerLike } from "./maplibre-types";
34
34
  import { placeTags, type Placed } from "./tag-placement";
35
35
  import type { MapHandle } from "./use-map";
@@ -208,9 +208,9 @@ export function useOverlaySync(ready: boolean, handle: Pick<MapHandle, "mapRef">
208
208
  const map = handle.mapRef.current;
209
209
  if (!ready || !map) return;
210
210
  setLine(map, PLANNED_LAYER, props.planned);
211
- setLine(map, TRAVELLED_LAYER, props.travelled);
211
+ setTravelled(map, TRAVELLED_LAYER, props.travelled, props.travelledParts);
212
212
  map.setPaintProperty(TRAVELLED_LAYER, "line-color", props.travelledColor ?? theme.travelled);
213
- }, [ready, props.planned, props.travelled, props.travelledColor]);
213
+ }, [ready, props.planned, props.travelled, props.travelledParts, props.travelledColor]);
214
214
 
215
215
  useEffect(() => {
216
216
  if (ready) overlays.draw();