UNPKG

@nextgis/ngw-map

Version:
686 lines (678 loc) 20.4 kB
/** Bundle of @nextgis/ngw-map; version: 3.0.1; author: NextGIS */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var icons = require('@nextgis/icons'); var NgwConnector = require('@nextgis/ngw-connector'); var ngwKit = require('@nextgis/ngw-kit'); var utils = require('@nextgis/utils'); var webmap = require('@nextgis/webmap'); var events = require('events'); var qmsKit = require('@nextgis/qms-kit'); function appendNgwResources(options, resource, defOptions, overwriteOptions) { if (typeof resource === "number" || typeof resource === "string") { resource = Number(resource); options.push({ ...defOptions, resource }); } else if (Array.isArray(resource)) { const [resourceId, id] = resource; options.push({ ...defOptions, resource: resourceId, id, ...overwriteOptions }); } else if (typeof resource === "object") { options.push({ ...defOptions, ...resource, ...overwriteOptions }); } } const OPTIONS = { target: "map", baseUrl: "", whitlabel: false, controls: webmap.getDefaultControls(), controlsOptions: { ZOOM: { position: "top-left" }, ATTRIBUTION: { position: "bottom-right", customAttribution: [ '<a href="https://nextgis.com" target="_blank">\xA9NextGIS</a>' ] } }, pixelRadius: 10 }; function prepareWebMapOptions(options) { const kits = [new qmsKit.QmsKit()]; if (options.starterKits) { options.starterKits.forEach((x) => { kits.push(x); }); } if (!options.connector) { options.connector = new NgwConnector({ baseUrl: options.baseUrl || "", auth: options.auth, withCredentials: options.withCredentials }); } else if (options.connector) { options.baseUrl = options.connector.options.baseUrl; } options = utils.deepmerge(OPTIONS, options); if (!options.center && !options.bounds) { options.bounds = [-179, -90, 180, 90]; } if (options.connector) { kits.push( new ngwKit.NgwKit({ connector: options.connector, auth: options.auth }) ); } options = { ...options, starterKits: kits, create: false }; return options; } var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); class NgwMap extends webmap.WebMap { constructor(options) { super(prepareWebMapOptions(options)); __publicField(this, "emitter", new events.EventEmitter()); __publicField(this, "connector"); __publicField(this, "_ngwLayers", {}); __publicField(this, "$$selectFromNgwRaster"); __publicField(this, "$$selectFromNgwVector"); __publicField(this, "_promises", { select: [], identify: [] }); if (options.connector) { this.connector = options.connector; } this._createWebMap().then(() => { const container = this.getContainer(); if (container) { container.classList.add("ngw-map-container"); } if (this.options.whitlabel) { this._whiteLabel(); } }); } /** * Organized addition to the map design and controls elements, * calling `control.onAdd(this.webMap.mapAdapter)` * @param control - object with onAdd and onRemove methods * or a string value indicating the name of the control installed in the map adapter * @param position - position relative to the map angles * @param options - initialization parameters if the control is set as a string value * * @example * ```javascript * ngwMap.addControl(new CustomControl(), 'bottom-left'); * ngwMap.addControl('ZOOM', 'top-right') * ``` */ async addControl(controlDef, position, options) { await this.onLoad("controls:create"); return super.addControl(controlDef, position, options); } /** * Add any (style, vector, webmap) NGW layer by resource definition. * @param options - set layer identification parameters and render method. * * @example * ```javascript * // Add raster layer resourceId is the style of 4004 layer * ngwMap.addNgwLayer({ resource: 4005 }); * // Add vector data from layer GEOJSON source * ngwMap.addNgwLayer({ * resource: 4038, * adapter: 'GEOJSON', * adapterOptions: { paint: { color: 'red' } } * }); * ``` */ async addNgwLayer(options) { await this.onMapLoad(); const { keyname, resourceId } = options; if (keyname || resourceId !== void 0) { utils.deprecatedWarn( "set `resource` options instead of `keyname` or `resourceId`" ); } const resource = options.resource; if (!keyname && !resourceId && !resource) { throw new Error( "resource, resourceId or keyname is required parameter to add NGW layer" ); } if (utils.defined(this.options.baseUrl)) { try { if (utils.defined(this.options.setViewDelay)) { options.adapterOptions = options.adapterOptions || {}; if (!utils.defined(options.adapterOptions.setViewDelay)) { options.adapterOptions.setViewDelay = this.options.setViewDelay; } } const adapter = ngwKit.createNgwLayerAdapter(options, this, this.connector); const adapterOpts = { visibility: true, // TODO: do not merge options, use only `adapterOptions` ...options, ...options.adapterOptions }; const layer = await this.addLayer( adapter, adapterOpts ); const id = layer && this.getLayerId(layer); if (layer && id) { this._ngwLayers[id] = { layer, resourceId: layer.resourceId }; layer.options.name = layer.options.name || layer.item && layer.item.resource.display_name; if (layer.options.baselayer) { const visibleLayerBaseLayer = this.getActiveBaseLayer(); if (visibleLayerBaseLayer) { return layer; } } } return layer; } catch (er) { const resId = utils.isObject(resource) && "id" in resource ? resource.id : keyname || resourceId || resource; console.error(`Can't add NGW layer ${resId}.`, er); } } } /** * Pans and zooms the map to the initial position specified in the options */ fit() { const { center, zoom, bounds } = this.options; if (center) { this.setCenter(center); if (zoom) { this.setZoom(zoom); } } else if (bounds) { this.fitBounds(bounds); } } fetchNgwLayerItem(options) { return ngwKit.fetchNgwLayerItem({ connector: this.connector, ...options }); } fetchNgwLayerItems(options) { return ngwKit.fetchNgwLayerItems({ connector: this.connector, ...options }); } fetchNgwLayerFeature(options) { return ngwKit.fetchNgwLayerFeature({ connector: this.connector, ...options }); } fetchNgwLayerFeatures(options) { return ngwKit.fetchNgwLayerFeatureCollection({ connector: this.connector, ...options }); } fetchIdentifyItem(identify, requestOptions) { const abortController = new AbortController(); const abortSignal = abortController.signal; if (requestOptions == null ? void 0 : requestOptions.signal) { requestOptions.signal.addEventListener("abort", abortController.abort); } requestOptions = requestOptions || {}; requestOptions.signal = abortSignal; const promise = ngwKit.fetchIdentifyItem({ identify, connector: this.connector, requestOptions // multiple, }); this._addPromise("identify", promise, abortController); return promise; } fetchIdentifyGeoJson(identify, { multiple, signal } = {}) { const abortController = new AbortController(); if (signal) { if (signal.aborted) { return Promise.reject(new NgwConnector.errors.AbortError()); } signal.addEventListener("abort", () => { abortController.abort("AbortError"); }); } const promise = ngwKit.fetchIdentifyGeoJson({ identify, connector: this.connector, multiple, requestOptions: { signal: abortController.signal } }); if (promise && "then" in promise) { this._addPromise("identify", promise, abortController); return promise; } else { return Promise.resolve(promise); } } /** * @deprecated use {@link fetchIdentifyGeoJson} instead */ getIdentifyGeoJson(identify, multiple = false) { return this.fetchIdentifyGeoJson(identify, { multiple }); } async getNgwLayers() { await this.onLoad(); return this._ngwLayers; } async getNgwLayerByResourceId(id) { for (const n in this._ngwLayers) { const mem = this._ngwLayers[n]; if (mem.resourceId === id) { return mem && mem.layer; } else if (mem.layer.getIdentificationIds) { const ids = await mem.layer.getIdentificationIds(); if (ids && ids.some((x) => x === id)) { return mem.layer; } } if (mem.layer.getDependLayers) { const dependLayers = mem.layer.getDependLayers(); const dependFit = dependLayers.find((x) => { return x.item && "style_parent_id" in x.item && x.item.style_parent_id !== void 0 && x.item.style_parent_id === id; }); if (dependFit) { return dependFit.layer; } } } } /** * Move map to layer. If the layer is NGW resource, extent will be received from the server * * @example * ```javascript * const ngwLayer = ngwMap.addNgwLayer({ id: 'ngw_layer_name', resource: 4005 }); * ngwMap.fitLayer(ngwLayer); * ngwMap.fitLayer('ngw_layer_name'); * ``` */ async fitLayer(layerDef, options) { let id; if (typeof layerDef === "string" || typeof layerDef === "number") { id = String(id); } else { id = layerDef.id; } const ngwLayer = id && this._ngwLayers[id]; if (ngwLayer) { if (ngwLayer.layer.getBounds) { const bounds = await ngwLayer.layer.getBounds(); if (bounds) { this.fitBounds(bounds, options); } } else { let item; if (ngwLayer.layer.item) { item = ngwLayer.layer.item; } else { const resourceId = ngwLayer.resourceId; item = await this.connector.getResource(resourceId); } if (item) { this.fitResource(item.resource.id); } } } else { super.fitLayer( typeof layerDef === "number" ? String(layerDef) : layerDef, options ); } } async fitResource(resource, options) { const resourceId = await this.connector.resources.getIdOrFail(resource); const extent = await ngwKit.fetchNgwExtent({ resourceId, connector: this.connector }); if (extent) { this.fitBounds(extent, options); } } /** @deprecated use {@link fitLayer} instead */ async zoomToLayer(layerDef) { return this.fitLayer(layerDef); } onLoad(event = "ngw-map:create") { return super.onLoad(event); } removeLayer(layerDef) { const layer = this.getLayer(layerDef); if (layer) { const layerId = this.getLayerId(layer); if (layerId) { delete this._ngwLayers[layerId]; } super.removeLayer(layer); } } enableSelection() { if (!this.$$selectFromNgwRaster) { this.$$selectFromNgwRaster = (ev) => { const count = this._getSelectListenersCount(); if (count) { this.selectFromNgwRaster(ev); } }; this.$$selectFromNgwVector = (ev) => { const count = this._getSelectListenersCount(); if (count) { this._selectFromNgwVector(ev); } }; this.emitter.on("click", this.$$selectFromNgwRaster); this.emitter.on("layer:click", this.$$selectFromNgwVector); } } disableSelection() { if (this.$$selectFromNgwRaster) { this.emitter.removeListener("click", this.$$selectFromNgwRaster); this.$$selectFromNgwRaster = void 0; } if (this.$$selectFromNgwVector) { this.emitter.removeListener("layer:click", this.$$selectFromNgwVector); this.$$selectFromNgwVector = void 0; } } /** * @deprecated use {@link fetchNgwLayerItem} instead */ getNgwLayerItem(options) { return this.fetchNgwLayerItem(options); } /** * @deprecated use {@link fetchNgwLayerItems} instead */ getNgwLayerItems(options) { return this.fetchNgwLayerItems(options); } /** * @deprecated use {@link fetchNgwLayerFeature} instead */ getNgwLayerFeature(options) { return this.fetchNgwLayerFeature(options); } /** * @deprecated use {@link fetchNgwLayerFeatures} instead */ getNgwLayerFeatures(options) { return this.fetchNgwLayerFeatures(options); } /** @deprecated use {@link cancelPromises} instead */ cancelPromise(...args) { this.cancelPromises(...args); } cancelPromises(...args) { if (!args.length) { args = Object.keys(this._promises); } args.forEach((name) => { const group = this._promises[name]; if (group) { group.forEach((x) => x[1].abort()); this._promises[name] = []; } }); } async selectFromNgwRaster(ev) { var _a; this._emitStatusEvent("ngw:preselect"); const promises = []; const layers = Object.values(this._ngwLayers); layers.sort((a, b) => { if (a.layer.order && b.layer.order) { return b.layer.order - a.layer.order; } return 1; }); for (const l of layers) { const layer = l.layer; const identFunc = typeof layer.getIdentificationIds === "function" ? layer.getIdentificationIds : false; const interactive = (_a = layer.options.interactive) != null ? _a : true; if (identFunc && layer.options.selectable && interactive && this.isLayerVisible(layer)) { const layerIds = identFunc.call(layer); promises.push(layerIds); } } const getIdsPromise = Promise.all(promises); const getIds = await getIdsPromise; const ids = []; for (const x of getIds) { if (x) { ids.push(...x); } } if (!ids.length) { this._emitStatusEvent("ngw:select", null); return; } const pixelRadius = this.options.pixelRadius || 10; const center = this.getCenter(); let zoom = this.getZoom(); zoom = zoom !== void 0 ? zoom : 20; if (!center || !zoom) { this._emitStatusEvent("ngw:select", null); return; } const radius = utils.getIdentifyRadius(center, zoom, pixelRadius); let geom; if (this.options.highlightIdentification) { const highlightOptions = this.options.highlightIdentification; const highlightDuration = typeof highlightOptions === "number" ? highlightOptions : 1e3; const [lng, lat] = ev.lngLat; geom = { type: "Polygon", coordinates: [utils.getCirclePolygonCoordinates(lng, lat, radius)] }; const highlightIdentificationLayer = await this.addGeoJsonLayer({ data: { type: "Feature", geometry: geom } }); if (highlightDuration !== Infinity) { setTimeout(() => { this.removeLayer(highlightIdentificationLayer); }, highlightDuration); } } const abortController = new AbortController(); const selectPromise = ngwKit.sendIdentifyRequest(ev, { layers: ids, connector: this.connector, radius, geom, signal: abortController.signal }).then((resp) => { const identify = { ...resp, resources: ids, sourceType: "raster", event: ev }; const identifyEvent = this._prepareToIdentify(identify); this._emitStatusEvent("ngw:select", identifyEvent); return identifyEvent; }); this._addPromise("select", selectPromise, abortController); return selectPromise; } _addPromise(groupName, promise, abortController) { const group = this._promises[groupName]; if (group && group.findIndex((g) => g[0] === promise) === -1) { const removeFromGroup = () => { const index = group.findIndex((g) => g[0] === promise); if (index !== -1) { group.splice(index, 1); } }; promise.then(removeFromGroup, removeFromGroup); group.push([promise, abortController]); } } _isFitFromResource() { const params = this._initMapState; if (params.zoom && params.center) { return false; } return true; } async _createWebMap() { await this.create(); if (this.options.qmsId) { this._addQmsBaseLayer(); } if (this.options.osm) { this._addOsmBaseLayer(); } const resources = []; const layerFitAllowed = this._isFitFromResource(); if (this.options.webmapId) { appendNgwResources(resources, this.options.webmapId, { fit: layerFitAllowed }); } if (this.options.resources && Array.isArray(this.options.resources)) { for (const x of this.options.resources) { const overwriteOptions = {}; if (!layerFitAllowed) { overwriteOptions.fit = false; } appendNgwResources(resources, x, {}, overwriteOptions); } } for (const r of resources) { try { await this.addNgwLayer(r); } catch (er) { console.warn(er); } } this._emitStatusEvent("ngw-map:create", this); this.enableSelection(); } _addOsmBaseLayer() { this.addBaseLayer("OSM"); } _addQmsBaseLayer() { let qmsId; let qmsLayerName; if (Array.isArray(this.options.qmsId)) { qmsId = this.options.qmsId[0]; qmsLayerName = this.options.qmsId[1]; } else { qmsId = Number(this.options.qmsId); } const qmsLayerOptions = { qmsId }; if (qmsLayerName) { qmsLayerOptions.id = qmsLayerName; } this.addBaseLayer("QMS", qmsLayerOptions); } _selectFromNgwVector(ev) { const layer = ev.layer; const selectable = layer.options.selectable && this.isLayerVisible(layer); if (!selectable) { return void 0; } const id = layer.item && layer.item.resource.id; const feature = ev.feature; if (id !== void 0 && feature) { const featureId = feature.id; if (featureId) { const identifyFeature = { id: Number(featureId), fields: feature.properties || {}, label: `#${id}`, layerId: Number(id), parent: "", geom: feature.geometry }; const items = { featureCount: 1, features: [identifyFeature] }; const identify = { featureCount: 1, [id]: items }; this._emitStatusEvent( "ngw:select", this._prepareToIdentify({ ...identify, resources: [id], sourceType: "vector" }) ); return identify; } } } _prepareToIdentify(identify) { const getIdentifyItems_ = () => { return ngwKit.getIdentifyItems(identify, true).map((x) => { return ngwKit.createIdentifyItem({ feature: x.feature, connector: this.connector }); }); }; return { ...identify, getIdentifyItems: getIdentifyItems_ }; } _getSelectListenersCount() { return this.emitter.listenerCount("ngw:select"); } async _whiteLabel() { const container = this.getContainer(); if (container) { const logo = await ngwKit.getCompanyLogo( this.connector, this.options.companyLogoOptions ); if (logo) { container.appendChild(logo); } } } } __publicField(NgwMap, "getIcon", icons.getIcon); async function createNgwMap(options) { const ngwMap = new NgwMap(options); return ngwMap.onLoad(); } exports.NgwMap = NgwMap; exports.createNgwMap = createNgwMap; Object.keys(webmap).forEach(function (k) { if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) exports[k] = webmap[k]; }); //# sourceMappingURL=ngw-map.cjs.js.map