olMap.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. // 引入OpenLayers的主模块
  2. import Map from 'ol/Map';
  3. import View from 'ol/View';
  4. import Feature from 'ol/Feature';
  5. import Point from 'ol/geom/Point';
  6. import VectorLayer from 'ol/layer/Vector';
  7. import VectorSource from 'ol/source/Vector';
  8. import Style from 'ol/style/Style';
  9. import Icon from 'ol/style/Icon';
  10. import Text from 'ol/style/Text';
  11. import Projection from 'ol/proj/Projection';
  12. import { getWidth, getTopLeft } from 'ol/extent';
  13. import TileLayer from 'ol/layer/Tile';
  14. import WMTS from 'ol/source/WMTS';
  15. import WMTSTileGrid from 'ol/tilegrid/WMTS';
  16. import WMTSCapabilities from 'ol/format/WMTSCapabilities';
  17. import { Fill, Stroke } from 'ol/style';
  18. import proj4 from 'proj4';
  19. import { register } from 'ol/proj/proj4';
  20. import { defaults } from 'ol/control';
  21. import Vector from 'ol/layer/Vector';
  22. import SourceVector from 'ol/source/Vector';
  23. import GeoJSON from 'ol/format/GeoJSON';
  24. import { fromLonLat } from 'ol/proj';
  25. import axios from 'axios';
  26. import { fromExtent } from 'ol/geom/Polygon';
  27. import { LinearRing, Polygon } from 'ol/geom';
  28. import { Tile } from 'ol';
  29. // import olPlot from 'ol-plot';
  30. // import { activate } from '../ol-plot/ol-plot'
  31. proj4.defs('EPSG:4490', '+proj=longlat +ellps=GRS80 +no_defs +type=crs');
  32. 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');
  33. register(proj4);
  34. const commonUrl = import.meta.env.VITE_APP_BASE_API2 + 'api/oneShare/proxyHandler/gd/';
  35. const projection = new Projection({
  36. code: 'EPSG:4490',
  37. units: 'degrees'
  38. });
  39. const projectionExtent = [-180, -90, 180, 90];
  40. const size = getWidth(projectionExtent) / 256;
  41. const resolutions = [];
  42. for (let z = 2; z < 22; ++z) {
  43. resolutions[z] = size / Math.pow(2, z);
  44. }
  45. export class olMap {
  46. private map;
  47. private options;
  48. private markers = [];
  49. private drawOptions = {
  50. graphicsType: 'circle',
  51. strokeColor: '#f80102',
  52. strokeOpacity: 1,
  53. strokeWeight: 2,
  54. fillColor: '#f80102',
  55. fillOpacity: 0,
  56. strokeStyle: 'solid'
  57. };
  58. // private { currentState, commit, undo, history, future } = useHistory();
  59. private overlays = [];
  60. private overlaysData = [];
  61. private graphicsType = '';
  62. private plot;
  63. private vectorLayer;
  64. private maskLayer;
  65. constructor(options) {
  66. this.options = options;
  67. this.map = new Map({
  68. controls: defaults({
  69. zoom: false,
  70. rotate: false
  71. }),
  72. layers: [],
  73. target: options.dom,
  74. view: new View({
  75. center: options.center && options.center.length === 2 ? [options.center[0], options.center[1]] : [110.90153121597234, 21.98323671981171],
  76. zoom: options.zoom ? options.zoom : 9.6,
  77. projection: projection,
  78. maxZoom: options.maxZoom ? options.maxZoom : 18,
  79. minZoom: options.minZoom ? options.minZoom : 1
  80. })
  81. });
  82. // 初始化比例尺
  83. if (options.showScale) {
  84. // map.addControl(new AMap.Scale());
  85. }
  86. if (options.drawTool?.use) {
  87. this.initMouseTool(options.drawTool);
  88. }
  89. this.initLayer(options);
  90. }
  91. async initLayer(options) {
  92. // 添加新的图层
  93. if (Array.isArray(options.id)) {
  94. for (const layer of options.id) {
  95. await this.formatXml(layer); // 等待当前 layer 处理完成
  96. }
  97. } else if (options.id) {
  98. // 如果 options.id 不是数组,但确实是一个图层,则直接处理
  99. await this.formatXml(options.id);
  100. }
  101. console.log('wan');
  102. // 创建Vector层并添加到地图上
  103. this.vectorLayer = new VectorLayer({
  104. source: new VectorSource({
  105. features: []
  106. })
  107. });
  108. this.map.addLayer(this.vectorLayer);
  109. if (typeof this.options.onLoadCompleted === 'function') {
  110. this.options.onLoadCompleted(this.map);
  111. }
  112. }
  113. formatXml(code, minZoom, maxZoom, zIndex, visible) {
  114. const xml = new WMTSCapabilities();
  115. // axios.post(commonUrl + 'YZT1723547712680', '<wfs:GetFeature xmlns:wfs="http://www.opengis.net/wfs"service="WFS"version="1.0.0"outputFormat="GeoJson"maxFeatures="99999"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.opengis.net/wfshttp://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd">\n' +
  116. // '<wfs:QuerytypeName="GDSMMSZJGZDTJX_2023"userecent="true"/>\n' +
  117. // '</wfs:GetFeature>');
  118. return this.getCapabilities(code).then((lists) => {
  119. const geojson = xml.read(lists.data);
  120. const data = geojson.Contents.Layer[0];
  121. const layerParam = {
  122. layerName: data.Abstract,
  123. styleName: data.Identifier,
  124. tilematrixset: data.TileMatrixSetLink[0].TileMatrixSet,
  125. format: data.Format[0]
  126. };
  127. this.createWmsLayer(code, layerParam, minZoom, maxZoom, zIndex, visible);
  128. });
  129. }
  130. // 请求接口获取地图信息
  131. getCapabilities(code) {
  132. return axios.get(commonUrl + code + '?SERVICE=WMTS&REQUEST=GetCapabilities');
  133. }
  134. // 请求地图图片加载图层
  135. createWmsLayer(code, layerParam, minZoom = 0, maxZoom, zIndex = -1, visible = true) {
  136. const source = new WMTS({
  137. url: commonUrl + code,
  138. crossOrigin: 'Anonymous',
  139. layer: layerParam.layerName,
  140. style: layerParam.styleName,
  141. matrixSet: layerParam.tilematrixset,
  142. format: layerParam.format,
  143. wrapX: true,
  144. tileGrid: new WMTSTileGrid({
  145. origin: getTopLeft(projectionExtent),
  146. resolutions: resolutions,
  147. matrixIds: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21']
  148. })
  149. });
  150. const layer = new TileLayer({
  151. source: source,
  152. zIndex: zIndex,
  153. minZoom: minZoom,
  154. maxZoom,
  155. visible: visible
  156. });
  157. layer.set('layerName', code);
  158. this.map.addLayer(layer);
  159. console.log(code);
  160. }
  161. // 初始化绘画工具
  162. initMouseTool(options) {
  163. this.drawOptions = {
  164. graphicsType: options.graphicsType ? options.graphicsType : 'cirlce',
  165. strokeColor: options.color,
  166. strokeOpacity: 1,
  167. strokeWeight: 2,
  168. fillColor: options.color,
  169. fillOpacity: options.drawType === '1' ? 0 : 0.5,
  170. strokeStyle: 'solid'
  171. };
  172. // this.plot = new olPlot(this.map, {
  173. // zoomToExtent: true,
  174. // ...this.drawOptions
  175. // });
  176. // this.plot.plotDraw.on('drawEnd', this.onDrawEnd.bind(this));
  177. }
  178. // 绘制结束事件
  179. onDrawEnd(event) {
  180. const feature = event.feature;
  181. const aa = feature.getGeometry();
  182. // 继续编辑编辑
  183. this.drawGraphics(this.drawOptions.graphicsType);
  184. }
  185. // 绘制图形
  186. drawGraphics(type: string) {
  187. if (type === 'circle') {
  188. // 绘制圆形
  189. // activate('Circle');
  190. } else if (type === 'rectangle') {
  191. // 绘制矩形
  192. this.plot.plotDraw.activate('RectAngle');
  193. } else if (type === 'polygon') {
  194. // 绘制多边形
  195. this.plot.plotDraw.activate('Polygon');
  196. } else if (type === 'freePolygon') {
  197. // 绘制索套
  198. this.plot.plotDraw.activate('FreePolygon');
  199. }
  200. }
  201. // 关闭绘制
  202. closeDraw() {
  203. this.plot.plotDraw.deactivate();
  204. }
  205. // 切换图层
  206. async replaceLayers(newLayers) {
  207. // 遍历当前的所有图层并移除它们
  208. this.map.getLayers().forEach((layer) => {
  209. this.map.removeLayer(layer);
  210. });
  211. // 添加新的图层
  212. if (Array.isArray(newLayers)) {
  213. for (const layer of newLayers) {
  214. await this.formatXml(layer); // 等待当前 layer 处理完成
  215. }
  216. } else if (newLayers) {
  217. // 如果 options.id 不是数组,但确实是一个图层,则直接处理
  218. await this.formatXml(newLayers);
  219. }
  220. // 创建Vector层并添加到地图上
  221. this.vectorLayer = new VectorLayer({
  222. source: new VectorSource({
  223. features: []
  224. })
  225. });
  226. this.map.addLayer(this.vectorLayer);
  227. const point = JSON.parse(JSON.stringify(this.markers));
  228. this.markers = [];
  229. this.addMarker(point);
  230. }
  231. addMarker(points) {
  232. this.clearMarker('point');
  233. points.forEach((point) => {
  234. // 创建标注点
  235. const feature = new Feature({
  236. geometry: new Point(point.lnglat),
  237. name: point.name
  238. });
  239. // 定义样式
  240. const style = new Style({
  241. image: new Icon({
  242. anchor: [0.5, point.size[1]],
  243. anchorXUnits: 'fraction',
  244. anchorYUnits: 'pixels',
  245. src: point.icon
  246. }),
  247. text: new Text({
  248. text: point.name,
  249. fill: new Fill({
  250. color: '#000'
  251. }),
  252. stroke: new Stroke({
  253. color: '#fff',
  254. width: 3
  255. })
  256. })
  257. });
  258. feature.setStyle(style);
  259. this.markers.push(point);
  260. this.vectorLayer.getSource().addFeature(feature);
  261. });
  262. }
  263. // 清除所有标加
  264. clearMarker(id) {
  265. if (!this.vectorLayer) return;
  266. this.vectorLayer.getSource().clear();
  267. }
  268. /**
  269. *
  270. * @param {Geojon} chaozhou 根据geojson对象创建Featrue对象
  271. * @param {String} layerName 图层名称
  272. * @returns VectorLayer
  273. */
  274. createVecByJson(json, layerName = '') {
  275. const format = new GeoJSON();
  276. const fs = format.readFeatures(json);
  277. this.removeMask2();
  278. this.maskLayer = new VectorLayer({
  279. source: new VectorSource(),
  280. style: new Style({
  281. fill: new Fill({
  282. color: 'rgba(16, 36, 59, 0.65)'
  283. }),
  284. stroke: new Stroke({
  285. color: 'rgba(38, 138, 185, 1)',
  286. width: 2
  287. })
  288. }),
  289. zIndex: 99
  290. });
  291. this.map.addLayer(this.maskLayer);
  292. const extent = [-180, -90, 180, 90];
  293. const polygonRing = fromExtent(extent);
  294. fs.forEach((x) => {
  295. const ft = x.values_.geometry;
  296. const coords = ft.getCoordinates();
  297. coords.forEach((coord) => {
  298. const linearRing = new LinearRing(coord[0]);
  299. polygonRing.appendLinearRing(linearRing);
  300. });
  301. });
  302. const convertFt = new Feature({
  303. geometry: polygonRing
  304. });
  305. this.maskLayer.getSource().addFeature(convertFt);
  306. }
  307. // 分布图遮罩层
  308. createMask(data) {
  309. this.removeMask();
  310. if (!data || data.length === 0) return;
  311. data.forEach((item) => {
  312. // 遮罩图层的样式
  313. const maskStyle = new Style({
  314. fill: new Fill({
  315. color: item.color // 红色遮罩,50%透明度
  316. }),
  317. stroke: new Stroke({
  318. color: 'rgba(159,159,159,0.7)',
  319. width: 1
  320. })
  321. });
  322. // 遮罩图层的矢量数据源(初始为空)
  323. const maskSource = new VectorSource();
  324. // 创建一个多边形特征
  325. const polygonFeature = new Feature({
  326. geometry: new Polygon(item.points)
  327. });
  328. const maskLayer = new VectorLayer({
  329. source: maskSource,
  330. style: maskStyle,
  331. properties: {
  332. name: 'mask'
  333. }
  334. });
  335. this.map.addLayer(maskLayer);
  336. // 将多边形特征添加到遮罩数据源中
  337. maskSource.addFeature(polygonFeature);
  338. });
  339. }
  340. removeMask() {
  341. //移除图层
  342. const layersArray = this.map.getLayers().getArray();
  343. layersArray.forEach((layer) => {
  344. // 检查图层是否有自定义属性,并且该属性是否匹配你要移除的图层的标识符
  345. if (layer.get('name') === 'mask') {
  346. this.map.removeLayer(layer);
  347. }
  348. });
  349. }
  350. removeMask2() {
  351. if (this.maskLayer) {
  352. this.map.removeLayer(this.maskLayer);
  353. this.maskLayer = null;
  354. }
  355. }
  356. }