map.vue 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192
  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: 'http://t3.tianditu.com/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: 'http://t3.tianditu.com/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. crossOrigin: 'anonymous',
  251. params: {
  252. LAYERS: 'cdut_920',
  253. TILED: true
  254. },
  255. servertype: 'geoserver',
  256. transition: 0
  257. })
  258. // nameCN: '文化地图'
  259. })
  260. ],
  261. interactions: defaultInteractions({
  262. pinchRotate: false // 移动端禁止地图旋转
  263. }),
  264. view: new View({
  265. center: center,
  266. zoom: zoom,
  267. extent: extent,
  268. maxZoom: 18.5
  269. }),
  270. controls: control.defaults({
  271. zoom: false
  272. })
  273. // controls: control.defaults().extend([
  274. // new control.MousePosition()
  275. // ])
  276. })
  277. setTimeout(function () { map.updateSize() })
  278. },
  279. /**
  280. * @description:开启聚合
  281. */
  282. addCluster: function (layerName, layerStyle) {
  283. let layer = map.getLayers().array_
  284. for (let i = 0; i < layer.length; i++) {
  285. if (layer[i].className_ === layerName) {
  286. var targetLayer = layer[i]
  287. }
  288. }
  289. if (targetLayer) {
  290. let features = targetLayer.getSource().getFeatures()
  291. let source = new VectorSource({
  292. features: features
  293. })
  294. let clusterSource = new Cluster({
  295. distance: 20,
  296. source: source
  297. })
  298. targetLayer.setSource(clusterSource)
  299. let style = (feature) => {
  300. let features = feature.get('features')
  301. let size = features.length
  302. let lastFeature = features[size - 1]
  303. let lonArr = []
  304. let latArr = []
  305. // 存储图标聚合的点的矩形范围
  306. if (feature.get('features').length > 1) {
  307. for (let i = 0; i < size - 1; i++) {
  308. let coordinate = features[i].values_.geometry.flatCoordinates
  309. lonArr.push(coordinate[0])
  310. latArr.push(coordinate[1])
  311. }
  312. let maxLon = Math.max(...lonArr)
  313. let minLon = Math.min(...lonArr)
  314. let maxLat = Math.max(...latArr)
  315. let minLat = Math.min(...latArr)
  316. let extent = [minLon, minLat, maxLon, maxLat]
  317. feature.set('extent', extent)
  318. }
  319. feature.set('id', lastFeature.values_.id)
  320. feature.set('type', lastFeature.values_.type)
  321. feature.set('number', feature.get('features').length)
  322. let style = layerStyle
  323. return style
  324. }
  325. targetLayer.setStyle(style)
  326. }
  327. },
  328. /**
  329. * @description:通过图片范围结合设备尺寸计算extent
  330. * @param {array} leftTop:左上坐标
  331. * @param {array} rightBot:右下坐标
  332. * @returns {array}
  333. */
  334. getExtentFromPNG: function (leftTop, rightBot) {
  335. // 屏幕高度宽度
  336. let width = window.screen.width
  337. let height = window.screen.height
  338. // png坐标(atcmap中获取)
  339. // let imgLeft = leftTop[0]
  340. let imgTop = leftTop[1]
  341. let imgRight = rightBot[0]
  342. let imgBottom = rightBot[1]
  343. // png比例*(根据发布的png)
  344. // let imgWidthratio = 9
  345. let imgHeightratio = 20
  346. // 屏幕比例(根据设备获取)
  347. // let screenWidthratio = 9 // 先假设都为9,其他情况todo
  348. let screenHeightratio = 9 * height / width // 先假设都小于20,其他情况todo
  349. // 计算显示范围
  350. let screenRight = imgRight
  351. let screenBottom = imgTop - (imgTop - imgBottom) * (screenHeightratio / imgHeightratio)
  352. // 得到屏幕显示范围
  353. // let screen_lefttop = [imgLeft, imgTop] // 屏幕显示的左上角
  354. let screenRightbottom = [screenRight, screenBottom] // 即屏幕显示的右下角
  355. return screenRightbottom
  356. },
  357. /**
  358. * @description:构建popup覆盖层
  359. * @returns {void}
  360. */
  361. initPopupOverLay: function () {
  362. var container = document.getElementById('pcPopup')
  363. this.popup = new Overlay({
  364. element: container,
  365. autoPan: true,
  366. autoPanAnimation: {
  367. duration: 250
  368. }
  369. })
  370. map.addOverlay(this.popup)
  371. },
  372. /**
  373. * @description:绘制要素
  374. * @param {String} title:图层名称
  375. * @param {Object of {GeoJSON,String,String}} msg:要素信息(含有geometry,id,type)
  376. * @param {String} type:所属类别, 文化类:'culture' / 消息类: 'notice'
  377. * @param {Boolean} isRefresh:是否刷新图层
  378. * @param {Boolean} isLoacate:是否缩放到要素
  379. * @returns {void}
  380. */
  381. printFeature: function (title, msg, type, isRefresh = false, isLocate = false, isRelate = false) {
  382. // 初始化图层
  383. var layer = this.getLayerByTitle(title)
  384. if (layer !== null) {
  385. // 非首次调用,清除图层中的要素
  386. if (isRefresh) {
  387. layer.getSource().clear()
  388. }
  389. } else {
  390. // 首次调用,创建图层
  391. layer = new VectorLayer({
  392. title: title,
  393. class: 'layer',
  394. className: title,
  395. // extent: this.extent,
  396. source: new VectorSource({
  397. })
  398. })
  399. map.addLayer(layer)
  400. }
  401. // GeoJSON格式转换为ol.feature格式,样式装载
  402. var geometry = msg.geometry
  403. var style
  404. switch (type) {
  405. case 'notice':
  406. style = this.noticeStyles
  407. break
  408. case 'report':
  409. style = this.reportStyles
  410. break
  411. case 'culture':
  412. style = this.cultureStyles
  413. break
  414. case 'other':
  415. style = this.otherStyles
  416. break
  417. }
  418. var feature = this.GeoJSON_to_Feature(geometry, style)
  419. // 要素属性装载
  420. feature.set('id', msg.id)
  421. feature.set('type', type)
  422. // 要素装载入图层
  423. // 1.起始点
  424. layer.getSource().addFeature(feature)
  425. // 2.关联线
  426. let fe = null
  427. if (isRelate && msg.relate) {
  428. fe = this.GeoJSON_to_Feature(msg.relate, style)
  429. fe.set('id', msg.id)
  430. fe.set('type', type)
  431. layer.getSource().addFeature(fe)
  432. }
  433. // 缩放至要素
  434. if (isLocate) {
  435. let locatedFeature = feature
  436. let feaType = 'origin'
  437. if (isRelate && msg.relate) {
  438. locatedFeature = fe
  439. feaType = 'relate'
  440. }
  441. this.locateAtFeature(locatedFeature, feaType)
  442. }
  443. },
  444. /**
  445. * @description:根据 GeoJSON 格式数据绘制要素
  446. * tips:目前支持类型:Point,MultiLineString
  447. * @param {GeoJSON} geometry:GeoJSON格式数据
  448. * @param {Array of ol.Style} styles:样式
  449. * @returns {ol.feature} 返回由GeoJSON转换成的配制好样式的ol.feature
  450. */
  451. GeoJSON_to_Feature: function (geometry, styles) {
  452. if (!geometry.type) {
  453. console.log('printFromGeoJSON 所输入的GeoJSON不符合规范')
  454. return
  455. }
  456. var feature = null
  457. // 按geometry.type类型创建要素并赋予样式
  458. switch (geometry.type) {
  459. case 'Point':
  460. feature = new Feature({
  461. geometry: new Point(olProj.fromLonLat(geometry.coordinates, 'EPSG:3857')),
  462. shape: geometry.type
  463. })
  464. feature.setStyle(styles.Point)
  465. break
  466. case 'MultiLineString':
  467. // let geo = geometry.coordinates.map(x => {
  468. // return olProj.fromLonLat(x, 'EPSG:3857')
  469. // })
  470. // feature = new Feature({
  471. // geometry: new LineString(geo),
  472. // shape: geometry.type
  473. // })
  474. // feature.setStyle(styles.LineString)
  475. let coords = []
  476. // 多线
  477. geometry.coordinates.forEach(i => {
  478. // 多点
  479. let co = i.map(x => {
  480. x = olProj.fromLonLat(x, 'EPSG:3857')
  481. return x
  482. })
  483. coords.push(co)
  484. })
  485. feature = new Feature({
  486. geometry: new MultiLineString(coords),
  487. shape: geometry.type
  488. })
  489. feature.setStyle(styles.LineString)
  490. break
  491. default:
  492. console.log('printFromGeoJSON不支持该"' + geometry.type + '"类型')
  493. return
  494. }
  495. return feature
  496. },
  497. /**
  498. * @description:ol.feature 转 GeoJSon
  499. * tips:目前支持类型:Point,LineString;
  500. * @param {ol.feature} feature
  501. * @returns {GeoJSON}
  502. */
  503. Feature_to_GeoJSon: function (feature) {
  504. let baseType = feature[0].type
  505. // 多点取第一个点,多线取多线
  506. // eslint-disable-next-line no-unneeded-ternary
  507. let isMulti = feature.length > 1 ? true : false
  508. // eslint-disable-next-line no-unneeded-ternary
  509. isMulti = baseType === 'LineString' ? true : false
  510. if (isMulti) {
  511. let type = 'MultiLineString'
  512. let coords = []
  513. // 多线
  514. feature.forEach(i => {
  515. i = i.coordinates
  516. // 多点
  517. let co = i.map(x => {
  518. x = olProj.toLonLat(x)
  519. return x
  520. })
  521. coords.push(co)
  522. })
  523. return {
  524. type: type,
  525. coordinates: coords
  526. }
  527. } else {
  528. let coord = feature[0].coordinates
  529. switch (baseType) {
  530. case 'LineString':
  531. coord = coord.map(x => {
  532. x = olProj.toLonLat(x)
  533. return x
  534. })
  535. break
  536. case 'Point':
  537. coord = olProj.toLonLat(coord)
  538. break
  539. }
  540. return {
  541. type: baseType,
  542. coordinates: coord
  543. }
  544. }
  545. },
  546. /**
  547. * @description:缩放至要素
  548. * @param {ol.Feature} feature:要素
  549. * @param {int} zoom: 缩放级别
  550. * @return {void}
  551. */
  552. locateAtFeature: function (feature, type, zoom = 17.5) {
  553. let view = map.getView()
  554. view.setZoom(zoom)
  555. if (this.$store.state.isMobile && type !== 'relate') {
  556. let coord = Extent.getCenter(feature.getGeometry().getExtent())
  557. coord[1] = coord[1] * 1.00006
  558. view.setCenter(coord)
  559. } else {
  560. view.setCenter(Extent.getCenter(feature.getGeometry().getExtent()))
  561. }
  562. if (type === 'relate') {
  563. view.setZoom(zoom * 0.975)
  564. }
  565. },
  566. /**
  567. * @description:获取并渲染最近若干天的通知
  568. * @param {int} day: 天数
  569. * @returns {void}
  570. */
  571. loadRecentNotices: function (day) {
  572. var that = this
  573. this.$axios
  574. .post('/notice/recent', {
  575. day: day
  576. })
  577. .then(res => {
  578. res.data.forEach(item => {
  579. that.printFeature('noticeLayer', item, 'notice')
  580. })
  581. this.addCluster('noticeLayer', this.noticeStyles.Point)
  582. })
  583. },
  584. /**
  585. * @description:获取并渲染最近若干天的报道
  586. * @param {int} day: 天数
  587. * @returns {void}
  588. */
  589. loadRecentReports: function (day) {
  590. var that = this
  591. this.$axios
  592. .post('/report/recent', {
  593. day: day
  594. })
  595. .then(res => {
  596. res.data.forEach(item => {
  597. that.printFeature('reportLayer', item, 'report')
  598. })
  599. this.addCluster('reportLayer', this.reportStyles.Point)
  600. })
  601. },
  602. /**
  603. * @description:获取并渲染所有文化设施
  604. * @returns {void}
  605. */
  606. loadCulture: function () {
  607. var that = this
  608. this.$axios
  609. .post('/culture/all')
  610. .then(res => {
  611. res.data.forEach(e => {
  612. that.printFeature('cultureLayer', e, 'culture')
  613. })
  614. this.addCluster('cultureLayer', this.cultureStyles.Point)
  615. })
  616. },
  617. /**
  618. * @description:加载并渲染'更多'
  619. */
  620. loadOthers: function () {
  621. var that = this
  622. this.$axios
  623. .post('/others/all')
  624. .then(res => {
  625. res.data.forEach(e => {
  626. that.printFeature('otherLayer', e, 'other')
  627. })
  628. this.addCluster('otherLayer', this.otherStyles.Point)
  629. })
  630. },
  631. /**
  632. * @description: 地图要素点击事件
  633. * @return {void}
  634. */
  635. mapClick: function () {
  636. var that = this
  637. // 根据设备类型设置点击事件
  638. var clickFun = this.$store.state.isMobile ? mobileClickFun : pcClickFun
  639. map.on('singleclick', clickFun)
  640. async function mobileClickFun (e) {
  641. var feature = map.forEachFeatureAtPixel(e.pixel, function (feature) {
  642. return feature
  643. })
  644. if (feature) {
  645. var id = feature.get('id')
  646. let type = feature.get('type')
  647. let number = feature.get('number')
  648. if (number === 1) {
  649. let data = null
  650. switch (type) {
  651. case 'notice':
  652. data = await that.loadNoticeByID(id)
  653. break
  654. case 'report':
  655. data = await that.loadReportByID(id)
  656. break
  657. case 'culture':
  658. data = await that.loadCultureByID(id)
  659. break
  660. case 'other':
  661. data = await that.loadOthersByID(id)
  662. break
  663. }
  664. that.printFeature('markLayer', data, type, true, true, true)
  665. that.isShow = true
  666. bus.$emit('closeList')
  667. } else {
  668. // 当点击的图标个数大于1时设置视角范围为多个图标的矩形范围
  669. let extent = feature.get('extent')
  670. map.getView().fit(extent, map.getSize())
  671. }
  672. } else {
  673. that.closePopup()
  674. }
  675. }
  676. async function pcClickFun (e) {
  677. // var coordinate = e.coordinate
  678. var feature = map.forEachFeatureAtPixel(e.pixel, feature => {
  679. return feature
  680. })
  681. if (feature) {
  682. let number = feature.get('number')
  683. if (number === 1) {
  684. bus.$emit('printMapMark', {
  685. type: feature.get('type'),
  686. id: feature.get('id')
  687. })
  688. } else {
  689. // 当点击的图标个数大于1时设置视角范围为多个图标的矩形范围
  690. let extent = feature.get('extent')
  691. map.getView().fit(extent, map.getSize())
  692. }
  693. } else {
  694. that.closePopup()
  695. }
  696. }
  697. },
  698. /**
  699. * @description: ol封装:通过title属性获取图层
  700. * @param {title} 图层title值
  701. * @return {layer / null}
  702. */
  703. getLayerByTitle: function (title) {
  704. var layers = map.getLayers().array_
  705. for (let i = 0; i < layers.length; i++) {
  706. if (layers[i].get('title') === title) {
  707. return layers[i]
  708. } else {
  709. continue
  710. }
  711. }
  712. return null
  713. },
  714. /**
  715. * @description:通过id查询载入通知信息
  716. */
  717. loadReportByID: async function (id) {
  718. var that = this
  719. var res
  720. await this.$axios
  721. .post('/report/detail', {
  722. id: id
  723. })
  724. .then(response => {
  725. that.popupData.info = response.data
  726. that.popupData.type = '新闻报道'
  727. res = response.data
  728. })
  729. return res
  730. },
  731. /**
  732. * @description:通过id查询载入通知信息
  733. */
  734. loadNoticeByID: async function (id) {
  735. var that = this
  736. var res
  737. await this.$axios
  738. .post('/notice/detail', {
  739. id: id
  740. })
  741. .then(response => {
  742. that.popupData.info = response.data
  743. that.popupData.type = '活动通知'
  744. res = response.data
  745. })
  746. return res
  747. },
  748. /**
  749. * @description:通过id 查询载入文化信息
  750. */
  751. loadCultureByID: async function (id) {
  752. var that = this
  753. var res
  754. await this.$axios
  755. .post('/culture/detail', {
  756. id: id
  757. })
  758. .then(response => {
  759. response.data.content = response.data.content.join('')
  760. that.popupData.info = response.data
  761. that.popupData.type = '文化设施'
  762. res = response.data
  763. })
  764. return res
  765. },
  766. /**
  767. * @description:通过id 查询载入'其他'信息
  768. */
  769. loadOthersByID: async function (id) {
  770. var that = this
  771. var res
  772. await this.$axios
  773. .post('/others/detail', {
  774. id: id
  775. })
  776. .then(response => {
  777. that.popupData.info = response.data
  778. that.popupData.type = '活动通知'
  779. res = response.data
  780. res = response.data
  781. })
  782. return res
  783. },
  784. /**
  785. * @description:设置并聚焦到popup的显示位置
  786. * @param {ol.coordinate}坐标
  787. * @param {ol.zoom}缩放级别
  788. */
  789. setPopupPosition: function (coordinate, zoom = 18) {
  790. this.popup.setPosition(coordinate)
  791. this.isShow = true
  792. var view = map.getView()
  793. view.setCenter(coordinate)
  794. // view.setZoom(zoom)
  795. },
  796. /**
  797. * @description:根据pc端与mobile端不同的popup关闭事件
  798. * @param {DOM} dom:点击按钮dom
  799. */
  800. closePopup: function (dom) {
  801. if (this.$store.state.isMobile) {
  802. this.isShow = false
  803. } else {
  804. this.popup.setPosition(undefined)
  805. this.isShow = false
  806. // 消除按钮聚焦
  807. if (dom) {
  808. dom.blur()
  809. }
  810. }
  811. return false
  812. },
  813. /**
  814. * @description:绘制要素
  815. */
  816. drawBegin: function () {
  817. // 更改为绘制状态
  818. this.isDraw = true
  819. let col = this.drawColor
  820. switch (this.drawType) {
  821. case '点':
  822. DrawShape.drawPoint(col, map)
  823. break
  824. case '线':
  825. DrawShape.drawLine(col, map)
  826. break
  827. }
  828. },
  829. /**
  830. * @description:结束绘制要素
  831. */
  832. drawEnd: function () {
  833. this.isDraw = false
  834. let data = DrawShape.closeDrawShape()
  835. if (data.length !== 0) {
  836. data = this.Feature_to_GeoJSon(data)
  837. } else {
  838. data = null
  839. }
  840. switch (this.drawType) {
  841. case '点':
  842. bus.$emit('drawGeometryEnd', data)
  843. break
  844. case '线':
  845. bus.$emit('drawRelateEnd', data)
  846. break
  847. }
  848. },
  849. // LayerSelector related
  850. // 底图选择 和 消息选择 的图层切换
  851. getCheckedMap: function (checkMapList) {
  852. this.checkMapList = checkMapList
  853. util.map.setMapVisible(map, checkMapList, 'basemap')
  854. },
  855. getCheckedTag: function (checkTagList) {
  856. this.checkTagList = checkTagList
  857. util.map.setMapVisible(map, checkTagList, 'layer')
  858. },
  859. /**
  860. * @description: 监听视图变化,调整slogan可见
  861. */
  862. sloganListener: function () {
  863. var that = this
  864. // 获取放置地图的div
  865. var mapDiv = document.getElementById('mapview')
  866. // 当鼠标滚轮事件发生时,执行一些操作
  867. function onMouseWheel (ev) {
  868. window.setTimeout(function () {
  869. let zoom = map.getView().getZoom()
  870. if (zoom > 15.3) {
  871. that.slogan.isShow = false
  872. } else {
  873. that.slogan.isShow = true
  874. }
  875. // FF 和 Chrome
  876. if (ev.preventDefault) {
  877. ev.preventDefault()// 阻止默认事件
  878. }
  879. return false
  880. }, 500)
  881. }
  882. addEvent(mapDiv, 'mousewheel', onMouseWheel)
  883. addEvent(mapDiv, 'DOMMouseScroll', onMouseWheel)
  884. addEvent(mapDiv, 'touchmove', onMouseWheel)
  885. function addEvent (obj, xEvent, fn) {
  886. if (obj.attachEvent) {
  887. obj.attachEvent('on' + xEvent, fn)
  888. } else {
  889. obj.addEventListener(xEvent, fn, false)
  890. }
  891. }
  892. },
  893. /**
  894. * @description: eventBus的bus.$on 触发事件汇总
  895. */
  896. busOnAction: function () {
  897. var that = this
  898. // mobile端:绘制报道标识与popup弹窗
  899. bus.$on('showMsgDetail', async msg => {
  900. let data
  901. let id = msg.id
  902. switch (msg.type) {
  903. case 'notice':
  904. await that.loadNoticeByID(id)
  905. .then(res => {
  906. data = res
  907. })
  908. break
  909. case 'report':
  910. await that.loadReportByID(id)
  911. .then(res => {
  912. data = res
  913. })
  914. break
  915. case 'culture':
  916. await that.loadCultureByID(id)
  917. .then(res => {
  918. data = res
  919. })
  920. break
  921. case 'other':
  922. await that.loadOthersByID(id)
  923. .then(res => {
  924. data = res
  925. })
  926. break
  927. }
  928. that.printFeature('markLayer', data, msg.type, true, true, true)
  929. that.isShow = true
  930. })
  931. // PC端:根据各个类型的id 绘制地图标识与popup弹窗
  932. bus.$on('printMapMark', async msg => {
  933. let data
  934. let id = msg.id
  935. switch (msg.type) {
  936. case 'notice':
  937. await that.loadNoticeByID(id)
  938. .then(res => {
  939. data = res
  940. })
  941. break
  942. case 'report':
  943. await that.loadReportByID(id)
  944. .then(res => {
  945. data = res
  946. })
  947. break
  948. case 'culture':
  949. await that.loadCultureByID(id)
  950. .then(res => {
  951. data = res
  952. })
  953. break
  954. case 'other':
  955. await that.loadOthersByID(id)
  956. .then(res => {
  957. data = res
  958. })
  959. break
  960. }
  961. that.printFeature('markLayer', data, msg.type, true, true, true)
  962. // 显示popup
  963. var feature = that.getLayerByTitle('markLayer').getSource().getFeatures()[0]
  964. var coord = feature.getGeometry().getCoordinates()
  965. that.setPopupPosition(coord)
  966. })
  967. // 刷新地图标识
  968. bus.$on('refreshMap', () => {
  969. map.removeLayer(that.getLayerByTitle('noticeLayer'))
  970. map.removeLayer(that.getLayerByTitle('reportLayer'))
  971. map.removeLayer(that.getLayerByTitle('cultureLayer'))
  972. map.removeLayer(that.getLayerByTitle('otherLayer'))
  973. map.removeLayer(that.getLayerByTitle('markLayer'))
  974. that.loadOthers()
  975. that.loadCulture()
  976. that.loadRecentReports(7)
  977. that.loadRecentNotices(7)
  978. that.closePopup()
  979. })
  980. // 绘制
  981. bus.$on('drawBegin', type => {
  982. that.drawType = type
  983. that.drawBegin(type)
  984. })
  985. // 关闭弹窗
  986. bus.$on('closePopup', () => {
  987. that.closePopup()
  988. })
  989. }
  990. },
  991. mounted () {
  992. this.initMap()
  993. this.initPopupOverLay()
  994. this.busOnAction()
  995. this.loadRecentReports(365)
  996. this.loadRecentNotices(365)
  997. this.loadOthers()
  998. this.loadCulture()
  999. this.mapClick()
  1000. this.sloganListener()
  1001. },
  1002. watch: {
  1003. drawType: function () {
  1004. DrawShape.closeDrawShape()
  1005. this.drawBegin()
  1006. },
  1007. isShow: function () {
  1008. if (this.isShow === true) {
  1009. this.slogan.isShow = false
  1010. }
  1011. }
  1012. },
  1013. filters: {
  1014. // 超过100位显示省略号
  1015. ellipsis: function (value) {
  1016. if (!value) return ''
  1017. if (value.length > 70) {
  1018. return value.slice(0, 70) + '...'
  1019. }
  1020. return value
  1021. }
  1022. }
  1023. }
  1024. </script>
  1025. <!-- Add "scoped" attribute to limit CSS to this component only -->
  1026. <style scoped>
  1027. #mapview{
  1028. width: 100%;
  1029. height: 100%;
  1030. position: absolute;
  1031. /* background: rgb(135,191,150); */
  1032. }
  1033. #div-draw {
  1034. position: absolute;
  1035. left: 50%;
  1036. top:2px;
  1037. z-index: 100;
  1038. background: white;
  1039. border-radius: 5px;
  1040. padding: 10px 10px 10px 10px;
  1041. border: 1px solid gray;
  1042. transform: translateX(-50%);
  1043. }
  1044. /*图层切换弹出框样式*/
  1045. #basemap-content {
  1046. position: absolute;
  1047. font-size: 12px;
  1048. z-index: 100;
  1049. background: rgba(255, 255, 255, 0.7);
  1050. opacity: 0.95;
  1051. right: 0px;
  1052. margin-top: 40px;
  1053. height: 50px;
  1054. width:65px;
  1055. align-content: center;
  1056. }
  1057. .basemap-item {
  1058. padding: 5px;
  1059. cursor: pointer;
  1060. }
  1061. .basemap-text,.online-map-text{
  1062. width: 60px;
  1063. height: 12px;
  1064. }
  1065. .basemap-text{
  1066. color: #007bff;
  1067. font-weight: bold;
  1068. font-family: "Source Han Sans CN";
  1069. }
  1070. /*图层与消息按钮样式*/
  1071. .info-select-button {
  1072. width: 22px;
  1073. height: 20px;
  1074. }
  1075. .info-select-button-div {
  1076. width: 22px;
  1077. height: 22px;
  1078. z-index: 999;
  1079. cursor: pointer;
  1080. position: absolute;
  1081. }
  1082. .layer-select-button {
  1083. width: 22px;
  1084. height: 22px;
  1085. }
  1086. .layer-select-button-div {
  1087. width: 22px;
  1088. height: 22px;
  1089. z-index: 999;
  1090. right: 3px;
  1091. cursor: pointer;
  1092. position: absolute;
  1093. }
  1094. </style>