filestash/public/assets/pages/viewerpage/application_map.js
MickaelK aed8712fd7 fix (map): map loading issues
when trying to load a shp file, it would load indefinitly with window.L
being undefined
2025-09-23 14:11:58 +10:00

134 lines
5.4 KiB
JavaScript

import { createElement, nop } from "../../lib/skeleton/index.js";
import rxjs, { effect } from "../../lib/rx.js";
import { qs, safe } from "../../lib/dom.js";
import ajax from "../../lib/ajax.js";
import { load as loadPlugin } from "../../model/plugin.js";
import { loadCSS, loadJS } from "../../helpers/loader.js";
import { createLoader } from "../../components/loader.js";
import ctrlError from "../ctrl_error.js";
import componentDownloader, { init as initDownloader } from "./application_downloader.js";
import { renderMenubar, buttonDownload } from "./component_menubar.js";
class IMap {
toGeoJSON() { throw new Error("NOT_IMPLEMENTED"); }
}
export default async function(render, { mime, getDownloadUrl = nop, getFilename = nop, acl$ = rxjs.EMPTY }) {
const $page = createElement(`
<div class="component_map">
<component-menubar filename="${safe(getFilename())}"></component-menubar>
<div id="map"></div>
</div>
`);
render($page);
const $menubar = renderMenubar(
qs($page, "component-menubar"),
buttonDownload(getFilename(), getDownloadUrl()),
);
const map = window.L.map("map");
const removeLoader = createLoader(qs($page, "#map"));
await effect(ajax({ url: getDownloadUrl(), responseType: "arraybuffer" }).pipe(
rxjs.mergeMap(async({ response }) => {
const loader = await loadPlugin(mime);
if (!loader) {
try {
loadGeoJSON(map, JSON.parse(new TextDecoder().decode(response)));
window.L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", { maxZoom: 21 }).addTo(map);
}
catch (err) { componentDownloader(render, { mime, acl$, getFilename, getDownloadUrl }); }
return rxjs.EMPTY;
}
const mapImpl = new (await loader(IMap, { mime, getDownloadUrl, getFilename, $menubar }))(response, {
map, $page, L: window.L,
});
loadGeoJSON(map, await mapImpl.toGeoJSON());
}),
removeLoader,
rxjs.catchError(ctrlError()),
));
}
export async function init($root) {
const priors = $root ? [
$root.classList.add("component_page_viewerpage"),
loadCSS(import.meta.url, "./component_menubar.css"),
loadCSS(import.meta.url, "../ctrl_viewerpage.css"),
] : [];
await Promise.all([
loadJS(import.meta.url, "../../lib/vendor/leaflet/leaflet.js"),
loadCSS(import.meta.url, "../../lib/vendor/leaflet/leaflet.css"),
loadCSS(import.meta.url, "./application_map.css"),
initDownloader(),
...priors,
]);
}
function loadGeoJSON(map, content) {
const overlay = { global: window.L.layerGroup([]) };
let n = 0;
const geojson = window.L.geoJSON(content, {
style: (feature) => {
const style = { color: "#3388ff", weight: 3 };
if (feature.properties.color) style.color = feature.properties.color;
if (feature.properties.weight) style.weight = feature.properties.weight;
return style;
},
pointToLayer: (feature, latlng) => {
return window.L.circleMarker(latlng, {
radius: 6,
fillColor: "#e2e2e2",
color: "#000000",
opacity: 0.5,
weight: 1,
fillOpacity: 0.3
});
},
onEachFeature: (feature, shape) => {
n += 1;
if (n > 10000) return;
const { group = "global", ...props } = feature.properties || {};
const featureObject = (function() {
if (props["name"]) shape = shape.bindPopup(props["name"]);
switch (props["popup::type"]) {
case "text":
shape = shape.bindPopup(props["popup::content"]);
break;
case "html":
shape = shape.bindPopup((function() {
const $richLabel = window.L.DomUtil.create("div", "");
$richLabel.innerHTML = props["popup::content"];
if ($richLabel.querySelector("script")) $richLabel.innerHTML = `__BLOCKED_CONTENT__`;
return $richLabel;
})(), {
className: "leaflet-measure-resultpopup",
autoPanPadding: [10, 10],
});
break;
}
return shape;
})(feature.geometry || {});
if (!featureObject) return;
if (!overlay[group]) overlay[group] = window.L.layerGroup([]);
overlay[group].addLayer(featureObject);
}
});
// center map around bounds
try {
const center = geojson.getBounds().getCenter();
const zoom = (function(p1, p2) {
const distance = Math.log10(1 + Math.abs(p1.lat - p2.lat) + Math.abs(p1.lng - p2.lng));
const [a, b] = distance > 0.5 ? [-4, 11] : [-15, 15];
return Math.floor(a * distance + b);
})(geojson.getBounds().getNorthEast(), geojson.getBounds().getSouthWest());
map.setView([center.lat, center.lng], zoom);
} catch (err) {
map.setView([0, 0], 2);
}
// display everything
Object.keys(overlay).forEach((key) => overlay[key].addTo(map));
delete overlay["global"];
if (Object.keys(overlay).length > 0) window.L.control.layers({}, overlay).addTo(map);
}