@tomtom-org/maps-sdk-plugin-flyover 0.0.6 → 0.0.7

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
@@ -11,7 +11,7 @@ it crosses, and it parks the followed position, marked with an arrow, where you
11
11
 
12
12
  ## Quickstart
13
13
 
14
- This plugin declares `@tomtom-org/maps-sdk` and `maplibre-gl` as peer dependencies and bundles neither, so install both in your project too.
14
+ 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
15
 
16
16
  ```bash
17
17
  npm install @tomtom-org/maps-sdk maplibre-gl @tomtom-org/maps-sdk-plugin-flyover
@@ -35,7 +35,8 @@ flyover.start();
35
35
  ## Features
36
36
 
37
37
  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.
38
+ to re-time when the route changes. By default, the flight loops: it wraps at the destination and
39
+ never lands. With `loop: false`, it stops at the destination instead.
39
40
 
40
41
  - **Aim** — at the next guidance instruction, a fixed distance down the road or a number of the
41
42
  route's own vertices.
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,7 +46,6 @@ 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
@@ -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,52 +36,8 @@ 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
42
  Version: 6.13.0
165
43
  License: BSD-3-Clause
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,10 +136,20 @@ 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
145
155
  * The route is the only geometry it needs. There's no path of camera keyframes to author and no
@@ -174,6 +184,8 @@ export declare class RouteFlyover {
174
184
  private route;
175
185
  private camera;
176
186
  private readonly onProgress;
187
+ private readonly loop;
188
+ private readonly onArrive;
177
189
  private readonly marker;
178
190
  private animationFrame;
179
191
  private lastFrameTime;
@@ -190,7 +202,10 @@ export declare class RouteFlyover {
190
202
  constructor(map: TomTomMap, options: RouteFlyoverOptions);
191
203
  /** Whether the flight is advancing. */
192
204
  get running(): boolean;
193
- /** Starts, or resumes, the flight, ramping up to its speed. */
205
+ /**
206
+ * Starts, or resumes, the flight, ramping up to its speed. A flight that doesn't loop and has
207
+ * arrived starts again from the departure.
208
+ */
194
209
  start(): void;
195
210
  /**
196
211
  * Stops the flight where it is. {@link start} resumes from there. The centre clamp returns to
@@ -205,8 +220,13 @@ export declare class RouteFlyover {
205
220
  getCamera(): FlyoverCamera;
206
221
  /** Replaces the marker riding the route, or hides it with `visible: false`. */
207
222
  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;
223
+ /**
224
+ * Moves the flight to a point along the route: a share of its length within 0..1, or a time or
225
+ * distance travelled, or a clock time, the way `getCoordinateAtRouteProgress` reads them. A
226
+ * point outside the route moves it to the nearer end, and a clock time on a route without a
227
+ * departure time to the departure.
228
+ */
229
+ seek(progress: number | RouteProgressQuery): void;
210
230
  /**
211
231
  * Stops the flight and gives the map back. The marker leaves, and the padding returns to what
212
232
  * the map had before the flight first placed the camera.
@@ -214,15 +234,19 @@ export declare class RouteFlyover {
214
234
  remove(): void;
215
235
  private readonly readViewport;
216
236
  private routeLengthInMeters;
237
+ private distanceAt;
238
+ private hasArrived;
217
239
  private readonly step;
218
240
  private coordinateAt;
219
241
  private positionAt;
220
- private wrapped;
242
+ private metersAheadTo;
243
+ private alongRoute;
221
244
  private roadHeading;
222
245
  private instructions;
223
246
  /**
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.
247
+ * The instruction the flight is heading for — the first one still ahead of it. Past the last,
248
+ * a loop heads for the first of all and a flight that doesn't loop for the last.
249
+ * `undefined` when the route carries no guidance.
226
250
  */
227
251
  private instructionAhead;
228
252
  private pointIndexHere;
@@ -256,7 +280,8 @@ export declare class RouteFlyover {
256
280
  /**
257
281
  * One frame: where the flight has got to, and a step of the camera towards what the last survey
258
282
  * decided. Without `elapsedSeconds` — a seek, a new route, a changed setting — the camera is
259
- * surveyed and placed at its targets outright.
283
+ * surveyed and placed at its targets outright. The frame that `arrives` surveys too, so the
284
+ * progress reported last is the destination.
260
285
  */
261
286
  private placeCamera;
262
287
  }
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{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)}},zoomForMetersPerPixel=(e,t)=>Math.log2(78271.51696484374*Math.cos(degreesToRadians(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;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=((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.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,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=MercatorCoordinate.fromLngLat([n,s],h),c=(this.config.size??44)/2*(1/(512*2**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,((e,{x:t,y:r,z:i})=>{const a=Float32Array.from(e);for(let o=0;o<4;o++)a[12+o]=e[o]*t+e[4+o]*r+e[8+o]*i+e[12+o];return a})(t.defaultProjectionData.mainMatrix,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)}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)}},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)*((e,t)=>78271.51696484374*Math.cos(degreesToRadians(t))/2**e)(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,61 +1,14 @@
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",
package/package.json CHANGED
@@ -2,15 +2,14 @@
2
2
  "name": "@tomtom-org/maps-sdk-plugin-flyover",
3
3
  "author": "TomTom International B.V.",
4
4
  "license": "See in LICENSE.txt",
5
- "version": "0.0.6",
5
+ "version": "0.0.7",
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
11
  "@tomtom-org/maps-sdk": ">=0.64.0 <1.0.0 || >=1.0.0-rc.0 <1.0.0",
12
+ "@turf/turf": "^7.4.0",
14
13
  "maplibre-gl": "^6.13.0"
15
14
  },
16
15
  "devDependencies": {
@@ -23,7 +22,7 @@
23
22
  "typescript": "^6.0.3",
24
23
  "vite": "8.3.3",
25
24
  "vitest": "^5.0.3",
26
- "@tomtom-org/maps-sdk": "1.0.0-rc.2"
25
+ "@tomtom-org/maps-sdk": "1.0.0-rc.3"
27
26
  },
28
27
  "files": [
29
28
  "dist",