map.vue 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199
  1. <template>
  2. <div id="mapbox">
  3. <!-- 地图 -->
  4. <div id="mapview" class="map" @click="basemapShow = false">
  5. </div>
  6. <!-- 图层 和 消息选择 -->
  7. <layer-selector
  8. @getCheckedMap = 'getCheckedMap'
  9. @getCheckedTag = 'getCheckedTag'
  10. ></layer-selector>
  11. <!-- 绘图 控件 -->
  12. <div
  13. id='div-draw'
  14. v-if="isDraw"
  15. class='float-right'
  16. >
  17. <b-form inline>
  18. <!-- <b-form-group label="绘制类型:" label-for="input-draw-type">
  19. <b-form-select
  20. id="input-draw-type"
  21. class= "mb-2 mr-3 ml-2 mb-sm-0"
  22. v-model="drawType"
  23. :options="drawTypeOption"
  24. required
  25. ></b-form-select>
  26. </b-form-group> -->
  27. <b-button variant="danger" @click="drawEnd" >结束绘制</b-button>
  28. </b-form>
  29. </div>
  30. <!-- popup -->
  31. <div>
  32. <!-- PC端popup -->
  33. <div id="pcPopup" class="ol-popup" v-if="this.$store.state.isMobile === false">
  34. <PhoneCard
  35. :title="popupData.info.title"
  36. :time="popupData.info.time"
  37. :info="popupData.info.content"
  38. :url="popupData.info.url"
  39. :img="popupData.info.img"
  40. :isMobile = "false"
  41. >
  42. </PhoneCard>
  43. </div>
  44. <!-- Mobile端popup -->
  45. <div id="mobilePopup" v-else v-show="isShow">
  46. <PhoneCard
  47. :title="popupData.info.title"
  48. :time="popupData.info.time"
  49. :info="popupData.info.content"
  50. :url="popupData.info.url"
  51. :img="popupData.info.img"
  52. :isMobile = 'true'
  53. >
  54. </PhoneCard>
  55. </div>
  56. </div>
  57. <!-- slogan -->
  58. <div v-if="this.$store.state.isMobile === true">
  59. <Slogan v-show="slogan.isShow" :slogan="slogan.content"></Slogan>
  60. </div>
  61. </div>
  62. </template>
  63. <script>
  64. import util from '../util'
  65. // openlayer
  66. import 'ol/ol.css'
  67. import {Map, View} from 'ol'
  68. import * as Extent from 'ol/extent'
  69. import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer'
  70. import * as olProj from 'ol/proj'
  71. import {Point, MultiLineString} from 'ol/geom'
  72. import {defaults as defaultInteractions} from 'ol/interaction'
  73. import Feature from 'ol/Feature'
  74. import * as control from 'ol/control'
  75. import {Style, Icon, Stroke} from 'ol/style'
  76. import {Cluster, Vector as VectorSource} from 'ol/source'
  77. import TileSource from 'ol/source/TileWMS'
  78. import XYZ from 'ol/source/XYZ'
  79. import Overlay from 'ol/Overlay'
  80. // import OSM from 'ol/source/OSM'
  81. // eventBus公共实例
  82. import bus from '../../static/js/eventBus'
  83. // icon
  84. import culture from '../assets/icon/culture.svg'
  85. import info from '../assets/icon/info.svg'
  86. import report from '../assets/icon/report.svg'
  87. import more from '../assets/icon/more.svg'
  88. // draw shape
  89. import DrawShape from '../../static/js/startDrawShape'
  90. // card
  91. import phoneCard from './card.vue'
  92. // slogan
  93. import slogan from './slogan.vue'
  94. // 地图对象
  95. // eslint-disable-next-line
  96. var map = null
  97. export default {
  98. name: 'Map',
  99. components: {
  100. PhoneCard: phoneCard,
  101. Slogan: slogan,
  102. LayerSelector: () => import('./LayerSelector.vue') // 消息和底图选择
  103. },
  104. data () {
  105. return {
  106. noticeStyles: { // 通知标注 样式
  107. Point: new Style({
  108. image: new Icon({
  109. crossOrigin: 'anonymous',
  110. src: info,
  111. scale: 0.225
  112. })
  113. }),
  114. LineString: new Style({
  115. stroke: new Stroke({
  116. color: '#ff8c42',
  117. width: 6
  118. })
  119. })
  120. },
  121. reportStyles: { // 报道/新闻 标注 样式
  122. Point: new Style({
  123. image: new Icon({
  124. crossOrigin: 'anonymous',
  125. src: report,
  126. scale: 0.25
  127. })
  128. }),
  129. LineString: new Style({
  130. stroke: new Stroke({
  131. color: '#2953a5',
  132. width: 6
  133. })
  134. })
  135. },
  136. cultureStyles: { // 文化标注 样式
  137. Point: new Style({
  138. image: new Icon({
  139. crossOrigin: 'anonymous',
  140. src: culture,
  141. scale: 0.225
  142. })
  143. }),
  144. LineString: new Style({
  145. stroke: new Stroke({
  146. color: '#f51a51',
  147. width: 6
  148. })
  149. })
  150. },
  151. otherStyles: { // 更多 标注 样式
  152. Point: new Style({
  153. image: new Icon({
  154. crossOrigin: 'anonymous',
  155. src: more,
  156. scale: 0.2
  157. })
  158. }),
  159. LineString: new Style({
  160. stroke: new Stroke({
  161. color: '#f51a51',
  162. width: 6
  163. })
  164. })
  165. },
  166. // popup的overlay对象
  167. popup: null,
  168. popupData: { // PC端 地图弹出框信息
  169. type: '',
  170. info: ''
  171. },
  172. // mobile端popup控制
  173. isShow: false,
  174. // 绘制状态
  175. isDraw: false,
  176. // 绘制选项
  177. drawTypeOption: ['线', '点'],
  178. // 绘制类型
  179. drawType: '线',
  180. // 绘制颜色
  181. drawColor: '#585eaa',
  182. // 信息显示列表(LayerSelector)
  183. checkTagList: [],
  184. checkMapList: [],
  185. // slogan
  186. slogan: {
  187. isShow: true,
  188. content: ''
  189. }
  190. }
  191. },
  192. methods: {
  193. /**
  194. * @description:构建地图
  195. * @returns {void}
  196. */
  197. initMap: function () {
  198. // PNG范围
  199. let leftTop = [11592187.538105225, 3592590.111732335]
  200. let rightBottom = [11594513.693708975, 3587420.877057335]
  201. // 经纬度
  202. // let leftTop = [104.13439162531515, 30.690273107307597]
  203. // let rightBottom = [104.15523854491164, 30.650437034690334]
  204. rightBottom = this.getExtentFromPNG(leftTop, rightBottom)
  205. // leftTop = olProj.fromLonLat(leftTop)
  206. // rightBottom = olProj.fromLonLat(rightBottom)
  207. // 根据设备的不同设置地图范围
  208. const MOBILE = [leftTop[0], rightBottom[1], rightBottom[0], leftTop[1]]
  209. // const PC = [11591064, 3589994, 11595665, 3592078]
  210. const PC = [11591064, 3589994, 11596565, 3592078]
  211. let extent = this.$store.state.isMobile ? MOBILE : PC
  212. let center = [
  213. (extent[0] + extent[2]) / 2,
  214. (extent[1] + extent[3]) / 2
  215. ]
  216. // let center = [
  217. // (leftTop[0] + rightBottom[0]) / 2,
  218. // (leftTop[1] + rightBottom[1]) / 2
  219. // ]
  220. let zoom = this.$store.state.isMobile ? 14.5 : 15.5
  221. map = new Map({
  222. target: 'mapview',
  223. layers: [
  224. // 天地图 地图
  225. new TileLayer({
  226. class: 'basemap',
  227. title: 'tiandi',
  228. source: new XYZ({
  229. url: 'https://t3.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=a7baca459fe5be059d34849072e84fd0'
  230. }),
  231. visible: true
  232. // nameCN: '在线地图'
  233. }),
  234. // 天地图 地图标注
  235. new TileLayer({
  236. class: 'basemap',
  237. title: 'tiandi',
  238. source: new XYZ({
  239. url: 'https://t3.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=a7baca459fe5be059d34849072e84fd0'
  240. }),
  241. visible: true
  242. // nameCN: '天地图标注'
  243. }),
  244. // 文化地图
  245. new TileLayer({
  246. class: 'basemap',
  247. title: 'cdut',
  248. source: new TileSource({
  249. // url: 'http://cn-cd-ali-1.natfrp.cloud:10265/geoserver/CDUT/wms',
  250. // url: 'http://113.125.147.162:8081/geoserver/CDUT/wms',
  251. // url: 'http://139.155.247.43/geoserver/CDUT/wms',
  252. url: 'https://geo.itopmap.com/geoserver/CDUT/wms',
  253. crossOrigin: 'anonymous',
  254. params: {
  255. LAYERS: 'cdut_920',
  256. TILED: true
  257. },
  258. servertype: 'geoserver',
  259. transition: 0
  260. })
  261. // nameCN: '文化地图'
  262. })
  263. ],
  264. interactions: defaultInteractions({
  265. pinchRotate: false // 移动端禁止地图旋转
  266. }),
  267. view: new View({
  268. center: center,
  269. zoom: zoom,
  270. extent: extent,
  271. maxZoom: 18.5
  272. }),
  273. controls: control.defaults({
  274. zoom: false
  275. })
  276. // controls: control.defaults().extend([
  277. // new control.MousePosition()
  278. // ])
  279. })
  280. setTimeout(function () { map.updateSize() })
  281. },
  282. /**
  283. * @description:开启聚合
  284. */
  285. addCluster: function (layerName, layerStyle) {
  286. let layer = map.getLayers().array_
  287. for (let i = 0; i < layer.length; i++) {
  288. if (layer[i].className_ === layerName) {
  289. var targetLayer = layer[i]
  290. }
  291. }
  292. if (targetLayer) {
  293. let features = targetLayer.getSource().getFeatures()
  294. let source = new VectorSource({
  295. features: features
  296. })
  297. let clusterSource = new Cluster({
  298. distance: 20,
  299. source: source
  300. })
  301. targetLayer.setSource(clusterSource)
  302. let style = (feature) => {
  303. let features = feature.get('features')
  304. let size = features.length
  305. let lastFeature = features[size - 1]
  306. let lonArr = []
  307. let latArr = []
  308. // 存储图标聚合的点的矩形范围
  309. if (feature.get('features').length > 1) {
  310. for (let i = 0; i < size; i++) {
  311. let coordinate = features[i].values_.geometry.flatCoordinates
  312. lonArr.push(coordinate[0])
  313. latArr.push(coordinate[1])
  314. }
  315. let maxLon = Math.max(...lonArr)
  316. let minLon = Math.min(...lonArr)
  317. let maxLat = Math.max(...latArr)
  318. let minLat = Math.min(...latArr)
  319. let extent = [minLon, minLat, maxLon, maxLat]
  320. feature.set('extent', extent)
  321. }
  322. feature.set('id', lastFeature.values_.id)
  323. feature.set('type', lastFeature.values_.type)
  324. feature.set('number', feature.get('features').length)
  325. let style = layerStyle
  326. return style
  327. }
  328. targetLayer.setStyle(style)
  329. }
  330. },
  331. /**
  332. * @description:通过图片范围结合设备尺寸计算extent
  333. * @param {array} leftTop:左上坐标
  334. * @param {array} rightBot:右下坐标
  335. * @returns {array}
  336. */
  337. getExtentFromPNG: function (leftTop, rightBot) {
  338. // 屏幕高度宽度
  339. let width = window.screen.width
  340. let height = window.screen.height
  341. // png坐标(atcmap中获取)
  342. // let imgLeft = leftTop[0]
  343. let imgTop = leftTop[1]
  344. let imgRight = rightBot[0]
  345. let imgBottom = rightBot[1]
  346. // png比例*(根据发布的png)
  347. // let imgWidthratio = 9
  348. let imgHeightratio = 20
  349. // 屏幕比例(根据设备获取)
  350. // let screenWidthratio = 9 // 先假设都为9,其他情况todo
  351. let screenHeightratio = 9 * height / width // 先假设都小于20,其他情况todo
  352. // 计算显示范围
  353. let screenRight = imgRight
  354. let screenBottom = imgTop - (imgTop - imgBottom) * (screenHeightratio / imgHeightratio)
  355. // 得到屏幕显示范围
  356. // let screen_lefttop = [imgLeft, imgTop] // 屏幕显示的左上角
  357. let screenRightbottom = [screenRight, screenBottom] // 即屏幕显示的右下角
  358. return screenRightbottom
  359. },
  360. /**
  361. * @description:构建popup覆盖层
  362. * @returns {void}
  363. */
  364. initPopupOverLay: function () {
  365. var container = document.getElementById('pcPopup')
  366. this.popup = new Overlay({
  367. element: container,
  368. autoPan: true,
  369. autoPanAnimation: {
  370. duration: 250
  371. }
  372. })
  373. map.addOverlay(this.popup)
  374. },
  375. /**
  376. * @description:绘制要素
  377. * @param {String} title:图层名称
  378. * @param {Object of {GeoJSON,String,String}} msg:要素信息(含有geometry,id,type)
  379. * @param {String} type:所属类别, 文化类:'culture' / 消息类: 'notice'
  380. * @param {Boolean} isRefresh:是否刷新图层
  381. * @param {Boolean} isLoacate:是否缩放到要素
  382. * @returns {void}
  383. */
  384. printFeature: function (title, msg, type, number = null, isRefresh = false, isLocate = false, isRelate = false) {
  385. // 初始化图层
  386. var layer = this.getLayerByTitle(title)
  387. if (layer !== null) {
  388. // 非首次调用,清除图层中的要素
  389. if (isRefresh) {
  390. layer.getSource().clear()
  391. }
  392. } else {
  393. // 首次调用,创建图层
  394. layer = new VectorLayer({
  395. title: title,
  396. class: 'layer',
  397. className: title,
  398. // extent: this.extent,
  399. source: new VectorSource({
  400. })
  401. })
  402. map.addLayer(layer)
  403. }
  404. // GeoJSON格式转换为ol.feature格式,样式装载
  405. var geometry = msg.geometry
  406. var style
  407. switch (type) {
  408. case 'notice':
  409. style = this.noticeStyles
  410. break
  411. case 'report':
  412. style = this.reportStyles
  413. break
  414. case 'culture':
  415. style = this.cultureStyles
  416. break
  417. case 'other':
  418. style = this.otherStyles
  419. break
  420. }
  421. var feature = this.GeoJSON_to_Feature(geometry, style)
  422. // 要素属性装载
  423. feature.set('id', msg.id)
  424. feature.set('type', type)
  425. feature.set('number', number)
  426. // 要素装载入图层
  427. // 1.起始点
  428. layer.getSource().addFeature(feature)
  429. // 2.关联线
  430. let fe = null
  431. if (isRelate && msg.relate) {
  432. fe = this.GeoJSON_to_Feature(msg.relate, style)
  433. fe.set('id', msg.id)
  434. fe.set('type', type)
  435. layer.getSource().addFeature(fe)
  436. }
  437. // 缩放至要素
  438. if (isLocate) {
  439. let locatedFeature = feature
  440. let feaType = 'origin'
  441. if (isRelate && msg.relate) {
  442. locatedFeature = fe
  443. feaType = 'relate'
  444. }
  445. this.locateAtFeature(locatedFeature, feaType)
  446. }
  447. },
  448. /**
  449. * @description:根据 GeoJSON 格式数据绘制要素
  450. * tips:目前支持类型:Point,MultiLineString
  451. * @param {GeoJSON} geometry:GeoJSON格式数据
  452. * @param {Array of ol.Style} styles:样式
  453. * @returns {ol.feature} 返回由GeoJSON转换成的配制好样式的ol.feature
  454. */
  455. GeoJSON_to_Feature: function (geometry, styles) {
  456. if (!geometry.type) {
  457. console.log('printFromGeoJSON 所输入的GeoJSON不符合规范')
  458. return
  459. }
  460. var feature = null
  461. // 按geometry.type类型创建要素并赋予样式
  462. switch (geometry.type) {
  463. case 'Point':
  464. feature = new Feature({
  465. geometry: new Point(olProj.fromLonLat(geometry.coordinates, 'EPSG:3857')),
  466. shape: geometry.type
  467. })
  468. feature.setStyle(styles.Point)
  469. break
  470. case 'MultiLineString':
  471. // let geo = geometry.coordinates.map(x => {
  472. // return olProj.fromLonLat(x, 'EPSG:3857')
  473. // })
  474. // feature = new Feature({
  475. // geometry: new LineString(geo),
  476. // shape: geometry.type
  477. // })
  478. // feature.setStyle(styles.LineString)
  479. let coords = []
  480. // 多线
  481. geometry.coordinates.forEach(i => {
  482. // 多点
  483. let co = i.map(x => {
  484. x = olProj.fromLonLat(x, 'EPSG:3857')
  485. return x
  486. })
  487. coords.push(co)
  488. })
  489. feature = new Feature({
  490. geometry: new MultiLineString(coords),
  491. shape: geometry.type
  492. })
  493. feature.setStyle(styles.LineString)
  494. break
  495. default:
  496. console.log('printFromGeoJSON不支持该"' + geometry.type + '"类型')
  497. return
  498. }
  499. return feature
  500. },
  501. /**
  502. * @description:ol.feature 转 GeoJSon
  503. * tips:目前支持类型:Point,LineString;
  504. * @param {ol.feature} feature
  505. * @returns {GeoJSON}
  506. */
  507. Feature_to_GeoJSon: function (feature) {
  508. let baseType = feature[0].type
  509. // 多点取第一个点,多线取多线
  510. // eslint-disable-next-line no-unneeded-ternary
  511. let isMulti = feature.length > 1 ? true : false
  512. // eslint-disable-next-line no-unneeded-ternary
  513. isMulti = baseType === 'LineString' ? true : false
  514. if (isMulti) {
  515. let type = 'MultiLineString'
  516. let coords = []
  517. // 多线
  518. feature.forEach(i => {
  519. i = i.coordinates
  520. // 多点
  521. let co = i.map(x => {
  522. x = olProj.toLonLat(x)
  523. return x
  524. })
  525. coords.push(co)
  526. })
  527. return {
  528. type: type,
  529. coordinates: coords
  530. }
  531. } else {
  532. let coord = feature[0].coordinates
  533. switch (baseType) {
  534. case 'LineString':
  535. coord = coord.map(x => {
  536. x = olProj.toLonLat(x)
  537. return x
  538. })
  539. break
  540. case 'Point':
  541. coord = olProj.toLonLat(coord)
  542. break
  543. }
  544. return {
  545. type: baseType,
  546. coordinates: coord
  547. }
  548. }
  549. },
  550. /**
  551. * @description:缩放至要素
  552. * @param {ol.Feature} feature:要素
  553. * @param {int} zoom: 缩放级别
  554. * @return {void}
  555. */
  556. locateAtFeature: function (feature, type, zoom = 17.5) {
  557. let view = map.getView()
  558. view.setZoom(zoom)
  559. if (this.$store.state.isMobile && type !== 'relate') {
  560. let coord = Extent.getCenter(feature.getGeometry().getExtent())
  561. coord[1] = coord[1] * 1.00006
  562. view.setCenter(coord)
  563. } else {
  564. view.setCenter(Extent.getCenter(feature.getGeometry().getExtent()))
  565. }
  566. if (type === 'relate') {
  567. view.setZoom(zoom * 0.975)
  568. }
  569. },
  570. /**
  571. * @description:获取并渲染最近若干天的通知
  572. * @param {int} day: 天数
  573. * @returns {void}
  574. */
  575. loadRecentNotices: function (day) {
  576. var that = this
  577. this.$axios
  578. .post('/notice/recent', {
  579. day: day
  580. })
  581. .then(res => {
  582. res.data.forEach(item => {
  583. that.printFeature('noticeLayer', item, 'notice')
  584. })
  585. this.addCluster('noticeLayer', this.noticeStyles.Point)
  586. })
  587. },
  588. /**
  589. * @description:获取并渲染最近若干天的报道
  590. * @param {int} day: 天数
  591. * @returns {void}
  592. */
  593. loadRecentReports: function (day) {
  594. var that = this
  595. this.$axios
  596. .post('/report/recent', {
  597. day: day
  598. })
  599. .then(res => {
  600. res.data.forEach(item => {
  601. that.printFeature('reportLayer', item, 'report')
  602. })
  603. this.addCluster('reportLayer', this.reportStyles.Point)
  604. })
  605. },
  606. /**
  607. * @description:获取并渲染所有文化设施
  608. * @returns {void}
  609. */
  610. loadCulture: function () {
  611. var that = this
  612. this.$axios
  613. .post('/culture/all')
  614. .then(res => {
  615. res.data.forEach(e => {
  616. that.printFeature('cultureLayer', e, 'culture')
  617. })
  618. this.addCluster('cultureLayer', this.cultureStyles.Point)
  619. })
  620. },
  621. /**
  622. * @description:加载并渲染'更多'
  623. */
  624. loadOthers: function () {
  625. var that = this
  626. this.$axios
  627. .post('/others/all')
  628. .then(res => {
  629. res.data.forEach(e => {
  630. that.printFeature('otherLayer', e, 'other')
  631. })
  632. this.addCluster('otherLayer', this.otherStyles.Point)
  633. })
  634. },
  635. /**
  636. * @description: 地图要素点击事件
  637. * @return {void}
  638. */
  639. mapClick: function () {
  640. var that = this
  641. // 根据设备类型设置点击事件
  642. var clickFun = this.$store.state.isMobile ? mobileClickFun : pcClickFun
  643. map.on('singleclick', clickFun)
  644. async function mobileClickFun (e) {
  645. var feature = map.forEachFeatureAtPixel(e.pixel, function (feature) {
  646. return feature
  647. })
  648. if (feature) {
  649. var id = feature.get('id')
  650. let type = feature.get('type')
  651. let number = feature.get('number')
  652. if (number === 1) {
  653. let data = null
  654. switch (type) {
  655. case 'notice':
  656. data = await that.loadNoticeByID(id)
  657. break
  658. case 'report':
  659. data = await that.loadReportByID(id)
  660. break
  661. case 'culture':
  662. data = await that.loadCultureByID(id)
  663. break
  664. case 'other':
  665. data = await that.loadOthersByID(id)
  666. break
  667. }
  668. that.printFeature('markLayer', data, type, number, true, true, true)
  669. that.isShow = true
  670. bus.$emit('closeList')
  671. } else {
  672. // 当点击的图标个数大于1时设置视角范围为多个图标的矩形范围
  673. let extent = feature.get('extent')
  674. map.getView().fit(extent, map.getSize())
  675. }
  676. } else {
  677. that.closePopup()
  678. }
  679. }
  680. async function pcClickFun (e) {
  681. // var coordinate = e.coordinate
  682. var feature = map.forEachFeatureAtPixel(e.pixel, feature => {
  683. return feature
  684. })
  685. if (feature) {
  686. let number = feature.get('number')
  687. if (number === 1) {
  688. bus.$emit('printMapMark', {
  689. type: feature.get('type'),
  690. id: feature.get('id'),
  691. number: feature.get('number')
  692. })
  693. } else {
  694. // 当点击的图标个数大于1时设置视角范围为多个图标的矩形范围
  695. let extent = feature.get('extent')
  696. map.getView().fit(extent, map.getSize())
  697. }
  698. } else {
  699. that.closePopup()
  700. }
  701. }
  702. },
  703. /**
  704. * @description: ol封装:通过title属性获取图层
  705. * @param {title} 图层title值
  706. * @return {layer / null}
  707. */
  708. getLayerByTitle: function (title) {
  709. var layers = map.getLayers().array_
  710. for (let i = 0; i < layers.length; i++) {
  711. if (layers[i].get('title') === title) {
  712. return layers[i]
  713. } else {
  714. continue
  715. }
  716. }
  717. return null
  718. },
  719. /**
  720. * @description:通过id查询载入通知信息
  721. */
  722. loadReportByID: async function (id) {
  723. var that = this
  724. var res
  725. await this.$axios
  726. .post('/report/detail', {
  727. id: id
  728. })
  729. .then(response => {
  730. that.popupData.info = response.data
  731. that.popupData.type = '新闻报道'
  732. res = response.data
  733. })
  734. return res
  735. },
  736. /**
  737. * @description:通过id查询载入通知信息
  738. */
  739. loadNoticeByID: async function (id) {
  740. var that = this
  741. var res
  742. await this.$axios
  743. .post('/notice/detail', {
  744. id: id
  745. })
  746. .then(response => {
  747. that.popupData.info = response.data
  748. that.popupData.type = '活动通知'
  749. res = response.data
  750. })
  751. return res
  752. },
  753. /**
  754. * @description:通过id 查询载入文化信息
  755. */
  756. loadCultureByID: async function (id) {
  757. var that = this
  758. var res
  759. await this.$axios
  760. .post('/culture/detail', {
  761. id: id
  762. })
  763. .then(response => {
  764. response.data.content = response.data.content.join('')
  765. that.popupData.info = response.data
  766. that.popupData.type = '文化设施'
  767. res = response.data
  768. })
  769. return res
  770. },
  771. /**
  772. * @description:通过id 查询载入'其他'信息
  773. */
  774. loadOthersByID: async function (id) {
  775. var that = this
  776. var res
  777. await this.$axios
  778. .post('/others/detail', {
  779. id: id
  780. })
  781. .then(response => {
  782. that.popupData.info = response.data
  783. that.popupData.type = '活动通知'
  784. res = response.data
  785. res = response.data
  786. })
  787. return res
  788. },
  789. /**
  790. * @description:设置并聚焦到popup的显示位置
  791. * @param {ol.coordinate}坐标
  792. * @param {ol.zoom}缩放级别
  793. */
  794. setPopupPosition: function (coordinate, zoom = 18) {
  795. this.popup.setPosition(coordinate)
  796. this.isShow = true
  797. var view = map.getView()
  798. view.setCenter(coordinate)
  799. // view.setZoom(zoom)
  800. },
  801. /**
  802. * @description:根据pc端与mobile端不同的popup关闭事件
  803. * @param {DOM} dom:点击按钮dom
  804. */
  805. closePopup: function (dom) {
  806. if (this.$store.state.isMobile) {
  807. this.isShow = false
  808. } else {
  809. this.popup.setPosition(undefined)
  810. this.isShow = false
  811. // 消除按钮聚焦
  812. if (dom) {
  813. dom.blur()
  814. }
  815. }
  816. return false
  817. },
  818. /**
  819. * @description:绘制要素
  820. */
  821. drawBegin: function () {
  822. // 更改为绘制状态
  823. this.isDraw = true
  824. let col = this.drawColor
  825. switch (this.drawType) {
  826. case '点':
  827. DrawShape.drawPoint(col, map)
  828. break
  829. case '线':
  830. DrawShape.drawLine(col, map)
  831. break
  832. }
  833. },
  834. /**
  835. * @description:结束绘制要素
  836. */
  837. drawEnd: function () {
  838. this.isDraw = false
  839. let data = DrawShape.closeDrawShape()
  840. if (data.length !== 0) {
  841. data = this.Feature_to_GeoJSon(data)
  842. } else {
  843. data = null
  844. }
  845. switch (this.drawType) {
  846. case '点':
  847. bus.$emit('drawGeometryEnd', data)
  848. break
  849. case '线':
  850. bus.$emit('drawRelateEnd', data)
  851. break
  852. }
  853. },
  854. // LayerSelector related
  855. // 底图选择 和 消息选择 的图层切换
  856. getCheckedMap: function (checkMapList) {
  857. this.checkMapList = checkMapList
  858. util.map.setMapVisible(map, checkMapList, 'basemap')
  859. },
  860. getCheckedTag: function (checkTagList) {
  861. this.checkTagList = checkTagList
  862. util.map.setMapVisible(map, checkTagList, 'layer')
  863. },
  864. /**
  865. * @description: 监听视图变化,调整slogan可见
  866. */
  867. sloganListener: function () {
  868. var that = this
  869. // 获取放置地图的div
  870. var mapDiv = document.getElementById('mapview')
  871. // 当鼠标滚轮事件发生时,执行一些操作
  872. function onMouseWheel (ev) {
  873. window.setTimeout(function () {
  874. let zoom = map.getView().getZoom()
  875. if (zoom > 15.3) {
  876. that.slogan.isShow = false
  877. } else {
  878. that.slogan.isShow = true
  879. }
  880. // FF 和 Chrome
  881. if (ev.preventDefault) {
  882. ev.preventDefault()// 阻止默认事件
  883. }
  884. return false
  885. }, 500)
  886. }
  887. addEvent(mapDiv, 'mousewheel', onMouseWheel)
  888. addEvent(mapDiv, 'DOMMouseScroll', onMouseWheel)
  889. addEvent(mapDiv, 'touchmove', onMouseWheel)
  890. function addEvent (obj, xEvent, fn) {
  891. if (obj.attachEvent) {
  892. obj.attachEvent('on' + xEvent, fn)
  893. } else {
  894. obj.addEventListener(xEvent, fn, false)
  895. }
  896. }
  897. },
  898. /**
  899. * @description: eventBus的bus.$on 触发事件汇总
  900. */
  901. busOnAction: function () {
  902. var that = this
  903. // mobile端:绘制报道标识与popup弹窗
  904. bus.$on('showMsgDetail', async msg => {
  905. let data
  906. let id = msg.id
  907. switch (msg.type) {
  908. case 'notice':
  909. await that.loadNoticeByID(id)
  910. .then(res => {
  911. data = res
  912. })
  913. break
  914. case 'report':
  915. await that.loadReportByID(id)
  916. .then(res => {
  917. data = res
  918. })
  919. break
  920. case 'culture':
  921. await that.loadCultureByID(id)
  922. .then(res => {
  923. data = res
  924. })
  925. break
  926. case 'other':
  927. await that.loadOthersByID(id)
  928. .then(res => {
  929. data = res
  930. })
  931. break
  932. }
  933. that.printFeature('markLayer', data, msg.type, null, true, true, true)
  934. that.isShow = true
  935. })
  936. // PC端:根据各个类型的id 绘制地图标识与popup弹窗
  937. bus.$on('printMapMark', async msg => {
  938. let data
  939. let id = msg.id
  940. let number = msg.number
  941. switch (msg.type) {
  942. case 'notice':
  943. await that.loadNoticeByID(id)
  944. .then(res => {
  945. data = res
  946. })
  947. break
  948. case 'report':
  949. await that.loadReportByID(id)
  950. .then(res => {
  951. data = res
  952. })
  953. break
  954. case 'culture':
  955. await that.loadCultureByID(id)
  956. .then(res => {
  957. data = res
  958. })
  959. break
  960. case 'other':
  961. await that.loadOthersByID(id)
  962. .then(res => {
  963. data = res
  964. })
  965. break
  966. }
  967. that.printFeature('markLayer', data, msg.type, number, true, true, true)
  968. // 显示popup
  969. var feature = that.getLayerByTitle('markLayer').getSource().getFeatures()[0]
  970. var coord = feature.getGeometry().getCoordinates()
  971. that.setPopupPosition(coord)
  972. })
  973. // 刷新地图标识
  974. bus.$on('refreshMap', () => {
  975. map.removeLayer(that.getLayerByTitle('noticeLayer'))
  976. map.removeLayer(that.getLayerByTitle('reportLayer'))
  977. map.removeLayer(that.getLayerByTitle('cultureLayer'))
  978. map.removeLayer(that.getLayerByTitle('otherLayer'))
  979. map.removeLayer(that.getLayerByTitle('markLayer'))
  980. that.loadOthers()
  981. that.loadCulture()
  982. that.loadRecentReports(7)
  983. that.loadRecentNotices(7)
  984. that.closePopup()
  985. })
  986. // 绘制
  987. bus.$on('drawBegin', type => {
  988. that.drawType = type
  989. that.drawBegin(type)
  990. })
  991. // 关闭弹窗
  992. bus.$on('closePopup', () => {
  993. that.closePopup()
  994. })
  995. }
  996. },
  997. mounted () {
  998. this.initMap()
  999. this.initPopupOverLay()
  1000. this.busOnAction()
  1001. this.loadRecentReports(365)
  1002. this.loadRecentNotices(365)
  1003. this.loadOthers()
  1004. this.loadCulture()
  1005. this.mapClick()
  1006. this.sloganListener()
  1007. },
  1008. watch: {
  1009. drawType: function () {
  1010. DrawShape.closeDrawShape()
  1011. this.drawBegin()
  1012. },
  1013. isShow: function () {
  1014. if (this.isShow === true) {
  1015. this.slogan.isShow = false
  1016. }
  1017. }
  1018. },
  1019. filters: {
  1020. // 超过100位显示省略号
  1021. ellipsis: function (value) {
  1022. if (!value) return ''
  1023. if (value.length > 70) {
  1024. return value.slice(0, 70) + '...'
  1025. }
  1026. return value
  1027. }
  1028. }
  1029. }
  1030. </script>
  1031. <!-- Add "scoped" attribute to limit CSS to this component only -->
  1032. <style scoped>
  1033. #mapview{
  1034. width: 100%;
  1035. height: 100%;
  1036. position: absolute;
  1037. /* background: rgb(135,191,150); */
  1038. }
  1039. #div-draw {
  1040. position: absolute;
  1041. left: 50%;
  1042. top:2px;
  1043. z-index: 100;
  1044. background: white;
  1045. border-radius: 5px;
  1046. padding: 10px 10px 10px 10px;
  1047. border: 1px solid gray;
  1048. transform: translateX(-50%);
  1049. }
  1050. /*图层切换弹出框样式*/
  1051. #basemap-content {
  1052. position: absolute;
  1053. font-size: 12px;
  1054. z-index: 100;
  1055. background: rgba(255, 255, 255, 0.7);
  1056. opacity: 0.95;
  1057. right: 0px;
  1058. margin-top: 40px;
  1059. height: 50px;
  1060. width:65px;
  1061. align-content: center;
  1062. }
  1063. .basemap-item {
  1064. padding: 5px;
  1065. cursor: pointer;
  1066. }
  1067. .basemap-text,.online-map-text{
  1068. width: 60px;
  1069. height: 12px;
  1070. }
  1071. .basemap-text{
  1072. color: #007bff;
  1073. font-weight: bold;
  1074. font-family: "Source Han Sans CN";
  1075. }
  1076. /*图层与消息按钮样式*/
  1077. .info-select-button {
  1078. width: 22px;
  1079. height: 20px;
  1080. }
  1081. .info-select-button-div {
  1082. width: 22px;
  1083. height: 22px;
  1084. z-index: 999;
  1085. cursor: pointer;
  1086. position: absolute;
  1087. }
  1088. .layer-select-button {
  1089. width: 22px;
  1090. height: 22px;
  1091. }
  1092. .layer-select-button-div {
  1093. width: 22px;
  1094. height: 22px;
  1095. z-index: 999;
  1096. right: 3px;
  1097. cursor: pointer;
  1098. position: absolute;
  1099. }
  1100. </style>