1. 动画飞到指定地点

ol飞行动画函数,参数为目标点和缩放级别,缩放级别默认为15级。

/**
 * @description:动画飞到指定地点
 * @param point
 * @param zoomNum
 */
export function flyToPoint(point,zoomNum = 15){
  if (window._map){
    const view = window._map.getView()
    view.animate({ center: point },{ zoom: zoomNum })
  }
}

2. 鼠标指针类型

设置鼠标指针类型函数,用于地图绘制时改变鼠标指针。参数为CSS指针类型。

/**
 * @description:设置鼠标指针类型
 * @param cursor:鼠标指针类型
 * default(箭头)、help(箭头带问号)
 * wait(转圈)、crosshair(十字)
 * text(文本选择)、move(移动)
 * pointer(点击手势)、grab(抓取手势)
 */
exportfunction setCursor(cursor){
if (window._map) {
    const map = window._map
    const targetEle = map.getTargetElement()
    targetEle.style.cursor = cursor
  }
}

3. 清除目标图层

根据图层名称移除图层。参数layerName为自定义参数名,需要在创建图层时设置layerName属性。

/**
 * @description:清除指定图层
 * @param map:地图对象,默认为全局地图对象
 * @param layerName:图层名
 */
export function removeLayerByName(layerName,map = window._map){
  const layers = map.getLayers().getArray()
  layers.forEach(targetLayer => {
    const props = targetLayer.getProperties()
    if (layerName === props["layerName"]) {map.removeLayer(targetLayer)}
  })
}

4. 清除叠加图层

根据叠加图层名称移除叠加图层。参数overName为自定义参数名,需要在创建叠加图层时设置overName属性。

/**
 * @description:清除Overlay(叠加图层)
 * @param map:地图对象,默认为全局地图对象
 * @param overName:覆盖对象名称
 */
export function removeOverlayByName(overName,map = window._map){
  const layers = map.getOverlays().getArray()
  layers.forEach(targetLayer => {
    const props = targetLayer.getProperties()
    if (overName === props["layerName"]) {map.removeOverlay(targetLayer)}
  })
}

5. 清除所有图层

清除所有图层方法用于清除除了底图和指定过滤图层之外的其他图层,也包括叠加图层,其中属性isBaseMapisTileLayer为过滤条件,可以自定义设置。

/**
 * @description:清除除了底图的所有图层
 * @param map:地图对象,默认为全局地图对象
 */
exportfunction removeAllLayer(map = window._map){
  // 清除图层
  const layers = map.getLayers().getArray()
  const tarLayers = layers.map(layer => {
    const props = layer.getProperties()
    if (!props.isBaseMap && !props.isTileLayer){
      return layer
    }
  })
  tarLayers.forEach(tar => {
    map.removeLayer(tar)
  })

  // 清除Overlay
  const overLayers = map.getOverlays().getArray()
  overLayers.forEach(overLayer => map.removeOverlay(overLayer))
}

6. 信息弹窗

信息弹窗用于展示图层或者要素属性信息,在WebGIS开发中经常用到,属于GIS必备功能。该方法稍微有点复杂,参数有点儿多,需要注意参数类型是否正确。

其中property参数为要素属性对象,信息弹窗字段模板popupColumns如下:

// 项目字段
const PROJECT_POPUP_COLUMNS = [
  {
    "name":"projectName",
    "comment":"项目名称"
  },
  {
    "name":"xzqmc",
    "comment":"行政区名称"
  },
  {
    "name":"projectDirect",
    "comment":"招商方向"
  },
]

6.1. 信息弹窗方法

信息弹窗结构如下,主要由头部、角标以及属性表格三部分构成。

/**
 * 设置 Popup 信息弹窗
 * @param property:要素属性
 * @param popupColumns:信息弹窗字段
 * @param polygonGeometry:信息弹窗几何对象【Geometry】
 * @param map:信息弹窗显示地图
 */
exportfunction setPopup(property, popupColumns, polygonGeometry, map) {
  removeOverlayByName('overLay',map)
  //  自定义popup容器
  const popupDiv = document.createElement('div')
  popupDiv.setAttribute('class', 'custom-popup')
  // 自定义popup头部
  const headerDiv = document.createElement('div')
  headerDiv.setAttribute('class', 'custom-popup-header')
  const titleSpan = document.createElement('span')
  titleSpan.setAttribute('class', 'custom-popup-title')
  titleSpan.textContent = "属性信息"
  const closeSpan = document.createElement('span')
  closeSpan.setAttribute('class', 'custom-popup-close')
  closeSpan.textContent = "X"
  headerDiv.appendChild(titleSpan)
  headerDiv.appendChild(closeSpan)
  // 自定义头部定位角标
  const headerAngleIcon = document.createElement('span')
  headerAngleIcon.setAttribute('class', 'custom-header-angle')
  // 自定义popup表格
  const tableEle = document.createElement('table')
  tableEle.className = "popup-table"
  tableEle.setAttribute('border','1')
  tableEle.setAttribute('cellpadding','0')
  tableEle.setAttribute('cellspacing','0')

  Object.values(popupColumns).forEach((prop,index) => {
    if (prop["name"] === 'id' || prop["name"] === 'import_oid') return
    const trEle = document.createElement('tr')
    trEle.className = 'table-tr'
    const firstTdEle = document.createElement('td')
    const secondTdEle = document.createElement('td')
    // firstTdEle.innerText = popupColumns[index].name //popupColumns[index].comment
    firstTdEle.innerText = popupColumns[index].comment
    secondTdEle.innerText = property[popupColumns[index].name] || '暂无'

    trEle.appendChild(firstTdEle)
    trEle.appendChild(secondTdEle)
    tableEle.appendChild(trEle)
  })
  popupDiv.appendChild(headerAngleIcon)
  popupDiv.appendChild(headerDiv)
  popupDiv.appendChild(tableEle)
  const extent = polygonGeometry.getExtent()
  const center = getCenter(extent)

  // 创建Overlay popup
  const overlay = new Overlay({
    id: "temp-polygon",
    position: center,
    element: popupDiv,
    offset: [0,20],
    autoPan: false,
    autoPanMargin: 1.25,
    positioning: 'top-center'
  })
  overlay.setProperties({ layerName: "overLay" })
  map.addOverlay(overlay)

  // 监听popup移除事件
  closeSpan.addEventListener('click',evt => {
    removeOverlayByName('overLay',map)
  })
}

6.2. 信息弹窗CSS结构

/**
* openLayers 样式
*/

.ol-overlay-container p {
  margin: 5px 0 !important;
}

.ol-overlay-container {
  color: #fff;
  border-radius: 2px;
  padding: 2px;
  line-height: 16px;
}

.ol-overlay-container {
  max-height: 250px;
  .popup-analyse-btn {
    width: 100%;
    background-color: rgb(219, 197, 137);
    padding: 10px;
    border-radius: 2.5px;
    margin-top: 10px;
    display: inline-block;
    color: #fffefe;
    border-color: #fff;
    text-align: center;
    &:hover {
      cursor: pointer;
      color: #fff;
      filter: brightness(110%) opacity(100%);
      transition: all .5s ease-in;
      background: linear-gradient(to bottom right, #9a99f1, #0167cc);
    }

    &:focus {
      filter: brightness(120%);
      transition: all .5s ease-in;
      background: radial-gradient(circle at center, #9a99f1, #0167cc);
    }

  }
  .custom-popup{
    max-height: 250px;
    max-width: 350px;
    overflow-y: scroll;
  }

  .custom-popup-header{
    position: sticky;
    top: 0;
    z-index: 99;
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    padding: 0 10px;
    height: 45px;
    line-height: 45px;
    background-image: url(../assets/image/sw_01.png);
    background-color: #0167cc;;
    border-top-left-radius: 2.5px;
    border-top-right-radius: 2.5px;

    .custom-popup-title{
      color: #fff;
      font-weight: bold;
      font-size: 16px;
    }
    .custom-popup-close{
      display: block;
      width: 30px;
      height: 30px;
      margin-top: 6px;
      line-height: 30px;
      color: #9c9c9c;
      font-size: 16px;
      border-radius: 50%;
      text-align: center;
      &:hover{
        cursor: pointer;
        font-size: 18px;
        color: red;
        border-radius: 50%;
        background-color: #9bcbde;
        transition: all .5s ease-in;
        //filter: brightness(1.5);
      }
    }
  }

  .custom-header-angle{
    position: absolute;
    display: block;
    top: -15px;
    left: 50%;
    width: 0;
    height: 0;
    transform: translateX(-50%);
    border-left: 40px solid transparent;
    border-right: 40px solid transparent;
    border-bottom: 30px solid #003468;
  }

  .popup-table{
    max-height: 250px;
    overflow-y: auto;
    width: 100%;
    height: 100%;
    background-size: 100% 100%;
    background-color: #409eff21;
    border: 1px solid #d9d9d9ad;
    border-collapse: collapse;
    background-image: url(../assets/image/sw_02.png);
    .table-tr{
      width: 100%;
      &:hover{
        cursor: pointer;
        background-color: #0c698d61;
      }
      td{
        padding: 10px 5px;
        line-height: 1.5;
      }
      td:first-child{
        text-align: right;
        width: 45%;
      }
      td:last-child{
        text-align: left;
        width: 55%;
      }
    }
  }
  .select-analyse-popup{
    table{
      border: 1px solid #fff;
      border-collapse: collapse;
      tr{
        td{
          padding: 10px 5px;
          line-height: 1.5;
        }
        td:first-child{
          text-align: right;
        }
        td:last-child{
          text-align: left;
        }
      }
    }
  }
}

.query-header{
  position: sticky;
  top: 0;
  z-index: 99;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  padding: 0 10px;
  height: 45px;
  line-height: 45px;
  background-color: #0167cc;;
  border-top-left-radius: 2.5px;
  border-top-right-radius: 2.5px;
  .query-header-span{
    color: #fff;
    font-weight: bold;
    font-size: 16px;
  }
  .query-header-close{
    display: block;
    width: 30px;
    height: 30px;
    margin-top: 6px;
    line-height: 30px;
    color: #9c9c9c;
    font-size: 16px;
    border-radius: 50%;
    text-align: center;
    &:hover{
      cursor: pointer;
      font-size: 18px;
      color: red;
      border-radius: 50%;
      background-color: #9bcbde;
      transition: all .5s ease-in;
      //filter: brightness(1.5);
    }
  }
}

.query-tabs{
  position: sticky;
  padding: 10px;
  background: #004066;
  width: 100%;
  overflow-x: scroll;
  .query-tab-content{
    white-space: nowrap;
    scrollbar-width: thin;
    scrollbar-color: #999999 #dddddd;
  }
  .query-tab-span{
    padding: 5px;
    display: inline-block;
    margin-right: 10px;
    border: 1px solid #ccc;
    border-radius: 2.5px;
  }
  .query-tab-span:hover{
    cursor: pointer;
    background: #0796f0;
    transition: all .5s ease-in;
  }
}

.query-tab-active{
  background: #0796f0;
  font-weight: bold;
}

7. 图层查询信息弹窗

图层查询信息弹窗主要用于地图点选查询,可能会查询不止一个图层。在信息弹窗方法的基础上进行改进,主要用于显示多个图层属性。

/**
 * 设置 Popup 数据查询信息弹窗
 * @param results:分析结果数据
 * @param map:信息弹窗显示地图
 */
exportfunction openPopupOfQueryLayer(results, map) {
  removeOverlayByName('overLay',map)
  //  自定义popup容器
  const queryWrap = document.createElement('div')
  queryWrap.setAttribute('class', 'custom-popup')
  // 自定义popup头部
  const headerDiv = document.createElement('header')
  headerDiv.setAttribute('class', 'custom-popup-header')
  const titleSpan = document.createElement('span')
  titleSpan.setAttribute('class', 'custom-popup-title')
  titleSpan.textContent = "属性信息"
  const closeSpan = document.createElement('span')
  closeSpan.setAttribute('class', 'custom-popup-close')
  closeSpan.textContent = "X"
  headerDiv.appendChild(titleSpan)
  headerDiv.appendChild(closeSpan)
  // 自定义属性内容区域
  const queryBody = document.createElement('div')
  queryBody.setAttribute('class', 'query-body')
  // 自定义头部定位角标
  const headerAngleIcon = document.createElement('span')
  headerAngleIcon.setAttribute('class', 'custom-header-angle')
  // 自定义popup表格
  const tableEle = document.createElement('table')
  tableEle.className = "popup-table"
  tableEle.setAttribute('border','1')
  tableEle.setAttribute('cellpadding','0')
  tableEle.setAttribute('cellspacing','0')

  // 自定义查询图层标题
  const queryTabs = document.createElement('div')
  queryTabs.setAttribute('class', 'query-tabs')
  const queryTabContent = document.createElement("div")
  queryTabContent.setAttribute('class', 'query-tab-content')

  results.forEach(feature => {
    if (!feature.geometry){
      return
    }
    const queryTabSpan = document.createElement('span')
    queryTabSpan.textContent = feature.label
    queryTabSpan.setAttribute('class', 'query-tab-span')
    queryTabContent.appendChild(queryTabSpan)
  })
  queryTabs.appendChild(queryTabContent)
  // 添加默认选中样式
  const firstChild = queryTabContent.firstChild
  firstChild.classList.add('query-tab-active')
  // 添加要素默认样式
let popupInfo = results[0]
  // 事件委托,展示目标选项,筛选显示图层
  const tabArr = queryTabContent.childNodes
  queryTabContent.addEventListener('click', evt => {
    const targetElement = evt.target
    if (targetElement.tagName.toUpperCase() !== "SPAN"){
      return
    }
    removeOverlayByName('overLay',map)
    tabArr.forEach(tab => {
      tab.classList.remove('query-tab-active')
    })
    targetElement.classList.add('query-tab-active')
    const layerName = targetElement.textContent

    popupInfo = results.find(result => {
      const defaultPolygon = popupInfo["polygon"]
      defaultPolygon.setStyle(defaultStyle)
      return result.label === layerName
    })
    tableEle.innerHTML = ""
    showOverlay(popupInfo)
  })

  const showOverlay = (popupInfo) => {
    if (!popupInfo){
      console.log("信息弹窗:",popupInfo)
      tableEle.innerHTML = "<span>暂无数据</span>"
    }
    const popupColumns = popupInfo['popupColumns']
    const property = popupInfo["properties"]

    const defaultPolygon = popupInfo["polygon"]
    defaultPolygon.setStyle(geometrySelectStyle["Polygon"])

    Object.values(popupColumns).forEach((prop,index) => {
      if (prop["name"] === 'id' || prop["name"] === 'import_oid') return
      const trEle = document.createElement('tr')
      trEle.className = 'table-tr'
      const firstTdEle = document.createElement('td')
      const secondTdEle = document.createElement('td')
      // firstTdEle.innerText = popupColumns[index].name //popupColumns[index].comment
      firstTdEle.innerText = popupColumns[index].comment
      secondTdEle.innerText = property[popupColumns[index].name] || '暂无'

      trEle.appendChild(firstTdEle)
      trEle.appendChild(secondTdEle)
      tableEle.appendChild(trEle)
    })
    const geometry = popupInfo['geometry']
    const geom = new GeoJSON().readGeometry(geometry)
    const extent = geom.getExtent()
    const center = getCenter(extent)
    map.getView().fit(extent)
    // 创建Overlay popup
    const overlay = new Overlay({
      id: "temp-polygon",
      position: center,
      element: queryWrap,
      offset: [0,20],
      autoPan: false,
      autoPanMargin: 1.25,
      positioning: 'top-center'
    })
    overlay.setProperties({ layerName: "overLay" })
    map.addOverlay(overlay)

    queryWrap.appendChild(headerAngleIcon)
    queryWrap.appendChild(headerDiv)
    queryWrap.appendChild(queryTabs)
    queryWrap.appendChild(tableEle)
  }
  showOverlay(popupInfo)
  // 监听popup移除事件
  closeSpan.addEventListener('click',evt => {
    removeOverlayByName('overLay',map)
  })
}

8. ol样式库

ol样式库主要用于全局图层、要素样式设置,包括默认样式对象、选中样式对象等。这样当需要调整要素样式的时候只需要修改样式库代码即可,而无需修改代码逻辑。

import Style from 'ol/style/Style';
import { Fill, Stroke } from "ol/style";
import CircleStyle from "ol/style/Circle";

/**
 * 图形默认样式
 * @type {Style}
 */
const defaultStyle = new Style({
  // 填充色
  fill: new Fill({
    color: "rgba(251, 33, 2, 0.10)"
  }),
  // 边线色
  stroke: new Stroke({
    color: "rgba(251, 33, 2, 0.5)",
    width: 2.5
  })
})

/**
 * 行政区默认样式
 * @type {Style}
 */
const defaultRegionStyle = new Style({
  // 填充色
  fill: new Fill({
    color: 'rgba(255, 255, 255, 0.2)'
  }),
  // 边线色
  stroke: new Stroke({
    color: "#fffcc3",
    width: 2
  })
})
/**
 * 几何对象默认样式
 * @type {{Circle: Style, MultiPolygon: Style, LineString: Style, Box: Style, Point: Style, Polygon: Style}}
 */
const geometryDefaultStyle = {
  // 多边形
"MultiPolygon": new Style({
    fill: new Fill({
      color: "rgba(251, 33, 2, 0.10)"
    }),
    stroke: new Stroke({
      color: "rgba(251, 33, 2, 0.85)",
      width: 2.5
    })
  }),
  // 面
"Polygon": new Style({
    fill: new Fill({
      color: "rgba(251, 33, 2, 0.10)"
    }),
    stroke: new Stroke({
      color: "rgba(251, 33, 2, 0.85)",
      width: 2.5
    })
  }),
  // 线
"LineString": new Style({
    stroke: new Stroke({
      color: "rgba(251, 33, 2, 0.85)",
      width: 2.5
    })
  }),
  // 点
"Point": new Style({
    image: new CircleStyle({
      fill: new Fill({
        color: "rgba(251, 33, 2, 0.5)"
      }),
      radius: 8
    })
  }),
  // 圆形
"Circle": new Style({
    fill: new Fill({
      color: "rgba(251, 33, 2, 0.10)"
    }),
    stroke: new Stroke({
      color: "rgba(251, 33, 2, 0.85)",
      width: 2
    })
  }),
  // 矩形
"Box": new Style({
    fill: new Fill({
      color: "rgba(251, 33, 2, 0.10)"
    }),
    stroke: new Stroke({
      color: "rgba(251, 33, 2, 0.85)",
      width: 2
    })
  })
}
/**
 * 几何对象选中样式
 * @type {{MultiPolygon: Style, LineString: Style, Point: Style, Polygon: Style}}
 */
const geometrySelectStyle = {
  // 多边形
"MultiPolygon": new Style({
    fill: new Fill({
      color: "rgba(251, 33, 2, 0.10)"
    }),
    stroke: new Stroke({
      color: "rgba(0,255,255,0.9)",
      lineDash: [4],
      width: 4.5
    })
  }),
  // 面
"Polygon": new Style({
    fill: new Fill({
      color: "rgba(251, 33, 2, 0.10)"
    }),
    stroke: new Stroke({
      color: "rgba(0,255,255,0.85)",
      lineDash: [4],
      width: 3.5
    })
  }),
  // 线
"LineString": new Style({
    stroke: new Stroke({
      color: "rgba(0,255,255,0.85)",
      lineDash: [4],
      width: 3.5
    })
  }),
  // 点
"Point": new Style({
    image: new CircleStyle({
      fill: new Fill({
        color: "rgba(10,213,253)"
      }),
      radius: 8
    })
  })
}

export {
  geometryDefaultStyle,
  geometrySelectStyle,
  defaultStyle,
  defaultRegionStyle
}

9. ol工具集(全)

/**
 * @name: olTool
 * @description: ol库工具类
 **/

import Overlay from "ol/Overlay";
import { getCenter } from 'ol/extent';
import GeoJSON from "ol/format/GeoJSON";
import { defaultStyle, geometrySelectStyle } from "@/utils/OpenLayers/olStyles";

/**
 * @description:动画飞到指定地点
 * @param point
 * @param zoomNum
 */
exportfunction flyToPoint(point,zoomNum = 15){
if (window._map){
    const view = window._map.getView()
    view.animate({ center: point },{ zoom: zoomNum })
  }
}

/**
 * @description:设置鼠标指针类型
 * @param cursor:鼠标指针类型
 * default(箭头)、help(箭头带问号)
 * wait(转圈)、crosshair(十字)
 * text(文本选择)、move(移动)
 * pointer(点击手势)、grab(抓取手势)
 */
exportfunction setCursor(cursor){
if (window._map) {
    const map = window._map
    const targetEle = map.getTargetElement()
    targetEle.style.cursor = cursor
  }
}

/**
 * @description:清除指定图层
 * @param map:地图对象,默认为全局地图对象
 * @param layerName:图层名
 */
exportfunction removeLayerByName(layerName,map = window._map){
  const layers = map.getLayers().getArray()
  layers.forEach(targetLayer => {
    const props = targetLayer.getProperties()
    if (layerName === props["layerName"]) {map.removeLayer(targetLayer)}
  })
}

/**
 * @description:清除Overlay(叠加图层)
 * @param map:地图对象,默认为全局地图对象
 * @param overName:覆盖对象名称
 */
exportfunction removeOverlayByName(overName,map = window._map){
  const layers = map.getOverlays().getArray()
  layers.forEach(targetLayer => {
    const props = targetLayer.getProperties()
    if (overName === props["layerName"]) {map.removeOverlay(targetLayer)}
  })
}

/**
 * @description:清除除了底图的所有图层
 * @param map:地图对象,默认为全局地图对象
 */
exportfunction removeAllLayer(map = window._map){
  // 清除图层
  const layers = map.getLayers().getArray()
  const tarLayers = layers.map(layer => {
    const props = layer.getProperties()
    if (!props.isBaseMap && !props.isTileLayer){
      return layer
    }
  })
  tarLayers.forEach(tar => {
    map.removeLayer(tar)
  })

  // 清除Overlay
  const overLayers = map.getOverlays().getArray()
  overLayers.forEach(overLayer => map.removeOverlay(overLayer))
}

/**
 * 设置 Popup 信息弹窗
 * @param property:要素属性
 * @param popupColumns:信息弹窗字段
 * @param polygonGeometry:信息弹窗几何对象【Geometry】
 * @param map:信息弹窗显示地图
 */
exportfunction setPopup(property, popupColumns, polygonGeometry, map) {
  removeOverlayByName('overLay',map)
  //  自定义popup容器
  const popupDiv = document.createElement('div')
  popupDiv.setAttribute('class', 'custom-popup')
  // 自定义popup头部
  const headerDiv = document.createElement('div')
  headerDiv.setAttribute('class', 'custom-popup-header')
  const titleSpan = document.createElement('span')
  titleSpan.setAttribute('class', 'custom-popup-title')
  titleSpan.textContent = "属性信息"
  const closeSpan = document.createElement('span')
  closeSpan.setAttribute('class', 'custom-popup-close')
  closeSpan.textContent = "X"
  headerDiv.appendChild(titleSpan)
  headerDiv.appendChild(closeSpan)
  // 自定义头部定位角标
  const headerAngleIcon = document.createElement('span')
  headerAngleIcon.setAttribute('class', 'custom-header-angle')
  // 自定义popup表格
  const tableEle = document.createElement('table')
  tableEle.className = "popup-table"
  tableEle.setAttribute('border','1')
  tableEle.setAttribute('cellpadding','0')
  tableEle.setAttribute('cellspacing','0')

  Object.values(popupColumns).forEach((prop,index) => {
    if (prop["name"] === 'id' || prop["name"] === 'import_oid') return
    const trEle = document.createElement('tr')
    trEle.className = 'table-tr'
    const firstTdEle = document.createElement('td')
    const secondTdEle = document.createElement('td')
    // firstTdEle.innerText = popupColumns[index].name //popupColumns[index].comment
    firstTdEle.innerText = popupColumns[index].comment
    secondTdEle.innerText = property[popupColumns[index].name] || '暂无'

    trEle.appendChild(firstTdEle)
    trEle.appendChild(secondTdEle)
    tableEle.appendChild(trEle)
  })
  popupDiv.appendChild(headerAngleIcon)
  popupDiv.appendChild(headerDiv)
  popupDiv.appendChild(tableEle)
  const extent = polygonGeometry.getExtent()
  const center = getCenter(extent)

  // 创建Overlay popup
  const overlay = new Overlay({
    id: "temp-polygon",
    position: center,
    element: popupDiv,
    offset: [0,20],
    autoPan: false,
    autoPanMargin: 1.25,
    positioning: 'top-center'
  })
  overlay.setProperties({ layerName: "overLay" })
  map.addOverlay(overlay)

  // 监听popup移除事件
  closeSpan.addEventListener('click',evt => {
    removeOverlayByName('overLay',map)
  })
}

/**
 * 设置 Popup 数据查询信息弹窗
 * @param results:分析结果数据
 * @param map:信息弹窗显示地图
 */
exportfunction openPopupOfQueryLayer(results, map) {
  removeOverlayByName('overLay',map)
  //  自定义popup容器
  const queryWrap = document.createElement('div')
  queryWrap.setAttribute('class', 'custom-popup')
  // 自定义popup头部
  const headerDiv = document.createElement('header')
  headerDiv.setAttribute('class', 'custom-popup-header')
  const titleSpan = document.createElement('span')
  titleSpan.setAttribute('class', 'custom-popup-title')
  titleSpan.textContent = "属性信息"
  const closeSpan = document.createElement('span')
  closeSpan.setAttribute('class', 'custom-popup-close')
  closeSpan.textContent = "X"
  headerDiv.appendChild(titleSpan)
  headerDiv.appendChild(closeSpan)
  // 自定义属性内容区域
  const queryBody = document.createElement('div')
  queryBody.setAttribute('class', 'query-body')
  // 自定义头部定位角标
  const headerAngleIcon = document.createElement('span')
  headerAngleIcon.setAttribute('class', 'custom-header-angle')
  // 自定义popup表格
  const tableEle = document.createElement('table')
  tableEle.className = "popup-table"
  tableEle.setAttribute('border','1')
  tableEle.setAttribute('cellpadding','0')
  tableEle.setAttribute('cellspacing','0')

  // 自定义查询图层标题
  const queryTabs = document.createElement('div')
  queryTabs.setAttribute('class', 'query-tabs')
  const queryTabContent = document.createElement("div")
  queryTabContent.setAttribute('class', 'query-tab-content')

  results.forEach(feature => {
    if (!feature.geometry){
      return
    }
    const queryTabSpan = document.createElement('span')
    queryTabSpan.textContent = feature.label
    queryTabSpan.setAttribute('class', 'query-tab-span')
    queryTabContent.appendChild(queryTabSpan)
  })
  queryTabs.appendChild(queryTabContent)
  // 添加默认选中样式
  const firstChild = queryTabContent.firstChild
  firstChild.classList.add('query-tab-active')
  // 添加要素默认样式
let popupInfo = results[0]
  // 事件委托,展示目标选项,筛选显示图层
  const tabArr = queryTabContent.childNodes
  queryTabContent.addEventListener('click', evt => {
    const targetElement = evt.target
    if (targetElement.tagName.toUpperCase() !== "SPAN"){
      return
    }
    removeOverlayByName('overLay',map)
    tabArr.forEach(tab => {
      tab.classList.remove('query-tab-active')
    })
    targetElement.classList.add('query-tab-active')
    const layerName = targetElement.textContent

    popupInfo = results.find(result => {
      const defaultPolygon = popupInfo["polygon"]
      defaultPolygon.setStyle(defaultStyle)
      return result.label === layerName
    })
    tableEle.innerHTML = ""
    showOverlay(popupInfo)
  })

  const showOverlay = (popupInfo) => {
    if (!popupInfo){
      console.log("信息弹窗:",popupInfo)
      tableEle.innerHTML = "<span>暂无数据</span>"
    }
    const popupColumns = popupInfo['popupColumns']
    const property = popupInfo["properties"]

    const defaultPolygon = popupInfo["polygon"]
    defaultPolygon.setStyle(geometrySelectStyle["Polygon"])

    Object.values(popupColumns).forEach((prop,index) => {
      if (prop["name"] === 'id' || prop["name"] === 'import_oid') return
      const trEle = document.createElement('tr')
      trEle.className = 'table-tr'
      const firstTdEle = document.createElement('td')
      const secondTdEle = document.createElement('td')
      // firstTdEle.innerText = popupColumns[index].name //popupColumns[index].comment
      firstTdEle.innerText = popupColumns[index].comment
      secondTdEle.innerText = property[popupColumns[index].name] || '暂无'

      trEle.appendChild(firstTdEle)
      trEle.appendChild(secondTdEle)
      tableEle.appendChild(trEle)
    })
    const geometry = popupInfo['geometry']
    const geom = new GeoJSON().readGeometry(geometry)
    const extent = geom.getExtent()
    const center = getCenter(extent)
    map.getView().fit(extent)
    // 创建Overlay popup
    const overlay = new Overlay({
      id: "temp-polygon",
      position: center,
      element: queryWrap,
      offset: [0,20],
      autoPan: false,
      autoPanMargin: 1.25,
      positioning: 'top-center'
    })
    overlay.setProperties({ layerName: "overLay" })
    map.addOverlay(overlay)

    queryWrap.appendChild(headerAngleIcon)
    queryWrap.appendChild(headerDiv)
    queryWrap.appendChild(queryTabs)
    queryWrap.appendChild(tableEle)
  }
  showOverlay(popupInfo)
  // 监听popup移除事件
  closeSpan.addEventListener('click',evt => {
    removeOverlayByName('overLay',map)
  })
}