// 引入OpenLayers的主模块 import Map from 'ol/Map'; import View from 'ol/View'; import Feature from 'ol/Feature'; import Point from 'ol/geom/Point'; import VectorLayer from 'ol/layer/Vector'; import VectorSource from 'ol/source/Vector'; import Style from 'ol/style/Style'; import Icon from 'ol/style/Icon'; import Text from 'ol/style/Text'; import Projection from 'ol/proj/Projection'; import { getWidth, getTopLeft } from 'ol/extent'; import TileLayer from 'ol/layer/Tile'; import WMTS from 'ol/source/WMTS'; import WMTSTileGrid from 'ol/tilegrid/WMTS'; import WMTSCapabilities from 'ol/format/WMTSCapabilities'; import { Fill, Stroke } from 'ol/style'; import proj4 from 'proj4'; import { register } from 'ol/proj/proj4'; import { defaults } from 'ol/control'; import Vector from 'ol/layer/Vector'; import SourceVector from 'ol/source/Vector'; import GeoJSON from 'ol/format/GeoJSON'; import { fromLonLat } from 'ol/proj'; import axios from 'axios'; import { fromExtent } from 'ol/geom/Polygon'; import { LinearRing, Polygon } from 'ol/geom'; import { Tile } from 'ol'; import {Graticule} from "ol/layer"; import { mergeGeoJsonPolygons } from '@/utils/gisUtils'; // import olPlot from 'ol-plot'; // import { activate } from '../ol-plot/ol-plot' const commonUrl = import.meta.env.VITE_APP_BASE_API2 + 'api/oneShare/proxyHandler/gd/'; // proj4.defs('EPSG:4490', '+proj=longlat +ellps=GRS80 +no_defs +type=crs'); proj4.defs('EPSG:4490', 'GEOGCS["China Geodetic Coordinate System 2000",DATUM["China_2000",SPHEROID["CGCS2000",6378137,298.257222101,AUTHORITY["EPSG","1024"]],AUTHORITY["EPSG","1043"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4490"]]'); // proj4.defs('EPSG:4525', '+proj=tmerc +lat_0=0 +lon_0=111 +k=1 +x_0=37500000 +y_0=0 +ellps=GRS80 +units=m +no_defs +type=crs'); register(proj4); const projection = new Projection({ code: 'EPSG:4490', units: 'degrees', axisOrientation: 'neu' }); projection.setExtent([-180, -90, 180, 90]) projection.setWorldExtent([-180, -90, 180, 90]) const projectionExtent = [-180, -90, 180, 90]; const size = getWidth(projectionExtent) / 256; const resolutions = []; for (let z = 2; z < 22; ++z) { resolutions[z] = size / Math.pow(2, z); } export class olMap { private map; private options; private markers = []; private drawOptions = { graphicsType: 'circle', strokeColor: '#f80102', strokeOpacity: 1, strokeWeight: 2, fillColor: '#f80102', fillOpacity: 0, strokeStyle: 'solid' }; // private { currentState, commit, undo, history, future } = useHistory(); private overlays = []; private overlaysData = []; private graphicsType = ''; private plot; private vectorLayer; private maskLayer; private maskLayer2 = []; constructor(options) { this.options = options; this.map = new Map({ controls: defaults({ zoom: false, rotate: false }), layers: [], target: options.dom, view: new View({ center: options.center && options.center.length === 2 ? [options.center[0], options.center[1]] : [110.90153121597234, 21.98323671981171], zoom: options.zoom ? options.zoom : 9.6, projection: projection, maxZoom: options.maxZoom ? options.maxZoom : 18, minZoom: options.minZoom ? options.minZoom : 1 }) }); // 初始化比例尺 if (options.showScale) { // this.map.addControl(new AMap.Scale()); } if (options.drawTool?.use) { this.initMouseTool(options.drawTool); } this.initLayer(options); } async initLayer(options) { // 添加新的图层 if (Array.isArray(options.id)) { for (const layer of options.id) { if (typeof layer === "string") { await this.formatXml(layer); // 等待当前 layer 处理完成 } else { await this.formatXml(layer.id, layer.minZoom, layer.maxZoom, layer.zIndex, layer.visible); // 等待当前 layer 处理完成 } } } else if (options.id) { // 如果 options.id 不是数组,但确实是一个图层,则直接处理 await this.formatXml(options.id, options.minZoom, options.maxZoom, options.zIndex, options.visible); } // 创建Vector层并添加到地图上 this.vectorLayer = new VectorLayer({ source: new VectorSource({ features: [] }) }); this.map.addLayer(this.vectorLayer); if (typeof this.options.onLoadCompleted === 'function') { this.options.onLoadCompleted(this.map); } } formatXml(code: string, minZoom?: number, maxZoom?: number, zIndex?: number, visible?: boolean) { const xml = new WMTSCapabilities(); return this.getCapabilities(code).then((lists) => { const geojson = xml.read(lists.data); const data = geojson.Contents.Layer[0]; const layerParam = { layerName: data.Abstract, styleName: data.Identifier, tilematrixset: data.TileMatrixSetLink[0].TileMatrixSet, format: data.Format[0] }; this.createWmsLayer(code, layerParam, minZoom, maxZoom, zIndex, visible); }); } // 请求接口获取地图信息 getCapabilities(code) { return axios.get(commonUrl + code + '?SERVICE=WMTS&REQUEST=GetCapabilities'); } // 请求地图图片加载图层 createWmsLayer(code, layerParam, minZoom = 0, maxZoom, zIndex = -1, visible = true) { const source = new WMTS({ url: commonUrl + code, crossOrigin: 'Anonymous', layer: layerParam.layerName, style: layerParam.styleName, matrixSet: layerParam.tilematrixset, format: layerParam.format, wrapX: true, tileGrid: new WMTSTileGrid({ origin: getTopLeft(projectionExtent), resolutions: resolutions, matrixIds: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21'] }) }); const layer = new TileLayer({ name: code, source: source, zIndex: zIndex, minZoom: minZoom, maxZoom, visible: visible }); layer.set('layerName', code); this.map.addLayer(layer); } // 初始化绘画工具 initMouseTool(options) { this.drawOptions = { graphicsType: options.graphicsType ? options.graphicsType : 'cirlce', strokeColor: options.color, strokeOpacity: 1, strokeWeight: 2, fillColor: options.color, fillOpacity: options.drawType === '1' ? 0 : 0.5, strokeStyle: 'solid' }; // this.plot = new olPlot(this.map, { // zoomToExtent: true, // ...this.drawOptions // }); // this.plot.plotDraw.on('drawEnd', this.onDrawEnd.bind(this)); } // 绘制结束事件 onDrawEnd(event) { const feature = event.feature; const aa = feature.getGeometry(); // 继续编辑编辑 this.drawGraphics(this.drawOptions.graphicsType); } // 绘制图形 drawGraphics(type: string) { if (type === 'circle') { // 绘制圆形 // activate('Circle'); } else if (type === 'rectangle') { // 绘制矩形 this.plot.plotDraw.activate('RectAngle'); } else if (type === 'polygon') { // 绘制多边形 this.plot.plotDraw.activate('Polygon'); } else if (type === 'freePolygon') { // 绘制索套 this.plot.plotDraw.activate('FreePolygon'); } } // 关闭绘制 closeDraw() { this.plot.plotDraw.deactivate(); } // 切换图层 async replaceLayers(newLayers, loadendFunc) { // 遍历当前的所有图层并移除它们 this.map.getLayers().forEach((layer) => { this.map.removeLayer(layer); }); if (Array.isArray(newLayers)) { for (const layer of newLayers) { if (typeof layer === "string") { await this.formatXml(layer); // 等待当前 layer 处理完成 } else { await this.formatXml(layer.id, layer.minZoom, layer.maxZoom, layer.zIndex, layer.visible); // 等待当前 layer 处理完成 } } } else { // 如果 options.id 不是数组,但确实是一个图层,则直接处理 await this.formatXml(newLayers.id, newLayers.minZoom, newLayers.maxZoom, newLayers.zIndex, newLayers.visible); } // 创建Vector层并添加到地图上 this.vectorLayer = new VectorLayer({ source: new VectorSource({ features: [] }) }); this.map.addLayer(this.vectorLayer); const point = JSON.parse(JSON.stringify(this.markers)); this.markers = []; this.addMarker(point); if (loadendFunc) { loadendFunc(); } } addMarker(points) { this.clearMarker('point'); points.forEach((point) => { // 创建标注点 const feature = new Feature({ geometry: new Point(point.lnglat), name: point.name }); // 定义样式 const style = new Style({ image: new Icon({ anchor: [0.5, point.size[1]], anchorXUnits: 'fraction', anchorYUnits: 'pixels', src: point.icon }), text: new Text({ text: point.name, fill: new Fill({ color: '#000' }), stroke: new Stroke({ color: '#fff', width: 3 }) }) }); feature.setStyle(style); this.markers.push(point); this.vectorLayer.getSource().addFeature(feature); }); } // 清除所有标加 clearMarker(id) { if (!this.vectorLayer) return; this.vectorLayer.getSource().clear(); } /** * * @param {Geojon} chaozhou 根据geojson对象创建Featrue对象 * @returns VectorLayer */ createVecByJson(json, options) { const format = new GeoJSON(); const fs = format.readFeatures(json); this.maskLayer = new VectorLayer({ source: new VectorSource(), style: new Style({ fill: new Fill({ color: options.fillColor ? options.fillColor : 'rgba(16, 36, 59, 0.65)' }), stroke: new Stroke({ color: options.strokeColor ? options.strokeColor : 'rgba(38, 138, 185, 1)', width: 2 }) }), zIndex: options.zIndex ? options.zIndex : 99 }); this.map.addLayer(this.maskLayer); const extent = [-180, -90, 180, 90]; const polygonRing = fromExtent(extent); fs.forEach((x) => { const ft = x.values_.geometry; const coords = ft.getCoordinates(); coords.forEach((coord) => { const linearRing = new LinearRing(coord[0]); polygonRing.appendLinearRing(linearRing); }); }); const convertFt = new Feature({ geometry: polygonRing }); this.maskLayer.getSource().addFeature(convertFt); } createVecByJson2(json, options) { if (this.maskLayer2 && this.maskLayer2.length > 0) { this.maskLayer2.forEach((layer) => { this.map.addLayer(layer); }); } else { // const layer = new VectorLayer({ // source: new VectorSource(), // style: new Style({ // fill: new Fill({ // color: options.fillColor ? options.fillColor : 'rgba(16, 36, 59, 0.65)' // }), // stroke: new Stroke({ // color: options.strokeColor ? options.strokeColor : 'rgba(38, 138, 185, 1)', // width: 2 // }) // }), // zIndex: options.zIndex ? options.zIndex : 99 // }); // // 合并区边界 // const format = new GeoJSON(); // const data2 = mergeGeoJsonPolygons(json); // const fs = format.readFeatures(data2); // const extent = [-180, -90, 180, 90]; // const polygonRing = fromExtent(extent); // fs.forEach((x) => { // const ft = x.values_.geometry; // const coords = ft.getCoordinates(); // coords.forEach((coord) => { // const linearRing = new LinearRing(coord[0]); // polygonRing.appendLinearRing(linearRing); // }); // }); // const convertFt = new Feature({ // geometry: polygonRing // }); // layer.getSource().addFeature(convertFt); // this.maskLayer2.push(layer); // this.map.addLayer(layer); // 边界部分 json.features.forEach((feature) => { if (feature.geometry.type === 'Polygon') { const polygonPath = feature.geometry.coordinates[0].map((coord) => { return [coord[0], coord[1]]; }); const feature2 = new Feature({ geometry: new Polygon([polygonPath]) }); const vector = new VectorLayer({ source: new VectorSource(), style: new Style({ fill: new Fill({ color: 'rgba(0, 0, 0, 0)' }), stroke: new Stroke({ color: options.strokeColor ? options.strokeColor : '#268ab9', width: options.strokeWeight ? options.strokeWeight : 1 }) }) }); vector.getSource().addFeature(feature2); this.maskLayer2.push(vector); this.map.addLayer(vector); } else if (feature.geometry.type === 'MultiPolygon') { feature.geometry.coordinates.forEach((polygonCoords) => { const polygonPath = polygonCoords.map((ring) => { return ring.map((coord) => { return [coord[0], coord[1]]; }); }); const outerPath = polygonPath; const feature2 = new Feature({ geometry: new Polygon(outerPath), }); const vector = new VectorLayer({ source: new VectorSource(), style: new Style({ fill: new Fill({ color: 'rgba(0, 0, 0, 0)' }), stroke: new Stroke({ color: options.strokeColor ? options.strokeColor : '#268ab9', width: options.strokeWeight ? options.strokeWeight : 1 }) }) }); vector.getSource().addFeature(feature2); this.maskLayer2.push(vector); this.map.addLayer(vector); }); } }); } } /** * @description 创建矢量图层 * @param {String} layerName 图层名称 * @param {Number} zIndex 地图层级默认是0 * @returns */ createVecLayer(layerName = '', zIndex = 0) { const source = new SourceVector({ crossOrigin: 'anonymous' }); const layer = new Vector({ source, zIndex }); layer.set('layerName', layerName); return layer; } // 分布图遮罩层 createMask(data) { this.removeMask(); if (!data || data.length === 0) return; data.forEach((item) => { if (!item.points || item.points.length === 0) return; // 遮罩图层的样式 const maskStyle = new Style({ fill: new Fill({ color: item.color // 红色遮罩,50%透明度 }), stroke: new Stroke({ color: 'rgba(159,159,159,0.7)', width: 1 }) }); // 遮罩图层的矢量数据源(初始为空) const maskSource = new VectorSource(); // 创建一个多边形特征 const polygonFeature = new Feature({ geometry: new Polygon(item.points) }); const maskLayer = new VectorLayer({ source: maskSource, style: maskStyle, properties: { name: 'mask' } }); this.map.addLayer(maskLayer); // 将多边形特征添加到遮罩数据源中 maskSource.addFeature(polygonFeature); }); } removeMask() { //移除图层 const layersArray = this.map.getLayers().getArray(); layersArray.forEach((layer) => { // 检查图层是否有自定义属性,并且该属性是否匹配你要移除的图层的标识符 if (layer.get('name') === 'mask') { this.map.removeLayer(layer); } }); } removeMask2() { if (this.maskLayer) { this.map.removeLayer(this.maskLayer); this.maskLayer = null; } } removeMask3(isHide) { if (this.maskLayer2 && this.maskLayer2.length > 0) { this.maskLayer2.forEach((layer) => { this.map.removeLayer(layer); }); if (!isHide) { this.maskLayer2 = []; } } } /** * 绘制经纬线 * visible: boolean 是否可见 */ handleLngLatLine(visible: boolean) { // 创建经纬网图层 const graticule = new Graticule({ name: 'Graticule', showLabels: true, // 为每条刻度线绘制一个带有各自纬度/经度的标签 wrapX: false, // 是否水平重复经纬网 targetSize: 230, zIndex: 99999, strokeStyle: new Stroke({ // 用于绘制刻度线的样式 color: '#dcdcdc', // 线条颜色 width: 1, // 线条宽度 }), lonLabelStyle: new Text({ font: '12px Calibri,sans-serif', textBaseline: 'bottom', fill: new Fill({ color: '#9d9d9d' }) }), latLabelPosition: 0, latLabelStyle: new Text({ font: '12px Calibri,sans-serif', textAlign: 'left', textBaseline: 'end', fill: new Fill({ color: '#9d9d9d' }) }) }); if (visible) { this.map.addLayer(graticule) } else { this.removeLayer('Graticule') } } /** * 移除指定name的layer * layerName: string * */ removeLayer(layerName: string) { const layers = this.map.getLayers(); layers.forEach((element) => { if (!!element && element.get('name') === layerName) { //移除 this.map.removeLayer(element); } }); } }