美文网首页webglGIS加油站
mapboxGL列表和地图联动

mapboxGL列表和地图联动

作者: 牛老师讲webgis | 来源:发表于2021-05-10 22:39 被阅读0次

    概述

    列表和地图联动是webgis中一个非常常见的功能,本文讲一下在mapboxGL中结合vue如何实现此功能。

    效果

    GIF.gif

    实现思路

    1. 获取数据

    获取数据并将数据保存起来;

    2. 列表展示

    列表简单的用ulli来实现。

    3. 地图展示

    数据获取之后,通过document.createElement()的方式创建marker,将结果在地图上展示。

    4. 列表地图联动

    联动存在两个交互:鼠标移动和点击选中,所以需要两个变量用来记录当前鼠标经过的和点击选中的,如果鼠标经过的和点击选中发生变化的时候,去设置对应的样式即可。

    实现代码

    <template>
      <div class="search-panel">
        <div
          class="search-result">
        <h4 class="title">
          查询结果
        </h4>
        <ul
          class="result-list">
          <li
            v-for="(item, index) in searchResult"
            :key="index"
            :class="getClass(item)"
            @mouseover="currentMarker = item"
            @mouseout="currentMarker = {}"
            @click="selectMarker = item">
            <div class="marker">
              <span>{{ index + 1 }}</span>
            </div>
            <div class="info">
              <b>{{ item.name }}</b><br>
              {{ item.addr }}
            </div>
          </li>
        </ul>
      </div>
    </template>
    
    <script>
    export default {
      name: 'Search',
      data() {
        return {
          searchResult: [], //记录查询结果
          markers: [],
          currentMarker: {},
          selectMarker: {},
          markerPopup: null
        };
      },
      methods: {
        init() {
          this.markerPopup = new mapboxgl.Popup({
            closeButton: false,
            closeOnClick: false,
            className: 'marker-popup',
            offset: [0, -15],
            anchor: 'bottom'
          });
          // 造测试数据
          this.searchByKeyword();
        },
        getRandomPos() {
          const bbox = [79.740682, 20.10212, 134.0345, 44.8279];
          const lon = Math.random() * (bbox[2] - bbox[0] + 1) + bbox[0];
          const lat = Math.random() * (bbox[3] - bbox[1] + 1) + bbox[1];
          return [lon, lat];
        },
        getClass(item) { // 设置列表样式
          let cls = item.id === this.currentMarker.id ? 'active' : '';
          cls += item.id === this.selectMarker.id ? ' select' : '';
          return cls;
        },
        setMarkersClass() { // 设置地图marker样式
          this.searchResult.forEach(item => {
            const dom = document.getElementById(item.id);
            if (item.id === this.currentMarker.id) {
              dom.classList.add('active');
            } else {
              dom.classList.remove('active');
            }
            if (item.id === this.selectMarker.id) {
              dom.classList.add('select');
            } else {
              dom.classList.remove('select');
            }
          });
        },
        searchByKeyword() {
          const that = this;
          if (this.keyword !== '') {
            that.loading = true;
            that.searchResult = [];
            this.removeMarkers();
            setTimeout(() => {
              for (let i = 0; i < 10; ++i) {
                that.searchResult.push({
                  id: 'marker' + i,
                  name: '大石地铁站',
                  addr: '广东省广州市番禺区大石地铁站',
                  pos: that.getRandomPos()
                });
              }
              // 添加markers
              that.addMarkers2Map();
              that.loading = false;
            }, 2000);
          }
        },
        addMarkers2Map() {
          const that = this;
          const map = window.map;
          that.searchResult.forEach((item, index) => {
            const ele = document.createElement('div');
            ele.setAttribute('class', 'map-marker');
            ele.setAttribute('id', item.id);
            ele.innerText = (index + 1).toString();
            const option = {
              element: ele
            };
            const marker = new mapboxgl.Marker(option)
              .setLngLat(item.pos)
              .addTo(map);
            that.markers.push(marker);
    
            ele.onmouseover = () => {
              that.currentMarker = item;
            };
            ele.onmouseout = () => {
              that.currentMarker = {};
            };
            ele.onclick = () => {
              that.selectMarker = item;
            };
          });
        },
        removeMarkers() {
          this.markers.forEach(marker => {
            marker.remove();
          });
        },
        showMarkerInfo() {
          const that = this;
          if (this.selectMarker.id) {
            const description = `
                <h5>
                   ${this.selectMarker.name}
                   <span class="close el-icon-close" id="popupClose"></span>
                </h5>
                <ul>
                  <li>温度: 20℃</li>
                  <li>湿度: 52%</li>
                  <li>降水: 1mm</li>
                  <li>风速: 4m/s</li>
                  <li>风向: 无持续风向</li>
                </ul>
              `;
            this.markerPopup
              .setLngLat(this.selectMarker.pos)
              .setHTML(description)
              .addTo(window.map);
            // 添加关闭事件
            document.getElementById('popupClose').onclick = () => {
              that.selectMarker = {};
            };
            window.map.flyTo({
              center: this.selectMarker.pos
            });
          } else {
            this.markerPopup.remove();
          }
        }
      },
      watch: {
        currentMarker(val) {
          this.setMarkersClass();
        },
        selectMarker(val) {
          this.setMarkersClass();
          this.showMarkerInfo();
        }
      }
    };
    </script>
    
    <style scoped lang="scss">
    @import '../../assets/css/map';
    .search-panel {
      position: absolute;
      top: $padding;
      left: $padding;
      z-index: 99;
      .search-result {
        width: 315px;
        background-color: $bg-color;
        border-radius: 4px;
        padding-bottom: 10px;
        .title {
          margin: 0;
          padding: 10px;
          border-bottom: 1px solid #ccc;
          i {
            float: right;
            font-size: 14px;
            &:hover,
            &.active {
              cursor: pointer;
              color: $active-color;
              text-decoration: underline;
            }
          }
        }
      }
      .result-list {
        margin: 10px 0;
        min-height: 100px;
        li {
          padding: 8px 10px;
          overflow: hidden;
          border-bottom: 1px dashed #ddd;
          &:hover,
          &.active,
          &.select {
            cursor: pointer;
            .marker span {
              background-image: url('../../assets/images/marker-blue.png');
            }
          }
          &.select {
            background-color: rgba(0, 0, 0, 0.05);
          }
          .marker {
            float: left;
            width: 35px;
            text-align: center;
            line-height: 30px;
            span {
              width: 26px;
              height: 26px;
              line-height: 20px;
              text-align: center;
              display: inline-block;
              background-image: url('../../assets/images/marker-red.png');
              background-size: 100%;
              color: white;
              border-radius: 100%;
            }
          }
          .info {
            float: left;
          }
        }
      }
    }
    </style>
    <style lang="scss">
    @import '../../assets/css/map';
    .map-marker {
      width: 26px;
      height: 26px;
      line-height: 20px;
      text-align: center;
      background-image: url('../../assets/images/marker-red.png');
      background-size: 100%;
      color: white;
      border-radius: 100%;
      cursor: pointer;
      &:hover,
      &.active,
      &.select {
        background-image: url('../../assets/images/marker-blue.png');
      }
    }
    .marker-popup {
      color: white;
      .mapboxgl-popup-content {
        background-color: $black65;
        margin: 0;
        padding: 8px;
        white-space: nowrap;
        font-size: 12px;
        h5 {
          margin: 0 0 3px 0;
          padding: 3px 0;
          font-size: 14px;
          span {
            float: right;
            cursor: pointer;
          }
        }
        label {
          display: inline-block;
          text-align: right;
          width: 65px;
        }
      }
      .mapboxgl-popup-tip {
        border-top-color: $black65 !important;
      }
    
      .mapboxgl-popup-close-button {
        color: white;
      }
    }
    </style>
    

    相关文章

      网友评论

        本文标题:mapboxGL列表和地图联动

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