map.vue 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150
  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.2
  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.538105225, 3592590.111732335]
  202. let rightBottom = [11594513.693708975, 3587420.877057335]
  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.5) {
  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.000065
  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. loadRecentNotices: function (day) {
  558. var that = this
  559. this.$axios
  560. .post('/notice/recent', {
  561. day: day
  562. })
  563. .then(res => {
  564. res.data.forEach(item => {
  565. that.printFeature('noticeLayer', item, 'notice')
  566. })
  567. this.addCluster('noticeLayer', this.noticeStyles.Point)
  568. })
  569. },
  570. /**
  571. * @description:获取并渲染最近若干天的报道
  572. * @param {int} day: 天数
  573. * @returns {void}
  574. */
  575. loadRecentReports: function (day) {
  576. var that = this
  577. this.$axios
  578. .post('/report/recent', {
  579. day: day
  580. })
  581. .then(res => {
  582. res.data.forEach(item => {
  583. that.printFeature('reportLayer', item, 'report')
  584. })
  585. this.addCluster('reportLayer', this.reportStyles.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. // 当鼠标滚轮事件发生时,执行一些操作
  839. function onMouseWheel (ev) {
  840. window.setTimeout(function () {
  841. let zoom = map.getView().getZoom()
  842. console.log('zoom:' + zoom)
  843. if (zoom > 15.3) {
  844. that.slogan.isShow = false
  845. } else {
  846. that.slogan.isShow = true
  847. }
  848. // FF 和 Chrome
  849. if (ev.preventDefault) {
  850. ev.preventDefault()// 阻止默认事件
  851. }
  852. return false
  853. }, 500)
  854. }
  855. addEvent(mapDiv, 'mousewheel', onMouseWheel)
  856. addEvent(mapDiv, 'DOMMouseScroll', onMouseWheel)
  857. addEvent(mapDiv, 'touchmove', onMouseWheel)
  858. function addEvent (obj, xEvent, fn) {
  859. if (obj.attachEvent) {
  860. obj.attachEvent('on' + xEvent, fn)
  861. } else {
  862. obj.addEventListener(xEvent, fn, false)
  863. }
  864. }
  865. },
  866. /**
  867. * @description:图层 点聚合
  868. */
  869. openCluster: function () {
  870. cluster.openNoticeLayerCluster(info, map)
  871. cluster.openReportLayerCluster(report, map)
  872. cluster.openCultureLayerCluster(culture, map)
  873. cluster.openOtherLayerCluster(more, map)
  874. },
  875. /**
  876. * @description: eventBus的bus.$on 触发事件汇总
  877. */
  878. busOnAction: function () {
  879. var that = this
  880. // mobile端:绘制报道标识与popup弹窗
  881. bus.$on('showReportDetail', async id => {
  882. that.loadReportByID(id)
  883. .then(res => {
  884. that.printFeature('markLayer', res, 'report', true, true, true)
  885. that.isShow = true
  886. })
  887. })
  888. // PC端:根据各个类型的id 绘制地图标识与popup弹窗
  889. bus.$on('printMapMark', async msg => {
  890. let data
  891. let id = msg.id
  892. switch (msg.type) {
  893. case 'notice':
  894. await that.loadNoticeByID(id)
  895. .then(res => {
  896. data = res
  897. })
  898. break
  899. case 'report':
  900. await that.loadReportByID(id)
  901. .then(res => {
  902. data = res
  903. })
  904. break
  905. case 'culture':
  906. await that.loadCultureByID(id)
  907. .then(res => {
  908. data = res
  909. })
  910. break
  911. case 'other':
  912. await that.loadOthersByID(id)
  913. .then(res => {
  914. data = res
  915. })
  916. break
  917. }
  918. that.printFeature('markLayer', data, msg.type, true, true, true)
  919. // 显示popup
  920. var feature = that.getLayerByTitle('markLayer').getSource().getFeatures()[0]
  921. var coord = feature.getGeometry().getCoordinates()
  922. that.setPopupPosition(coord)
  923. })
  924. // 刷新地图标识
  925. bus.$on('refreshMap', () => {
  926. map.removeLayer(that.getLayerByTitle('noticeLayer'))
  927. map.removeLayer(that.getLayerByTitle('reportLayer'))
  928. map.removeLayer(that.getLayerByTitle('cultureLayer'))
  929. map.removeLayer(that.getLayerByTitle('otherLayer'))
  930. map.removeLayer(that.getLayerByTitle('markLayer'))
  931. that.loadOthers()
  932. that.loadCulture()
  933. that.loadRecentReports(7)
  934. that.loadRecentNotices(7)
  935. that.closePopup()
  936. })
  937. // 绘制
  938. bus.$on('drawBegin', type => {
  939. that.drawType = type
  940. that.drawBegin(type)
  941. })
  942. // 关闭弹窗
  943. bus.$on('closePopup', () => {
  944. that.closePopup()
  945. })
  946. }
  947. },
  948. mounted () {
  949. this.initMap()
  950. this.initPopupOverLay()
  951. this.busOnAction()
  952. this.loadRecentReports(365)
  953. this.loadRecentNotices(365)
  954. this.loadOthers()
  955. this.loadCulture()
  956. this.openCluster()
  957. this.mapClick()
  958. this.sloganListener()
  959. },
  960. watch: {
  961. drawType: function () {
  962. DrawShape.closeDrawShape()
  963. this.drawBegin()
  964. },
  965. isShow: function () {
  966. if (this.isShow === true) {
  967. this.slogan.isShow = false
  968. }
  969. }
  970. },
  971. filters: {
  972. // 超过100位显示省略号
  973. ellipsis: function (value) {
  974. if (!value) return ''
  975. if (value.length > 70) {
  976. return value.slice(0, 70) + '...'
  977. }
  978. return value
  979. }
  980. }
  981. }
  982. </script>
  983. <!-- Add "scoped" attribute to limit CSS to this component only -->
  984. <style scoped>
  985. #mapview{
  986. width: 100%;
  987. height: 100%;
  988. position: absolute;
  989. /* background: rgb(135,191,150); */
  990. }
  991. #div-draw {
  992. position: absolute;
  993. left: 50%;
  994. top:2px;
  995. z-index: 100;
  996. background: white;
  997. border-radius: 5px;
  998. padding: 10px 10px 10px 10px;
  999. border: 1px solid gray;
  1000. transform: translateX(-50%);
  1001. }
  1002. /*图层切换弹出框样式*/
  1003. #basemap-content {
  1004. position: absolute;
  1005. font-size: 12px;
  1006. z-index: 100;
  1007. background: rgba(255, 255, 255, 0.7);
  1008. opacity: 0.95;
  1009. right: 0px;
  1010. margin-top: 40px;
  1011. height: 50px;
  1012. width:65px;
  1013. align-content: center;
  1014. }
  1015. .basemap-item {
  1016. padding: 5px;
  1017. cursor: pointer;
  1018. }
  1019. .basemap-text,.online-map-text{
  1020. width: 60px;
  1021. height: 12px;
  1022. }
  1023. .basemap-text{
  1024. color: #007bff;
  1025. font-weight: bold;
  1026. font-family: "Source Han Sans CN";
  1027. }
  1028. /*图层与消息按钮样式*/
  1029. .info-select-button {
  1030. width: 22px;
  1031. height: 20px;
  1032. }
  1033. .info-select-button-div {
  1034. width: 22px;
  1035. height: 22px;
  1036. z-index: 999;
  1037. cursor: pointer;
  1038. position: absolute;
  1039. }
  1040. .layer-select-button {
  1041. width: 22px;
  1042. height: 22px;
  1043. }
  1044. .layer-select-button-div {
  1045. width: 22px;
  1046. height: 22px;
  1047. z-index: 999;
  1048. right: 3px;
  1049. cursor: pointer;
  1050. position: absolute;
  1051. }
  1052. </style>