Combine adjacent plats
curl -LO "https://cdn.jsdelivr.net/npm/@turf/turf@6/turf.min.js"
This commit is contained in:
parent
08b3a0bac5
commit
9352930ba6
2 changed files with 186 additions and 29 deletions
127
map.html
127
map.html
|
|
@ -6,6 +6,7 @@
|
||||||
<title>Lawrence Deer Club Maps</title>
|
<title>Lawrence Deer Club Maps</title>
|
||||||
<link rel="stylesheet" href="/leaflet/leaflet.css" />
|
<link rel="stylesheet" href="/leaflet/leaflet.css" />
|
||||||
<script src="/leaflet/leaflet.js"></script>
|
<script src="/leaflet/leaflet.js"></script>
|
||||||
|
<script src="/turf.min.js"></script>
|
||||||
<style>
|
<style>
|
||||||
html, body {
|
html, body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
@ -136,27 +137,56 @@
|
||||||
</div>`;
|
</div>`;
|
||||||
document.getElementById('lightbox').style.display = 'block';
|
document.getElementById('lightbox').style.display = 'block';
|
||||||
}
|
}
|
||||||
function calculateCentroid(points) {
|
function collectPlatEdges(featureCollection) {
|
||||||
// https://en.wikipedia.org/wiki/Centroid#Of_a_polygon
|
const segments = new Map();
|
||||||
let area = 0;
|
|
||||||
let centroidLat = 0;
|
|
||||||
let centroidLng = 0;
|
|
||||||
|
|
||||||
for (let i = 0; i < points.length; i++) {
|
const addSegment = (start, end) => {
|
||||||
const { lat: lat1, lng: lng1 } = points[i];
|
if (!start || !end || start.length !== 2 || end.length !== 2) {
|
||||||
const { lat: lat2, lng: lng2 } = points[(i + 1) % points.length]; // Next vertex, wrapping around
|
return;
|
||||||
|
}
|
||||||
|
if (start[0] === end[0] && start[1] === end[1]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const forwardKey = `${start[0]},${start[1]}|${end[0]},${end[1]}`;
|
||||||
|
const backwardKey = `${end[0]},${end[1]}|${start[0]},${start[1]}`;
|
||||||
|
const key = forwardKey < backwardKey ? forwardKey : backwardKey;
|
||||||
|
if (!segments.has(key)) {
|
||||||
|
segments.set(key, { from: start, to: end });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const determinant = lat1 * lng2 - lng1 * lat2;
|
const visitRing = (ring) => {
|
||||||
area += determinant;
|
if (!Array.isArray(ring) || ring.length < 2) {
|
||||||
centroidLat += (lat1 + lat2) * determinant;
|
return;
|
||||||
centroidLng += (lng1 + lng2) * determinant;
|
}
|
||||||
|
for (let i = 0; i < ring.length - 1; i++) {
|
||||||
|
addSegment(ring[i], ring[i + 1]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const feature of featureCollection.features) {
|
||||||
|
if (!feature || !feature.geometry) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const { type, coordinates } = feature.geometry;
|
||||||
|
if (type === "Polygon") {
|
||||||
|
for (const ring of coordinates) {
|
||||||
|
visitRing(ring);
|
||||||
|
}
|
||||||
|
} else if (type === "MultiPolygon") {
|
||||||
|
for (const polygon of coordinates) {
|
||||||
|
for (const ring of polygon) {
|
||||||
|
visitRing(ring);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
area *= 0.5;
|
const features = [];
|
||||||
centroidLat /= (6 * area);
|
for (const segment of segments.values()) {
|
||||||
centroidLng /= (6 * area);
|
features.push(turf.lineString([segment.from, segment.to]));
|
||||||
|
}
|
||||||
return [centroidLat, centroidLng];
|
return turf.featureCollection(features);
|
||||||
}
|
}
|
||||||
(async function() {
|
(async function() {
|
||||||
const map = L.map('map', {
|
const map = L.map('map', {
|
||||||
|
|
@ -193,19 +223,58 @@
|
||||||
const plats = await plats_req.json();
|
const plats = await plats_req.json();
|
||||||
const data = await data_req.json();
|
const data = await data_req.json();
|
||||||
|
|
||||||
L.geoJSON(plats, {
|
const platFeatures = Array.isArray(plats.features) ? plats.features : [];
|
||||||
filter: feature => !feature.properties.TAO_NAME.toLowerCase().includes("lawrence deer club"),
|
const filteredPlats = {
|
||||||
onEachFeature: function(feature, layer) {
|
type: "FeatureCollection",
|
||||||
const centroid = calculateCentroid(layer.getLatLngs()[0]);
|
features: platFeatures.filter(feature => {
|
||||||
const label = L.marker(centroid, {
|
const name = feature?.properties?.TAO_NAME;
|
||||||
icon: L.divIcon({
|
if (typeof name !== "string") {
|
||||||
iconSize: null,
|
return false;
|
||||||
className: "label",
|
}
|
||||||
html: "<div>" + feature.properties.TAO_NAME + "</div>"
|
return !name.toLowerCase().includes("lawrence deer club");
|
||||||
})
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (filteredPlats.features.length > 0) {
|
||||||
|
// draw deduplicated plat boundaries with a subtle stroke so the merged shapes stay legible
|
||||||
|
const platEdges = collectPlatEdges(filteredPlats);
|
||||||
|
if (platEdges.features.length > 0) {
|
||||||
|
L.geoJSON(platEdges, {
|
||||||
|
style: {
|
||||||
|
weight: 2,
|
||||||
|
dashArray: "15 25", // px on, px off
|
||||||
|
},
|
||||||
|
interactive: false,
|
||||||
}).addTo(map);
|
}).addTo(map);
|
||||||
},
|
}
|
||||||
}).addTo(map);
|
|
||||||
|
const dissolvedPlats = turf.dissolve(filteredPlats, { propertyName: "TAO_NAME" });
|
||||||
|
|
||||||
|
if (dissolvedPlats && dissolvedPlats.features) {
|
||||||
|
L.geoJSON(dissolvedPlats, {
|
||||||
|
// style: {
|
||||||
|
// color: "#004f9f",
|
||||||
|
// weight: 2,
|
||||||
|
// fillOpacity: 0.1,
|
||||||
|
// },
|
||||||
|
onEachFeature(feature, layer) {
|
||||||
|
if (!feature || !feature.geometry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const labelPoint = turf.pointOnFeature(feature);
|
||||||
|
const [lng, lat] = labelPoint.geometry.coordinates;
|
||||||
|
L.marker([lat, lng], {
|
||||||
|
icon: L.divIcon({
|
||||||
|
iconSize: null,
|
||||||
|
className: "label",
|
||||||
|
html: "<div>" + feature.properties.TAO_NAME + "</div>",
|
||||||
|
}),
|
||||||
|
interactive: false,
|
||||||
|
}).addTo(map);
|
||||||
|
},
|
||||||
|
}).addTo(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
L.geoJSON(track, {
|
L.geoJSON(track, {
|
||||||
style: {
|
style: {
|
||||||
|
|
|
||||||
88
turf.min.js
vendored
Normal file
88
turf.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue