UNPKG

@ciniki/iclient-maplibregl

Version:

@supermapgis/iclient-maplibregl 是一套基于 Maplibre GL 的云 GIS 网络客户端开发平台, 支持访问 SuperMap iServer / iEdge / iPortal / iManager / Online 的地图、服务和资源,为用户提供了完整专业的 GIS 能力, 同时提供了优秀的可视化功能。

196 lines (188 loc) 6.84 kB
/* Copyright© 2000 - 2025 SuperMap Software Co.Ltd. All rights reserved. * This program are made available under the terms of the Apache License, Version 2.0 * which accompanies this distribution and is available at http://www.apache.org/licenses/LICENSE-2.0.html.*/ /** * reference and modification * dereklieu/cool-grid, cloudybay/leaflet.latlng-graticule * (https://github.com/dereklieu/cool-grid, https://github.com/cloudybay/leaflet.latlng-graticule) * Apache Licene 2.0 * thanks dereklieu, cloudybay */ import { Util as CommonUtil } from '@ciniki/iclient-common/commontypes/Util'; import { getIntersection } from '@ciniki/iclient-common/util/MapCalculateUtil'; import { FGBLayerRenderer } from '@ciniki/iclient-common/overlay/fgb/FGBLayerRenderer'; /** * @class FGBLayer * @category Visualization FGB * @classdesc FGB 图层类。该图层把 {@link FlatGeobuf} 格式解析为点线面要素。 * FlatGeobuf(FGB)是一种用于存储地理要素的坐标、类型的二进制编码格式。 * FGB 格式与传统的 Shapefile、GeoJSON 等文件格式类似,支持地理空间矢量数据的存储,但 FGB 格式具有更高的存储效率和更快的读写速度, * 适用于大量静态数据的编码与传输。 * @version 11.1.0 * @modulecategory Overlay * @param {Object} options - 参数。 * @param {string} [options.layerID] - 图层 ID。默认使用 CommonUtil.createUniqueID("FGBlayer_") 创建图层 ID。 * @param {boolean} [options.strategy='bbox'] - 指定加载策略,可选值为 all,bbox。all 为全量加载,bbox 为当前可见范围加载。 * @param {Array} [options.extent] - 加载范围,参数规范为: [minX, minY, maxX, maxY],传递此参数后,图层将使用局部加载。 * @param {function} [options.featureLoader] - 要素自定义方法,接收要素作为参数,需返回要素。 * @param {Object} [options.paint] - 参数内容详见: {@link https://docs.mapbox.com/mapbox-gl-js/style-spec/layers/#paint-property}。 * @param {Object} [options.layout] - 参数内容详见: {@link https://docs.mapbox.com/mapbox-gl-js/style-spec/layers/#layout-property}。 * @param {Object} [options.sourceOptions] - 参数内容详见: {@link mapboxgl.source}。 * @usage */ const PAINT_MAP = { circle: { 'circle-radius': 6, 'circle-color': '#3fb1e3', 'circle-opacity': 1, 'circle-blur': 0, 'circle-translate': [0, 0], 'circle-stroke-width': 0, 'circle-stroke-color': '#000', 'circle-stroke-opacity': 1 }, line: { 'line-opacity': 1, 'line-color': '#3fb1e3', 'line-width': 3, 'line-blur': 1 }, fill: { 'fill-opacity': 0.8, 'fill-color': '#3fb1e3', 'fill-translate': [0, 0], 'fill-antialias': true, 'fill-outline-color': '#3fb1e3' } }; export class FGBLayer { constructor(options = {}) { this.id = options.layerID ? options.layerID : CommonUtil.createUniqueID('FGBLayer_'); this.layerId = this.id + 'outer'; this.sourceId = this.layerId; this.options = options; this.strategy = options.strategy || 'bbox'; this.url = options.url; this.layerType = ''; this.type='custom'; this.renderingMode = '3d'; this.overlay = true; this.extent = options.extent; this._updateFeaturesFn = this._updateFeatures.bind(this); this.interaction = true; this.events = 'all'; } /** * @function FGBLayer.prototype.onAdd * @param {maplibregl.Map} map - MapLibreGL Map 对象。 */ onAdd(map) { this.map = map; let extent = []; if (this.strategy === 'bbox') { const bounds = this.map.getBounds().toArray(); extent = [ bounds[0][0], bounds[0][1], bounds[1][0], bounds[1][1] ]; this.map.on('moveend', this._updateFeaturesFn); } if (this.extent) { const intersectExtent = getIntersection(this.extent, extent); if (intersectExtent && intersectExtent.length) { extent = intersectExtent; } else { extent = this.extent; } } this.renderer = new FGBLayerRenderer(this.options); this._handleFeatures(extent); } /** * @function FGBLayer.prototype.render */ render() { } /** * @function FGBLayer.prototype.onRemove */ onRemove() { if (this.map.getLayer(this.layerId)) { this.map.removeLayer(this.layerId); } this.map.off('moveend', this._updateFeaturesFn); } /** * @function FGBLayer.prototype.on */ on(type, listener) { this.map.on(type, this.layerId, listener); } /** * @function FGBLayer.prototype.off */ off(type, listener) { this.map.off(type, this.layerId, listener); } /** * @function FGBLayer.prototype.once */ once(type, listener) { this.map.once(type, this.layerId, listener); } /** * @function FGBLayer.prototype.moveLayer * @description 设置图层可见性。 * @param {string} layerID - 待插入的图层 ID。 * @param {boolean} [beforeId=true] - 将本图层插入到图层 ID 为layerID 的图层之前。 */ moveLayer(id, beforeId) { this.map.moveLayer(id, beforeId); } /** * @function FGBLayer.prototype.setVisibility * @description 设置图层可见性。 * @param {boolean} [visibility] - 是否显示图层(当前地图的 resolution 在最大最小 resolution 之间)。 */ setVisibility(visibility) { const visible = visibility ? 'visible': 'none'; this.map.setLayoutProperty(this.layerId, 'visibility', visible); } async _handleFeatures(bounds) { let iter = await this.renderer._loadData(bounds); const features = await this.renderer.iterateFeatures(iter); if (!this.map.getSource(this.sourceId)) { this.map.addSource(this.sourceId, { type: 'geojson', data: features }); } else { this.map.getSource(this.sourceId).setData(features); } if (!this.map.getLayer(this.layerId)) { this.layerType = this.renderer.layerType; const layer = Object.assign({ id: this.layerId, type: this.layerType, source: this.sourceId, paint: Object.assign(PAINT_MAP[this.layerType], this.options.paint) || {}, layout: this.options.layout || {} }); this.map.addLayer(layer); } } async _updateFeatures() { const bounds = this.map.getBounds().toArray(); const extentToLoad = [bounds[0][0], bounds[0][1], bounds[1][0], bounds[1][1]]; const alreadyLoaded = this.renderer._forEachInExtent(extentToLoad, (object) => { return this.renderer._containsExtent(object.extent, extentToLoad); }); if (!alreadyLoaded) { let iter = await this.renderer._loadData(extentToLoad); const features = await this.renderer.iterateFeatures(iter); this.map.getSource(this.sourceId).setData(features); } } }