@tomtom-org/maps-sdk-plugin-flyover 0.0.6 → 0.1.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
@@ -4,6 +4,8 @@ This plugin adds a camera that flies a route on a [TomTom Maps SDK for JavaScrip
4
4
  map. It follows the line, aims at the junctions ahead and frames them. It keeps clear of the terrain
5
5
  it crosses, and it parks the followed position, marked with an arrow, where you want it on screen.
6
6
 
7
+ > **Public preview.** This plugin is in [Public Preview](https://docs.tomtom.com/legal/public-preview) until its 1.0.0 release.
8
+
7
9
  ## Docs & examples
8
10
 
9
11
  - Developer guide: https://docs.tomtom.com/maps-sdk-js/guides/plugins/flyover
@@ -11,7 +13,7 @@ it crosses, and it parks the followed position, marked with an arrow, where you
11
13
 
12
14
  ## Quickstart
13
15
 
14
- This plugin declares `@tomtom-org/maps-sdk` and `maplibre-gl` as peer dependencies and bundles neither, so install both in your project too.
16
+ This plugin declares `@tomtom-org/maps-sdk`, `maplibre-gl` and `@turf/turf` as peer dependencies and bundles none of them, so install the first two in your project too. `@turf/turf` is one of the SDK's own peers, so it installs with the SDK.
15
17
 
16
18
  ```bash
17
19
  npm install @tomtom-org/maps-sdk maplibre-gl @tomtom-org/maps-sdk-plugin-flyover
@@ -35,7 +37,8 @@ flyover.start();
35
37
  ## Features
36
38
 
37
39
  The route is the only geometry it needs. There are no camera keyframes to author and no animation
38
- to re-time when the route changes. The flight loops. It wraps at the destination and never lands.
40
+ to re-time when the route changes. By default, the flight loops: it wraps at the destination and
41
+ never lands. With `loop: false`, it stops at the destination instead.
39
42
 
40
43
  - **Aim** — at the next guidance instruction, a fixed distance down the road or a number of the
41
44
  route's own vertices.
@@ -51,3 +54,7 @@ to re-time when the route changes. The flight loops. It wraps at the destination
51
54
  ## License
52
55
 
53
56
  See [LICENSE.txt](./LICENSE.txt).
57
+
58
+ ## Security
59
+
60
+ To report a security vulnerability, follow [SECURITY.md](https://github.com/tomtom-international/maps-sdk-js/blob/main/SECURITY.md), which keeps it private.
package/THIRD_PARTY.txt CHANGED
@@ -13,132 +13,14 @@ by the licenses reproduced here.
13
13
 
14
14
  --------------------------------------------------------------------------------
15
15
 
16
- Name: @turf/bearing
16
+ Name: @turf/turf
17
17
  Version: 7.4.0
18
18
  License: MIT
19
- Bundled: true
20
- Description: Takes two points and finds the geographic bearing between them.
21
- Repository: git://github.com/Turfjs/turf.git
22
- Homepage: https://github.com/Turfjs/turf
23
- Author: Turf Authors
24
- License Text:
25
- ===
26
-
27
- The MIT License (MIT)
28
-
29
- Copyright (c) 2017 TurfJS
30
-
31
- Permission is hereby granted, free of charge, to any person obtaining a copy of
32
- this software and associated documentation files (the "Software"), to deal in
33
- the Software without restriction, including without limitation the rights to
34
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
35
- the Software, and to permit persons to whom the Software is furnished to do so,
36
- subject to the following conditions:
37
-
38
- The above copyright notice and this permission notice shall be included in all
39
- copies or substantial portions of the Software.
40
-
41
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
43
- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
44
- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
45
- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
46
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
47
-
48
-
49
-
50
- ---
51
-
52
- Name: @turf/destination
53
- Version: 7.4.0
54
- License: MIT
55
- Bundled: true
56
- Description: turf destination module
57
- Repository: git://github.com/Turfjs/turf.git
58
- Homepage: https://github.com/Turfjs/turf
59
- Author: Turf Authors
60
- Contributors:
61
- Pavel Rozvora <@prozvora>
62
- License Text:
63
- ===
64
-
65
- The MIT License (MIT)
66
-
67
- Copyright (c) 2017 TurfJS
68
-
69
- Permission is hereby granted, free of charge, to any person obtaining a copy of
70
- this software and associated documentation files (the "Software"), to deal in
71
- the Software without restriction, including without limitation the rights to
72
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
73
- the Software, and to permit persons to whom the Software is furnished to do so,
74
- subject to the following conditions:
75
-
76
- The above copyright notice and this permission notice shall be included in all
77
- copies or substantial portions of the Software.
78
-
79
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
80
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
81
- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
82
- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
83
- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
84
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
85
-
86
-
87
-
88
- ---
89
-
90
- Name: @turf/helpers
91
- Version: 7.4.0
92
- License: MIT
93
- Bundled: true
94
- Description: Provides helper functions to create GeoJSON features, like points, lines, or areas on a map.
95
- Repository: git://github.com/Turfjs/turf.git
96
- Homepage: https://github.com/Turfjs/turf
97
- Author: Turf Authors
98
- Contributors:
99
- Tom MacWright <@tmcw>
100
- Stefano Borghi <@stebogit>
101
- Denis Carriere <@DenisCarriere>
102
- William Nordmann <@wnordmann>
103
- License Text:
104
- ===
105
-
106
- The MIT License (MIT)
107
-
108
- Copyright (c) 2017 TurfJS
109
-
110
- Permission is hereby granted, free of charge, to any person obtaining a copy of
111
- this software and associated documentation files (the "Software"), to deal in
112
- the Software without restriction, including without limitation the rights to
113
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
114
- the Software, and to permit persons to whom the Software is furnished to do so,
115
- subject to the following conditions:
116
-
117
- The above copyright notice and this permission notice shall be included in all
118
- copies or substantial portions of the Software.
119
-
120
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
121
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
122
- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
123
- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
124
- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
125
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
126
-
127
-
128
-
129
- ---
130
-
131
- Name: @turf/invariant
132
- Version: 7.4.0
133
- License: MIT
134
- Bundled: true
135
- Description: Lightweight utility for input validation and data extraction in Turf.js. Ensures GeoJSON inputs are in the correct format and extracts specific components like coordinates or geometries.
19
+ Bundled: false (peer dependency)
20
+ Description: a JavaScript library for performing geospatial operations with GeoJSON
136
21
  Repository: git://github.com/Turfjs/turf.git
137
22
  Homepage: https://github.com/Turfjs/turf
138
23
  Author: Turf Authors
139
- Contributors:
140
- Tom MacWright <@tmcw>
141
- Denis Carriere <@DenisCarriere>
142
24
  License Text:
143
25
  ===
144
26
 
@@ -164,11 +46,10 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
164
46
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
165
47
 
166
48
 
167
-
168
49
  ---
169
50
 
170
51
  Name: maplibre-gl
171
- Version: 6.13.0
52
+ Version: 6.15.0
172
53
  License: BSD-3-Clause
173
54
  Bundled: false (peer dependency)
174
55
  Description: BSD licensed community fork of mapbox-gl, a WebGL interactive maps library
@@ -1,91 +1,13 @@
1
- The following third-party components are bundled into this package. Their licenses
2
- are reproduced below.
3
-
4
- Name: @turf/helpers
5
- Version: 7.4.0
6
- License: MIT
7
- Bundled: true
8
- Description: Provides helper functions to create GeoJSON features, like points, lines, or areas on a map.
9
- Repository: git://github.com/Turfjs/turf.git
10
- Homepage: https://github.com/Turfjs/turf
11
- Author: Turf Authors
12
- Contributors:
13
- Tom MacWright <@tmcw>
14
- Stefano Borghi <@stebogit>
15
- Denis Carriere <@DenisCarriere>
16
- William Nordmann <@wnordmann>
17
- License Text:
18
- ===
19
-
20
- The MIT License (MIT)
21
-
22
- Copyright (c) 2017 TurfJS
23
-
24
- Permission is hereby granted, free of charge, to any person obtaining a copy of
25
- this software and associated documentation files (the "Software"), to deal in
26
- the Software without restriction, including without limitation the rights to
27
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
28
- the Software, and to permit persons to whom the Software is furnished to do so,
29
- subject to the following conditions:
30
-
31
- The above copyright notice and this permission notice shall be included in all
32
- copies or substantial portions of the Software.
33
-
34
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
36
- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
37
- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
38
- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
39
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40
-
41
-
42
-
43
- ---
44
-
45
- Name: @turf/invariant
46
- Version: 7.4.0
47
- License: MIT
48
- Bundled: true
49
- Description: Lightweight utility for input validation and data extraction in Turf.js. Ensures GeoJSON inputs are in the correct format and extracts specific components like coordinates or geometries.
50
- Repository: git://github.com/Turfjs/turf.git
51
- Homepage: https://github.com/Turfjs/turf
52
- Author: Turf Authors
53
- Contributors:
54
- Tom MacWright <@tmcw>
55
- Denis Carriere <@DenisCarriere>
56
- License Text:
57
- ===
58
-
59
- The MIT License (MIT)
60
-
61
- Copyright (c) 2017 TurfJS
62
-
63
- Permission is hereby granted, free of charge, to any person obtaining a copy of
64
- this software and associated documentation files (the "Software"), to deal in
65
- the Software without restriction, including without limitation the rights to
66
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
67
- the Software, and to permit persons to whom the Software is furnished to do so,
68
- subject to the following conditions:
69
-
70
- The above copyright notice and this permission notice shall be included in all
71
- copies or substantial portions of the Software.
72
-
73
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
74
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
75
- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
76
- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
77
- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
78
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
79
-
80
-
81
-
82
- ---
1
+ The following third-party components are declared as peer dependencies. Their code is
2
+ NOT bundled into this package: your package manager installs them alongside it and
3
+ your application bundles them. The licenses below apply to those copies, and each of
4
+ these components may in turn install its own dependencies under their own licenses.
83
5
 
84
- Name: @turf/bearing
6
+ Name: @turf/turf
85
7
  Version: 7.4.0
86
8
  License: MIT
87
- Bundled: true
88
- Description: Takes two points and finds the geographic bearing between them.
9
+ Bundled: false (peer dependency)
10
+ Description: a JavaScript library for performing geospatial operations with GeoJSON
89
11
  Repository: git://github.com/Turfjs/turf.git
90
12
  Homepage: https://github.com/Turfjs/turf
91
13
  Author: Turf Authors
@@ -114,54 +36,10 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
114
36
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
115
37
 
116
38
 
117
-
118
39
  ---
119
40
 
120
- Name: @turf/destination
121
- Version: 7.4.0
122
- License: MIT
123
- Bundled: true
124
- Description: turf destination module
125
- Repository: git://github.com/Turfjs/turf.git
126
- Homepage: https://github.com/Turfjs/turf
127
- Author: Turf Authors
128
- Contributors:
129
- Pavel Rozvora <@prozvora>
130
- License Text:
131
- ===
132
-
133
- The MIT License (MIT)
134
-
135
- Copyright (c) 2017 TurfJS
136
-
137
- Permission is hereby granted, free of charge, to any person obtaining a copy of
138
- this software and associated documentation files (the "Software"), to deal in
139
- the Software without restriction, including without limitation the rights to
140
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
141
- the Software, and to permit persons to whom the Software is furnished to do so,
142
- subject to the following conditions:
143
-
144
- The above copyright notice and this permission notice shall be included in all
145
- copies or substantial portions of the Software.
146
-
147
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
148
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
149
- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
150
- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
151
- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
152
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
153
-
154
-
155
-
156
- --------------------------------------------------------------------------------
157
-
158
- The following third-party components are declared as peer dependencies. Their code is
159
- NOT bundled into this package: your package manager installs them alongside it and
160
- your application bundles them. The licenses below apply to those copies, and each of
161
- these components may in turn install its own dependencies under their own licenses.
162
-
163
41
  Name: maplibre-gl
164
- Version: 6.13.0
42
+ Version: 6.15.0
165
43
  License: BSD-3-Clause
166
44
  Bundled: false (peer dependency)
167
45
  Description: BSD licensed community fork of mapbox-gl, a WebGL interactive maps library
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { CustomImage, SVGIconStyleOptions, TomTomMap } from "@tomtom-org/maps-sdk/map";
2
- import { Route } from "@tomtom-org/maps-sdk/core";
2
+ import { Route, RouteProgressQuery } from "@tomtom-org/maps-sdk/core";
3
3
  //#region src/framing.d.ts
4
4
  /**
5
5
  * Where the position being followed sits in the view, as fractions of the viewport: `{ x: 0.5, y:
@@ -136,12 +136,24 @@ type RouteFlyoverOptions = {
136
136
  marker?: FlyoverMarkerConfig;
137
137
  /** Called with the flight's progress, once per survey rather than once per frame. */
138
138
  onProgress?: (progress: FlyoverProgress) => void;
139
+ /**
140
+ * Whether the flight wraps at the destination and flies on from the departure. Without the loop,
141
+ * it stops at the destination and calls {@link onArrive}, and a {@link RouteFlyover.start} from
142
+ * there flies the route again from its departure.
143
+ * @default true
144
+ */
145
+ loop?: boolean;
146
+ /** Called when a flight that doesn't {@link loop} reaches the destination and stops there. */
147
+ onArrive?: () => void;
139
148
  };
140
149
  /**
141
- * A camera that flies a route on a loop. Every frame, it advances a distance along the line, reads
142
- * the route's coordinate at that distance, and points itself at where it will be next.
150
+ * A camera that flies a route, on a loop or once to the destination. Every frame, it advances a
151
+ * distance along the line, reads the route's coordinate at that distance, and points itself at
152
+ * where it will be next.
143
153
  *
144
154
  * @remarks
155
+ * **[Public Preview](https://docs.tomtom.com/legal/public-preview)** until the plugin's 1.0.0 release.
156
+ *
145
157
  * The route is the only geometry it needs. There's no path of camera keyframes to author and no
146
158
  * animation to re-time when the route changes. What it adds on top of following the line:
147
159
  *
@@ -174,6 +186,8 @@ export declare class RouteFlyover {
174
186
  private route;
175
187
  private camera;
176
188
  private readonly onProgress;
189
+ private readonly loop;
190
+ private readonly onArrive;
177
191
  private readonly marker;
178
192
  private animationFrame;
179
193
  private lastFrameTime;
@@ -190,7 +204,10 @@ export declare class RouteFlyover {
190
204
  constructor(map: TomTomMap, options: RouteFlyoverOptions);
191
205
  /** Whether the flight is advancing. */
192
206
  get running(): boolean;
193
- /** Starts, or resumes, the flight, ramping up to its speed. */
207
+ /**
208
+ * Starts, or resumes, the flight, ramping up to its speed. A flight that doesn't loop and has
209
+ * arrived starts again from the departure.
210
+ */
194
211
  start(): void;
195
212
  /**
196
213
  * Stops the flight where it is. {@link start} resumes from there. The centre clamp returns to
@@ -205,8 +222,13 @@ export declare class RouteFlyover {
205
222
  getCamera(): FlyoverCamera;
206
223
  /** Replaces the marker riding the route, or hides it with `visible: false`. */
207
224
  setMarker(marker: FlyoverMarkerConfig): void;
208
- /** Moves the flight to a point along the route, as a share of its length within 0..1. */
209
- seek(fraction: number): void;
225
+ /**
226
+ * Moves the flight to a point along the route: a share of its length within 0..1, or a time or
227
+ * distance travelled, or a clock time, the way `getCoordinateAtRouteProgress` reads them. A
228
+ * point outside the route moves it to the nearer end, and a clock time on a route without a
229
+ * departure time to the departure.
230
+ */
231
+ seek(progress: number | RouteProgressQuery): void;
210
232
  /**
211
233
  * Stops the flight and gives the map back. The marker leaves, and the padding returns to what
212
234
  * the map had before the flight first placed the camera.
@@ -214,15 +236,19 @@ export declare class RouteFlyover {
214
236
  remove(): void;
215
237
  private readonly readViewport;
216
238
  private routeLengthInMeters;
239
+ private distanceAt;
240
+ private hasArrived;
217
241
  private readonly step;
218
242
  private coordinateAt;
219
243
  private positionAt;
220
- private wrapped;
244
+ private metersAheadTo;
245
+ private alongRoute;
221
246
  private roadHeading;
222
247
  private instructions;
223
248
  /**
224
- * The instruction the flight is heading for — the first one still ahead of it, and the first of
225
- * all once the loop has passed the last. `undefined` when the route carries no guidance.
249
+ * The instruction the flight is heading for — the first one still ahead of it. Past the last,
250
+ * a loop heads for the first of all and a flight that doesn't loop for the last.
251
+ * `undefined` when the route carries no guidance.
226
252
  */
227
253
  private instructionAhead;
228
254
  private pointIndexHere;
@@ -256,7 +282,8 @@ export declare class RouteFlyover {
256
282
  /**
257
283
  * One frame: where the flight has got to, and a step of the camera towards what the last survey
258
284
  * decided. Without `elapsedSeconds` — a seek, a new route, a changed setting — the camera is
259
- * surveyed and placed at its targets outright.
285
+ * surveyed and placed at its targets outright. The frame that `arrives` surveys too, so the
286
+ * progress reported last is the destination.
260
287
  */
261
288
  private placeCamera;
262
289
  }
package/dist/index.es.js CHANGED
@@ -1 +1 @@
1
- import{calculateProgressAtRoutePoint as e,generateId as t,getCoordinateAtRouteProgress as r}from"@tomtom-org/maps-sdk/core";import{MercatorCoordinate as i}from"maplibre-gl";var a=6371008.8,n={centimeters:637100880,centimetres:637100880,cm:637100880,degrees:360/(2*Math.PI),deg:360/(2*Math.PI),feet:20902260.511392,ft:20902260.511392,inches:39.37*a,in:39.37*a,kilometers:6371.0088,kilometres:6371.0088,km:6371.0088,meters:a,metres:a,m:a,miles:3958.761333810546,mi:3958.761333810546,millimeters:6371008800,millimetres:6371008800,mm:6371008800,nauticalmiles:a/1852,nmi:a/1852,radians:1,rad:1,yards:6967335.223679999,yd:6967335.223679999};function o(e,t,r={}){if(!e)throw new Error("coordinates is required");if(!Array.isArray(e))throw new Error("coordinates must be an Array");if(e.length<2)throw new Error("coordinates must be at least 2 numbers long");if(!m(e[0])||!m(e[1]))throw new Error("coordinates must contain numbers");return function(e,t,r={}){const i={type:"Feature"};return(0===r.id||r.id)&&(i.id=r.id),r.bbox&&(i.bbox=r.bbox),i.properties=t||{},i.geometry=e,i}({type:"Point",coordinates:e},t,r)}function s(e){return e%(2*Math.PI)*180/Math.PI}function h(e){return e%360*Math.PI/180}function m(e){return!isNaN(e)&&null!==e&&!Array.isArray(e)}function c(e){if(!e)throw new Error("coord is required");if(!Array.isArray(e)){if("Feature"===e.type&&null!==e.geometry&&"Point"===e.geometry.type)return[...e.geometry.coordinates];if("Point"===e.type)return[...e.coordinates]}if(Array.isArray(e)&&e.length>=2&&!Array.isArray(e[0])&&!Array.isArray(e[1]))return[...e];throw new Error("coord must be GeoJSON Point or an Array of numbers")}function d(e,t,r={}){if(!0===r.final)return function(e,t){let r=d(t,e);return r=(r+180)%360,r>180?r-360:r}(e,t);const i=c(e),a=c(t),n=h(i[0]),o=h(a[0]),m=h(i[1]),u=h(a[1]),g=Math.sin(o-n)*Math.cos(u),l=Math.cos(m)*Math.sin(u)-Math.sin(m)*Math.cos(u)*Math.cos(o-n);return s(Math.atan2(g,l))}function u(e,t,r,i={}){const a=c(e),m=h(a[0]),d=h(a[1]),u=h(r),g=function(e,t="kilometers"){const r=n[t];if(!r)throw new Error(t+" units is invalid");return e/r}(t,i.units),l=Math.asin(Math.sin(d)*Math.cos(g)+Math.cos(d)*Math.sin(g)*Math.cos(u)),p=s(m+Math.atan2(Math.sin(u)*Math.sin(g)*Math.cos(d),Math.cos(g)-Math.sin(d)*Math.sin(l))),v=s(l);return void 0!==a[2]?o([p,v,a[2]],i.properties):o([p,v],i.properties)}var g=(e,t)=>function(e){let t=e%360;return t<0&&(t+=360),t}(d(e,t)),l=(e,t)=>(t-e+540)%360-180,p=(e,t,r)=>Math.min(Math.max(e,t),r),v=e=>({value:e,velocity:0}),M=1e-6,f=(e,t,r,i,a=Number.POSITIVE_INFINITY)=>{const n=4/i,o=2*a/n,s=p(e.value-t,-o,o);if(Math.abs(s)<M&&Math.abs(e.velocity)<M)return v(t);const h=(e.velocity+n*s)*r,m=Math.exp(-n*r);return{value:e.value-s+(s+h)*m,velocity:(e.velocity-n*h)*m}},y=(e,t,r,i,a)=>{const n=f(e,e.value+l(e.value,t),r,i,a);return{value:(n.value+360)%360,velocity:n.velocity}},A=e=>p(e,.05,.95),w=e=>({x:.5,y:.5+p(e,0,60)/60*.16666666666666663}),T=(e,t)=>{const r=A(e.x)-.5,i=A(e.y)-.5,a=(e,t)=>Math.max(2*e*t,0);return{left:a(r,t.width),right:a(-r,t.width),top:a(i,t.height),bottom:a(-i,t.height)}},E=40075016.686/512,b=(e,t)=>Math.log2(E*Math.cos(h(t))/e),x=({viewportHeight:e,fieldOfViewDegrees:t})=>.5*e/Math.tan(h(t)/2),_=(e,t)=>x(t)*((e,t)=>E*Math.cos(h(t))/2**e)(e,t.latitudeDegrees),I=(e,t)=>{const r=document.createElementNS("http://www.w3.org/2000/svg",e);for(const[i,a]of Object.entries(t))r.setAttribute(i,a);return r},R=e=>`data:image/svg+xml;charset=utf-8,${encodeURIComponent(e)}`,L=(e,t)=>{const r="arrow"===e.type?R((({fillColor:e="#105287",outlineColor:t="white",outlineOpacity:r=1},i)=>{const a=I("svg",{viewBox:"0 0 24 24",width:String(i),height:String(i)});return a.append(I("path",{d:"M12 3l8 18-8-4-8 4z",fill:e,stroke:t,"stroke-opacity":String(r),"stroke-width":"3","stroke-linejoin":"round","paint-order":"stroke"})),(new XMLSerializer).serializeToString(a)})(e,t)):e.image;if("string"!=typeof r)return r;const i=new Image;return i.crossOrigin="anonymous",i.src=r.includes("<svg")?R(r):r,i},P=(e,t,r)=>{const i=e.createShader(t);if(!i)throw new Error("The fly-over marker could not create a shader");return e.shaderSource(i,r),e.compileShader(i),i},k=class{map;id=`tomtom-flyover-marker-${t()}`;type="custom";renderingMode="2d";config={};placed;raster;gl;drawing;removed=!1;stopRestoring;constructor(e,t){this.map=e,this.stopRestoring=e.addStyleChangeHandler({onStyleChanged:()=>this.install()}),this.installWhenReady(),this.apply(t)}apply(e){this.config=e;const t=e.size??44;var r;(async(e,t)=>{const r=L(e,t);await r.decode();const i=document.createElement("canvas");i.width=t,i.height=t;const a=t/Math.max(r.naturalWidth,r.naturalHeight,1),[n,o]=[r.naturalWidth*a,r.naturalHeight*a];return i.getContext("2d")?.drawImage(r,(t-n)/2,(t-o)/2,n,o),i})(e.image??{type:"arrow"},(r=t,Math.min(2**Math.ceil(Math.log2(Math.max(r*devicePixelRatio,1))),512))).then(t=>{this.config===e&&(this.raster=t,this.releaseTexture(),this.map.mapLibreMap.triggerRepaint())}).catch(e=>console.warn("The fly-over marker image could not be loaded",e)),this.map.mapLibreMap.triggerRepaint()}place(e,t){this.placed={position:e,heading:t},this.map.mapLibreMap.triggerRepaint()}remove(){this.removed=!0,this.stopRestoring(),this.map.mapLibreMap.getLayer(this.id)&&this.map.mapLibreMap.removeLayer(this.id)}onAdd(e,t){this.gl=t,this.drawing=(e=>{const t=e.createProgram(),r=e.createBuffer();if(!t||!r)throw new Error("The fly-over marker could not create its program");return e.attachShader(t,P(e,e.VERTEX_SHADER,"\nuniform mat4 u_matrix;\nuniform vec2 u_right;\nuniform vec2 u_forward;\nattribute vec2 a_corner;\nvarying vec2 v_uv;\nvoid main() {\n v_uv = vec2(a_corner.x, -a_corner.y) * 0.5 + 0.5;\n gl_Position = u_matrix * vec4(u_right * a_corner.x + u_forward * a_corner.y, 0.0, 1.0);\n}")),e.attachShader(t,P(e,e.FRAGMENT_SHADER,"\nprecision mediump float;\nuniform sampler2D u_image;\nvarying vec2 v_uv;\nvoid main() {\n gl_FragColor = texture2D(u_image, v_uv);\n}")),e.linkProgram(t),e.bindBuffer(e.ARRAY_BUFFER,r),e.bufferData(e.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),e.STATIC_DRAW),{program:t,corners:r,texture:void 0,uniforms:{matrix:e.getUniformLocation(t,"u_matrix"),right:e.getUniformLocation(t,"u_right"),forward:e.getUniformLocation(t,"u_forward"),image:e.getUniformLocation(t,"u_image")},corner:e.getAttribLocation(t,"a_corner")}})(t)}onRemove(e,t){this.releaseTexture(),this.drawing&&(t.deleteProgram(this.drawing.program),t.deleteBuffer(this.drawing.corners)),this.drawing=void 0,this.gl=void 0}render(e,t){const{drawing:r,placed:a,raster:n}=this;if(!r||!a||!n||!1===this.config.visible)return;r.texture??=((e,t)=>{const r=e.createTexture()??void 0;return e.bindTexture(e.TEXTURE_2D,r??null),e.pixelStorei(e.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!0),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,t),e.pixelStorei(e.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),e.generateMipmap(e.TEXTURE_2D),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR_MIPMAP_LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),r})(e,n);const o=this.map.mapLibreMap,[s,m]=a.position,c=o.queryTerrainElevation([s,m])??0,d=i.fromLngLat([s,m],c),u=(this.config.size??44)/2*(1/(512*2**o.getZoom()));const g=h(a.heading),[l,p]=[Math.sin(g)*u,Math.cos(g)*u];e.useProgram(r.program),e.uniformMatrix4fv(r.uniforms.matrix,!1,((e,{x:t,y:r,z:i})=>{const a=Float32Array.from(e);for(let n=0;n<4;n++)a[12+n]=e[n]*t+e[4+n]*r+e[8+n]*i+e[12+n];return a})(t.defaultProjectionData.mainMatrix,d)),e.uniform2f(r.uniforms.right,p,l),e.uniform2f(r.uniforms.forward,l,-p),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,r.texture??null),e.uniform1i(r.uniforms.image,0),e.bindBuffer(e.ARRAY_BUFFER,r.corners),e.enableVertexAttribArray(r.corner),e.vertexAttribPointer(r.corner,2,e.FLOAT,!1,0,0),e.disable(e.DEPTH_TEST),e.enable(e.BLEND),e.blendFunc(e.ONE,e.ONE_MINUS_SRC_ALPHA),e.drawArrays(e.TRIANGLE_STRIP,0,4)}releaseTexture(){this.drawing?.texture&&this.gl?.deleteTexture(this.drawing.texture),this.drawing&&(this.drawing.texture=void 0)}installWhenReady(){this.map.mapReady?this.install():this.map.mapLibreMap.once("styledata",()=>this.installWhenReady())}install(){this.removed||this.map.mapLibreMap.getLayer(this.id)||this.map.mapLibreMap.addLayer(this)}},D={speedKMH:200,pitch:70,aim:{mode:"instruction",fallbackMetersAhead:250},zoom:{mode:"instructions",instructionsAhead:2}},H=2,S=2,C=3,F=1.5,U=1.5,z=.6,N=.5,X=15,O=e=>p(e,11,15),G=class{map;route;camera;onProgress;marker;animationFrame;lastFrameTime=0;traveledDistanceInMeters=0;speedKMH=v(0);motion;target;framedZoom;secondsSinceSurvey=0;viewport={width:1,height:1};flying=!1;pageCenterClampedToGround=!0;pagePadding;constructor(e,t){this.map=e,this.route=t.route,this.camera={...D,...t.camera},this.onProgress=t.onProgress??(()=>{});const r=e.mapLibreMap,i=this.targetAnchor();this.motion={bearing:v(r.getBearing()),zoom:v(r.getZoom()),pitch:v(r.getPitch()),anchorX:v(i.x),anchorY:v(i.y),elevation:v(r.getCenterElevation()),markerHeading:v(0)},this.target={bearing:this.motion.bearing.value,zoom:this.motion.zoom.value,elevation:this.motion.elevation.value,markerHeading:0},this.framedZoom=this.target.zoom,this.readViewport(),r.on("resize",this.readViewport),this.marker=new k(e,t.marker??{}),this.placeMarkerOutright()}get running(){return void 0!==this.animationFrame}start(){if(this.running)return;const e=this.map.mapLibreMap;this.pageCenterClampedToGround=e.getCenterClampedToGround(),e.setCenterClampedToGround(!1),this.speedKMH=v(0),this.lastFrameTime=performance.now(),this.animationFrame=requestAnimationFrame(this.step)}stop(){void 0!==this.animationFrame&&(cancelAnimationFrame(this.animationFrame),this.animationFrame=void 0,this.map.mapLibreMap.setCenterClampedToGround(this.pageCenterClampedToGround))}setRoute(e){this.route=e,this.traveledDistanceInMeters=0,this.flying=!1,this.running?this.placeCamera():this.placeMarkerOutright()}setCamera(e){this.camera={...this.camera,...e},this.flying&&!this.running&&this.placeCamera()}getCamera(){return{...this.camera}}setMarker(e){this.marker.apply(e)}seek(e){this.traveledDistanceInMeters=this.routeLengthInMeters()*p(e,0,1),this.placeCamera()}remove(){this.stop(),this.marker.remove();const e=this.map.mapLibreMap;e.off("resize",this.readViewport),this.pagePadding&&e.setPadding(this.pagePadding)}readViewport=()=>{const e=this.map.mapLibreMap.getCanvas();this.viewport={width:Math.max(e.clientWidth,1),height:Math.max(e.clientHeight,1)}};routeLengthInMeters(){return this.route.properties.summary.lengthInMeters}step=e=>{const t=p((e-this.lastFrameTime)/1e3,0,.25);this.lastFrameTime=e;const r=this.speedKMH.value;this.speedKMH=f(this.speedKMH,this.camera.speedKMH,t,H);const i=(r+this.speedKMH.value)/2/3.6;this.traveledDistanceInMeters=this.wrapped(this.traveledDistanceInMeters+i*t),this.placeCamera(t),this.animationFrame=requestAnimationFrame(this.step)};coordinateAt(e){return r(this.route,{traveledDistanceInMeters:e})}positionAt(e){return this.coordinateAt(this.wrapped(this.traveledDistanceInMeters+e))?.position}wrapped(e){const t=this.routeLengthInMeters();return t>0?(e%t+t)%t:0}roadHeading(){const[e,t]=[-15,X].map(e=>this.coordinateAt(this.traveledDistanceInMeters+e)?.position);return e&&t?g(e,t):void 0}instructions(){return this.route.properties.guidance?.instructions??[]}instructionAhead(e=0){const t=this.instructions();if(!t.length)return;const r=t.findIndex(e=>e.routeOffsetInMeters>this.traveledDistanceInMeters);return t[Math.min((-1===r?0:r)+e,t.length-1)]}pointIndexHere(){let t=0,r=this.route.geometry.coordinates.length-1;for(;t<r;){const i=Math.floor((t+r)/2),a=e(this.route,i);void 0!==a&&a.distanceInMeters<this.traveledDistanceInMeters?t=i+1:r=i}return t}aimPosition(){const e=this.camera.aim;switch(e.mode){case"distance":return this.positionAt(e.metersAhead);case"points":{const t=this.route.geometry.coordinates;return t[(this.pointIndexHere()+e.pointsAhead)%t.length]}case"instruction":{const t=this.instructionAhead(),r=t&&this.wrapped(t.routeOffsetInMeters-this.traveledDistanceInMeters);return void 0===r?this.positionAt(e.fallbackMetersAhead):this.positionAt(r)}}}modeZoom(e){const t=this.camera.zoom;if("fixed"===t.mode)return t.zoom;if("speed"===t.mode){const e=Math.log2(Math.max(this.camera.speedKMH,1)/90);return O(14-1*e)}const r=this.instructionAhead(Math.max(t.instructionsAhead,1)-1);if(!r)return O(14);const i=this.wrapped(r.routeOffsetInMeters-this.traveledDistanceInMeters)*Math.cos(h(Math.min(this.camera.pitch,85)));return O(((e,t,r)=>b(Math.max(e,1)/Math.max(t,1),r))(i,.6*this.viewport.height,e))}clearanceZoom(e,t,r){const i=h(Math.min(this.camera.pitch,85)),a=_(this.motion.zoom.value,r)*Math.sin(i)/1e3,n=this.motion.bearing.value+180;let o=200;for(let s=0;s<4;s++){const r=s/4,i=u(e,a*(1-r),n).geometry.coordinates,h=this.groundAt(i);void 0!==h&&(o=Math.max(o,200+(h-t)/(1-r)))}return((e,t)=>b(Math.max(e,1)/x(t),t.latitudeDegrees))(o/Math.cos(i),r)}groundAt([e,t]){return this.map.mapLibreMap.queryTerrainElevation([e,t])??void 0}survey(e){const t={latitudeDegrees:e[1],viewportHeight:this.viewport.height,fieldOfViewDegrees:this.map.mapLibreMap.getVerticalFieldOfView()},r=this.aimPosition();r&&(this.target.bearing=((e,t,r)=>Math.abs(l(e,t))>r?t:e)(this.target.bearing,g(e,r),2.5)),this.target.markerHeading=this.roadHeading()??this.target.markerHeading;const i=this.modeZoom(t.latitudeDegrees),a="instructions"===this.camera.zoom.mode?.2:0;Math.abs(i-this.framedZoom)>a&&(this.framedZoom=i);const n=this.groundAt(e);void 0===n?(this.map.mapLibreMap.getTerrain()||(this.target.elevation=0),this.target.zoom=this.framedZoom):(this.target.elevation=n,this.target.zoom=Math.min(this.framedZoom,this.clearanceZoom(e,n,t)))}targetAnchor(){return this.camera.anchor??w(this.camera.pitch)}ease(e){const{motion:t,target:r}=this,i=this.targetAnchor(),a=(t,r,i)=>f(t,r,e,i);this.motion={bearing:y(t.bearing,r.bearing,e,S,22),markerHeading:y(t.markerHeading,r.markerHeading,e,N),zoom:a(t.zoom,r.zoom,C),elevation:a(t.elevation,r.elevation,z),pitch:a(t.pitch,this.camera.pitch,F),anchorX:a(t.anchorX,i.x,U),anchorY:a(t.anchorY,i.y,U)}}settle(){const e=this.targetAnchor();this.motion={bearing:v(this.target.bearing),markerHeading:v(this.target.markerHeading),zoom:v(this.target.zoom),elevation:v(this.target.elevation),pitch:v(this.camera.pitch),anchorX:v(e.x),anchorY:v(e.y)}}placeMarkerOutright(){const e=this.positionAt(0);this.target.markerHeading=this.roadHeading()??this.target.markerHeading,this.motion.markerHeading=v(this.target.markerHeading),e&&this.marker.place(e,this.target.markerHeading)}placeCamera(e){const t=this.coordinateAt(this.traveledDistanceInMeters);if(!t)return;const r=void 0!==e&&this.flying;this.secondsSinceSurvey+=e??0;const i=!r||this.secondsSinceSurvey>=.2;i&&(this.secondsSinceSurvey=0,this.survey(t.position)),r?this.ease(e):this.settle(),this.flying=!0;const[a,n]=t.position,{bearing:o,zoom:s,pitch:h,elevation:m,anchorX:c,anchorY:d,markerHeading:u}=this.motion,g=this.map.mapLibreMap;this.pagePadding??=g.getPadding(),g.jumpTo({center:[a,n],elevation:m.value,bearing:o.value,pitch:h.value,zoom:s.value,padding:T({x:c.value,y:d.value},this.viewport)}),this.marker.place(t.position,u.value),i&&this.onProgress({traveledDistanceInMeters:t.distanceInMeters,traveledTimeInSeconds:t.travelTimeInSeconds})}};export{G as RouteFlyover,w as anchorForPitch};
1
+ import{MERCATOR_UNITS_PER_EPSG3857_METER,localFrameMatrix}from"@tomtom-org/maps-sdk/map";import{bearing,bearingToAzimuth,degreesToRadians,destination}from"@turf/turf";import{calculateProgressAtRoutePoint,generateId,getCoordinateAtRouteProgress}from"@tomtom-org/maps-sdk/core";import{MercatorCoordinate}from"maplibre-gl";var headingBetween=(e,t)=>bearingToAzimuth(bearing(e,t)),shortestTurn=(e,t)=>(t-e+540)%360-180,clamp=(e,t,r)=>Math.min(Math.max(e,t),r),springAt=e=>({value:e,velocity:0}),springTowards=(e,t,r,i,a=Number.POSITIVE_INFINITY)=>{const o=4/i,n=2*a/o,s=clamp(e.value-t,-n,n);if(Math.abs(s)<1e-6&&Math.abs(e.velocity)<1e-6)return springAt(t);const h=(e.velocity+o*s)*r,m=Math.exp(-o*r);return{value:e.value-s+(s+h)*m,velocity:(e.velocity-o*h)*m}},springTowardsBearing=(e,t,r,i,a)=>{const o=springTowards(e,e.value+shortestTurn(e.value,t),r,i,a);return{value:(o.value+360)%360,velocity:o.velocity}},clampFraction=e=>clamp(e,.05,.95),anchorForPitch=e=>({x:.5,y:.5+clamp(e,0,60)/60*.16666666666666663}),anchorPadding=(e,t)=>{const r=clampFraction(e.x)-.5,i=clampFraction(e.y)-.5,a=(e,t)=>Math.max(2*e*t,0);return{left:a(r,t.width),right:a(-r,t.width),top:a(i,t.height),bottom:a(-i,t.height)}},EQUATOR_METERS_PER_PIXEL=1/(512*MERCATOR_UNITS_PER_EPSG3857_METER),epsg3857MetersPerPixel=e=>EQUATOR_METERS_PER_PIXEL/2**e,metersPerPixel=(e,t)=>epsg3857MetersPerPixel(e)*Math.cos(degreesToRadians(t)),zoomForMetersPerPixel=(e,t)=>Math.log2(metersPerPixel(0,t)/e),cameraDistanceInPixels=({viewportHeight:e,fieldOfViewDegrees:t})=>.5*e/Math.tan(degreesToRadians(t)/2),svgElement=(e,t)=>{const r=document.createElementNS("http://www.w3.org/2000/svg",e);for(const[i,a]of Object.entries(t))r.setAttribute(i,a);return r},svgDataUri=e=>`data:image/svg+xml;charset=utf-8,${encodeURIComponent(e)}`,compile=(e,t,r)=>{const i=e.createShader(t);if(!i)throw new Error("The fly-over marker could not create a shader");return e.shaderSource(i,r),e.compileShader(i),i},PositionMarker=class{map;id=`tomtom-flyover-marker-${generateId()}`;type="custom";renderingMode="2d";config={};placed;raster;gl;drawing;customLayer;constructor(e,t){this.map=e,this.customLayer=e.addCustomLayer(this),this.apply(t)}apply(e){this.config=e;const t=e.size??44;var r;(async(e,t)=>{const r=((e,t)=>{const r="arrow"===e.type?svgDataUri((({fillColor:e="#105287",outlineColor:t="white",outlineOpacity:r=1},i)=>{const a=svgElement("svg",{viewBox:"0 0 24 24",width:String(i),height:String(i)});return a.append(svgElement("path",{d:"M12 3l8 18-8-4-8 4z",fill:e,stroke:t,"stroke-opacity":String(r),"stroke-width":"3","stroke-linejoin":"round","paint-order":"stroke"})),(new XMLSerializer).serializeToString(a)})(e,t)):e.image;if("string"!=typeof r)return r;const i=new Image;return i.crossOrigin="anonymous",i.src=r.includes("<svg")?svgDataUri(r):r,i})(e,t);await r.decode();const i=document.createElement("canvas");i.width=t,i.height=t;const a=t/Math.max(r.naturalWidth,r.naturalHeight,1),[o,n]=[r.naturalWidth*a,r.naturalHeight*a];return i.getContext("2d")?.drawImage(r,(t-o)/2,(t-n)/2,o,n),i})(e.image??{type:"arrow"},(r=t,Math.min(2**Math.ceil(Math.log2(Math.max(r*devicePixelRatio,1))),512))).then(t=>{this.config===e&&(this.raster=t,this.releaseTexture(),this.map.mapLibreMap.triggerRepaint())}).catch(e=>console.warn("The fly-over marker image could not be loaded",e)),this.map.mapLibreMap.triggerRepaint()}place(e,t){this.placed={position:e,heading:t},this.map.mapLibreMap.triggerRepaint()}remove(){this.customLayer.remove()}onAdd(e,t){this.gl=t,this.drawing=(e=>{const t=e.createProgram(),r=e.createBuffer();if(!t||!r)throw new Error("The fly-over marker could not create its program");return e.attachShader(t,compile(e,e.VERTEX_SHADER,"\nuniform mat4 u_matrix;\nuniform vec2 u_right;\nuniform vec2 u_forward;\nattribute vec2 a_corner;\nvarying vec2 v_uv;\nvoid main() {\n v_uv = vec2(a_corner.x, -a_corner.y) * 0.5 + 0.5;\n gl_Position = u_matrix * vec4(u_right * a_corner.x + u_forward * a_corner.y, 0.0, 1.0);\n}")),e.attachShader(t,compile(e,e.FRAGMENT_SHADER,"\nprecision mediump float;\nuniform sampler2D u_image;\nvarying vec2 v_uv;\nvoid main() {\n gl_FragColor = texture2D(u_image, v_uv);\n}")),e.linkProgram(t),e.bindBuffer(e.ARRAY_BUFFER,r),e.bufferData(e.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),e.STATIC_DRAW),{program:t,corners:r,texture:void 0,uniforms:{matrix:e.getUniformLocation(t,"u_matrix"),right:e.getUniformLocation(t,"u_right"),forward:e.getUniformLocation(t,"u_forward"),image:e.getUniformLocation(t,"u_image")},corner:e.getAttribLocation(t,"a_corner")}})(t)}onRemove(e,t){this.releaseTexture(),this.drawing&&(t.deleteProgram(this.drawing.program),t.deleteBuffer(this.drawing.corners)),this.drawing=void 0,this.gl=void 0}render(e,t){const{drawing:r,placed:i,raster:a}=this;if(!r||!i||!a||!1===this.config.visible)return;r.texture??=((e,t)=>{const r=e.createTexture()??void 0;return e.bindTexture(e.TEXTURE_2D,r??null),e.pixelStorei(e.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!0),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,t),e.pixelStorei(e.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),e.generateMipmap(e.TEXTURE_2D),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR_MIPMAP_LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),r})(e,a);const o=this.map.mapLibreMap,[n,s]=i.position,h=o.queryTerrainElevation([n,s])??0,m=localFrameMatrix(t.defaultProjectionData.mainMatrix,[n,s],{altitude:MercatorCoordinate.fromLngLat([0,0],h).z/MERCATOR_UNITS_PER_EPSG3857_METER,units:"mercatorMeters",centerLatitude:o.getCenter().lat}),c=(this.config.size??44)/2*epsg3857MetersPerPixel(o.getZoom()),g=degreesToRadians(i.heading),[d,l]=[Math.sin(g)*c,Math.cos(g)*c];e.useProgram(r.program),e.uniformMatrix4fv(r.uniforms.matrix,!1,Float32Array.from(m)),e.uniform2f(r.uniforms.right,l,-d),e.uniform2f(r.uniforms.forward,d,l),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,r.texture??null),e.uniform1i(r.uniforms.image,0),e.bindBuffer(e.ARRAY_BUFFER,r.corners),e.enableVertexAttribArray(r.corner),e.vertexAttribPointer(r.corner,2,e.FLOAT,!1,0,0),e.disable(e.DEPTH_TEST),e.enable(e.BLEND),e.blendFunc(e.ONE,e.ONE_MINUS_SRC_ALPHA),e.drawArrays(e.TRIANGLE_STRIP,0,4)}releaseTexture(){this.drawing?.texture&&this.gl?.deleteTexture(this.drawing.texture),this.drawing&&(this.drawing.texture=void 0)}},DEFAULT_CAMERA={speedKMH:200,pitch:70,aim:{mode:"instruction",fallbackMetersAhead:250},zoom:{mode:"instructions",instructionsAhead:2}},HEADING_SPAN_METERS=15,clampZoom=e=>clamp(e,11,15),RouteFlyover=class{map;route;camera;onProgress;loop;onArrive;marker;animationFrame;lastFrameTime=0;traveledDistanceInMeters=0;speedKMH=springAt(0);motion;target;framedZoom;secondsSinceSurvey=0;viewport={width:1,height:1};flying=!1;pageCenterClampedToGround=!0;pagePadding;constructor(e,t){this.map=e,this.route=t.route,this.camera={...DEFAULT_CAMERA,...t.camera},this.onProgress=t.onProgress??(()=>{}),this.loop=t.loop??!0,this.onArrive=t.onArrive??(()=>{});const r=e.mapLibreMap,i=this.targetAnchor();this.motion={bearing:springAt(r.getBearing()),zoom:springAt(r.getZoom()),pitch:springAt(r.getPitch()),anchorX:springAt(i.x),anchorY:springAt(i.y),elevation:springAt(r.getCenterElevation()),markerHeading:springAt(0)},this.target={bearing:this.motion.bearing.value,zoom:this.motion.zoom.value,elevation:this.motion.elevation.value,markerHeading:0},this.framedZoom=this.target.zoom,this.readViewport(),r.on("resize",this.readViewport),this.marker=new PositionMarker(e,t.marker??{}),this.placeMarkerOutright()}get running(){return void 0!==this.animationFrame}start(){if(this.running)return;this.hasArrived()&&(this.traveledDistanceInMeters=0,this.flying=!1);const e=this.map.mapLibreMap;this.pageCenterClampedToGround=e.getCenterClampedToGround(),e.setCenterClampedToGround(!1),this.speedKMH=springAt(0),this.lastFrameTime=performance.now(),this.animationFrame=requestAnimationFrame(this.step)}stop(){void 0!==this.animationFrame&&(cancelAnimationFrame(this.animationFrame),this.animationFrame=void 0,this.map.mapLibreMap.setCenterClampedToGround(this.pageCenterClampedToGround))}setRoute(e){this.route=e,this.traveledDistanceInMeters=0,this.flying=!1,this.running?this.placeCamera():this.placeMarkerOutright()}setCamera(e){this.camera={...this.camera,...e},this.flying&&!this.running&&this.placeCamera()}getCamera(){return{...this.camera}}setMarker(e){this.marker.apply(e)}seek(e){const t=this.routeLengthInMeters();this.traveledDistanceInMeters="number"==typeof e?t*clamp(e,0,1):clamp(this.distanceAt(e),0,t),this.placeCamera()}remove(){this.stop(),this.marker.remove();const e=this.map.mapLibreMap;e.off("resize",this.readViewport),this.pagePadding&&e.setPadding(this.pagePadding)}readViewport=()=>{const e=this.map.mapLibreMap.getCanvas();this.viewport={width:Math.max(e.clientWidth,1),height:Math.max(e.clientHeight,1)}};routeLengthInMeters(){return this.route.properties.summary.lengthInMeters}distanceAt(e){return"traveledDistanceInMeters"in e?e.traveledDistanceInMeters:getCoordinateAtRouteProgress(this.route,e)?.distanceInMeters??0}hasArrived(){return!this.loop&&this.traveledDistanceInMeters>=this.routeLengthInMeters()}step=e=>{const t=clamp((e-this.lastFrameTime)/1e3,0,.25);this.lastFrameTime=e;const r=this.speedKMH.value;this.speedKMH=springTowards(this.speedKMH,this.camera.speedKMH,t,2);const i=(r+this.speedKMH.value)/2/3.6;this.traveledDistanceInMeters=this.alongRoute(this.traveledDistanceInMeters+i*t);const a=this.hasArrived();if(this.placeCamera(t,a),a)return this.stop(),void this.onArrive();this.animationFrame=requestAnimationFrame(this.step)};coordinateAt(e){return getCoordinateAtRouteProgress(this.route,{traveledDistanceInMeters:e})}positionAt(e){return this.coordinateAt(this.alongRoute(this.traveledDistanceInMeters+e))?.position}metersAheadTo(e){const t=e-this.traveledDistanceInMeters;return this.loop?this.alongRoute(t):Math.max(t,0)}alongRoute(e){const t=this.routeLengthInMeters();return this.loop?t>0?(e%t+t)%t:0:clamp(e,0,t)}roadHeading(){const[e,t]=[-15,HEADING_SPAN_METERS].map(e=>this.coordinateAt(this.traveledDistanceInMeters+e)?.position);return e&&t?headingBetween(e,t):void 0}instructions(){return this.route.properties.guidance?.instructions??[]}instructionAhead(e=0){const t=this.instructions();if(!t.length)return;const r=t.findIndex(e=>e.routeOffsetInMeters>this.traveledDistanceInMeters),i=this.loop?0:t.length-1;return t[Math.min((-1===r?i:r)+e,t.length-1)]}pointIndexHere(){let e=0,t=this.route.geometry.coordinates.length-1;for(;e<t;){const r=Math.floor((e+t)/2),i=calculateProgressAtRoutePoint(this.route,r);void 0!==i&&i.distanceInMeters<this.traveledDistanceInMeters?e=r+1:t=r}return e}aimPosition(){const e=this.camera.aim;switch(e.mode){case"distance":return this.positionAt(e.metersAhead);case"points":{const t=this.route.geometry.coordinates,r=this.pointIndexHere()+e.pointsAhead;return t[this.loop?r%t.length:Math.min(r,t.length-1)]}case"instruction":{const t=this.instructionAhead(),r=t&&this.metersAheadTo(t.routeOffsetInMeters);return void 0===r?this.positionAt(e.fallbackMetersAhead):this.positionAt(r)}}}modeZoom(e){const t=this.camera.zoom;if("fixed"===t.mode)return t.zoom;if("speed"===t.mode){const e=Math.log2(Math.max(this.camera.speedKMH,1)/90);return clampZoom(14-1*e)}const r=this.instructionAhead(Math.max(t.instructionsAhead,1)-1);if(!r)return clampZoom(14);const i=this.metersAheadTo(r.routeOffsetInMeters)*Math.cos(degreesToRadians(Math.min(this.camera.pitch,85)));return clampZoom(((e,t,r)=>zoomForMetersPerPixel(Math.max(e,1)/Math.max(t,1),r))(i,.6*this.viewport.height,e))}clearanceZoom(e,t,r){const i=degreesToRadians(Math.min(this.camera.pitch,85)),a=((e,t)=>cameraDistanceInPixels(t)*metersPerPixel(e,t.latitudeDegrees))(this.motion.zoom.value,r)*Math.sin(i)/1e3,o=this.motion.bearing.value+180;let n=200;for(let s=0;s<4;s++){const r=s/4,i=destination(e,a*(1-r),o).geometry.coordinates,h=this.groundAt(i);void 0!==h&&(n=Math.max(n,200+(h-t)/(1-r)))}return((e,t)=>zoomForMetersPerPixel(Math.max(e,1)/cameraDistanceInPixels(t),t.latitudeDegrees))(n/Math.cos(i),r)}groundAt([e,t]){return this.map.mapLibreMap.queryTerrainElevation([e,t])??void 0}survey(e){const t={latitudeDegrees:e[1],viewportHeight:this.viewport.height,fieldOfViewDegrees:this.map.mapLibreMap.getVerticalFieldOfView()},r=this.aimPosition();!r||r[0]===e[0]&&r[1]===e[1]||(this.target.bearing=((e,t)=>Math.abs(shortestTurn(e,t))>2.5?t:e)(this.target.bearing,headingBetween(e,r))),this.target.markerHeading=this.roadHeading()??this.target.markerHeading;const i=this.modeZoom(t.latitudeDegrees),a="instructions"===this.camera.zoom.mode?.2:0;Math.abs(i-this.framedZoom)>a&&(this.framedZoom=i);const o=this.groundAt(e);void 0===o?(this.map.mapLibreMap.getTerrain()||(this.target.elevation=0),this.target.zoom=this.framedZoom):(this.target.elevation=o,this.target.zoom=Math.min(this.framedZoom,this.clearanceZoom(e,o,t)))}targetAnchor(){return this.camera.anchor??anchorForPitch(this.camera.pitch)}ease(e){const{motion:t,target:r}=this,i=this.targetAnchor(),a=(t,r,i)=>springTowards(t,r,e,i);this.motion={bearing:springTowardsBearing(t.bearing,r.bearing,e,2,22),markerHeading:springTowardsBearing(t.markerHeading,r.markerHeading,e,.5),zoom:a(t.zoom,r.zoom,3),elevation:a(t.elevation,r.elevation,.6),pitch:a(t.pitch,this.camera.pitch,1.5),anchorX:a(t.anchorX,i.x,1.5),anchorY:a(t.anchorY,i.y,1.5)}}settle(){const e=this.targetAnchor();this.motion={bearing:springAt(this.target.bearing),markerHeading:springAt(this.target.markerHeading),zoom:springAt(this.target.zoom),elevation:springAt(this.target.elevation),pitch:springAt(this.camera.pitch),anchorX:springAt(e.x),anchorY:springAt(e.y)}}placeMarkerOutright(){const e=this.positionAt(0);this.target.markerHeading=this.roadHeading()??this.target.markerHeading,this.motion.markerHeading=springAt(this.target.markerHeading),e&&this.marker.place(e,this.target.markerHeading)}placeCamera(e,t=!1){const r=this.coordinateAt(this.traveledDistanceInMeters);if(!r)return;const i=void 0!==e&&this.flying;this.secondsSinceSurvey+=e??0;const a=!i||t||this.secondsSinceSurvey>=.2;a&&(this.secondsSinceSurvey=0,this.survey(r.position)),i?this.ease(e):this.settle(),this.flying=!0;const[o,n]=r.position,{bearing:s,zoom:h,pitch:m,elevation:c,anchorX:g,anchorY:d,markerHeading:l}=this.motion,p=this.map.mapLibreMap;this.pagePadding??=p.getPadding(),p.jumpTo({center:[o,n],elevation:c.value,bearing:s.value,pitch:m.value,zoom:h.value,padding:anchorPadding({x:g.value,y:d.value},this.viewport)}),this.marker.place(r.position,l.value),a&&this.onProgress({traveledDistanceInMeters:r.distanceInMeters,traveledTimeInSeconds:r.travelTimeInSeconds})}};export{RouteFlyover,anchorForPitch};
@@ -1,65 +1,18 @@
1
1
  [
2
2
  {
3
- "name": "@turf/helpers",
3
+ "name": "@turf/turf",
4
4
  "version": "7.4.0",
5
5
  "license": "MIT",
6
- "bundled": true,
7
- "description": "Provides helper functions to create GeoJSON features, like points, lines, or areas on a map.",
8
- "repository": "git://github.com/Turfjs/turf.git",
9
- "homepage": "https://github.com/Turfjs/turf",
10
- "author": "Turf Authors",
11
- "contributors": [
12
- "Tom MacWright <@tmcw>",
13
- "Stefano Borghi <@stebogit>",
14
- "Denis Carriere <@DenisCarriere>",
15
- "William Nordmann <@wnordmann>"
16
- ],
17
- "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2017 TurfJS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
18
- },
19
- {
20
- "name": "@turf/invariant",
21
- "version": "7.4.0",
22
- "license": "MIT",
23
- "bundled": true,
24
- "description": "Lightweight utility for input validation and data extraction in Turf.js. Ensures GeoJSON inputs are in the correct format and extracts specific components like coordinates or geometries.",
25
- "repository": "git://github.com/Turfjs/turf.git",
26
- "homepage": "https://github.com/Turfjs/turf",
27
- "author": "Turf Authors",
28
- "contributors": [
29
- "Tom MacWright <@tmcw>",
30
- "Denis Carriere <@DenisCarriere>"
31
- ],
32
- "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2017 TurfJS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
33
- },
34
- {
35
- "name": "@turf/bearing",
36
- "version": "7.4.0",
37
- "license": "MIT",
38
- "bundled": true,
39
- "description": "Takes two points and finds the geographic bearing between them.",
40
- "repository": "git://github.com/Turfjs/turf.git",
41
- "homepage": "https://github.com/Turfjs/turf",
42
- "author": "Turf Authors",
43
- "contributors": [],
44
- "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2017 TurfJS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
45
- },
46
- {
47
- "name": "@turf/destination",
48
- "version": "7.4.0",
49
- "license": "MIT",
50
- "bundled": true,
51
- "description": "turf destination module",
6
+ "bundled": false,
7
+ "description": "a JavaScript library for performing geospatial operations with GeoJSON",
52
8
  "repository": "git://github.com/Turfjs/turf.git",
53
9
  "homepage": "https://github.com/Turfjs/turf",
54
10
  "author": "Turf Authors",
55
- "contributors": [
56
- "Pavel Rozvora <@prozvora>"
57
- ],
58
- "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2017 TurfJS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
11
+ "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2017 TurfJS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
59
12
  },
60
13
  {
61
14
  "name": "maplibre-gl",
62
- "version": "6.13.0",
15
+ "version": "6.15.0",
63
16
  "license": "BSD-3-Clause",
64
17
  "bundled": false,
65
18
  "description": "BSD licensed community fork of mapbox-gl, a WebGL interactive maps library",
package/package.json CHANGED
@@ -1,29 +1,28 @@
1
1
  {
2
2
  "name": "@tomtom-org/maps-sdk-plugin-flyover",
3
3
  "author": "TomTom International B.V.",
4
- "license": "See in LICENSE.txt",
5
- "version": "0.0.6",
4
+ "license": "SEE LICENSE IN LICENSE.txt",
5
+ "version": "0.1.0",
6
6
  "type": "module",
7
7
  "description": "A camera that flies a route on a TomTomMap: it follows the line, aims at the junctions ahead, frames them, clears the terrain it crosses, and parks the followed position where you want it on screen",
8
8
  "types": "dist/index.d.ts",
9
- "dependencies": {
10
- "@turf/turf": "^7.4.0"
11
- },
9
+ "sideEffects": false,
12
10
  "peerDependencies": {
13
- "@tomtom-org/maps-sdk": ">=0.64.0 <1.0.0 || >=1.0.0-rc.0 <1.0.0",
14
- "maplibre-gl": "^6.13.0"
11
+ "@tomtom-org/maps-sdk": "^1.0.0-rc.4",
12
+ "@turf/turf": "^7.4.0",
13
+ "maplibre-gl": "^6.15.0"
15
14
  },
16
15
  "devDependencies": {
17
16
  "@tsconfig/recommended": "^1.0.13",
18
17
  "@types/geojson": "^7946.0.16",
19
- "@types/node": "^26.6.4",
20
- "@vitest/coverage-v8": "^5.0.3",
21
- "jsdom": "^30.1.2",
22
- "rolldown": "^1.2.13",
18
+ "@types/node": "^26.6.5",
19
+ "@vitest/coverage-v8": "^5.0.5",
20
+ "jsdom": "^30.1.3",
21
+ "rolldown": "^1.2.14",
23
22
  "typescript": "^6.0.3",
24
- "vite": "8.3.3",
25
- "vitest": "^5.0.3",
26
- "@tomtom-org/maps-sdk": "1.0.0-rc.2"
23
+ "vite": "^8.3.4",
24
+ "vitest": "^5.0.5",
25
+ "@tomtom-org/maps-sdk": "1.0.0-rc.4"
27
26
  },
28
27
  "files": [
29
28
  "dist",