美文网首页
地图上覆盖物压盖的优化

地图上覆盖物压盖的优化

作者: 牛老师讲webgis | 来源:发表于2020-02-19 21:48 被阅读0次

    概述

    在做webgis的时候,会经常性的碰到地图覆盖物压盖的情况。本文讲述一种基于聚类思路的解决办法,实现使用的是openlayers4+。

    效果

    效果

    默认展示第一个点(第一个点可根据一些业务逻辑进行处理,文中简单的做了处理,取了第一个点),鼠标经过第一个点的时候再将其他压盖的点展示出来。

    实现

    1. htm

    <!doctype html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <meta http-equiv="x-ua-compatible" content="ie=edge">
      <title>地图叠加物</title>
      <meta name="description" content="">
      <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
      <link rel="stylesheet" href="css/main.css">
      <link rel="stylesheet" href="https://openlayers.org/en/v4.6.5/css/ol.css" type="text/css">
    </head>
    
    <body>
      <div id="app">
        <div id="map"></div>
        <div
          :style="{left: selectedX + 'px', top: selectedY + 'px'}"
          :class="selectedCluster.length > 0 ? 'show': 'hide'"
          class="overlays">
          <div
            v-for="(item, index) in selectedCluster"
            :key="index"
            class="circle-overlay cluster-overlay"
            :style="{background: colorMap[item.level], marginLeft: padding / 2 + 'px'}">
          </div>
        </div>
      </div>
    
      <script src="https://openlayers.org/en/v4.6.5/build/ol.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/vue"></script>
      <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
      <script src="js/overlay.js"></script>
    </body>
    </html>
    

    2. js

    var that, map;
    
    var app = new Vue({
      el: '#app',
      data: {
        size: 20,
        padding: 2,
        overlays: [
          {
            id: 1,
            coords: [11760366.56, 4662347.84],
            level: 2
          },
          {
            id: 2,
            coords: [11760366.56, 4662347.84],
            level: 1
          },
          {
            id: 3,
            coords: [11760366.56, 4662347.84],
            level: 3
          },
          {
            id: 4,
            coords: [12760366.56, 4662347.84],
            level: 2
          },
          {
            id: 5,
            coords: [12760366.56, 4662347.84],
            level: 1
          },
          {
            id: 6,
            coords: [12760366.56, 4662347.84],
            level: 3
          }
        ],
        clusterData: [],
        mapOverlays: [],
        colorMap: {
          1: 'blue',
          2: 'orange',
          3: 'red'
        },
        mapZoom: -1,
        firstInit: false,
        selectedX: 0,
        selectedY: 0,
        selectedCluster: []
      },
      mounted() {
        that = this;
        that.initMap();
      },
      watch: {
        mapZoom(newVal, oldVal) {
          if (oldVal === -1) that.initOverlays();
        }
      },
      methods: {
        initMap() {
          var osm = new ol.layer.Tile({
            source: new ol.source.OSM()
          });
          map = new ol.Map({
            controls: ol.control.defaults({
              attribution: false
            }),
            target: 'map',
            layers: [osm],
            view: new ol.View({
              minZoom: 3,
              maxZoom: 18,
              center: [11760366.56, 4662347.84],
              zoom: 4
            })
          });
          map.on('moveend', e => {
            that.mapZoom = map.getView().getZoom();
          });
        },
        // 创建新的聚类
        createCluster(d) {
          that.clusterData.push({
            p: d,
            data: [d]
          });
        },
        // 判断距离
        clusterTest(p1, p2) {
          const pixel1 = map.getPixelFromCoordinate(p1.coords);
          const pixel2 = map.getPixelFromCoordinate(p2.coords);
          // 判断两个点的屏幕距离是否小于图标大小:小于,是
          const dis = Math.abs(pixel1[0] - pixel2[0]);
          return dis < that.size;
        },
        // 处理聚类数据
        clusterOverlays() {
          for (var i = 0; i < that.overlays.length; i++) {
            const d = that.overlays[i];
            let _clustered = false;
            for (var j = 0;j < that.clusterData.length;j++) {
              const _d = that.clusterData[j].p;
              const isNear = that.clusterTest(d, _d);
              if (isNear) {
                that.clusterData[j].data.push(d);
                _clustered = true;
                break;
              }
            }
            if (!_clustered) that.createCluster(d);
          }
        },
        initOverlays() {
          that.clusterOverlays();
          // that.showAllOverlays();
          that.showFirstOverlay();
        },
        showFirstOverlay() {
          console.log(that.clusterData);
          for (var i = 0; i < that.clusterData.length; i++) {
            const d = that.clusterData[i].p;
            const dom = document.createElement('div');
            dom.style.background = that.colorMap[d.level];
            dom.setAttribute('class', 'circle-overlay');
            dom.setAttribute('index', i);
            const overlay = new ol.Overlay({
              element: dom,
              position: d.coords,
              positioning: 'center-center',
              offset: [0, 0]
            });
            map.addOverlay(overlay);
    
            // 添加dom事件
            dom.addEventListener('mouseover', evt => {
              const index = evt.target.getAttribute("index");
              const coords = that.clusterData[index].p.coords;
              const pixel = map.getPixelFromCoordinate(coords);
              that.selectedX = pixel[0] + that.size / 2 + that.padding;
              that.selectedY = pixel[1] - that.size / 2;
    
              // 删除第一个div
              const cData = that.clusterData[index].data.concat([]);
              cData.splice(0, 1);
              that.selectedCluster = cData;
            });
            dom.addEventListener('mouseout', evt => {
              that.selectedCluster = [];
            });
          }
        },
        showAllOverlays() {
          for (var i = 0; i < that.clusterData.length; i++) {
            const d = that.clusterData[i].data;
            const coords = that.clusterData[i].p.coords;
            for (var j = 0; j < d.length; j++) {
              const _d = d[j];
              const _xOff = j * (that.size + that.padding);
              const dom = document.createElement('div');
              dom.style.background = that.colorMap[_d.level];
              dom.setAttribute('class', 'circle-overlay');
              const overlay = new ol.Overlay({
                element: dom,
                position: coords,
                positioning: 'center-center',
                offset: [_xOff, 0]
              });
              map.addOverlay(overlay);
            }
          }
        }
      }
    });
    

    3.css

    .circle-overlay {
      border-radius: 50%;
      border: 2px solid #ffffff;
      box-shadow: 1px 1px 4px #ccc;
      width: 18px;
      height: 18px;
      line-height: 18px;
      text-align: center;
      cursor: pointer;
    }
    .overlays {
      position: absolute;
      z-index: 99;
      white-space: nowrap;
      overflow: hidden;
      &.hide {
        display: none;
        max-width: 0;
        transition: max-width 1s, display 1s;
      }
      &.show {
        display: block;
        max-width: 400px;
        transition: max-width 1s, display 1s;
      }
      .cluster-overlay {
        float: left;
      }
    }
    

    相关文章

      网友评论

          本文标题:地图上覆盖物压盖的优化

          本文链接:https://www.haomeiwen.com/subject/vppzfhtx.html