Created
August 30, 2020 05:53
-
-
Save Rukenshia/f225191a0a215a856f1f6b68850c8527 to your computer and use it in GitHub Desktop.
vfrmap.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>msfs2020-go/vfrmap</title> | |
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo="> | |
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet"> | |
<link rel="stylesheet" href="leafletjs/leaflet.css" /> | |
<script src="leafletjs/leaflet.js"></script> | |
<script src="leafletjs/leaflet.rotatedMarker.js"></script> | |
<style type="text/css"> | |
html, | |
body { | |
height: 100%; | |
margin: 0; | |
padding: 0; | |
} | |
body { | |
display: flex; | |
flex-direction: column; | |
} | |
#map { | |
background-color: gray; | |
flex-grow: 1; | |
} | |
#load-map { | |
position: absolute; | |
bottom: 0; | |
left: 0; | |
z-index: 14; | |
padding: 0.5em; | |
color: black; | |
background-color: red; | |
font-size: 2em; | |
font-weight: bold; | |
} | |
#teleport-popup p { | |
padding: 0.2em; | |
margin: 0; | |
text-align: center; | |
} | |
#teleport-popup p label { | |
padding-right: 0.2em; | |
} | |
</style> | |
<script> | |
"use strict"; | |
const MODE = { | |
BASIC: 0, | |
FULL: 1, | |
}; | |
let hud; | |
let map; | |
let marker; | |
let markerTeleport; | |
let markerIcon; | |
let popup; | |
let ws; | |
let plane_popup; | |
let teleport_popup; | |
let follow_plane = false; | |
let last_report = {}; | |
document.onkeyup = function (event) { | |
if (event.key === "Escape") { | |
toggle_follow(); | |
} | |
} | |
function select_mode(mode) { | |
if (mode === MODE.BASIC) { | |
hud.controls.switch_basic.classList.add('border-white'); | |
hud.controls.switch_basic.classList.remove('border-gray-700'); | |
hud.controls.switch_full.classList.remove('border-white'); | |
hud.controls.switch_full.classList.add('border-gray-700'); | |
hud.full_displays.forEach(e => e.classList.add('hidden')); | |
} else if (mode === MODE.FULL) { | |
hud.controls.switch_full.classList.add('border-white'); | |
hud.controls.switch_full.classList.remove('border-gray-700'); | |
hud.controls.switch_basic.classList.remove('border-white'); | |
hud.controls.switch_basic.classList.add('border-gray-700'); | |
hud.full_displays.forEach(e => e.classList.remove('hidden')); | |
} | |
} | |
function open_in_google_maps() { | |
var url = "https://www.google.com/maps/@" + last_report.latitude + "," + last_report.longitude + "," + map.getZoom() + "z" | |
window.open(url, '_blank'); | |
} | |
function updateMap(msg) { | |
var pos = L.latLng(msg.latitude, msg.longitude); | |
marker.setLatLng(pos); | |
marker.setRotationAngle(msg.heading); | |
plane_popup.pos.innerText = Number(pos.lat).toFixed(6) + "," + Number(pos.lng).toFixed(6); | |
//plane_popup.gmap.innerHTML = "<a href=\"https://www.google.com/maps/@" + pos.lat + "," + pos.lng + "," + map.getZoom() + "z\">google maps</a>"; | |
if (follow_plane) { | |
map.panTo(pos); | |
} | |
} | |
function updateHUD(msg) { | |
hud.altitude.innerText = msg.altitude; | |
hud.heading.innerText = msg.heading; | |
hud.airspeed.innerText = msg.airspeed; | |
hud.vertical_speed.innerText = msg.vertical_speed; | |
hud.flaps.innerText = msg.flaps; | |
hud.trim.innerText = msg.trim; | |
hud.rudder_trim.innerText = msg.rudder_trim; | |
} | |
ws = new WebSocket("ws://" + window.location.hostname + ":" + window.location.port + "/ws"); | |
ws.onopen = function () { | |
//console.log("ws open"); | |
}; | |
ws.onclose = function () { | |
//console.log("ws close"); | |
}; | |
ws.onmessage = function (e) { | |
var msg = JSON.parse(e.data); | |
//console.log("ws data", msg); | |
last_report = msg; | |
updateHUD(msg); | |
if (map !== undefined) { | |
updateMap(msg); | |
} | |
}; | |
function initMap() { | |
var pos = L.latLng(52.4727, -1.7523); | |
var osm = new L.TileLayer("http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { | |
maxZoom: 18, | |
minZoom: 2, | |
format: "image/png", | |
subdomains: ["a", "b", "c"] | |
}); | |
var openaip_cached_basemap = new L.TileLayer("http://{s}.tile.maps.openaip.net/geowebcache/service/tms/1.0.0/openaip_basemap@EPSG%3A900913@png/{z}/{x}/{y}.png", { | |
maxZoom: 14, | |
minZoom: 4, | |
tms: true, | |
//detectRetina: true, | |
subdomains: "12", | |
format: "image/png", | |
transparent: true | |
}); | |
var stamen_black_white = new L.TileLayer("http://{s}.tile.stamen.com/toner/{z}/{x}/{y}.png", { | |
maxZoom: 18, | |
minZoom: 2, | |
format: "image/png", | |
subdomains: ["a", "b", "c"] | |
}); | |
var stamen_terrain = new L.TileLayer("http://{s}.tile.stamen.com/terrain/{z}/{x}/{y}.png", { | |
maxZoom: 18, | |
minZoom: 2, | |
format: "image/png", | |
subdomains: ["a", "b", "c"] | |
}); | |
var stamen_water = new L.TileLayer("http://{s}.tile.stamen.com/watercolor/{z}/{x}/{y}.png", { | |
maxZoom: 18, | |
minZoom: 2, | |
format: "image/png", | |
subdomains: ["a", "b", "c"] | |
}); | |
map = new L.Map("map", { | |
layers: [osm], | |
center: pos, | |
zoom: 10, | |
attributionControl: false | |
}); | |
var attrib = L.control.attribution({ position: "bottomleft" }); | |
attrib.addAttribution("<a href=\"https://www.openaip.net\" target=\"_blank\" style=\"\">openAIP</a>"); | |
attrib.addAttribution("<a href=\"http://maps.stamen.com\" target=\"_blank\" style=\"\">Stamen</a>"); | |
attrib.addAttribution("<a href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\" style=\"\">© OpenStreetMap</a> contributors"); | |
attrib.addTo(map); | |
var baseMaps = { | |
"OpenStreetMap": osm, | |
"Stamen Terrain": stamen_terrain, | |
"Stamen Toner": stamen_black_white, | |
"Stamen Water": stamen_water, | |
}; | |
var overlayMaps = { | |
"Navigational Data": openaip_cached_basemap, | |
}; | |
L.control.layers(baseMaps, overlayMaps).addTo(map); | |
markerIcon = L.icon({ | |
iconUrl: "leafletjs/images/plane.png", | |
iconSize: [64, 64], | |
}); | |
marker = L.marker(pos, { | |
icon: markerIcon, | |
rotationAngle: 0, | |
rotationOrigin: "center", | |
}); | |
marker.addTo(map); | |
marker.bindPopup(L.popup({ autoPan: false }).setLatLng(pos).setContent(plane_popup.main)); | |
var markerPos = L.latLng(0, 0); | |
markerTeleport = L.marker(markerPos, {}); | |
markerTeleport.addTo(map); | |
markerTeleport.bindPopup(L.popup({ autoPan: false }).setContent(teleport_popup.main)); | |
set_teleport_marker(markerPos); | |
map.on('click', function (e) { | |
set_teleport_marker(e.latlng); | |
}); | |
} | |
function set_teleport_marker(latlng) { | |
markerTeleport.setLatLng(latlng); | |
teleport_popup.gps.value = latlng.lat.toFixed(8) + "," + latlng.lng.toFixed(8); | |
if (last_report.altitude) { | |
teleport_popup.altitude.value = last_report.altitude; | |
} | |
} | |
function teleport_here() { | |
//var pos = markerTeleport.getLatLng(); | |
var msg = JSON.stringify( | |
{ | |
"type": "teleport", | |
"lat": parseFloat(teleport_popup.gps.value.split(",")[0]), | |
"lng": parseFloat(teleport_popup.gps.value.split(",")[1]), | |
"altitude": parseFloat(teleport_popup.altitude.value) + 0.5, | |
} | |
); | |
console.log(msg); | |
ws.send(msg); | |
} | |
function toggle_follow() { | |
if (follow_plane) { | |
plane_popup.follow.innerText = "follow plane"; | |
} else { | |
plane_popup.follow.innerText = "don't follow plane"; | |
} | |
follow_plane = !follow_plane; | |
} | |
document.addEventListener("DOMContentLoaded", function (event) { | |
plane_popup = { | |
main: document.getElementById("plane-popup"), | |
pos: document.getElementById("plane-popup-pos"), | |
gmap: document.getElementById("plane-popup-gmap"), | |
follow: document.getElementById("plane-popup-follow"), | |
}; | |
teleport_popup = { | |
main: document.getElementById("teleport-popup"), | |
submit: document.getElementById("teleport-popup-submit"), | |
gps: document.getElementById("teleport-popup-gps"), | |
altitude: document.getElementById("teleport-popup-altitude"), | |
}; | |
hud = { | |
altitude: document.getElementById("altitude_value"), | |
heading: document.getElementById("heading_value"), | |
airspeed: document.getElementById("airspeed_value"), | |
vertical_speed: document.getElementById("vertical_speed_value"), | |
flaps: document.getElementById("flaps_value"), | |
trim: document.getElementById("trim_value"), | |
rudder_trim: document.getElementById("rudder_trim_value"), | |
controls: { | |
switch_basic: document.getElementById('switch_mode_basic'), | |
switch_full: document.getElementById('switch_mode_full'), | |
}, | |
basic_displays: document.querySelectorAll('.mode-basic'), | |
full_displays: document.querySelectorAll('.mode-full'), | |
}; | |
toggle_follow(); | |
initMap(); | |
}); | |
</script> | |
</head> | |
<body> | |
<div class="p-4 flex bg-black gap-2 text-white items-center justify-around"> | |
<div class="text-center mode-basic"> | |
<div class="text-xl" id="airspeed_value">0</div> | |
<div class="text-gray-500">Airspeed</div> | |
</div> | |
<div class="text-center mode-basic"> | |
<div class="text-xl" id="heading_value">0</div> | |
<div class="text-gray-500">Heading</div> | |
</div> | |
<div class="text-center mode-basic"> | |
<div class="text-xl" id="altitude_value">0</div> | |
<div class="text-gray-500">Altitude</div> | |
</div> | |
<div class="text-center mode-full"> | |
<div class="text-xl" id="vertical_speed_value">0</div> | |
<div class="text-gray-500">V.Speed</div> | |
</div> | |
<div class="text-center mode-full"> | |
<div class="text-xl" id="flaps_value">0</div> | |
<div class="text-gray-500">Flaps</div> | |
</div> | |
<div class="text-center mode-full"> | |
<div class="text-xl" id="trim_value">0</div> | |
<div class="text-gray-500">Trim</div> | |
</div> | |
<div class="text-center mode-full"> | |
<div class="text-xl" id="rudder_trim_value">0</div> | |
<div class="text-gray-500">R.Trim</div> | |
</div> | |
<div> | |
<div> | |
<button id="switch_mode_basic" class="w-full border border-gray-700 px-2 py-1.5 text-white rounded" | |
onclick="select_mode(MODE.BASIC)">basic</button> | |
</div> | |
<div class="mt-2"> | |
<button id="switch_mode_full" class="w-full border border-white px-2 py-1.5 text-white rounded" | |
onclick="select_mode(MODE.FULL)">full</button> | |
</div> | |
</div> | |
</div> | |
<div id="map"></div> | |
<div style="display:none;"> | |
<div id="plane-popup"> | |
<p> | |
<h3 id="plane-popup-pos"></h3> | |
</p> | |
<p><button id="plane-popup-gmap" onclick="open_in_google_maps();">open in google maps</button></p> | |
<p><button id="plane-popup-follow" onclick="toggle_follow();"></button></p> | |
</div> | |
<div id="teleport-popup"> | |
<p><label for="teleport-popup-gps">GPS:</label><input type="text" id="teleport-popup-gps"></p> | |
<p><label for="teleport-popup-alt">Altitude:</label><input type="text" id="teleport-popup-altitude"></p> | |
<p><button type="button" id="teleport-popup-submit" onclick="teleport_here();">teleport</button></p> | |
</div> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment