@@ -2,6 +2,10 @@ require('leaflet');
22
33if ( document . getElementById ( 'map' ) !== null ) {
44 var location ;
5+ var watchPosition ;
6+ var myLocationEnabled = false ;
7+ var myLocationRefresh = false ;
8+ var relativeDistanceControl ;
59 var centerLatLng = document . getElementById ( 'map' ) . dataset . center ;
610 var centerLatLngArr = [
711 centerLatLng . substring ( 0 , centerLatLng . indexOf ( ',' ) ) ,
@@ -13,16 +17,39 @@ if (document.getElementById('map') !== null) {
1317 } ) ;
1418
1519 var markerIcon = L . icon ( {
16- iconUrl : '/build/images/marker-icon.2b3e1faf .png' ,
17- iconSize : [ 25 , 41 ] ,
18- iconAnchor : [ 13 , 41 ] ,
20+ iconUrl : '/build/images/marker_icon .png' ,
21+ iconSize : [ 30 , 41 ] ,
22+ iconAnchor : [ 15 , 41 ] ,
1923 } )
2024
2125 L . tileLayer ( 'https://tile.openstreetmap.org/{z}/{x}/{y}.png' , {
2226 maxZoom : 19 ,
2327 attribution : '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
2428 } ) . addTo ( map ) ;
2529
30+ L . Control . MyLocation = L . Control . extend ( {
31+ onAdd : function ( map ) {
32+ viewLocationButton = L . DomUtil . create ( 'button' , 'leaflet-btn' ) ;
33+
34+ viewLocationButton . id = 'view-location-btn' ;
35+ viewLocationButton . innerHTML = '<i class="bi bi-compass"></i>' ;
36+ viewLocationButton . title = document . getElementById ( 'map' ) . dataset . showcurrentlocation ;
37+ viewLocationButton . setAttribute ( 'data-test' , 'current-location-btn' )
38+
39+ return viewLocationButton ;
40+ } ,
41+
42+ onRemove : function ( map ) {
43+ }
44+ } )
45+ L . control . MyLocation = function ( opts ) {
46+ return new L . Control . MyLocation ( opts ) ;
47+ }
48+
49+ L . control . MyLocation ( {
50+ position : 'bottomleft'
51+ } ) . addTo ( map ) ;
52+
2653 let latLng = L . latLng (
2754 centerLatLngArr
2855 ) ;
@@ -31,4 +58,130 @@ if (document.getElementById('map') !== null) {
3158
3259 map . addLayer ( location ) ;
3360 map . setMaxBounds ( latLng . toBounds ( 500 ) ) ;
61+
62+ document . getElementById ( 'view-location-btn' ) . onclick = function ( ) {
63+ myLocationEnabled = ! myLocationEnabled ;
64+ if ( myLocationEnabled ) {
65+ viewLocationButton . title = document . getElementById ( 'map' ) . dataset . hidecurrentlocation ;
66+ document . getElementById ( 'view-location-btn' ) . classList . add ( 'leaflet-btn-active' ) ;
67+ watchPosition = navigator . geolocation . watchPosition ( setCurrentPosition , failCurrentPosition ) ;
68+ } else {
69+ navigator . geolocation . clearWatch ( watchPosition ) ;
70+ disableCurrentLocation ( ) ;
71+ }
72+ }
73+
74+ function centerOnBounds ( bounds ) {
75+ map . panTo ( bounds . getCenter ( ) ) ;
76+ map . setMaxBounds ( bounds . pad ( 0.5 ) ) ;
77+ map . fitBounds ( bounds ) ;
78+ }
79+
80+ function centerOnMarker ( ) {
81+ map . removeLayer ( myLocation ) ;
82+ map . removeLayer ( line ) ;
83+ map . setMaxBounds ( latLng . toBounds ( 500 ) ) ;
84+ map . panTo ( latLng ) ;
85+ }
86+
87+ function failCurrentPosition ( err ) {
88+ switch ( err . code ) {
89+ case 1 :
90+ alert ( document . getElementById ( 'map' ) . dataset . error ) ;
91+ break ;
92+ default :
93+ alert ( err . message ) ;
94+ }
95+
96+ disableCurrentLocation ( ) ;
97+ }
98+
99+ function disableCurrentLocation ( ) {
100+ viewLocationButton . title = document . getElementById ( 'map' ) . dataset . showcurrentlocation ;
101+ document . getElementById ( 'view-location-btn' ) . classList . remove ( 'leaflet-btn-active' ) ;
102+
103+ if ( relativeDistanceControl !== undefined ) {
104+ relativeDistanceControl . remove ( ) ;
105+ relativeDistanceControl = undefined ;
106+ }
107+ myLocationRefresh = false ;
108+ centerOnMarker ( ) ;
109+ }
110+
111+ function setCurrentPosition ( position ) {
112+ if ( ! myLocationEnabled ) {
113+ return ;
114+ }
115+
116+ var currentLatLng = L . latLng ( parseFloat ( position . coords . latitude ) . toPrecision ( 6 ) , parseFloat ( position . coords . longitude ) . toPrecision ( 6 ) ) ;
117+
118+ var locationIcon = L . icon ( {
119+ iconUrl : '/build/images/location_icon.png' ,
120+ iconSize : [ 30 , 30 ] ,
121+ iconAnchor : [ 15 , 15 ] ,
122+ className : 'my-location-icon' ,
123+ } )
124+
125+
126+ let bounds = L . latLngBounds ( latLng , currentLatLng ) ;
127+ if ( myLocationRefresh ) {
128+ myLocation . setLatLng ( currentLatLng ) ;
129+ map . removeLayer ( line ) ;
130+ line = undefined ;
131+ distanceIndicator . innerHTML = printDistance ( map . distance ( currentLatLng , latLng ) ) ;
132+ // TODO:
133+ // When the user is moving, it would be nice to center on the bounds of the target and their location
134+ // but only if they haven't panned or zoomed - because otherwise that would be a frustrating experience.
135+ // This is difficult because leaflet cannot currently discern between automated and manual pan/zoom events.
136+ // Once this is available, we can implement it: https://github.com/Leaflet/Leaflet/pull/6929
137+ // centerOnBounds(bounds);
138+ } else {
139+ myLocation = L . marker ( currentLatLng , { icon : locationIcon , zIndexOffset : - 1000 } ) ;
140+ map . addLayer ( myLocation ) ;
141+ myLocationRefresh = true ;
142+ centerOnBounds ( bounds ) ;
143+
144+ L . Control . RelativeDistance = L . Control . extend ( {
145+ onAdd : function ( map ) {
146+ distanceIndicator = L . DomUtil . create ( 'div' , 'bg-light rounded shadow-sm opacity-75 p-1 fs-6' ) ;
147+
148+ distanceIndicator . id = 'distanceIndicator' ;
149+ distanceIndicator . title = document . getElementById ( 'map' ) . dataset . showcurrentlocation ;
150+ distanceIndicator . innerHTML = printDistance ( map . distance ( currentLatLng , latLng ) ) ;
151+ distanceIndicator . setAttribute ( 'data-test' , 'distance-indicator' )
152+
153+ return distanceIndicator ;
154+ } ,
155+
156+ onRemove : function ( map ) {
157+ }
158+ } )
159+ L . control . RelativeDistance = function ( opts ) {
160+ return new L . Control . RelativeDistance ( opts ) ;
161+ }
162+
163+ relativeDistanceControl = L . control . RelativeDistance ( {
164+ position : 'topright'
165+ } ) . addTo ( map ) ;
166+ }
167+
168+ line = L . polyline ( [ latLng , currentLatLng ] , { color : 'white' , weight : 6 , dashArray : '10,14' , className : 'location-path' } ) ;
169+ line . addTo ( map ) ;
170+ }
171+
172+ function printDistance ( meters ) {
173+ let distance ;
174+ if ( document . getElementById ( 'map' ) . dataset . measurementtype === 'km' ) {
175+ distance = parseFloat ( meters / 1000 ) . toFixed ( 1 ) ;
176+ } else {
177+ distance = parseFloat ( meters * 0.000621371192 ) . toFixed ( 1 ) ;
178+ }
179+
180+ if ( distance % 1 === 0 ) {
181+ distance = Math . round ( distance ) ;
182+ }
183+
184+ return distance + ' ' + document . getElementById ( 'map' ) . dataset . measurement + ' ' + document . getElementById ( 'map' ) . dataset . away ;
185+ }
34186}
187+
0 commit comments