OpenLayers地图标注之图文标注

注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key

地图标注是将空间位置信息点与地图关联、通过图标、窗口等形式把相关信息展现到地图上。在WebGIS中地图标注是重要的功能之一,可以为用户提供个性化服务,如兴趣点等。地图标注表现方式有图文标注、Popup标注、聚合标注等。本节主要介绍加载图文标注

1. 地图标注基本原理

地图标注通过在已知坐标点添加图片、文字或者图文的方式展现内容信息。可以通过鼠标点击获取目标点位置坐标,也可以通过属性传递获取。

2. 加载地图标注

OpenLayers地图标注由叠加类Overlay实现,主要内容参数为HTMLElement。示例通过document.createElement创建标注内容。

ini 复制代码
const htmlEle = document.createElement("div")
const closeEle = document.createElement('span')
const mainEle = document.createElement('div')

mainEle.className = 'ol-popup-main'
mainEle.textContent = "这是四川省"

closeEle.textContent = "x"
closeEle.className = "ol-popup-close"
htmlEle.className = "ol-popup"

htmlEle.appendChild(mainEle)
htmlEle.appendChild(closeEle)

通过map.addOverlay加载地图标注。

php 复制代码
const marker = new ol.Overlay({
    id: "maker",
    position: chengdu,
    element: htmlEle,
    offset: [0, -70], // x、y轴偏移量,正值向右向下,负值相反
    positioning: 'top-center', // 定位方式,顶部居中
    aotuPan: true,
    autoPanMargin: 1.25,
})
marker.setProperties({ layerName: 'overlay' }) // 设置标注图层属性
map.addOverlay(marker)

3. 移除标注图层

可以根据图层名称或者传入标注图层进行移除。

arduino 复制代码
function removeOverlayByName(layerName) {
    const overlays = map.getOverlays().getArray()
    // console.log("overlays:", overlays)
    overlays.forEach(layer => {
        console.log("layer.layerName:", layer.get('layerName'))
        if (layer.get('layerName') === layerName) map.removeOverlay(layer)
    });
}
function removeOverlayByLayer(overlay) {
    map.removeOverlay(overlay)
}

4. 打开和关闭Popup

OpenLayers中可以通过map.addOverlay实现Popup弹窗,在弹窗关闭之后,通过添加交互事件,在地图上点击目标要素打开PopupSelect类用于图层要素交互,可以通过Select.getFeatures()方法获取被选择的要素。

arduino 复制代码
function openPopup(overlay) {
  map.addOverlay(overlay)
}

function selectFeature(layer) {
    const selectEvt = new ol.interaction.Select({
        layers: [layer], // 用于选择要素的图层
        style: new ol.style.Style({
            image: new ol.style.Circle({
                radius: 5,
                fill: new ol.style.Fill({
                    color: 'yellow'
                }),
                stroke: new ol.style.Stroke({
                    color: 'red'
                })
            })
        })
    })
    // 激活选择事件
    selectEvt.setActive(true)
    map.addInteraction(selectEvt)
    map.on('click', evt => {
        console.log("getLayers:", map.getLayers().getArray())
        const layers = map.getLayers().getArray()
        layers.forEach(layer => {
            const props = layer.getProperties()
            if (props.layerName === "pointLayer") {
                openPopup(marker)
            }
        })
    })
}

5. 完整代码

其中libs文件夹下的包需要更换为自己下载的本地包或者引用在线资源。

xml 复制代码
<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>图文标注</title>
  <meta charset="utf-8" />
  <script src="../libs/js/ol-5.3.3.js"></script>
  <script src="../libs/js/jquery-2.1.1.min.js"></script>
  <link rel="stylesheet" href="../libs/css//ol.css">
  <style>
      * {
          padding: 0;
          margin: 0;
          font-size: 14px;
          font-family: '微软雅黑';
      }

      html,
      body {
          width: 100%;
          height: 100%;
      }

      #map {
          position: absolute;
          width: 100%;
          height: 100%;
      }

      .ol-mouse-position {
          padding: 5px;
          top: 10px;
          height: 40px;
          line-height: 40px;
          background: #060505ba;
          text-align: center;
          color: #fff;
          border-radius: 5px;
      }

      .ol-popup {
          position: relative;
          font-size: 16px;
          color: #4c4c4c;
          background-color: #ddd;
          border-radius: 5px;
      }

      .ol-popup::before {
          display: block;
          content: "";
          width: 0;
          height: 0;
          border-left: 15px solid transparent;
          border-right: 15px solid transparent;
          border-top: 10px solid #ddd;
          position: absolute;
          bottom: -8px;
          left: 50%;
          transform: translateX(-50%);
      }

      .ol-popup-main {
          padding: 20px;
      }

      .ol-popup-close {
          position: absolute;
          display: inline-block;
          top: -6px;
          right: 5px;
          color: #878282b5;
          font-size: 20px;
      }

      .ol-popup-close:hover {
          cursor: pointer;
          color: #0e0e0eb5;
          filter: brightness(120%);
      }
  </style>
</head>

<body>
  <div id="map" title="地图显示"></div>
</body>

</html>

<script>
  //地图投影坐标系
  const projection = ol.proj.get('EPSG:3857');
  //==============================================================================//
  //============================天地图服务参数简单介绍==============================//
  //================================vec:矢量图层==================================//
  //================================img:影像图层==================================//
  //================================cva:注记图层==================================//
  //======================其中:_c表示经纬度投影,_w表示球面墨卡托投影================//
  //==============================================================================//
  const TDTImgLayer = new ol.layer.Tile({
      title: "天地图影像图层",
      source: new ol.source.XYZ({
          url: "http://t0.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=2a890fe711a79cafebca446a5447cfb2",
          attibutions: "天地图注记描述",
          crossOrigin: "anoymous",
          wrapX: false
      })
  })
  const TDTImgCvaLayer = new ol.layer.Tile({
      title: "天地图影像注记图层",
      source: new ol.source.XYZ({
          url: "http://t0.tianditu.com/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=2a890fe711a79cafebca446a5447cfb2",
          attibutions: "天地图注记描述",
          crossOrigin: "anoymous",
          wrapX: false
      })
  })
  const map = new ol.Map({
      target: "map",
      loadTilesWhileInteracting: true,
      view: new ol.View({
          // center: [11421771, 4288300],
          // center: [102.6914059817791, 25.10595662891865],
          center: [104.0635986160487, 30.660919181071225],
          zoom: 10,
          worldsWrap: true,
          minZoom: 1,
          maxZoom: 20,
          projection: "EPSG:4326"
      }),
      // 鼠标控件:鼠标在地图上移动时显示坐标信息。
      controls: ol.control.defaults().extend([
          // 加载鼠标控件
          new ol.control.MousePosition()
      ])
  })

  map.addLayer(TDTImgLayer)
  map.addLayer(TDTImgCvaLayer)

  map.on('click', evt => {
    // 输出点击坐标
    console.log(evt.coordinate)
  })
  // 设置标注点
  const chengdu = [104.0635986160487, 30.660919181071225]

  // 添加点
  const pointLayer = new ol.layer.Vector({
      source: new ol.source.Vector({
          features: [
              new ol.Feature({
                  geometry: new ol.geom.Point(chengdu),
                  name: "chengdu"
              })
          ]
      }),
      style: new ol.style.Style({
          image: new ol.style.Circle({
              radius: 5,
              fill: new ol.style.Fill({
                  color: 'blue'
              })
          }),
          fill: new ol.style.Fill({
              color: "yellow"
          })
      })
  })
  pointLayer.setProperties({ "layerName": "pointLayer" })
  map.addLayer(pointLayer)

  const htmlEle = document.createElement("div")
  const closeEle = document.createElement('span')
  const mainEle = document.createElement('div')

  htmlEle.className = "ol-popup"
  mainEle.className = 'ol-popup-main'
  closeEle.className = "ol-popup-close"

  mainEle.textContent = "这是四川省"
  closeEle.textContent = "x"

  htmlEle.appendChild(mainEle)
  htmlEle.appendChild(closeEle)

  // 注册关闭popup事件
  closeEle.addEventListener('click', evt => {
      removeOverlayByName("overlay")
      // removeOverlayByLayer(marker)
  })
  const marker = new ol.Overlay({
      id: "maker",
      position: chengdu,
      element: htmlEle,
      offset: [0, -70], // x、y轴偏移量,正值向右向下,负值相反
      positioning: 'top-center', // 定位方式,顶部居中
      aotuPan: true,
      autoPanMargin: 1.25,
  })
  marker.setProperties({ layerName: 'overlay' })
  map.addOverlay(marker)

  selectFeature(pointLayer)

  function removeOverlayByName(layerName) {
      const overlays = map.getOverlays().getArray()
      // console.log("overlays:", overlays)
      overlays.forEach(layer => {
          console.log("layer.layerName:", layer.get('layerName'))
          if (layer.get('layerName') === layerName) map.removeOverlay(layer)
      });
  }
  function removeOverlayByLayer(overlay) {
      map.removeOverlay(overlay)
  }

  function openPopup(overlay) {
      map.addOverlay(overlay)
  }

  /**
   * pointLayer 点击监听事件
   * openlayers 中要素点击事件通过ol.interaction.Select实现,
   * 通过 getFeatures() 获取点击的要素
   */
  function selectFeature(layer) {
      const selectEvt = new ol.interaction.Select({
          layers: [layer], // 用于选择要素的图层
          style: new ol.style.Style({
              image: new ol.style.Circle({
                  radius: 5,
                  fill: new ol.style.Fill({
                      color: 'yellow'
                  }),
                  stroke: new ol.style.Stroke({
                      color: 'red'
                  })
              })
          })
      })
      // 激活选择事件
      selectEvt.setActive(true)
      map.addInteraction(selectEvt)
      map.on('click', evt => {
          console.log("getLayers:", map.getLayers().getArray())
          const layers = map.getLayers().getArray()
          layers.forEach(layer => {
              const props = layer.getProperties()
              if (props.layerName === "pointLayer") {
                  openPopup(marker)
              }
          })
          // 获取选择要素
          // const features = selectEvt.getFeatures().getArray()
          // console.log("feats:", features)
          // 若点击点要素,则打开Popup
          // if (features.length) {
          //     openPopup(marker)
          // }

          // 监听状态
          // selectEvt.on('change:active', evt => {
          //    features.forEach(features.remove, features)   
          // })
      })

  }
</script>

OpenLayers示例数据下载,请回复关键字:ol数据

全国信息化工程师-GIS 应用水平考试资料,请回复关键字:GIS考试

【GIS之路】 已经接入了智能助手,欢迎关注,欢迎提问。

欢迎访问我的博客网站-长谈GIShttp://shanhaitalk.com

都看到这了,不要忘记点赞、收藏 + 关注

本号不定时更新有关 GIS开发 相关内容,欢迎关注 !

相关推荐
Attacking-Coder31 分钟前
前端面试宝典---前端水印
前端
姑苏洛言3 小时前
基于微信公众号小程序的课表管理平台设计与实现
前端·后端
烛阴3 小时前
比UUID更快更小更强大!NanoID唯一ID生成神器全解析
前端·javascript·后端
Alice_hhu3 小时前
ResizeObserver 解决 echarts渲染不出来,内容宽度为 0的问题
前端·javascript·echarts
逃逸线LOF4 小时前
CSS之动画(奔跑的熊、两面反转盒子、3D导航栏、旋转木马)
前端·css
萌萌哒草头将军5 小时前
⚡️Vitest 3.2 发布,测试更高效;🚀Nuxt v4 测试版本发布,焕然一新;🚗Vite7 beta 版发布了
前端
技术小丁6 小时前
使用 HTML + JavaScript 在高德地图上实现物流轨迹跟踪系统
前端·javascript·html
小小小小宇6 小时前
React 并发渲染笔记
前端
stark张宇6 小时前
Web - 面向对象
前端·javascript
yanyu-yaya6 小时前
mac电脑安装 nvm 报错如何解决
java·前端·macos