olMap.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. import Map from 'ol/Map.js';
  2. import View from 'ol/View.js';
  3. import {
  4. defaults as defaultControls
  5. } from 'ol/control.js';
  6. // 工具类
  7. import {
  8. getWidth,
  9. getTopLeft
  10. } from 'ol/extent.js';
  11. import {
  12. get as getProjection
  13. } from 'ol/proj.js';
  14. import GeoJSON from 'ol/format/GeoJSON';
  15. import WMTSTileGrid from 'ol/tilegrid/WMTS.js';
  16. // layer->source->feature->style
  17. // layer
  18. import {
  19. Vector as VectorLayer,
  20. Tile as TileLayer
  21. } from 'ol/layer';
  22. // source
  23. import {
  24. WMTS
  25. } from 'ol/source';
  26. import VectorSource from 'ol/source/Vector';
  27. // import {
  28. // TileSuperMapRest
  29. // } from '@supermap/iclient-ol';
  30. // feature
  31. import Feature from 'ol/Feature';
  32. import {
  33. Point,
  34. Polygon,
  35. MultiPolygon,
  36. LineString
  37. } from 'ol/geom';
  38. // style
  39. import {
  40. Icon,
  41. Style,
  42. Text,
  43. Fill,
  44. Stroke
  45. } from 'ol/style';
  46. // 弹窗
  47. import Overlay from 'ol/Overlay';
  48. // 选择
  49. import {
  50. Select
  51. } from 'ol/interaction';
  52. export default class olMapClass {
  53. constructor() {
  54. this.popUp = [] //弹窗
  55. this.mapLayers = {} //地图图层
  56. this.layerSelect = {} //图层选择对象
  57. this.center = [] //中心点
  58. this.zoom = 13
  59. }
  60. /**
  61. * @description 初始化地图
  62. * @param {String} domId 地图容器
  63. * @param {Array<Number,Number>} center 中心点经纬度数组
  64. */
  65. initOlMap(domId, center, zoom) {
  66. this.center = center
  67. this.zoom = zoom
  68. window.olMap = new Map({
  69. target: domId,
  70. view: new View({
  71. projection: 'EPSG:4326',
  72. center: center,
  73. zoom: zoom,
  74. maxZoom: 22,
  75. minZoom: 1
  76. }),
  77. controls: defaultControls({
  78. zoom: false,
  79. rotate: false,
  80. attribution: false
  81. })
  82. });
  83. }
  84. /**
  85. * @description 回到原点
  86. */
  87. resetMap() {
  88. window.olMap.getView().setCenter(this.center)
  89. window.olMap.getView().setZoom(this.zoom)
  90. }
  91. /**
  92. * @description 销毁地图
  93. */
  94. destoryOlMap() {
  95. window.olMap && window.olMap.dispose();
  96. window.olMap = null;
  97. }
  98. /**
  99. * @description 创建地图监听事件
  100. * @param {String} type 监听事件类型
  101. * @param {Function} callBack 执行函数
  102. */
  103. initOlMapEvent(type, callBack) {
  104. window.olMap.on(type, (event) => {
  105. callBack(event)
  106. });
  107. }
  108. /**
  109. * @description 注销地图事件, handler必须是创建地图事件时的执行函数
  110. * @param {String} type 监听事件类型
  111. * @param {Function} handler 执行函数
  112. */
  113. destoryOlMapEvent(type, handler) {
  114. window.olMap.un(type, handler)
  115. }
  116. /**
  117. * @description 添加图层选择事件
  118. * @param {Array} layers 需要选择的图层
  119. * @param {String} id 创建的选择器id
  120. * @param {Function} getOption 生成marker配置的函数
  121. * @param {Object} iconOption 图标的配置
  122. * @param {Object} textOption 文字的配置
  123. * @param {Function} callBack 执行函数
  124. */
  125. addLayerSelect(layers, id, getOption, callBack, falied) {
  126. let select = new Select({
  127. layers: layers,
  128. style: (feature) => {
  129. let options = getOption(feature)
  130. feature.setStyle(
  131. new Style({
  132. image: options.icon ? new Icon(options.icon) : null,
  133. text: options.text ? new Text(options.text) : null
  134. })
  135. )
  136. }
  137. })
  138. this.layerSelect[id] = select
  139. window.olMap.addInteraction(select)
  140. // 选择事件
  141. select.on('select', (evt) => {
  142. // 没选中则自动清除已选的feature
  143. if (evt.selected.length === 0) {
  144. select.getFeatures().clear()
  145. if (falied) falied()
  146. return
  147. }
  148. // 选中后执行后续操作
  149. callBack(evt)
  150. })
  151. }
  152. /**
  153. * @description 添加feature到选择器
  154. * @param {String} selectId 选择器id
  155. * @param {Object} feature 要选择的feature
  156. */
  157. _addFeatureToSelect(selectId, feature) {
  158. if (this.layerSelect[selectId]) {
  159. this.layerSelect[selectId].getFeatures().push(feature)
  160. }
  161. }
  162. /**
  163. * @description 从图层中查找对应的feature并添加到选择器
  164. * @param {String} layerTypeName 图层大类名称
  165. * @param {String} layerName 图层名称
  166. * @param {String} featureId 图层中feature的内置id
  167. * @param {String} selectId 选择器id
  168. */
  169. addFeatureToSelectFromLayer(layerTypeName, layerName, featureId, selectId) {
  170. if (!this.mapLayers[layerTypeName]) {
  171. return
  172. }
  173. if (!this.mapLayers[layerTypeName][layerName]) {
  174. return
  175. }
  176. let layer = this.mapLayers[layerTypeName][layerName]
  177. let features = layer.getSource().getFeatures()
  178. features.forEach(feature => {
  179. if (feature.values_.id === featureId) {
  180. this._addFeatureToSelect(selectId, feature)
  181. }
  182. })
  183. }
  184. /**
  185. * @description 添加地图图层(天地图、超图)
  186. * @param {String} layerTypeName 图层大类名称
  187. * @param {String} layerName 图层名称, 用作控制显示隐藏
  188. * @param {String} type 图层类型, 用来判断添加方法 tdt:天地图, super:超图
  189. * @param {String} url 地图url
  190. * @param {Boolean} show 是否显示
  191. */
  192. addMapLayers(layerTypeName, layerName, type, url, show) {
  193. if (!url) {
  194. return
  195. }
  196. let layer = null
  197. if (type === 'tdt') {
  198. layer = this._addWmtsLayer(url)
  199. }
  200. if (type === 'super') {
  201. // layer = this._addSuperMapLayer(url)
  202. }
  203. layer.setVisible(show)
  204. // 第一次出现图层大类
  205. if (!this.mapLayers[layerTypeName]) {
  206. this.mapLayers[layerTypeName] = {}
  207. this.mapLayers[layerTypeName][layerName] = layer
  208. } else {
  209. this.mapLayers[layerTypeName][layerName] = layer
  210. }
  211. window.olMap.addLayer(layer)
  212. }
  213. /**
  214. * @description 添加marker、高亮图层等
  215. * @param {String} layerTypeName 图层大类名称
  216. * @param {String} layerName 图层名称, 用作控制显示隐藏
  217. * @param {Boolean} show 是否显示
  218. * @param {Array<any>} dataList 用于创建图层的原始数据
  219. * @param {Boolean} ifSource 是否需要添加source
  220. * @param {Object} iconOption 图标的配置
  221. * @param {Object} textOption 文字的配置
  222. */
  223. addVectorLayers(layerTypeName, layerName, show, dataList, ifSource, iconOption, textOption) {
  224. let vectorSource = new VectorSource({});
  225. // 需要source才循环添加
  226. if (ifSource) {
  227. dataList.map((marker, index) => {
  228. let iconFeature = new Feature({
  229. geometry: new Point([marker.longitude, marker.latitude]),
  230. name: marker.name + '-' + index,
  231. id: marker.id,
  232. population: 4000,
  233. rainfall: 500,
  234. position: [marker.longitude, marker.latitude],
  235. ...marker
  236. });
  237. let iconStyle = new Style({
  238. image: iconOption ? new Icon(iconOption) : null,
  239. text: textOption ? new Text(textOption) : null
  240. });
  241. iconFeature.setStyle(iconStyle);
  242. vectorSource.addFeature(iconFeature)
  243. })
  244. }
  245. let layer = new VectorLayer({
  246. source: vectorSource
  247. });
  248. layer.setVisible(show)
  249. // 第一次出现图层大类
  250. if (!this.mapLayers[layerTypeName]) {
  251. this.mapLayers[layerTypeName] = {}
  252. this.mapLayers[layerTypeName][layerName] = layer
  253. } else {
  254. this.mapLayers[layerTypeName][layerName] = layer
  255. }
  256. window.olMap.addLayer(layer)
  257. }
  258. /**
  259. * @description 更新图层的显示属性或设置geometry
  260. * @param {String} layerTypeName 图层大类名称
  261. * @param {String} layerName 图层名称
  262. * @param {Boolean} show 是否显示
  263. * @param {String} updateType 更新类型,feature:更新feature内的geometry,source:更新source
  264. * @param {Object} geometry {type:类型,coordinates:点位数组}
  265. */
  266. updateLayer(layerTypeName, layerName, show, updateType = 'feature', geometry) {
  267. if (!this.mapLayers[layerTypeName]) {
  268. return
  269. }
  270. if (!this.mapLayers[layerTypeName][layerName]) {
  271. return
  272. }
  273. let layer = this.mapLayers[layerTypeName][layerName]
  274. // 是否设置显示隐藏属性
  275. if (typeof show === 'boolean') {
  276. layer.setVisible(show)
  277. }
  278. if (geometry) {
  279. // 更新feature内的geometry
  280. if (updateType === 'feature') {
  281. let originFeatures = layer.getSource().getFeatures()
  282. if (originFeatures.length) {
  283. originFeatures.forEach(feature => {
  284. feature.setGeometry(this._getFeatureGeometry(geometry))
  285. })
  286. } else {
  287. let newGeometry = this._getFeatureGeometry(geometry)
  288. let newFeature = new Feature({
  289. geometry: newGeometry
  290. })
  291. let style = new Style({
  292. stroke: new Stroke({
  293. color: '#ff8c00',
  294. width: 5,
  295. lineCap: 'round',
  296. lineJoin: 'round'
  297. })
  298. })
  299. newFeature.setStyle(style)
  300. layer.getSource().addFeature(newFeature);
  301. }
  302. }
  303. // 更新source
  304. if (updateType === 'source') {
  305. layer.getSource().clear();
  306. let newGeometry = this._getFeatureGeometry(geometry)
  307. let newFeature = new Feature({
  308. geometry: newGeometry
  309. })
  310. let style = new Style({
  311. fill: new Fill({
  312. color: '#ff0000'
  313. }),
  314. stroke: new Stroke({
  315. color: '#ff0000',
  316. width: 3
  317. })
  318. })
  319. newFeature.setStyle(style)
  320. layer.getSource().addFeature(newFeature);
  321. }
  322. }
  323. }
  324. /**
  325. * @description 清除图层source
  326. * @param {String} layerTypeName 图层大类名称
  327. * @param {String} layerName 图层名称
  328. */
  329. clearLayerSource(layerTypeName, layerName) {
  330. if (!this.mapLayers[layerTypeName]) {
  331. return
  332. }
  333. if (!this.mapLayers[layerTypeName][layerName]) {
  334. return
  335. }
  336. let layer = this.mapLayers[layerTypeName][layerName]
  337. layer.getSource().clear();
  338. }
  339. /**
  340. * @description 更新图层的显示属性或设置geometry
  341. * @param {String} layerTypeName 图层大类名称
  342. * @param {String} layerName 图层名称
  343. */
  344. getLayer(layerTypeName, layerName) {
  345. if (!this.mapLayers[layerTypeName]) {
  346. return
  347. }
  348. let resLayerList = []
  349. if (!layerName) {
  350. for (let key in this.mapLayers[layerTypeName]) {
  351. resLayerList.push(this.mapLayers[layerTypeName][key])
  352. }
  353. } else {
  354. resLayerList = [this.mapLayers[layerTypeName][layerName]]
  355. }
  356. return resLayerList
  357. }
  358. /**
  359. * @description 删除图层
  360. * @param {String} layerTypeName 图层大类名称
  361. * @param {String} layerName 图层名称
  362. */
  363. removeLayer(layerTypeName) {
  364. if (!this.mapLayers[layerTypeName]) {
  365. return
  366. }
  367. for (let key in this.mapLayers[layerTypeName]) {
  368. let layer = this.mapLayers[layerTypeName][key]
  369. window.olMap.removeLayer(layer)
  370. }
  371. this.mapLayers[layerTypeName] = {}
  372. }
  373. /**
  374. * @description 内部方法, 用于创建wmts图层, 添加天地图底图
  375. * @param {String} url 地图url
  376. * @return {TileLayer} TileLayer 返回图层
  377. */
  378. _addWmtsLayer(url) {
  379. if (!url) return null
  380. let projection = getProjection('EPSG:4326')
  381. let extent = projection.getExtent()
  382. let width = getWidth(extent)
  383. let resolutions = [],
  384. matrixIds = []
  385. for (let z = 1; z < 19; z++) {
  386. resolutions[z] = width / (256 * Math.pow(2, z))
  387. matrixIds[z] = z
  388. }
  389. let tileGrid = new WMTSTileGrid({
  390. origin: getTopLeft(extent),
  391. resolutions,
  392. matrixIds
  393. })
  394. // 匹配坐标系、图层类型
  395. let type = url.match(new RegExp(/\/(.{3})_(c|w)\//))
  396. return new TileLayer({
  397. source: new WMTS({
  398. crossOrigin: 'anonymous',
  399. url: url,
  400. layer: type[1],
  401. matrixSet: type[2],
  402. format: 'tiles',
  403. style: 'default',
  404. wrapX: true,
  405. projection: projection,
  406. tileGrid
  407. })
  408. })
  409. }
  410. /**
  411. * @description 内部方法,根据geometry类型返回对应的feature
  412. * @param {Object} geometry 原始geometry数据{type, coordinates}
  413. */
  414. _getFeatureGeometry(geometry) {
  415. if (!geometry.type) {
  416. return
  417. }
  418. let featureGeometry;
  419. if (geometry.type === 'Point') {
  420. featureGeometry = new Point(geometry.coordinates)
  421. }
  422. if (geometry.type === 'Polygon') {
  423. featureGeometry = new Polygon(geometry.coordinates)
  424. }
  425. if (geometry.type === 'MultiPolygon') {
  426. featureGeometry = new MultiPolygon(geometry.coordinates)
  427. }
  428. if (geometry.type === 'LineString') {
  429. featureGeometry = new LineString(geometry.coordinates)
  430. }
  431. return featureGeometry;
  432. }
  433. /**
  434. * @description 添加popUp弹窗
  435. * @param {String} id 弹窗的id
  436. * @param {String} domId 弹窗的domId
  437. * @param {Boolean} show 初始化弹窗时是否显示
  438. * @param {Array<Number,Number>} position 要添加弹窗图的坐标数组
  439. */
  440. addPopUp(id, domId, show, position) {
  441. let popup = new Overlay({
  442. element: document.getElementById(domId),
  443. // 当前窗口可见
  444. autoPan: true,
  445. stopEvent: true,
  446. autoPanAnimation: {
  447. duration: 250
  448. }
  449. })
  450. window.olMap.addOverlay(popup)
  451. if (position && position instanceof Array) {
  452. show ? popup.setPosition(position) : popup.setPosition(undefined)
  453. } else {
  454. popup.setPosition(undefined)
  455. }
  456. this.popUp.push({
  457. popId: id,
  458. popObj: popup
  459. })
  460. }
  461. /**
  462. * @description 更新弹窗位置或显示隐藏
  463. * @param {String} id 弹窗的id
  464. * @param {Boolean} show 是否显示
  465. * @param {Array<Number,Number>} position 要添加弹窗图的坐标数组
  466. */
  467. updatePopUp(id, show, position) {
  468. if (!this.popUp.length) {
  469. return
  470. }
  471. let popup = this.popUp.find(pop => pop.popId === id)?.popObj
  472. if (!popup) {
  473. return
  474. }
  475. // 是否显示弹窗
  476. if (position && position instanceof Array) {
  477. show ? popup.setPosition(position) : popup.setPosition(undefined)
  478. } else {
  479. popup.setPosition(undefined)
  480. }
  481. }
  482. /**
  483. * @description 移除弹窗, 多个则传入弹窗id数组, 该方法会删除弹窗dom
  484. * @description 如果不想删除弹窗dom, 请使用updatePopUp()
  485. * @param {Array<String> & String} id 弹窗的id
  486. */
  487. removePopUp(id) {
  488. this.popUp.forEach(pop => {
  489. if (id && id instanceof Array) {
  490. id.indexOf(pop.popId) > -1 && window.olMap.removeOverlay(pop.popObj)
  491. }
  492. if (id && typeof id === 'string') {
  493. id === pop.popId && window.olMap.removeOverlay(pop.popObj)
  494. }
  495. })
  496. }
  497. /**
  498. * @description 移除所有弹窗, delDom会删除弹窗dom
  499. * @param {Boolean} delDom 是否移除dom
  500. */
  501. removeAllPopUp(delDom) {
  502. if (delDom) {
  503. window.olMap.getOverlays().clear()
  504. } else {
  505. this.popUp.forEach(pop => {
  506. pop.popObj.setPosition(undefined)
  507. })
  508. }
  509. }
  510. }