2024-11-26 20:41:37 -06:00
|
|
|
<!DOCTYPE html>
|
|
|
|
<html lang="en">
|
|
|
|
<head>
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
<title>Lawrence Deer Club Maps</title>
|
|
|
|
<link rel="stylesheet" href="/leaflet/leaflet.css" />
|
|
|
|
<script src="/leaflet/leaflet.js"></script>
|
|
|
|
<style>
|
|
|
|
html, body {
|
|
|
|
margin: 0;
|
|
|
|
padding: 0;
|
|
|
|
}
|
|
|
|
#map {
|
|
|
|
height: 100vh;
|
|
|
|
width: 100vw;
|
|
|
|
}
|
|
|
|
|
|
|
|
div.popup dt {
|
|
|
|
font-weight: bold;
|
|
|
|
}
|
|
|
|
|
2024-11-27 20:35:22 -06:00
|
|
|
.label {
|
|
|
|
font-weight: bold;
|
|
|
|
text-align: center;
|
|
|
|
margin-top: -1em;
|
|
|
|
}
|
|
|
|
.label div {
|
|
|
|
position: relative;
|
|
|
|
left: -50%;
|
|
|
|
top: 10px;
|
|
|
|
text-shadow: 0 0 2px white;
|
|
|
|
}
|
2024-11-30 12:26:39 -06:00
|
|
|
.leaflet-popup-content-wrapper {
|
|
|
|
height: min(800px, 60vh);
|
|
|
|
overflow-y: auto;
|
|
|
|
}
|
|
|
|
#popupcontainer {
|
|
|
|
position: relative;
|
|
|
|
z-index: 1000;
|
|
|
|
}
|
|
|
|
#popupcontainer .leaflet-popup-content-wrapper {
|
|
|
|
height: unset;
|
|
|
|
}
|
|
|
|
#popupcontainer .leaflet-popup {
|
|
|
|
transform: none !important;
|
|
|
|
position: fixed;
|
|
|
|
width: 100vw;
|
|
|
|
height: 100vh;
|
|
|
|
right: 0;
|
|
|
|
left: 0 !important;
|
|
|
|
top: 1em;
|
|
|
|
bottom: 1em !important;
|
|
|
|
overflow: auto;
|
|
|
|
}
|
|
|
|
#popupcontainer .leaflet-popup-content {
|
|
|
|
width: initial;
|
|
|
|
}
|
2024-11-26 20:41:37 -06:00
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div id="map"></div>
|
2024-11-30 12:26:39 -06:00
|
|
|
<div id="popupcontainer" class="leaflet-container"></div>
|
2024-11-26 20:41:37 -06:00
|
|
|
<script>
|
|
|
|
(async function() {
|
|
|
|
const map = L.map('map').setView([94.505, -0.09], 13);
|
|
|
|
// L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
|
|
// maxZoom: 19,
|
|
|
|
// attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
|
|
|
// }).addTo(map);
|
|
|
|
|
|
|
|
// Make these requests in parallel
|
|
|
|
const track_req_promise = fetch('data/track.geojson');
|
|
|
|
const plats_req_promise = fetch('data/plats.geojson');
|
|
|
|
const data_req_promise = fetch('data/data.json');
|
|
|
|
const track_req = await track_req_promise;
|
|
|
|
const plats_req = await plats_req_promise;
|
|
|
|
const data_req = await data_req_promise;
|
|
|
|
const track = await track_req.json();
|
|
|
|
const plats = await plats_req.json();
|
|
|
|
const data = await data_req.json();
|
|
|
|
|
2024-11-30 12:34:03 -06:00
|
|
|
L.geoJSON(track).addTo(map);
|
2024-11-26 20:41:37 -06:00
|
|
|
|
|
|
|
L.geoJSON(plats, {
|
2024-11-30 12:33:41 -06:00
|
|
|
filter: feature => !feature.properties.TAO_NAME.toLowerCase().includes("lawrence deer club"),
|
2024-11-27 20:35:22 -06:00
|
|
|
onEachFeature: function(feature, layer) {
|
|
|
|
const latLngs = layer.getLatLngs()[0];
|
|
|
|
const centerish = [ // TODO: actual centroid
|
|
|
|
latLngs.reduce((acc, i) => acc + i.lat, 0) / latLngs.length,
|
|
|
|
latLngs.reduce((acc, i) => acc + i.lng, 0) / latLngs.length,
|
|
|
|
];
|
|
|
|
|
|
|
|
const label = L.marker(centerish, {
|
|
|
|
icon: L.divIcon({
|
|
|
|
iconSize: null,
|
|
|
|
className: "label",
|
|
|
|
html: "<div>" + feature.properties.TAO_NAME + "</div>"
|
|
|
|
})
|
|
|
|
}).addTo(map);
|
|
|
|
},
|
2024-11-26 20:41:37 -06:00
|
|
|
}).addTo(map);
|
|
|
|
|
|
|
|
for (let stand of data.stands) {
|
|
|
|
if (stand.location) {
|
|
|
|
const marker = L.marker(stand.location).addTo(map);
|
|
|
|
const popupContentWrapper = document.createElement('div');
|
|
|
|
popupContentWrapper.classList.add('popup');
|
|
|
|
let attributesString = '<dl>';
|
|
|
|
for (let [attribute, value] of Object.entries(stand.attributes)) {
|
|
|
|
attributesString += `<dt>${attribute}</dt><dd>${value}</dd>`;
|
|
|
|
}
|
|
|
|
attributesString += '</dl>';
|
|
|
|
popupContentWrapper.innerHTML = `
|
|
|
|
<h2>${stand.name}</h2>
|
|
|
|
<img style="width: min(80vw, 300px);" src="images/${stand.image}">
|
|
|
|
${attributesString}
|
|
|
|
`;
|
2024-11-30 12:26:39 -06:00
|
|
|
let popupOptions = {};
|
|
|
|
// TODO: evaluate this when creating popup instead of at
|
|
|
|
// page instantiation time -- if the page is resized, this
|
|
|
|
// won't keep up with those changes.
|
|
|
|
if (window.visualViewport.width < 600) {
|
|
|
|
popupOptions.pane = document.getElementById('popupcontainer');
|
|
|
|
}
|
|
|
|
marker.bindPopup(popupContentWrapper, popupOptions);
|
2024-11-26 20:41:37 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
map.fitBounds([
|
|
|
|
[47.4865,-93.4068],
|
|
|
|
[47.4992,-93.3746],
|
|
|
|
]);
|
|
|
|
})();
|
|
|
|
</script>
|
|
|
|
</body>
|
|
|
|
</html>
|