UNPKG

@panoramax/web-viewer

Version:

Panoramax web viewer for geolocated pictures

146 lines (129 loc) 5.09 kB
import Basic from "./Basic"; import Map from "../ui/Map"; import { getUserLayerId } from "../../utils/map"; import { NavigationControl } from "!maplibre-gl"; // DO NOT REMOVE THE "!": bundled builds breaks otherwise !!! import "./CoverageMap.css"; import { default as InitParameters, alterMapState } from "../../utils/InitParameters"; /** * Coverage Map is a basic map showing Panoramax coverage. * * Make sure to set width/height through CSS for proper display. * @class Panoramax.components.core.CoverageMap * @element pnx-coverage-map * @extends Panoramax.components.core.Basic * @fires Panoramax.components.core.Basic#select * @fires Panoramax.components.core.Basic#ready * @fires Panoramax.components.core.Basic#broken * @property {Panoramax.components.ui.Loader} loader The loader screen * @property {Panoramax.utils.API} api The API manager * @property {Panoramax.components.ui.Map} map The MapLibre GL map itself * @example * ```html * <pnx-coverage-map * endpoint="https://panoramax.openstreetmap.fr/" * map='{"bounds": [[-73.9876, 40.7661], [-73.9397, 40.8002]]}' * style="width: 300px; height: 250px" * /> * ``` */ export default class CoverageMap extends Basic { /** * Component properties. * @memberof Panoramax.components.core.CoverageMap# * @type {Object} * @mixes Panoramax.components.core.Basic#properties * @property {string} endpoint URL to API to use (must be a [STAC API](https://github.com/radiantearth/stac-api-spec/blob/main/overview.md)) * @property {string} [picture] The picture ID to display * @property {string} [sequence] The sequence ID of the picture displayed * @property {object} [fetchOptions] Set custom options for fetch calls made against API ([same syntax as fetch options parameter](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters)) * @property {string[]} [users=[geovisio]] List of users IDs to use for map display (defaults to general map, identified as "geovisio") * @property {string|object} [mapstyle] The map's MapLibre style. This can be an a JSON object conforming to the schema described in the [MapLibre Style Specification](https://maplibre.org/maplibre-style-spec/), or a URL string pointing to one. Defaults to OSM vector tiles. * @property {string} [lang] To override language used for labels. Defaults to using user's preferred languages. * @property {object} [map] [Any map option available in Map class](#Panoramax.components.ui.Map).<br />Example: `map='{"bounds": [[-73.9876, 40.7661], [-73.9397, 40.8002]]}'` */ static properties = { map: {converter: Basic.GetJSONConverter()}, ...Basic.properties }; constructor() { super(); this._mapContainer = document.createElement("div"); this.onceAPIReady().then(() => { this.loader.setAttribute("value", 30); this._initParams = new InitParameters(InitParameters.GetComponentProperties(CoverageMap, this)); this._initMap(); }); } /** @private */ disconnectedCallback() { super.disconnectedCallback(); this.map?.destroy(); } getClassName() { return "CoverageMap"; } onceReady() { if(this.map && this.map.waitForEnoughMapLoaded) { return this.map.waitForEnoughMapLoaded(); } else { return new Promise(resolve => setTimeout(resolve, 100)).then(this.onceReady.bind(this)); } } /** @private */ render() { return [this.loader, this._mapContainer]; } getSubComponentsNames() { const scn = super.getSubComponentsNames(); scn.push("map"); return scn; } /** * Creates map object * @private */ _initMap() { // Override to avoid display of pictures symbols class MyMap extends Map { _getLayerStyleProperties(layer) { if(layer === "pictures_symbols") { return { layout: { visibility: "none" } }; } else { return super._getLayerStyleProperties(layer); } } } this.map = new MyMap(this, this._mapContainer, Object.assign({}, this._initParams.getMapInit(), { hash: true })); this.map.addControl(new NavigationControl({ showCompass: false })); this.loader.setAttribute("value", 70); this.addEventListener("select", this._onSelect.bind(this)); this.map.on("picture-click", e => this.select(e.seqId, e.picId)); this.map.on("sequence-click", e => this.select(e.seqId)); this.map.waitForEnoughMapLoaded().then(async () => { await alterMapState(this.map, this._initParams.getMapPostInit()); this.map.reloadLayersStyles(); this.loader.dismiss(); }); } /** * Select event handler * @private * @param {object} e Event details */ _onSelect(e) { // Move thumbnail to match selected element if(e.detail.picId || e.detail.seqId) { const layer = e.detail.picId ? "pictures" : "sequences"; const features = this.map.queryRenderedFeatures({ layers: [...this.map._userLayers].map(l => getUserLayerId(l, layer)), filter: ["==", ["get", "id"], e.detail.picId || e.detail.seqId] }); if(features.length >= 0 && features[0] != null) { this.map._attachPreviewToPictures({ features }, layer); } } } } customElements.define("pnx-coverage-map", CoverageMap);