mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Add a new Leaflet based map UI.
This is extremely WIP. It is not usable for play yet. Enable with `--new-map`.
This commit is contained in:
35
resources/ui/map/canvas.html
Normal file
35
resources/ui/map/canvas.html
Normal file
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>DCS Liberation Map</title>
|
||||
<script src="qrc:///qtwebchannel/qwebchannel.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
|
||||
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
|
||||
crossorigin=""/>
|
||||
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
|
||||
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
|
||||
crossorigin=""></script>
|
||||
|
||||
<script src="https://unpkg.com/esri-leaflet@3.0.1/dist/esri-leaflet.js"
|
||||
integrity="sha512-JmpptMCcCg+Rd6x0Dbg6w+mmyzs1M7chHCd9W8HPovnImG2nLAQWn3yltwxXRM7WjKKFFHOAKjjF2SC4CgiFBg=="
|
||||
crossorigin=""></script>
|
||||
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/leaflet-groupedlayercontrol@0.6.1/dist/leaflet.groupedlayercontrol.min.css"
|
||||
crossorigin="sha384-jTaPj8/7LfdZXicEJ/SUWan4gkbYw6lXyoRUNPMmNV3fYVfBzHJK8wD6A8Djh+3A">
|
||||
<script
|
||||
src="https://unpkg.com/leaflet-groupedlayercontrol@0.6.1/dist/leaflet.groupedlayercontrol.min.js"
|
||||
integrity="sha384-XAr1poM2RCR9/QQFki7ylrGSdmvYE0NuHghuRuxb/k9zJQA53y6qR5te5jJRZlcL"
|
||||
crossorigin="">
|
||||
</script>
|
||||
<style>
|
||||
body { padding: 0; margin: 0; }
|
||||
html, body, #map { height: 100%; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
</body>
|
||||
</html>
|
||||
220
resources/ui/map/map.js
Normal file
220
resources/ui/map/map.js
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* TODO:
|
||||
*
|
||||
* - Culling
|
||||
* - Threat zones
|
||||
* - Navmeshes
|
||||
* - CV waypoints
|
||||
* - Time of day/weather themeing
|
||||
* - Exclusion zones
|
||||
* - Commit ranges
|
||||
* - Waypoint info
|
||||
* - Supply route status
|
||||
* - Front line
|
||||
* - Debug flight plan drawing
|
||||
* - Icon variety
|
||||
*/
|
||||
|
||||
const Colors = Object.freeze({
|
||||
Blue: "#0084ff",
|
||||
Red: "#c85050",
|
||||
});
|
||||
|
||||
var map = L.map("map").setView([0, 0], 3);
|
||||
|
||||
// https://esri.github.io/esri-leaflet/api-reference/layers/basemap-layer.html
|
||||
var baseLayers = {
|
||||
"Imagery Clarity": L.esri.basemapLayer("ImageryClarity", { maxZoom: 17 }),
|
||||
"Imagery Firefly": L.esri.basemapLayer("ImageryFirefly", { maxZoom: 17 }),
|
||||
};
|
||||
|
||||
var defaultBaseMap = baseLayers["Imagery Clarity"];
|
||||
defaultBaseMap.addTo(map);
|
||||
|
||||
// Enabled by default, so addTo(map).
|
||||
var controlPointsLayer = L.layerGroup().addTo(map);
|
||||
var groundObjectsLayer = L.layerGroup().addTo(map);
|
||||
var supplyRoutesLayer = L.layerGroup().addTo(map);
|
||||
var redSamThreatLayer = L.layerGroup().addTo(map);
|
||||
var blueFlightPlansLayer = L.layerGroup().addTo(map);
|
||||
|
||||
// Added to map by the user via layer controls.
|
||||
var blueSamThreatLayer = L.layerGroup();
|
||||
var blueSamDetectionLayer = L.layerGroup();
|
||||
var redSamDetectionLayer = L.layerGroup();
|
||||
var redFlightPlansLayer = L.layerGroup();
|
||||
var selectedFlightPlansLayer = L.layerGroup();
|
||||
|
||||
L.control
|
||||
.groupedLayers(
|
||||
baseLayers,
|
||||
{
|
||||
"Points of Interest": {
|
||||
"Control points": controlPointsLayer,
|
||||
"Ground objects": groundObjectsLayer,
|
||||
"Supply routes": supplyRoutesLayer,
|
||||
},
|
||||
"Air Defenses": {
|
||||
"Ally SAM threat range": blueSamThreatLayer,
|
||||
"Enemy SAM threat range": redSamThreatLayer,
|
||||
"Ally SAM detection range": blueSamDetectionLayer,
|
||||
"Enemy SAM detection range": redSamDetectionLayer,
|
||||
},
|
||||
"Flight Plans": {
|
||||
"Hide": L.layerGroup(),
|
||||
"Show selected blue": selectedFlightPlansLayer,
|
||||
"Show all blue": blueFlightPlansLayer,
|
||||
"Show all red": redFlightPlansLayer,
|
||||
},
|
||||
},
|
||||
{ collapsed: false, exclusiveGroups: ["Flight Plans"] }
|
||||
)
|
||||
.addTo(map);
|
||||
|
||||
var friendlyCpIcon = new L.Icon({
|
||||
iconUrl:
|
||||
"https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-blue.png",
|
||||
shadowUrl:
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png",
|
||||
iconSize: [25, 41],
|
||||
iconAnchor: [12, 41],
|
||||
popupAnchor: [1, -34],
|
||||
shadowSize: [41, 41],
|
||||
});
|
||||
|
||||
var enemyCpIcon = new L.Icon({
|
||||
iconUrl:
|
||||
"https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-red.png",
|
||||
shadowUrl:
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png",
|
||||
iconSize: [25, 41],
|
||||
iconAnchor: [12, 41],
|
||||
popupAnchor: [1, -34],
|
||||
shadowSize: [41, 41],
|
||||
});
|
||||
|
||||
var game;
|
||||
new QWebChannel(qt.webChannelTransport, function (channel) {
|
||||
game = channel.objects.game;
|
||||
drawInitialMap();
|
||||
game.cleared.connect(clearAllLayers);
|
||||
game.mapCenterChanged.connect(recenterMap);
|
||||
game.controlPointsChanged.connect(drawControlPoints);
|
||||
game.groundObjectsChanged.connect(drawGroundObjects);
|
||||
game.supplyRoutesChanged.connect(drawSupplyRoutes);
|
||||
game.flightsChanged.connect(drawFlightPlans);
|
||||
});
|
||||
|
||||
function recenterMap(center) {
|
||||
map.setView(center, 8, { animate: true, duration: 1 });
|
||||
}
|
||||
|
||||
function iconFor(player) {
|
||||
if (player) {
|
||||
return friendlyCpIcon;
|
||||
} else {
|
||||
return enemyCpIcon;
|
||||
}
|
||||
}
|
||||
|
||||
function drawControlPoints() {
|
||||
controlPointsLayer.clearLayers();
|
||||
game.controlPoints.forEach((cp) => {
|
||||
L.marker(cp.position, { icon: iconFor(cp.blue) })
|
||||
.on("click", function () {
|
||||
cp.open_base_menu();
|
||||
})
|
||||
.addTo(controlPointsLayer);
|
||||
});
|
||||
}
|
||||
|
||||
function drawSamThreatsAt(tgo) {
|
||||
var detectionLayer = tgo.blue ? blueSamDetectionLayer : redSamDetectionLayer;
|
||||
var threatLayer = tgo.blue ? blueSamThreatLayer : redSamThreatLayer;
|
||||
var threatColor = tgo.blue ? Colors.Blue : Colors.Red;
|
||||
var detectionColor = tgo.blue ? "#bb89ff" : "#eee17b";
|
||||
|
||||
tgo.samDetectionRanges.forEach((range) => {
|
||||
L.circle(tgo.position, {
|
||||
radius: range,
|
||||
color: detectionColor,
|
||||
fill: false,
|
||||
weight: 2,
|
||||
}).addTo(detectionLayer);
|
||||
});
|
||||
|
||||
tgo.samThreatRanges.forEach((range) => {
|
||||
L.circle(tgo.position, {
|
||||
radius: range,
|
||||
color: threatColor,
|
||||
fill: false,
|
||||
weight: 2,
|
||||
}).addTo(threatLayer);
|
||||
});
|
||||
}
|
||||
|
||||
function drawGroundObjects() {
|
||||
groundObjectsLayer.clearLayers();
|
||||
blueSamDetectionLayer.clearLayers();
|
||||
redSamDetectionLayer.clearLayers();
|
||||
blueSamThreatLayer.clearLayers();
|
||||
redSamThreatLayer.clearLayers();
|
||||
game.groundObjects.forEach((tgo) => {
|
||||
L.marker(tgo.position, { icon: iconFor(tgo.blue) }).addTo(
|
||||
groundObjectsLayer
|
||||
);
|
||||
drawSamThreatsAt(tgo);
|
||||
});
|
||||
}
|
||||
|
||||
function drawSupplyRoutes() {
|
||||
supplyRoutesLayer.clearLayers();
|
||||
game.supplyRoutes.forEach((route) => {
|
||||
L.polyline(route.points).addTo(supplyRoutesLayer);
|
||||
});
|
||||
}
|
||||
|
||||
function drawFlightPlan(flight) {
|
||||
var layer = flight.blue ? blueFlightPlansLayer : redFlightPlansLayer;
|
||||
var color = flight.blue ? Colors.Blue : Colors.Red;
|
||||
var highlight = "#ffff00";
|
||||
var points = [];
|
||||
flight.flightPlan.forEach((waypoint) => {
|
||||
points.push(waypoint.position);
|
||||
L.circle(waypoint.position, { radius: 50, color: color }).addTo(layer);
|
||||
if (flight.selected) {
|
||||
L.circle(waypoint.position, { radius: 50, color: highlight }).addTo(
|
||||
selectedFlightPlansLayer
|
||||
);
|
||||
}
|
||||
});
|
||||
L.polyline(points, { color: color }).addTo(layer);
|
||||
if (flight.selected) {
|
||||
L.polyline(points, { color: highlight }).addTo(selectedFlightPlansLayer);
|
||||
}
|
||||
}
|
||||
|
||||
function drawFlightPlans() {
|
||||
blueFlightPlansLayer.clearLayers();
|
||||
redFlightPlansLayer.clearLayers();
|
||||
selectedFlightPlansLayer.clearLayers();
|
||||
game.flights.forEach((flight) => {
|
||||
drawFlightPlan(flight);
|
||||
});
|
||||
}
|
||||
|
||||
function drawInitialMap() {
|
||||
recenterMap(game.mapCenter);
|
||||
drawControlPoints();
|
||||
drawGroundObjects();
|
||||
drawSupplyRoutes();
|
||||
drawFlightPlans();
|
||||
}
|
||||
|
||||
function clearAllLayers() {
|
||||
map.eachLayer(function (layer) {
|
||||
if (layer.clearLayers !== undefined) {
|
||||
layer.clearLayers();
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user