From 4c5ccd55411d61c379bc17abfde2699f50da20d3 Mon Sep 17 00:00:00 2001
From: guanqb <18720758508@163.com>
Date: Fri, 22 Dec 2023 18:18:30 +0800
Subject: [PATCH] 保安员位置接口对接、生成图标点击弹窗展示

---
 src/views/check/components/OlMapBox.vue |  742 ++++++++++++++++++++++++++++++++-------------------------
 1 files changed, 417 insertions(+), 325 deletions(-)

diff --git a/src/views/check/components/OlMapBox.vue b/src/views/check/components/OlMapBox.vue
index 1957c7a..add9d6b 100644
--- a/src/views/check/components/OlMapBox.vue
+++ b/src/views/check/components/OlMapBox.vue
@@ -9,10 +9,19 @@
  * Copyright (c) 2023 by shuishen, All Rights Reserved.
 -->
 <template>
-  <div class="w100 h100">
-    <div id="OlMapBoxElement" class="w100 h100">
+    <div class="w100 h100">
+        <div id="OlMapBoxElement" class="w100 h100">
+        </div>
+        <div id="popup" class="ol-popup" v-show="isShowLivePersonInfoPopover">
+            <a href="#" id="popup-closer" class="ol-popup-closer"></a>
+            <div id="popup-content">
+                <p>名称:{{ livePersonData.realName }}</p>
+                <p>所属公司:{{ livePersonData.deptName }}</p>
+                <p>派遣单位:{{ livePersonData.dispatchCompany }}</p>
+                <p>更新时间:{{ livePersonData.recordTime }}</p>
+            </div>
+        </div>
     </div>
-  </div>
 </template>
 
 <script>
@@ -20,31 +29,32 @@
 import "ol/ol.css"
 import OlView from "ol/View.js"
 import {
-  // eslint-disable-next-line no-unused-vars
-  defaults as OlControlDefaults,
-  defaults,
-  // 全屏控件
-  FullScreen,
-  // 比例尺控件
-  ScaleLine,
-  // 缩放滚动条控件
-  // eslint-disable-next-line no-unused-vars
-  ZoomSlider,
-  // 鼠标位置控件
-  // eslint-disable-next-line no-unused-vars
-  MousePosition,
-  // -地图属性控件
-  Attribution,
-  // 鹰眼控件
-  // eslint-disable-next-line no-unused-vars
-  OverviewMap,
-  // 缩放到范围控件
-  // eslint-disable-next-line no-unused-vars
-  ZoomToExtent,
-  Rotate,
+    // eslint-disable-next-line no-unused-vars
+    defaults as OlControlDefaults,
+    defaults,
+    // 全屏控件
+    FullScreen,
+    // 比例尺控件
+    ScaleLine,
+    // 缩放滚动条控件
+    // eslint-disable-next-line no-unused-vars
+    ZoomSlider,
+    // 鼠标位置控件
+    // eslint-disable-next-line no-unused-vars
+    MousePosition,
+    // -地图属性控件
+    Attribution,
+    // 鹰眼控件
+    // eslint-disable-next-line no-unused-vars
+    OverviewMap,
+    // 缩放到范围控件
+    // eslint-disable-next-line no-unused-vars
+    ZoomToExtent,
+    Rotate,
 } from "ol/control.js"
 import OlSourceOSM from "ol/source/OSM.js"
 import OlLayerTile from "ol/layer/Tile.js"
+import Overlay from "ol/Overlay.js"
 
 import { Image as ImageLayer } from 'ol/layer'
 import ImageStatic from 'ol/source/ImageStatic.js'
@@ -80,332 +90,414 @@
 let layersObjcect = {}
 
 let baseMapLayer = {
-  yx: [],
-  sl: []
+    yx: [],
+    sl: []
 }
+
+let livePersonInfoPopover = null
+
 let options,
-  epsgcode,
-  isMvt = false
+    epsgcode,
+    isMvt = false
 
 let isMapResource = true
 export default {
-  name: 'OlMapBox',
+    name: 'OlMapBox',
 
-  props: {
-    mapType: {
-      type: String,
-      default: 'sl'
-    },
+    props: {
+        mapType: {
+            type: String,
+            default: 'sl'
+        },
 
-    mapContrast: {
-      type: String,
-      default: 'custom'
-    }
-  },
-
-  data () {
-    return {
-      publicPath: process.env.BASE_URL,
-    }
-  },
-
-
-  mounted () {
-    const that = this
-
-    this.$nextTick(() => {
-      mapView = new OlMap({
-        target: 'OlMapBoxElement',
-        layers: [],
-        view: new OlView({
-          // 初始化中心点坐标,经纬度一会自己换一下
-          center: [113, 24],
-          zoom: 18,
-          projection: "EPSG:4326"
-        }),
-      })
-
-      mapView.on("singleclick", function (event) {
-        mapView.forEachFeatureAtPixel(
-          event.pixel,
-          (feature) => {
-            feature.dispatchEvent && feature.dispatchEvent({ type: 'click', event: event })
-          }
-        )
-      })
-
-      that.baseInitLayer(that.mapType)
-
-
-      this.mapAddClusterLayer(
-        'livePersonLocationLayer',
-        '/public/img/map/location',
-        [{lng: 113, lat: 24}, {lng: 115, lat:24 }],
-        (e) => { },
-      )
-    })
-  },
-
-  methods: {
-    /**
-     * @description: 底图加载
-     * @param {*} type
-     * @return {*}
-     */
-    baseInitLayer (type) {
-      if (baseMapLayer.yx.length) {
-        baseMapLayer.yx.forEach(item => {
-          mapView.removeLayer(item)
-        })
-        baseMapLayer.yx = []
-      }
-
-      if (baseMapLayer.sl.length) {
-        baseMapLayer.sl.forEach(item => {
-          mapView.removeLayer(item)
-        })
-        baseMapLayer.sl = []
-      }
-
-      if (type == 'yx') {
-        let yxImgW = new OlLayerTile({
-          zIndex: 1,
-          title: '影像',
-          source: new XYZ({
-            url: 'https://t0.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=e45274b0235bb913eceb393aabbf9c9c',
-          })
-        })
-
-        mapView.addLayer(yxImgW)
-
-        baseMapLayer.yx.push(yxImgW)
-
-        let yxCvaW = new OlLayerTile({
-          zIndex: 2,
-          title: '影像标注',
-          source: new XYZ({
-            url: 'https://t0.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=e45274b0235bb913eceb393aabbf9c9c',
-          })
-        })
-
-        mapView.addLayer(yxCvaW)
-
-        baseMapLayer.yx.push(yxCvaW)
-      } else if (type == 'sl') {
-        let slVecW = new OlLayerTile({
-          zIndex: 2,
-          title: '矢量',
-          source: new XYZ({
-            url: 'https://t0.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=e45274b0235bb913eceb393aabbf9c9c',
-          })
-        })
-
-        mapView.addLayer(slVecW)
-
-        baseMapLayer.sl.push(slVecW)
-
-        let slCvaW = new OlLayerTile({
-          zIndex: 2,
-          title: '矢量标注',
-          source: new XYZ({
-            url: 'https://t0.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=e45274b0235bb913eceb393aabbf9c9c',
-          })
-        })
-
-        mapView.addLayer(slCvaW)
-
-        baseMapLayer.sl.push(slVecW)
-      }
-    },
-
-    // javascript 转换
-    lonLat2Mercator (lonlat) {
-      var mercator = {
-        x: 0,
-        y: 0
-      }
-      var earthRad = 6378137.0
-      mercator.x = lonlat.lng * Math.PI / 180 * earthRad
-      var a = lonlat.lat * Math.PI / 180
-      mercator.y = earthRad / 2 * Math.log((1.0 + Math.sin(a)) / (1.0 - Math.sin(a)))
-      return mercator
-    },
-
-    getCurItemFeature (params) {
-      const iconFeature = new Feature({
-        geometry: new Point([Number(params.lng), Number(params.lat)]),
-        attributes: params.item
-      })
-
-      let styleOptions = {
-        cursor: 'pointer',
-      }
-
-      if (params.url) {
-        styleOptions.image = new Icon({
-          scale: params.scale || 1,
-          imgSize: params.imgSize || [160, 221],
-          src: params.url,
-        })
-      }
-
-      if (params.text) {
-        let textElement = document.createElement('span')
-        textElement.innerHTML = params.text
-
-        let color = '#0000FF'
-
-        styleOptions.text = new Text({
-          // 对齐方式
-          textAlign: 'center',
-          // 文本基线
-          textBaseline: 'middle',
-          text: textElement.innerHTML,
-          font: '14px Arial',
-          fill: new Fill({
-            color: 'white'
-          }),
-          // 填充背景
-          backgroundFill: new Fill({
-            color: color
-          }),
-          padding: [2, 5, 2, 5],
-          stroke: new Stroke({ color: '#00000000', width: 1 })
-        })
-      }
-
-      iconFeature.setStyle(new Style(styleOptions))
-
-      iconFeature.on('click', (e) => {
-        if (params.event) {
-          params.event(e.target.values_.attributes.attr)
+        mapContrast: {
+            type: String,
+            default: 'custom'
         }
-      })
-
-      return iconFeature
     },
 
-    /**
-     * 删除图层
-     * @param {*} layerName 图层名称
-     */
-    mapRemoveLayer (layerNames) {
-      layerNames.forEach(item => {
-        if (layersObjcect[item] && layersObjcect[item] != null) {
-          mapView.removeLayer(layersObjcect[item])
-          delete layersObjcect[item]
+    data () {
+        return {
+            publicPath: process.env.BASE_URL,
+            livePersonData: {},
+            isShowLivePersonInfoPopover: false
         }
-
-        if (layersObjcect[item + 'ONE'] && layersObjcect[item + 'ONE'] != null) {
-          mapView.removeLayer(layersObjcect[item + 'ONE'])
-          delete layersObjcect[item + 'ONE']
-        }
-
-        if (layersObjcect[item + 'TWO'] && layersObjcect[item + 'TWO'] != null) {
-          mapView.removeLayer(layersObjcect[item + 'TWO'])
-          delete layersObjcect[item + 'TWO']
-        }
-      })
     },
 
-    // 添加聚合图层的新模式,水库点分布
-    mapAddClusterLayer (layerName, imgUrl, positionData, incident = (e) => { }, type = '') {
-      const that = this
 
-      if (!layersObjcect[layerName]) {
-        if (type == 'cluster') {
-          let source = new VectorSource()
+    mounted () {
+        const that = this
 
-          positionData.forEach(item => {
-            source.addFeature(that.getCurItemFeature({
-              item,
-              lng: item.lng,
-              lat: item.lat,
-              url: imgUrl,
-              event: incident
-            }))
-          })
-
-          let layer = new Cluster({
-            source: source,
-            distance: 100
-          })
-
-          layersObjcect[layerName] = new VectorLayer({
-            source: layer,
-            zIndex: 24,
-            style: (feature, resolution) => {
-              let size = feature.get('features').length
-
-              let radius = 10
-
-              if (size > 900) {
-                radius = 19
-              } else if (size > 600) {
-                radius = 16
-              } else if (size > 400) {
-                radius = 13
-              }
-
-              let style = new Style({
-                image: new Circle({
-                  radius: radius,
-                  stroke: new Stroke({
-                    color: 'blue',
-                    width: 1
-                  }),
-                  fill: new Fill({
-                    color: 'blue'
-                  })
+        this.$nextTick(() => {
+            mapView = new OlMap({
+                target: 'OlMapBoxElement',
+                layers: [],
+                view: new OlView({
+                    // 初始化中心点坐标,经纬度一会自己换一下
+                    center: [113, 24],
+                    zoom: 18,
+                    projection: "EPSG:4326"
                 }),
-                text: new Text({
-                  text: size.toString(),
-                  fill: new Fill({
-                    color: 'white'
-                  })
-                })
-              })
+            })
 
-              return style
-            }
-          })
+            mapView.on("singleclick", function (event) {
+                mapView.forEachFeatureAtPixel(
+                    event.pixel,
+                    (feature) => {
+                        feature.dispatchEvent && feature.dispatchEvent({ type: 'click', event: event })
+                    }
+                )
+            })
 
-          mapView.addLayer(layersObjcect[layerName])
-
-          return
-        } else {
-          layersObjcect[layerName] = new VectorLayer({
-            // 图标图层
-            zIndex: 24,
-            minZoom: 12,
-            source: new VectorSource(),
-          })
-        }
-
-        mapView.addLayer(layersObjcect[layerName])
-      }
-
-      positionData.forEach(item => {
-        layersObjcect[layerName].getSource().addFeature(that.getCurItemFeature({
-          item,
-          lng: item.lng,
-          lat: item.lat,
-          url: imgUrl,
-          event: incident
-        }))
-      })
+            that.baseInitLayer(that.mapType)
+        })
     },
-  },
+
+    methods: {
+        /**
+         * @description: 底图加载
+         * @param {*} type
+         * @return {*}
+         */
+        baseInitLayer (type) {
+            if (baseMapLayer.yx.length) {
+                baseMapLayer.yx.forEach(item => {
+                    mapView.removeLayer(item)
+                })
+                baseMapLayer.yx = []
+            }
+
+            if (baseMapLayer.sl.length) {
+                baseMapLayer.sl.forEach(item => {
+                    mapView.removeLayer(item)
+                })
+                baseMapLayer.sl = []
+            }
+
+            if (type == 'yx') {
+                let yxImgW = new OlLayerTile({
+                    zIndex: 1,
+                    title: '影像',
+                    source: new XYZ({
+                        url: 'https://t0.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=e45274b0235bb913eceb393aabbf9c9c',
+                    })
+                })
+
+                mapView.addLayer(yxImgW)
+
+                baseMapLayer.yx.push(yxImgW)
+
+                let yxCvaW = new OlLayerTile({
+                    zIndex: 2,
+                    title: '影像标注',
+                    source: new XYZ({
+                        url: 'https://t0.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=e45274b0235bb913eceb393aabbf9c9c',
+                    })
+                })
+
+                mapView.addLayer(yxCvaW)
+
+                baseMapLayer.yx.push(yxCvaW)
+            } else if (type == 'sl') {
+                let slVecW = new OlLayerTile({
+                    zIndex: 2,
+                    title: '矢量',
+                    source: new XYZ({
+                        url: 'https://t0.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=e45274b0235bb913eceb393aabbf9c9c',
+                    })
+                })
+
+                mapView.addLayer(slVecW)
+
+                baseMapLayer.sl.push(slVecW)
+
+                let slCvaW = new OlLayerTile({
+                    zIndex: 2,
+                    title: '矢量标注',
+                    source: new XYZ({
+                        url: 'https://t0.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=e45274b0235bb913eceb393aabbf9c9c',
+                    })
+                })
+
+                mapView.addLayer(slCvaW)
+
+                baseMapLayer.sl.push(slVecW)
+            }
+        },
+
+        // javascript 转换
+        lonLat2Mercator (lonlat) {
+            var mercator = {
+                x: 0,
+                y: 0
+            }
+            var earthRad = 6378137.0
+            mercator.x = lonlat.lng * Math.PI / 180 * earthRad
+            var a = lonlat.lat * Math.PI / 180
+            mercator.y = earthRad / 2 * Math.log((1.0 + Math.sin(a)) / (1.0 - Math.sin(a)))
+            return mercator
+        },
+
+        // 生成图标图层
+        getCurItemFeature (params) {
+            const iconFeature = new Feature({
+                geometry: new Point([Number(params.lng), Number(params.lat)]),
+                attributes: params.item
+            })
+
+            let styleOptions = {
+                cursor: 'pointer',
+            }
+
+            if (params.url) {
+                styleOptions.image = new Icon({
+                    scale: params.scale || 1,
+                    imgSize: params.imgSize || [160, 221],
+                    src: params.url,
+                })
+            }
+
+            if (params.text) {
+                let textElement = document.createElement('span')
+                textElement.innerHTML = params.text
+
+                let color = '#0000FF'
+
+                styleOptions.text = new Text({
+                    // 对齐方式
+                    textAlign: 'center',
+                    // 文本基线
+                    textBaseline: 'middle',
+                    text: textElement.innerHTML,
+                    font: '14px Arial',
+                    fill: new Fill({
+                        color: 'white'
+                    }),
+                    // 填充背景
+                    backgroundFill: new Fill({
+                        color: color
+                    }),
+                    padding: [2, 5, 2, 5],
+                    stroke: new Stroke({ color: '#00000000', width: 1 })
+                })
+            }
+
+            iconFeature.setStyle(new Style(styleOptions))
+
+            iconFeature.on('click', (e) => {
+                if (params.event) {//icon事件参数
+                    params.event(e.target.values_.attributes)//点击事件触发事件并传参
+                }
+            })
+            return iconFeature
+        },
+
+        /**
+         * 删除图层
+         * @param {*} layerName 图层名称
+         */
+        mapRemoveLayer (layerNames) {
+            layerNames.forEach(item => {
+                if (layersObjcect[item] && layersObjcect[item] != null) {
+                    mapView.removeLayer(layersObjcect[item])
+                    delete layersObjcect[item]
+                }
+
+                if (layersObjcect[item + 'ONE'] && layersObjcect[item + 'ONE'] != null) {
+                    mapView.removeLayer(layersObjcect[item + 'ONE'])
+                    delete layersObjcect[item + 'ONE']
+                }
+
+                if (layersObjcect[item + 'TWO'] && layersObjcect[item + 'TWO'] != null) {
+                    mapView.removeLayer(layersObjcect[item + 'TWO'])
+                    delete layersObjcect[item + 'TWO']
+                }
+            })
+        },
+
+        // 添加聚合图层的新模式,水库点分布
+        mapAddClusterLayer (layerName, imgUrl, positionData, incident = (e) => { }, type = '') {
+            const that = this
+
+            if (!layersObjcect[layerName]) {
+                if (type == 'cluster') {
+                    let source = new VectorSource()
+
+                    positionData.forEach(item => {
+                        source.addFeature(that.getCurItemFeature({
+                            item,
+                            lng: item.lng,
+                            lat: item.lat,
+                            url: imgUrl,
+                            event: incident
+                        }))
+                    })
+
+                    let layer = new Cluster({
+                        source: source,
+                        distance: 100
+                    })
+
+                    layersObjcect[layerName] = new VectorLayer({
+                        source: layer,
+                        zIndex: 24,
+                        style: (feature, resolution) => {
+                            let size = feature.get('features').length
+
+                            let radius = 10
+
+                            if (size > 900) {
+                                radius = 19
+                            } else if (size > 600) {
+                                radius = 16
+                            } else if (size > 400) {
+                                radius = 13
+                            }
+
+                            let style = new Style({
+                                image: new Circle({
+                                    radius: radius,
+                                    stroke: new Stroke({
+                                        color: 'blue',
+                                        width: 1
+                                    }),
+                                    fill: new Fill({
+                                        color: 'blue'
+                                    })
+                                }),
+                                text: new Text({
+                                    text: size.toString(),
+                                    fill: new Fill({
+                                        color: 'white'
+                                    })
+                                })
+                            })
+
+                            return style
+                        }
+                    })
+
+                    mapView.addLayer(layersObjcect[layerName])
+
+                    return
+                } else {
+                    layersObjcect[layerName] = new VectorLayer({
+                        // 图标图层
+                        zIndex: 24,
+                        minZoom: 12,
+                        source: new VectorSource(),
+                    })
+                }
+
+                mapView.addLayer(layersObjcect[layerName])
+            }
+
+            positionData.forEach(item => {
+                layersObjcect[layerName].getSource().addFeature(that.getCurItemFeature({
+                    item,
+                    lng: item.lng,
+                    lat: item.lat,
+                    url: imgUrl,
+                    event: incident
+                }))
+                mapView.getView().animate({ // 只设置需要的属性即可
+                    center: [item.lng, item.lat], // 中心点
+                    zoom: 18, // 缩放级别
+                    rotation: undefined, // 缩放完成view视图旋转弧度
+                    duration: 1000 // 缩放持续时间,默认不需要设置
+                })
+            })
+
+        },
+
+        // 生成地图弹窗
+        generateMapPopup (e) {
+            const that = this
+            this.livePersonData = e
+            this.isShowLivePersonInfoPopover = true
+            var container = document.getElementById('popup')
+            var closer = document.getElementById('popup-closer')
+
+            // 创建popup
+            livePersonInfoPopover = new Overlay({
+                element: container,
+                autoPan: true,
+                positioning: 'bottom-center',
+                stopEvent: false,
+                autoPanAnimation: {
+                    duration: 250
+                }
+            })
+            mapView.addOverlay(livePersonInfoPopover)
+            closer.onclick = function () {
+                livePersonInfoPopover.setPosition(undefined)
+                closer.blur()
+                return false
+            }
+            livePersonInfoPopover.setPosition([e.lng, e.lat])
+        },
+
+
+    }
 }
 </script>
 
 <style lang='scss' scope>
-
 .w100 {
-  width: 100%;
+    width: 100%;
 }
 
 .h100 {
-  height: 100%;
+    height: 100%;
+}
+
+.ol-popup {
+    position: absolute;
+    background-color: white;
+    -webkit-filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
+    filter: drop-shadow(0 1px 4px #FFC125);
+    padding: 15px;
+    border-radius: 10px;
+    border: 1px solid #cccccc;
+    bottom: 130px;
+    left: -114px;
+    min-width: 300px;
+}
+
+.ol-popup:after,
+.ol-popup:before {
+    top: 100%;
+    border: solid transparent;
+    content: " ";
+    height: 0;
+    width: 0;
+    position: absolute;
+    pointer-events: none;
+}
+
+.ol-popup:after {
+    border-top-color: white;
+    border-width: 10px;
+    left: 48px;
+    margin-left: -10px;
+}
+
+.ol-popup:before {
+    border-top-color: #cccccc;
+    border-width: 11px;
+    left: 48px;
+    margin-left: -11px;
+}
+
+.ol-popup-closer {
+    text-decoration: none;
+    position: absolute;
+    top: 2px;
+    right: 8px;
+    color: red;
+}
+
+.ol-popup-closer:after {
+    content: "✖";
 }
 </style>

--
Gitblit v1.9.3