UNPKG

@trailstash/ultra

Version:

A web based tool for making MapLibre GL maps with data from sources such as Overpass, GeoJSON, GPX, KML, TCX, etc

283 lines (266 loc) 6.96 kB
import { h, t } from "../lib/dom.js"; import { style as buttonCSS } from "./button.js"; import { normalizeCSS } from "../lib/normalize.js"; import { toQueryParams } from "../lib/queryParams.js"; import { htmlExport } from "../lib/htmlExport.js"; export class ExportModal extends HTMLElement { #center; #zoom; #query; #data; #style; constructor() { super(); } get center() { return this.#center; } set center(value) { this.#center = value; this.update(); } get zoom() { return this.#zoom; } set zoom(value) { this.#zoom = value; this.update(); } get query() { return this.#query; } set query(value) { this.#query = value; this.update(); } set data(data) { this.#data = data; this.update(); } get data() { return this.#data; } set style(style) { this.#style = style; this.update(); } get style() { return this.#style ? { ...this.#style, glyphs: this.#style && this.#style.glyphs ? new URL(this.#style.glyphs).searchParams.get("url") : undefined, } : null; } get html() { return htmlExport(this.style, "Ultra Export", "", { zoom: this.zoom, center: this.center, }); } connectedCallback() { const shadow = this.attachShadow({ mode: "open" }); const dataDownloadButton = h("button", {}, t("download")); dataDownloadButton.addEventListener("click", () => this.download(JSON.stringify(this.data), "ultra.geojson"), ); const styleDownloadButton = h("button", {}, t("download")); styleDownloadButton.addEventListener("click", () => { this.download(JSON.stringify(this.style), "style.json"); }); const htmlDownloadButton = h("button", {}, t("download")); htmlDownloadButton.addEventListener("click", () => { this.download(this.html, "ultra.html"); }); const queryDownloadButton = h("button", {}, t("download")); queryDownloadButton.addEventListener("click", () => { this.download(this.query, "query.ultra"); }); const dataCopyButton = h("button", {}, t("copy")); dataCopyButton.addEventListener("click", () => { navigator.clipboard.writeText(JSON.stringify(this.data)); }); const styleCopyButton = h("button", {}, t("copy")); styleCopyButton.addEventListener("click", () => { navigator.clipboard.writeText(JSON.stringify(this.style)); }); const htmlCopyButton = h("button", {}, t("copy")); htmlCopyButton.addEventListener("click", () => { navigator.clipboard.writeText(this.html); }); const queryCopyButton = h("button", {}, t("copy")); queryCopyButton.addEventListener("click", () => { navigator.clipboard.writeText(this.query); }); const div = h( "div", { style: "", slot: "modal-content" }, h( "style", {}, ` div { padding: 0 8px 8px; max-width: 100%; width: 460px; } details, .note { font-size: 0.8em; } h3, h5 { margin-bottom: 0; } input[type=text] { width: 100%; padding: 0; margin: 0; } label { display: block; } button { cursor: pointer; } `, ), h( "div", { className: "data" }, h("h3", {}, "Data"), h("p", {}, "Export the query result as GeoJSON"), dataDownloadButton, t(" "), dataCopyButton, ), h( "div", { className: "map" }, h("h3", {}, "Map"), h("fa-icon", { icon: "triangle-exclamation" }), h( "span", { className: "note" }, t(" Note: some styles' tiles have CORS restrictions"), ), h( "p", {}, t("Export the map as a MapLibre style "), h( "details", {}, h( "summary", {}, h("fa-icon", { icon: "triangle-exclamation" }), t(" usage notes"), ), t("Ultra's "), h( "a", { href: "https://overpass-ultra.us/docs/style/#png-sprites-via-https", target: "_blank", }, "sprite", ), t(" support, "), h( "a", { href: "https://overpass-ultra.us/docs/style/#fallback-fontstack", target: "_blank", }, "Fallback glyphs", ), t(", and interactive popups"), t(" are run-time features and aren't included in the generated "), h("code", {}, "style.json"), t(". You may experience issues with missing icons or text."), ), ), styleDownloadButton, t(" "), styleCopyButton, /* h( "p", {}, t("Export an interactive map"), h( "details", {}, h( "summary", {}, h("fa-icon", { icon: "triangle-exclamation" }), t(" usage notes"), ), t( "Ultra's interactive popups are not yet supported in exported HTML.", ), ), ), htmlDownloadButton, t(" "), htmlCopyButton, */ ), /* h( "div", { className: "query" }, h("h3", {}, "Query"), h("p", {}, "Export the Ultra query"), queryDownloadButton, t(" "), queryCopyButton, ), */ ); const button = h( "button-modal", { text: "Export", icon: "file-export" }, div, ); this.refs = { button, div, }; shadow.appendChild(button); this.update(); } update() { if (this.data) { this.refs.div.querySelector(".data").style.display = "block"; } else { this.refs.div.querySelector(".data").style.display = "none"; } if (this.style) { this.refs.button.refs.button.disabled = false; } else { this.refs.button.refs.button.disabled = true; } } download(data, filename) { const blob = new Blob([data], { type: "octet/stream" }); const url = window.URL.createObjectURL(blob); const link = h("a", { download: filename, href: url }); // this is necessary as link.click() does not work on the latest firefox link.dispatchEvent( new MouseEvent("click", { bubbles: true, cancelable: true, view: window, }), ); setTimeout(() => { // For Firefox it is necessary to delay revoking the ObjectURL window.URL.revokeObjectURL(url); link.remove(); }, 100); } }