Skip to content

Instantly share code, notes, and snippets.

@Rukenshia
Created August 30, 2020 05:53
Show Gist options
  • Save Rukenshia/f225191a0a215a856f1f6b68850c8527 to your computer and use it in GitHub Desktop.
Save Rukenshia/f225191a0a215a856f1f6b68850c8527 to your computer and use it in GitHub Desktop.
vfrmap.html
<!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