@nextgis/ngw-map
Version:
787 lines (781 loc) • 25.4 kB
JavaScript
/** 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