'use strict'; /* global mapuser userid disp noHeader mapKey navigator $ token */ import io from 'socket.io-client'; import $ from 'jquery'; import loadGoogleMapsAPI from 'load-google-maps-api'; // Variables var map, marker, elevator, newLoc; const mapElem = document.getElementById('map'), socket = io('//'+window.location.hostname); // Convert to feet if needed function metersToFeet(meters){ //console.log('metersToFeet('+meters+')') return (mapuser.settings.units=='standard')? (meters*3.28084).toFixed(): meters.toFixed() } // socket.io stuff socket .on('connect', function(){ console.log("Connected!"); // Can get location socket.emit('can-get', mapuser._id ); // Can set location too if (mapuser._id===userid) { socket.emit('can-set', userid ); } }) .on('disconnect', function(){ console.log("Disconnected!"); }) .on('error', function (err){ console.error('❌️',err.message); }); // Show/hide map if location is set/unset function toggleMaps(loc) { if (loc.lat===0&&loc.lon===0) { $('#map').hide(); $('#view').hide(); $('#notset').show(); } else { $('#map').show(); $('#view').show(); $('#notset').hide(); } } // Toggle maps on page load $(function() { toggleMaps(mapuser.last); // Controls var wpid, newloc; // Set location $('#set-loc').click(function(){ if (!userid===mapuser._id){ alert('You are not logged in! '); } else { if (!navigator.geolocation){ alert('Geolocation not enabled. '); } else { navigator.geolocation.getCurrentPosition( // Success callback function(pos){ var newloc = { ts: Date.now(), tok: token, usr: userid, alt: pos.coords.altitude, lat: pos.coords.latitude, lon: pos.coords.longitude, spd: (pos.coords.speed||0) }; socket.emit('set', newloc); toggleMaps(newloc); console.log('Set location:',newloc.lat+", "+newloc.lon); }, // Error callback function(err) { alert("Unable to set location."); console.error('❌️',err.message); }, // Options { enableHighAccuracy:true } ); } } }); // Track location $('#track-loc').click(function(){ if (!userid===mapuser._id) { alert('You are not logged in! '); } else { // Start tracking if (!wpid) { if (!navigator.geolocation) { alert('Unable to track location. '); } else { $('#track-loc').html('Stop').prop('title',"Click here to stop tracking your location. "); wpid = navigator.geolocation.watchPosition( // Success callback function(pos) { newloc = { ts: Date.now(), tok: token, usr: userid, lat: pos.coords.latitude, lon: pos.coords.longitude, alt: pos.coords.altitude, spd: (pos.coords.speed||0) } socket.emit('set',newloc) toggleMaps(newloc) console.log('Set location:',newloc.lat+", "+newloc.lon) }, // Error callback function(err){ alert("Unable to track location."); console.error(err.message); }, // Options { enableHighAccuracy:true } ); } } // Stop tracking else { $('#track-loc').html('Track').prop('title',"Click here to track your location. "); navigator.geolocation.clearWatch(wpid); wpid = undefined; } } }); // Clear location $('#clear-loc').click(function(){ if (!userid===mapuser._id) { alert('You are not logged in! '); } else { // Stop tracking if (wpid) { $('#track-loc').html('Track'); navigator.geolocation.clearWatch(wpid); wpid = undefined; } // Clear location newloc = { ts: Date.now(), tok: token, usr: userid, lat:0, lon:0, spd:0 }; socket.emit('set',newloc); // Turn off map toggleMaps(newloc); console.log('Cleared location'); } }); }); // Load google maps API loadGoogleMapsAPI({ key:mapKey }) .then( function(googlemaps) { // Create map if (disp!=='1') { // Create map and marker elements map = new googlemaps.Map( mapElem, { center: { lat: mapuser.last.lat, lng: mapuser.last.lon }, panControl: false, scrollwheel: true, scaleControl: (mapuser.settings.showScale)?true:false, draggable: false, zoom: mapuser.settings.defaultZoom, streetViewControl: false, zoomControlOptions: {position: googlemaps.ControlPosition.LEFT_TOP}, mapTypeId: (mapuser.settings.defaultMap=='road')?googlemaps.MapTypeId.ROADMAP:googlemaps.MapTypeId.HYBRID }); marker = new googlemaps.Marker({ position: { lat:mapuser.last.lat, lng:mapuser.last.lon }, title: mapuser.name, icon: (mapuser.settings.marker)?'/static/img/marker/'+mapuser.settings.marker+'.png':'/static/img/marker/red.png', map: map, draggable: false }); map.addListener('zoom_changed',function(){ map.setCenter(marker.getPosition()); }); // Create iFrame logo if (noHeader!=='0' && mapuser._id!=='demo') { const logoDiv = document.createElement('div'); logoDiv.id = 'map-logo'; logoDiv.innerHTML = ''+ '[]'+ "Tracman"; map.controls[googlemaps.ControlPosition.BOTTOM_LEFT].push(logoDiv); } // Create update time block const timeDiv = document.createElement('div'); timeDiv.id = 'timestamp'; if (mapuser.last.time) { timeDiv.innerHTML = 'location updated '+new Date(mapuser.last.time).toLocaleString(); } map.controls[googlemaps.ControlPosition.RIGHT_BOTTOM].push(timeDiv); // Create speed block if (mapuser.settings.showSpeed) { const speedSign = document.createElement('div'), speedLabel = document.createElement('div'), speedText = document.createElement('div'), speedUnit = document.createElement('div'); speedLabel.id = 'spd-label'; speedLabel.innerHTML = 'SPEED'; speedText.id = 'spd'; speedText.innerHTML = (mapuser.settings.units=='standard')?(parseFloat(mapuser.last.spd)*2.23694).toFixed():mapuser.last.spd.toFixed(); speedUnit.id = 'spd-unit'; speedUnit.innerHTML = (mapuser.settings.units=='standard')?'m.p.h.':'k.p.h.'; speedSign.id = 'spd-sign'; speedSign.appendChild(speedLabel); speedSign.appendChild(speedText); speedSign.appendChild(speedUnit); map.controls[googlemaps.ControlPosition.TOP_RIGHT].push(speedSign); } // Create altitude block if (mapuser.settings.showAlt) { elevator = new googlemaps.ElevationService; const altitudeSign = document.createElement('div'), altitudeLabel = document.createElement('div'), altitudeText = document.createElement('div'), altitudeUnit = document.createElement('div'); altitudeLabel.id = 'alt-label'; altitudeText.id = 'alt'; altitudeUnit.id = 'alt-unit'; altitudeSign.id = 'alt-sign'; altitudeText.innerHTML = ''; altitudeLabel.innerHTML = 'ALTITUDE'; parseAlt(mapuser.last).then( function(alt){ altitudeText.innerHTML = metersToFeet(alt) }).catch( function(err){ console.error("Could not load altitude from last known location: ",err) }); altitudeUnit.innerHTML = (mapuser.settings.units=='standard')?'feet':'meters'; altitudeSign.appendChild(altitudeLabel); altitudeSign.appendChild(altitudeText); altitudeSign.appendChild(altitudeUnit); map.controls[googlemaps.ControlPosition.TOP_RIGHT].push(altitudeSign); } } // Create streetview if (disp!=='0' && mapuser.settings.showStreetview) { updateStreetView(parseLoc(mapuser.last),10); } // Get altitude from Google API function getAlt(loc){ return new Promise( function(resolve,reject){ // Get elevator service elevator = elevator || new googlemaps.ElevationService; return elevator.getElevationForLocations({ // Query API 'locations': [{ lat:loc.lat, lng:loc.lon }] }, function(results, status, error_message) { // Success; return altitude if (status === googlemaps.ElevationStatus.OK && results[0]) { console.log("Altitude was retrieved from Google Elevations API as",results[0].elevation,'m') resolve( results[0].elevation ) } // Unable to get any altitude else { reject(Error(error_message)) } }); }) } // Parse altitude function parseAlt(loc){ //console.log('parseAlt('+loc+'})') return new Promise( function(resolve,reject){ // Check if altitude was provided if (typeof loc.alt=='number'){ console.log('Altitude was provided in loc as ',loc.alt,'m') resolve(loc.alt) } // No altitude provided else { console.log('No altitude was provided in loc') // Query google altitude API getAlt(loc).then( function(alt){ resolve(alt) }).catch( function (err) { reject(err) }) } }) } // Parse location function parseLoc(loc) { loc.spd = (mapuser.settings.units=='standard')?parseFloat(loc.spd)*2.23694:parseFloat(loc.spd); loc.dir = parseFloat(loc.dir); loc.lat = parseFloat(loc.lat); loc.lon = parseFloat(loc.lon); //loc.alt = parseAlt(loc); loc.tim = new Date(loc.tim).toLocaleString(); return loc; } // Got location socket.on('get', function(loc) { console.log("Got location:",loc.lat+", "+loc.lon); // Parse location newLoc = parseLoc(loc); // Update map if (disp!=='1') { //console.log('Updating map...') // Update time $('#timestamp').text('location updated '+newLoc.tim); // Update marker and map center googlemaps.event.trigger(map,'resize'); map.setCenter({ lat:newLoc.lat, lng:newLoc.lon }); marker.setPosition({ lat:newLoc.lat, lng:newLoc.lon }); // Update speed if (mapuser.settings.showSpeed) { $('#spd').text( newLoc.spd.toFixed() ); } // Update altitude if (mapuser.settings.showAlt) { //console.log('updating altitude...'); parseAlt(loc).then(function(alt){ $('#alt').text( metersToFeet(alt) ) }).catch(function(err){ $('#alt').text( '????' ) console.error(err); }) } } // Update street view if (disp!=='0' && mapuser.settings.showStreetview) { updateStreetView(newLoc,10); } }); // Get street view imagery function getStreetViewData(loc,rad,cb) { // Ensure that the location hasn't changed (or this is the initial setting) if ( newLoc == null || loc.tim===newLoc.tim ) { if (!sv) { var sv=new googlemaps.StreetViewService(); } sv.getPanorama({ location: { lat: loc.lat, lng: loc.lon }, radius: rad }, function(data,status){ switch (status){ // Success case googlemaps.StreetViewStatus.OK: cb(data); break; // No results in that radius case googlemaps.StreetViewStatus.ZERO_RESULTS: // Try again with a bigger radius getStreetViewData(loc,rad*2,cb); break; // Error default: console.error(new Error('❌️ Street view not available: '+status).message); } }); } } // Update streetview function updateStreetView(loc) { // Calculate bearing between user and position of streetview image // https://stackoverflow.com/a/26609687/3006854 function getBearing(userLoc, imageLoc) { return 90-( Math.atan2( userLoc.lat-imageLoc.latLng.lat(), userLoc.lon-imageLoc.latLng.lng() ) * (180/Math.PI) ) % 360; } // Get dimensions for sv request (images proportional to element up to 640x640) function getDimensions(element) { // Window is smaller than max if ( element.width()<640 && element.height()<640 ){ return element.width().toFixed()+'x'+element.height().toFixed(); } // Width must be made proportional to 640 else if (element.width()>element.height()) { return '640x'+(element.height()*640/element.width()).toFixed(); } // Height must be made proportional to 640 else { return (element.width()*640/element.height()).toFixed()+'x640'; } } // Set image getStreetViewData(loc, 2, function(data){ $('#viewImg').attr('src','https://maps.googleapis.com/maps/api/streetview?'+ 'size='+ getDimensions($('#view')) + '&location='+ data.location.latLng.lat() +','+ data.location.latLng.lng() + '&fov=90' + // Inclination // Show direction if moving, point to user if stationary '&heading='+ ( (loc.spd>2)? loc.dir: getBearing(loc,data.location) ).toString() + '&key='+ mapKey ); }); } // Error loading gmaps API }).catch( function(err) { console.error(err); });