UNPKG

@nextgis/ngw-map

Version:
787 lines (781 loc) 25.4 kB
/** Bundle of @nextgis/ngw-map; version: 3.0.1; author: NextGIS */ import { getIcon } from '@nextgis/icons'; import NgwConnector from '@nextgis/ngw-connector'; import { NgwKit, fetchNgwLayerItem, fetchNgwLayerItems, fetchNgwLayerFeature, fetchNgwLayerFeatureCollection, fetchIdentifyItem, fetchIdentifyGeoJson, createNgwLayerAdapter, fetchNgwExtent, sendIdentifyRequest, getCompanyLogo, getIdentifyItems, createIdentifyItem } from '@nextgis/ngw-kit'; import { deepmerge, deprecatedWarn, defined, isObject, getIdentifyRadius, getCirclePolygonCoordinates } from '@nextgis/utils'; import { getDefaultControls, WebMap } from '@nextgis/webmap'; export * from '@nextgis/webmap'; import { EventEmitter } from 'events'; import { QmsKit } from '@nextgis/qms-kit'; var __defProp$2 = Object.defineProperty; var __defProps$2 = Object.defineProperties; var __getOwnPropDescs$2 = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols$2 = Object.getOwnPropertySymbols; var __hasOwnProp$2 = Object.prototype.hasOwnProperty; var __propIsEnum$2 = Object.prototype.propertyIsEnumerable; var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues$2 = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp$2.call(b, prop)) __defNormalProp$2(a, prop, b[prop]); if (__getOwnPropSymbols$2) for (var prop of __getOwnPropSymbols$2(b)) { if (__propIsEnum$2.call(b, prop)) __defNormalProp$2(a, prop, b[prop]); } return a; }; var __spreadProps$2 = (a, b) => __defProps$2(a, __getOwnPropDescs$2(b)); function appendNgwResources(options, resource, defOptions, overwriteOptions) { if (typeof resource === "number" || typeof resource === "string") { resource = Number(resource); options.push(__spreadProps$2(__spreadValues$2({}, defOptions), { resource })); } else if (Array.isArray(resource)) { const [resourceId, id] = resource; options.push(__spreadValues$2(__spreadProps$2(__spreadValues$2({}, defOptions), { resource: resourceId, id }), overwriteOptions)); } else if (typeof resource === "object") { options.push(__spreadValues$2(__spreadValues$2(__spreadValues$2({}, defOptions), resource), overwriteOptions)); } } var __defProp$1 = Object.defineProperty; var __defProps$1 = Object.defineProperties; var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols; var __hasOwnProp$1 = Object.prototype.hasOwnProperty; var __propIsEnum$1 = Object.prototype.propertyIsEnumerable; var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues$1 = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp$1.call(b, prop)) __defNormalProp$1(a, prop, b[prop]); if (__getOwnPropSymbols$1) for (var prop of __getOwnPropSymbols$1(b)) { if (__propIsEnum$1.call(b, prop)) __defNormalProp$1(a, prop, b[prop]); } return a; }; var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b)); const OPTIONS = { target: "map", baseUrl: "", whitlabel: false, controls: 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()]; 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 = deepmerge(OPTIONS, options); if (!options.center && !options.bounds) { options.bounds = [-179, -90, 180, 90]; } if (options.connector) { kits.push( new NgwKit({ connector: options.connector, auth: options.auth }) ); } options = __spreadProps$1(__spreadValues$1({}, options), { starterKits: kits, create: false }); return options; } var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __reflectGet = Reflect.get; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); var __superGet = (cls, obj, key) => __reflectGet(__getProtoOf(cls), key, obj); var __async$1 = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; const _NgwMap = class _NgwMap extends WebMap { constructor(options) { super(prepareWebMapOptions(options)); __publicField(this, "emitter", new 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') * ``` */ addControl(controlDef, position, options) { return __async$1(this, null, function* () { yield this.onLoad("controls:create"); return __superGet(_NgwMap.prototype, this, "addControl").call(this, 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' } } * }); * ``` */ addNgwLayer(options) { return __async$1(this, null, function* () { yield this.onMapLoad(); const { keyname, resourceId } = options; if (keyname || resourceId !== void 0) { 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 (defined(this.options.baseUrl)) { try { if (defined(this.options.setViewDelay)) { options.adapterOptions = options.adapterOptions || {}; if (!defined(options.adapterOptions.setViewDelay)) { options.adapterOptions.setViewDelay = this.options.setViewDelay; } } const adapter = createNgwLayerAdapter(options, this, this.connector); const adapterOpts = __spreadValues(__spreadValues({ visibility: true }, options), options.adapterOptions); const layer = yield 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 = 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 fetchNgwLayerItem(__spreadValues({ connector: this.connector }, options)); } fetchNgwLayerItems(options) { return fetchNgwLayerItems(__spreadValues({ connector: this.connector }, options)); } fetchNgwLayerFeature(options) { return fetchNgwLayerFeature(__spreadValues({ connector: this.connector }, options)); } fetchNgwLayerFeatures(options) { return fetchNgwLayerFeatureCollection(__spreadValues({ 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 = 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 = 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 }); } getNgwLayers() { return __async$1(this, null, function* () { yield this.onLoad(); return this._ngwLayers; }); } getNgwLayerByResourceId(id) { return __async$1(this, null, function* () { 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 = yield 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'); * ``` */ fitLayer(layerDef, options) { return __async$1(this, null, function* () { 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 = yield 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 = yield this.connector.getResource(resourceId); } if (item) { this.fitResource(item.resource.id); } } } else { __superGet(_NgwMap.prototype, this, "fitLayer").call( this, typeof layerDef === "number" ? String(layerDef) : layerDef, options ); } }); } fitResource(resource, options) { return __async$1(this, null, function* () { const resourceId = yield this.connector.resources.getIdOrFail(resource); const extent = yield fetchNgwExtent({ resourceId, connector: this.connector }); if (extent) { this.fitBounds(extent, options); } }); } /** @deprecated use {@link fitLayer} instead */ zoomToLayer(layerDef) { return __async$1(this, null, function* () { 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] = []; } }); } selectFromNgwRaster(ev) { return __async$1(this, null, function* () { 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 = yield 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 = 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: [getCirclePolygonCoordinates(lng, lat, radius)] }; const highlightIdentificationLayer = yield this.addGeoJsonLayer({ data: { type: "Feature", geometry: geom } }); if (highlightDuration !== Infinity) { setTimeout(() => { this.removeLayer(highlightIdentificationLayer); }, highlightDuration); } } const abortController = new AbortController(); const selectPromise = sendIdentifyRequest(ev, { layers: ids, connector: this.connector, radius, geom, signal: abortController.signal }).then((resp) => { const identify = __spreadProps(__spreadValues({}, 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; } _createWebMap() { return __async$1(this, null, function* () { yield 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 { yield 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(__spreadProps(__spreadValues({}, identify), { resources: [id], sourceType: "vector" })) ); return identify; } } } _prepareToIdentify(identify) { const getIdentifyItems_ = () => { return getIdentifyItems(identify, true).map((x) => { return createIdentifyItem({ feature: x.feature, connector: this.connector }); }); }; return __spreadProps(__spreadValues({}, identify), { getIdentifyItems: getIdentifyItems_ }); } _getSelectListenersCount() { return this.emitter.listenerCount("ngw:select"); } _whiteLabel() { return __async$1(this, null, function* () { const container = this.getContainer(); if (container) { const logo = yield getCompanyLogo( this.connector, this.options.companyLogoOptions ); if (logo) { container.appendChild(logo); } } }); } }; __publicField(_NgwMap, "getIcon", getIcon); let NgwMap = _NgwMap; var __async = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; function createNgwMap(options) { return __async(this, null, function* () { const ngwMap = new NgwMap(options); return ngwMap.onLoad(); }); } export { NgwMap, createNgwMap }; //# sourceMappingURL=ngw-map.esm-bundler.js.map