263 linhas
7.0 KiB
HTML
263 linhas
7.0 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title></title>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
|
<style type="text/css" media="screen">
|
|
button.active{
|
|
background:red;
|
|
}
|
|
body{
|
|
margin:0;
|
|
padding:0;
|
|
height:100%;
|
|
background:#000;
|
|
color:#fff;
|
|
font-family: Helvetica, Arial, "MS Trebuchet", sans-serif;
|
|
}
|
|
#map, #droneStream{
|
|
width: 50%;
|
|
height: 400px;
|
|
float:left;
|
|
}
|
|
#data, #controls{
|
|
width:50%;
|
|
float:left;
|
|
}
|
|
#droneStream canvas{
|
|
width: 100%;
|
|
height: 400px;
|
|
}
|
|
.section{
|
|
width:33%;
|
|
float:left;
|
|
}
|
|
.section button{
|
|
padding:5px;
|
|
background:#fff;
|
|
border:none;
|
|
min-width:100px;
|
|
cursor:pointer;
|
|
}
|
|
#drone-position, #phone-position{
|
|
float:left;
|
|
width:50%;
|
|
}
|
|
</style>
|
|
<link rel="stylesheet" href="/leaflet.css" />
|
|
|
|
</head>
|
|
<body>
|
|
<div id="map"></div>
|
|
<div id='droneStream'></div>
|
|
<div id='controls'>
|
|
<div class='section'>
|
|
<button id='takeoff'>Takeoff</button><br />
|
|
<button id='land'>Land</button><br />
|
|
<button id='reset'>Reset</button>
|
|
</div>
|
|
<div class='section'>
|
|
<button id='go'>Go to waypoint</button><br />
|
|
<button id='home'>Return Home</button><br />
|
|
<button id='clear'>Clear Route</button>
|
|
</div>
|
|
<div class='section'>
|
|
<button id='follow'>Follow me</button>
|
|
<button id='manual'>Manual Control</button>
|
|
<button id='stop'>Stop</button>
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
<div id='data'>
|
|
<div id="phone-position">
|
|
Phone:
|
|
<span class='lat'>0</span>,
|
|
<span class='lon'>0</span>
|
|
(+/-<span class='accuracy'>0</span>m)
|
|
</div>
|
|
<div id="drone-position">
|
|
Drone:
|
|
<span class='lat'>0</span>,
|
|
<span class='lon'>0</span>
|
|
<br/>Distance:
|
|
<span class='distance'>0</span>m
|
|
<br/>
|
|
Battery:
|
|
<span class='battery'>0</span>%
|
|
</div>
|
|
</div>
|
|
|
|
<script src="http://maps.google.com/maps/api/js?v=3.2&sensor=false"></script>
|
|
<script src="leaflet.js"></script>
|
|
<script src="leaflet-google.js"></script>
|
|
<script src="/dronestream/nodecopter-client.js"></script>
|
|
<script src="jquery.js"></script>
|
|
<script src="/socket.io/socket.io.js"></script>
|
|
<script>
|
|
var socket = io.connect('/');
|
|
var lat, lon, map, laptop, drone, phone, phonePath, waypointPath, dronePath, startPosition;
|
|
var targetLat, targetLon;
|
|
var waypointMarkers = [];
|
|
var activeWaypoints = [];
|
|
var waypoints = [];
|
|
var follow = false;
|
|
|
|
var phoneIcon = L.icon({
|
|
iconUrl: 'images/iphone.png'
|
|
});
|
|
|
|
var laptopIcon = L.icon({
|
|
iconUrl: 'images/laptop.png'
|
|
});
|
|
|
|
var droneIcon = L.icon({
|
|
iconUrl: 'images/copter.png'
|
|
});
|
|
|
|
new NodecopterStream(document.getElementById("droneStream"));
|
|
|
|
navigator.geolocation.getCurrentPosition(initMap, defaultMap, { enableHighAccuracy:true });
|
|
|
|
function initMap(position){
|
|
lat = position.coords.latitude;
|
|
lon = position.coords.longitude;
|
|
|
|
map = L.map('map').setView([lat, lon], 20);
|
|
|
|
var googleLayer = new L.Google('SATELLITE');
|
|
map.addLayer(googleLayer);
|
|
|
|
laptop = L.marker([lat, lon], {icon: laptopIcon}).addTo(map)
|
|
|
|
map.on('click', function(e) {
|
|
waypointMarkers.push(L.marker(e.latlng).addTo(map))
|
|
waypoints.push([e.latlng.lat, e.latlng.lng])
|
|
if(waypointPath == undefined){
|
|
waypointPath = L.polyline(waypoints, {color: 'blue'}).addTo(map);
|
|
} else {
|
|
waypointPath.setLatLngs(waypoints)
|
|
}
|
|
});
|
|
}
|
|
|
|
function defaultMap(err){
|
|
console.log(err)
|
|
initMap({coords: { latitude: 51, longitude: 2 }})
|
|
}
|
|
|
|
function clearWaypoints(){
|
|
waypoints = []
|
|
map.removeLayer(waypointPath)
|
|
waypointPath = undefined
|
|
$.each(waypointMarkers, function(i,m){map.removeLayer(m)})
|
|
}
|
|
|
|
function setCurrentTarget(lat, lon){
|
|
targetLat = lat
|
|
targetLon = lon
|
|
socket.emit('go', {lat: targetLat, lon: targetLon})
|
|
}
|
|
|
|
function clearCurrentTarget(){
|
|
targetLat = undefined
|
|
targetLon = undefined
|
|
socket.emit('stop')
|
|
}
|
|
|
|
$(function(){
|
|
$('#takeoff').click(function(){
|
|
follow = false
|
|
socket.emit('takeoff')
|
|
if (drone != null){
|
|
startPosition = [drone._latlng.lat, drone._latlng.lng]
|
|
}
|
|
})
|
|
$('#land').click(function(){
|
|
follow = false
|
|
socket.emit('land')
|
|
startPosition = []
|
|
})
|
|
$('#reset').click(function(){
|
|
socket.emit('reset')
|
|
})
|
|
$('#stop').click(function(){
|
|
follow = false
|
|
clearCurrentTarget()
|
|
})
|
|
$('#clear').click(function(){
|
|
follow = false
|
|
clearWaypoints()
|
|
})
|
|
$('#home').click(function(){
|
|
follow = false
|
|
activeWaypoints = [startPosition[0], startPosition[1]]
|
|
setCurrentTarget(startPosition[0], startPosition[1])
|
|
})
|
|
$('#go').click(function(){
|
|
follow = false
|
|
if(waypoints.length > 0){
|
|
activeWaypoints = waypoints.slice(0);
|
|
// go to next waypoint
|
|
setCurrentTarget(activeWaypoints[0][0], activeWaypoints[0][1])
|
|
}
|
|
})
|
|
$('#follow').click(function(){
|
|
follow = true
|
|
})
|
|
$('#manual').click(function(){
|
|
// control via xbox
|
|
follow = false
|
|
})
|
|
})
|
|
|
|
socket.on('connect', function(){
|
|
socket.on('waypointReached', function(data){
|
|
activeWaypoints.shift()
|
|
if(activeWaypoints.length > 0){
|
|
// go to next waypoint
|
|
setCurrentTarget(activeWaypoints[0][0], activeWaypoints[0][1])
|
|
}
|
|
})
|
|
socket.on('drone', function(data){
|
|
if(data.lat != undefined){
|
|
if (drone == null){
|
|
drone = L.marker([data.lat, data.lon], {icon: droneIcon}).addTo(map)
|
|
dronePath = L.polyline([[data.lat, data.lon]], {color: 'green'}).addTo(map);
|
|
} else{
|
|
drone.setLatLng([data.lat, data.lon])
|
|
dronePath.addLatLng([data.lat, data.lon])
|
|
}
|
|
$('#drone-position .battery').text(data.battery)
|
|
$('#drone-position .lat').text(data.lat)
|
|
$('#drone-position .lon').text(data.lon)
|
|
$('#drone-position .distance').text(data.distance)
|
|
}
|
|
})
|
|
|
|
socket.on('phone', function(data){
|
|
if(data.lat != undefined){
|
|
if (laptop == null){
|
|
initMap(data.lat, data.lon)
|
|
}
|
|
if (phone == null){
|
|
phone = L.marker([data.lat, data.lon], {icon: phoneIcon}).addTo(map)
|
|
phonePath = L.polyline([[data.lat, data.lon]], {color: 'red'}).addTo(map);
|
|
} else {
|
|
phone.setLatLng([data.lat, data.lon])
|
|
phonePath.addLatLng([data.lat, data.lon])
|
|
}
|
|
if(follow){
|
|
setCurrentTarget(data.lat, data.lon)
|
|
}
|
|
$('#phone-position .lat').text(data.lat)
|
|
$('#phone-position .lon').text(data.lon)
|
|
$('#phone-position .accuracy').text(data.accuracy)
|
|
}
|
|
})
|
|
})
|
|
</script>
|
|
</body>
|
|
</html>
|