tracman-server/views/map.html

358 lines
12 KiB
HTML
Raw Normal View History

2016-03-31 17:06:21 -06:00
{% extends 'templates/base.html' %}
2016-05-31 21:54:21 -06:00
{% block title %}{{super()}} | {{mapuser.name}}{% endblock %}
2016-03-31 17:06:21 -06:00
{% block head %}
{{ super() }}
2016-05-31 21:54:21 -06:00
<link href="/static/css/map.css" rel="stylesheet">
2016-03-31 17:06:21 -06:00
<style>
2016-05-31 21:54:21 -06:00
section { display: none; }
#controls {
width: 100vw;
position: absolute;
bottom: 50px;
display: flex;
justify-content: space-around;
}#controls .btn {
background: #222;
width: 30vw;
}#controls .btn:hover {
background: #333;
}#controls #track {
width:35vw;
}
{% if mapuser.settings.showStreetview and disp!='0' %}
@media (orientation: portrait) {
#controls { bottom:30px }
}
{% endif %}
/*TODO: Smaller signs on mobile*/
/*.spd-sign {}*/
/*.alt-sign {}*/
2016-03-31 17:06:21 -06:00
.wrap { top:{% if not noHeader %}58{% else %}0{% endif %}px;}
img#panoImg { width:100%; height:100%; }
2016-05-31 21:54:21 -06:00
{% if mapuser.settings.showStreetview and disp!='0' and disp!='1' %}
2016-03-31 17:06:21 -06:00
/* show both */
2016-05-31 21:54:21 -06:00
@media (orientation: landscape) {
#map, #pano {
display:inline-block;
width:50%;
height:99%;
}2
#pano { float:right; }
2016-03-31 17:06:21 -06:00
}
@media (orientation: portrait) {
#map, #pano {
width:100%;
height:50%;
}
#pano { bottom:0; }
}
2016-05-31 21:54:21 -06:00
{% elif mapuser.settings.showStreetview and disp=='1' %}
2016-03-31 17:06:21 -06:00
/* show streetview */
#pano {
width:100%;
height:100%;}
#map {display:none;}
{% else %}
/* show map */
#map {
width:100%;
height:100%;}
#pano {display:none;}
{% endif %}
</style>
{% endblock %}
{% block main %}
<div class='wrap'>
2016-05-31 21:54:21 -06:00
{% if not mapuser.last.time %}
<div class='centered alert alert-warning'>
<b>No Location Found</b>
{% if user.id == mapuser.id %}
<br>You can <a href="#" onclick="setLocation()">click here to use this device's location</a>.
<br>Maybe you also want to <a href="/android">download the android app</a>.
{% else %}
<br>This user hasn't updated their location yet!
{% endif %}
</div>
2016-03-31 17:06:21 -06:00
{% else %}
2016-05-31 21:54:21 -06:00
<div id='map'><i class='loading fa fa-refresh fa-spin'></i></div>
{% if mapuser.settings.showStreetview and not noStreetview.length %}
<div id='pano'><i class='loading fa fa-refresh fa-spin'></i></div>
2016-03-31 17:06:21 -06:00
{% endif %}
{% endif %}
2016-05-31 21:54:21 -06:00
{% if user.id == mapuser.id %}
<div id='controls'>
<button class='btn' id='set' onclick="setLocation()">Set</button>
<button class='btn' id='track' onclick="trackLocation()" data-toggle="tooltop" title="Tracking location..." data-trigger="manual"><i class='fa fa-crosshairs'></i>&emsp;Track</button>
<button class='btn' id='clear' onclick="clearLocation()">Clear</button>
</div>
{% endif %}
2016-03-31 17:06:21 -06:00
</div>
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?key={{api}}&callback=initMap" async defer></script>
2016-03-31 17:06:21 -06:00
<script>
2016-05-31 21:54:21 -06:00
{ var wpid, map, pano, sv, marker, elevator,
socket = io.connect(),
mapuserid = {{mapuser._id |dump|safe}},
userid{% if user._id %} = {{user._id |dump|safe}}{% endif %},
settings = JSON.parse('{{mapuser.settings |dump|safe}}'),
last = JSON.parse('{{mapuser.last |dump|safe}}'),
noHeader = {{noHeader |dump|safe}},
disp = {{disp |dump|safe}}, // 0=map, 1=streetview, 2=both
panoElem = document.getElementById('pano');
}
2016-03-31 17:06:21 -06:00
// Parse location
function parseLoc(loc) {
loc.spd = (settings.units=='imperial')?parseFloat(loc.spd)*2.23694:parseFloat(loc.spd)
loc.dir = parseFloat(loc.dir);
loc.lat = parseFloat(loc.lat);
loc.lon = parseFloat(loc.lon);
loc.time = new Date(loc.time).toLocaleString()
loc.glatlng = new google.maps.LatLng(loc.lat, loc.lon);
return loc;
}
2016-05-31 21:54:21 -06:00
// Track location
function trackLocation() {
if (!userid==mapuserid) { alert('You are not logged in! '); }
else {
// Stop tracking
if (wpid) {
$('#controls > #track').html('<i class="fa fa-crosshairs"></i>&emsp;Track').tooltip('hide');
navigator.geolocation.clearWatch(wpid);
wpid = undefined;
// Start tracking
} else {
$('#controls > #track').html('<i class="fa fa-crosshairs fa-spin"></i>&emsp;Stop').tooltip('show');
if (!navigator.geolocation) { alert('Unable to track location. '); }
else {
wpid = navigator.geolocation.watchPosition(function(pos) {
socket.emit('app', {
usr: '{{user.id}}',
lat: pos.coords.latitude,
lon: pos.coords.longitude,
spd: (pos.coords.speed||0)
});
// console.log('Sent location:',pos.coords.latitude.toFixed(2)+','+pos.coords.longitude.toFixed(2));
}, function(err){
alert('Failed to track: \n'+err);
}, { enableHighAccuracy:true });
}
}
}
}
// Set location once
2016-03-31 17:06:21 -06:00
function setLocation() {
2016-05-31 21:54:21 -06:00
// TODO: Authenticate at server
if (!userid==mapuserid) { alert('You are not logged in! '); }
else {
if (!navigator.geolocation) { alert('Geolocation not enabled. '); }
else {
navigator.geolocation.getCurrentPosition(function(pos){
socket.emit('app', {
2016-05-31 21:54:21 -06:00
usr: userid,
lat: pos.coords.latitude,
lon: pos.coords.longitude,
spd: (pos.coords.speed||0)
});
}, function(err){
if (err) { alert('ERROR: '+err); }
else { location.reload(); }
}, { enableHighAccuracy:true });
2016-05-05 19:13:01 -06:00
}
}
2016-03-31 17:06:21 -06:00
}
2016-05-31 21:54:21 -06:00
// Clear location
function clearLocation() {
if (!userid==mapuserid) { alert('You are not logged in! '); }
else {
alert('Location clearing goes here');
//TODO: Delete user.last from db via AJAX
}
}
2016-03-31 17:06:21 -06:00
var getAltitude = function(location, elevator, cb){
elevator = elevator || new google.maps.ElevationService;
elevator.getElevationForLocations({
'locations': [location]
}, function(results, status) {
if (status === google.maps.ElevationStatus.OK && results[0]) {
cb(results[0].elevation);
}
});
}
function initMap() {
// Create map
if (disp!='1' || !settings.showStreetview) {
map = new google.maps.Map( document.getElementById('map'), {
center: new google.maps.LatLng( last.lat, last.lon ),
panControl: false,
draggable: false,
zoom: settings.defaultZoom,
streetViewControl: false,
zoomControlOptions: {position: google.maps.ControlPosition.LEFT_TOP},
mapTypeId: (settings.defaultMap=='road')?google.maps.MapTypeId.ROADMAP:google.maps.MapTypeId.HYBRID
});
marker = new google.maps.Marker({
position: { lat:last.lat, lng:last.lon },
2016-05-31 21:54:21 -06:00
title: {{ mapuser.name | dump | safe }},
2016-03-31 17:06:21 -06:00
map: map,
draggable: false
});
2016-04-17 12:08:49 -06:00
map.addListener('zoom_changed',function(){
map.setCenter(marker.getPosition());
});
2016-03-31 17:06:21 -06:00
// Create iFrame logo
if (noHeader.length) {
var logoDiv = document.createElement('div');
logoDiv.className = 'map-logo';
logoDiv.innerHTML = '<a href="https://tracman.org/">'+
'<img src="https://tracman.org/static/img/style/logo-28.png" alt="[]">'+
'Tracman</a>';
map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(logoDiv);
}
// Create update time block
var timeDiv = document.createElement('div');
timeDiv.className = 'tim';
if (last.time) {
timeDiv.innerHTML = 'location updated '+new Date(last.time).toLocaleString();
}
map.controls[google.maps.ControlPosition.RIGHT_BOTTOM].push(timeDiv);
// Create speed block
if (settings.showSpeed) {
var speedSign = document.createElement('div'),
speedLabel = document.createElement('div'),
speedText = document.createElement('div'),
speedUnit = document.createElement('div');
speedLabel.className = 'spd-label';
2016-05-31 21:54:21 -06:00
speedLabel.innerHTML = 'SPEED';
2016-03-31 17:06:21 -06:00
speedText.className = 'spd';
speedText.innerHTML = (settings.units=='imperial')?(parseFloat(last.spd)*2.23694).toFixed():last.spd.toFixed();
2016-05-31 21:54:21 -06:00
speedUnit.className = 'spd-unit';
2016-03-31 17:06:21 -06:00
speedUnit.innerHTML = (settings.units=='imperial')?'m.p.h.':'k.p.h.';
2016-05-31 21:54:21 -06:00
speedSign.className = 'spd-sign';
2016-03-31 17:06:21 -06:00
speedSign.appendChild(speedLabel);
speedSign.appendChild(speedText);
speedSign.appendChild(speedUnit);
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(speedSign);
}
// Create altitude block
if (settings.showAlt) {
var elevator = new google.maps.ElevationService;
var altitudeSign = document.createElement('div'),
altitudeLabel = document.createElement('div'),
altitudeText = document.createElement('div'),
altitudeUnit = document.createElement('div');
altitudeLabel.className = 'alt-label';
altitudeText.className = 'alt';
altitudeUnit.className = 'alt-unit';
altitudeSign.className = 'alt-sign';
altitudeText.innerHTML = '';
altitudeLabel.innerHTML = 'ALTITUDE';
getAltitude(new google.maps.LatLng(last.lat,last.lon), elevator, function(alt) {
if (alt) { altitudeText.innerHTML = (settings.units=='imperial')?(alt*3.28084).toFixed():alt.toFixed(); }
});
altitudeUnit.innerHTML = (settings.units=='imperial')?'feet above sea level':'meters above sea level';
altitudeSign.appendChild(altitudeLabel);
altitudeSign.appendChild(altitudeText);
altitudeSign.appendChild(altitudeUnit);
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(altitudeSign);
}
}
2016-05-05 19:13:01 -06:00
// Create/set streetview
updateStreet(parseLoc(last),10);
2016-05-05 19:13:01 -06:00
}
2016-05-13 21:20:36 -06:00
function getStreetViewData(loc,rad,cb) {
if (!sv) { var sv=new google.maps.StreetViewService(); }
2016-05-13 21:20:36 -06:00
sv.getPanorama({location:{lat:loc.lat,lng:loc.lon},radius:rad},function(data,status){
if (status===google.maps.StreetViewStatus.ZERO_RESULTS){ getStreetViewData(loc,rad*2,cb); }
else if (status!==google.maps.StreetViewStatus.OK){ console.log('Street view not available: '+status); }
else { cb(data); }
});
}
// Update streetview
function updateStreet(loc) {
if (loc.spd>1) { // moving
if (settings.showStreetview && disp!='0') {
var imgElem = document.getElementById('panoImg');
getStreetViewData(loc, 50, function(data){
if (!imgElem) {
// Create image
pano = undefined;
$('#pano').empty();
$('#pano').append($('<img>',{
alt: 'Street view image',
src: 'https://maps.googleapis.com/maps/api/streetview?size=800x800&location='+loc.lat+','+loc.lon+'&fov=90&heading='+loc.dir+'&key={{api}}',
id: 'panoImg'
}));
}
2016-05-13 21:20:36 -06:00
// Set image
$('#panoImg').attr('src','https://maps.googleapis.com/maps/api/streetview?size='+$('#pano').width()+'x'+$('#pano').height()+'&location='+data.location.latLng.lat()+','+data.location.latLng.lng()+'&fov=90&heading='+loc.dir+'&key={{api}}');
});
}
} else if (pano==null) { // not moving and pano not set
getStreetViewData(loc, 50, function(data){
// Create panorama
$('#pano').empty();
var panoOptions = {
panControl: false,
zoomControl: false,
addressControl: false,
linksControl: false,
};
pano = new google.maps.StreetViewPanorama(panoElem, panoOptions);
// Set panorama
pano.setPano(data.location.pano);
pano.setPov({
pitch: 0,
heading: Math.atan((loc.lon-data.location.latLng.lng())/(loc.lat-data.location.latLng.lat()))*(180/Math.PI)
});
});
2016-05-05 19:13:01 -06:00
}
2016-03-31 17:06:21 -06:00
}
// Sockets
2016-05-05 19:13:01 -06:00
socket.on('connect',function(){
2016-05-31 21:54:21 -06:00
socket.emit('room',
(userid)? 'app-'+userid :mapuserid
);
2016-03-31 17:06:21 -06:00
});
2016-05-05 19:13:01 -06:00
socket.on('trac',function(loc) {
loc = parseLoc(loc);
2016-03-31 17:06:21 -06:00
if (disp!='1' || !settings.showStreetview) {
2016-05-05 19:13:01 -06:00
$('.tim').text('location updated '+loc.time);
if (settings.showSpeed) { $('.spd').text(loc.spd.toFixed()); }
2016-03-31 17:06:21 -06:00
if (settings.showAlt) {
getAltitude({lat:loc.lat,lng:loc.lon}, elevator, function(alt) {
2016-03-31 17:06:21 -06:00
if (alt) { $('.alt').text((settings.units=='imperial')?(alt*3.28084).toFixed():alt.toFixed()); }
});
}
map.setCenter({lat:loc.lat,lng:loc.lon});
marker.setPosition({lat:loc.lat,lng:loc.lon});
2016-03-31 17:06:21 -06:00
}
updateStreet(loc,10);
2016-03-31 17:06:21 -06:00
});
</script>
{% endblock %}