map.vue 30 KB

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