@@ -6,6 +6,7 @@ import { featureColor } from 'maplibre/styles/styles'
66let marker
77let syncChartToViewport
88let canvasAbort
9+ let lastGpsPosition = null
910
1011export async function showElevationChart ( feature ) {
1112 const chartElement = document . getElementById ( 'route-elevation-chart' )
@@ -53,8 +54,38 @@ export async function showElevationChart (feature) {
5354 filterToViewport ( active , allLabels , allValues , allCoords )
5455 showElevationStats ( active . values )
5556
57+ // GPS position indicator plugin
58+ const gpsPlugin = {
59+ id : 'gpsPosition' ,
60+ afterDraw ( chart ) {
61+ if ( chart . _gpsChartIndex == null ) return
62+ const meta = chart . getDatasetMeta ( 0 )
63+ const element = meta . data [ chart . _gpsChartIndex ]
64+ if ( ! element ) return
65+
66+ const ctx = chart . ctx
67+ const yAxis = chart . scales . y
68+ ctx . save ( )
69+ ctx . beginPath ( )
70+ ctx . moveTo ( element . x , yAxis . top )
71+ ctx . lineTo ( element . x , yAxis . bottom )
72+ ctx . lineWidth = 2
73+ ctx . strokeStyle = '#3b82f6'
74+ ctx . setLineDash ( [ 4 , 4 ] )
75+ ctx . stroke ( )
76+
77+ // Draw a dot at the elevation value
78+ ctx . beginPath ( )
79+ ctx . arc ( element . x , element . y , 5 , 0 , Math . PI * 2 )
80+ ctx . fillStyle = '#3b82f6'
81+ ctx . fill ( )
82+ ctx . restore ( )
83+ }
84+ }
85+
5686 let chart = new Chart ( canvas , {
5787 type : 'line' ,
88+ plugins : [ gpsPlugin ] ,
5889 data : {
5990 labels : active . labels ,
6091 datasets : [ {
@@ -153,6 +184,25 @@ export async function showElevationChart (feature) {
153184 map . flyTo ( { center : [ coord [ 0 ] , coord [ 1 ] ] , duration : 1000 , curve : 0.3 } )
154185 } , { signal } )
155186
187+ // Update GPS position indicator on the chart
188+ window . addEventListener ( 'gps-position' , ( event ) => {
189+ if ( ! event . detail ) {
190+ lastGpsPosition = null
191+ chart . _gpsChartIndex = null
192+ chart . update ( 'none' )
193+ return
194+ }
195+
196+ lastGpsPosition = event . detail
197+ const idx = findNearestTrackIndex ( event . detail , allCoords )
198+ if ( idx === - 1 || idx < active . firstIdx || idx > active . lastIdx ) {
199+ chart . _gpsChartIndex = null
200+ } else {
201+ chart . _gpsChartIndex = idx - active . firstIdx
202+ }
203+ chart . update ( 'none' )
204+ } , { signal } )
205+
156206 // Sync chart with map viewport — show only the track section currently visible
157207 syncChartToViewport = ( ) => {
158208 if ( ! chart . canvas || ! chart . canvas . isConnected ) {
@@ -164,6 +214,16 @@ export async function showElevationChart (feature) {
164214 chart . data . labels = active . labels
165215 chart . data . datasets [ 0 ] . data = active . values
166216 showElevationStats ( active . values )
217+
218+ // Update GPS position indicator for new viewport
219+ if ( lastGpsPosition ) {
220+ const idx = findNearestTrackIndex ( lastGpsPosition , allCoords )
221+ chart . _gpsChartIndex = ( idx !== - 1 && idx >= active . firstIdx && idx <= active . lastIdx )
222+ ? idx - active . firstIdx : null
223+ } else {
224+ chart . _gpsChartIndex = null
225+ }
226+
167227 chart . update ( 'none' )
168228 }
169229
@@ -184,6 +244,21 @@ function computeDistances (coords) {
184244 return distances
185245}
186246
247+ // Find the nearest track point to the given GPS position
248+ // Returns index if within 25m threshold, else -1
249+ function findNearestTrackIndex ( lngLat , coords ) {
250+ let minDist = Infinity
251+ let minIdx = - 1
252+ for ( let i = 0 ; i < coords . length ; i ++ ) {
253+ const d = distance ( point ( [ lngLat . lng , lngLat . lat ] ) , point ( coords [ i ] ) , { units : 'meters' } )
254+ if ( d < minDist ) {
255+ minDist = d
256+ minIdx = i
257+ }
258+ }
259+ return minDist <= 25 ? minIdx : - 1
260+ }
261+
187262// Filter active data to only include points visible in the current map viewport
188263function filterToViewport ( active , allLabels , allValues , allCoords ) {
189264 const bounds = map . getBounds ( )
@@ -198,10 +273,14 @@ function filterToViewport (active, allLabels, allValues, allCoords) {
198273 active . labels = allLabels
199274 active . values = allValues
200275 active . coords = allCoords
276+ active . firstIdx = 0
277+ active . lastIdx = allCoords . length - 1
201278 } else {
202279 active . labels = allLabels . slice ( firstIdx , lastIdx + 1 )
203280 active . values = allValues . slice ( firstIdx , lastIdx + 1 )
204281 active . coords = allCoords . slice ( firstIdx , lastIdx + 1 )
282+ active . firstIdx = firstIdx
283+ active . lastIdx = lastIdx
205284 }
206285}
207286
0 commit comments