@trailstash/ultra
Version:
A web based tool for making MapLibre GL maps with data from sources such as Overpass, GeoJSON, GPX, KML, TCX, etc
124 lines (120 loc) • 3.33 kB
JavaScript
import { fetchIfHTTP } from "./util.js";
import { kml } from "@tmcw/togeojson";
const layers = (source) => [
{
id: `${source}-kml-fill`,
type: "fill",
source,
filter: ["==", ["geometry-type"], "Polygon"],
paint: {
"fill-color": ["coalesce", ["get", "fill"], "#555"],
"fill-opacity": ["coalesce", ["get", "fill-opacity"], 0.3],
},
},
{
id: `${source}-kml-fill-outline`,
type: "line",
source,
filter: ["==", ["geometry-type"], "Polygon"],
paint: {
"line-color": ["coalesce", ["get", "stroke"], "#555"],
"line-width": ["coalesce", ["get", "stroke-width"], 2],
"line-opacity": ["coalesce", ["get", "stroke-opacity"], 1],
},
layout: {
"line-join": "round",
"line-cap": "round",
},
},
{
id: `${source}-kml-line`,
type: "line",
source,
filter: ["==", ["geometry-type"], "LineString"],
paint: {
"line-color": ["coalesce", ["get", "stroke"], "#555"],
"line-width": ["coalesce", ["get", "stroke-width"], 2],
"line-opacity": ["coalesce", ["get", "stroke-opacity"], 1],
},
layout: {
"line-join": "round",
"line-cap": "round",
},
},
{
id: `${source}-kml-point`,
type: "symbol",
source,
filter: ["==", ["geometry-type"], "Point"],
layout: {
"icon-overlap": "always",
"icon-size": ["coalesce", ["get", "icon-scale"], 1],
"icon-anchor": "bottom",
"icon-image": "maki:marker",
},
paint: {
"icon-color": ["coalesce", ["get", "icon-color"], "#555"],
"icon-halo-color": ["coalesce", ["get", "stroke-color"], "#fff"],
"icon-halo-width": [
"coalesce",
["get", "stroke-width"],
[
"case",
["==", ["get", "marker-size"], "large"],
3,
["==", ["get", "marker-size"], "medium"],
1.5,
["==", ["get", "marker-size"], "small"],
1,
1.5,
],
],
},
},
];
const detect = async (query) => {
if (query.startsWith("https://www.google.com/maps/d/")) {
return true;
}
query = await fetchIfHTTP(query);
const doc = new window.DOMParser().parseFromString(query, "text/xml");
return (
!doc.querySelector("parsererror") &&
Array.from(doc.childNodes).some((x) => x.nodeName === "kml")
);
};
export default {
source: async function (query, controller) {
if (query.startsWith("https://www.google.com/maps/d/")) {
const url = new URL(query);
const mid = url.searchParams.get("mid");
if (mid) {
query = `https://www.google.com/maps/d/kml?mid=${mid}&forcekml=1`;
}
}
let doc = new window.DOMParser().parseFromString(query, "text/xml");
if (doc.querySelector("parsererror")) {
const resp = await fetch(query.trim(), { signal: controller.signal });
doc = new window.DOMParser().parseFromString(
await resp.text(),
"text/xml",
);
}
const data = kml(doc);
return { type: "geojson", data, generateId: true };
},
layers,
popupTemplate: `
<h2>{{properties.name}}</h2>
<p>{{properties.description}}</p>
<details>
<summary>Properties</summary>
{%- for prop in properties %}
<code>{{ prop[0] }} = {{ prop[1] }}</code>
<br>
{%- endfor %}
</details>
`,
detect,
fitBounds: true,
};