前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >地图上覆盖物压盖的优化

地图上覆盖物压盖的优化

作者头像
lzugis
发布2020-02-20 17:03:56
1.2K0
发布2020-02-20 17:03:56
举报

概述

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

效果

效果
效果

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

实现

1. htm

代码语言:javascript
复制
<!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

代码语言:javascript
复制
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

代码语言:javascript
复制
.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;
  }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-02-19 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 效果
  • 实现
    • 1. htm
      • 2. js
        • 3.css
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档