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