最近正在搞Mapbox-GL地图的一系列东西,按照公司的需求,要做成离线地图(点击这里),然后要在地图的基础上进行增加图标标记,线条连接、弹窗等等需求。ok废话不多,往下看。

如果还没有安装mapbox-gl的小伙伴请先看一下上篇的离线地图的文章,这里不再重复写安装步骤了,直接上代码:

一、在地图上增加图标

<template>
    <div>
         <div class="mapBOX" id="map" ref="basicMapbox"></div>
    </div>
</template>
 
<script>
let map;
 
import mapboxgl from 'mapbox-gl';
 
export default {
methods: {
    this.initMap(){
        let mapStyle = require('../../../static/style.json');// sytle.json看上一篇文章,或者使用官方的网址也可以:let mapStyle = "mapbox://styles/mapbox/streets-v11"
            map = new mapboxgl.Map({
            container: this.$refs.basicMapbox,
            style: mapStyle,
            // 中心点:北京市
            center: [116.469000,40.251706],
            zoom: 10,
            minZoom: 3,
            maxZoom: 15,
            fadeDuration: 100,
            antialias: true,
        });
 
        this.map.on('load', () => {
            // 图片需要是网络地址,前端本地地址行不通
            map.loadImage('http://ip/file/img/icon.png', (error, image) => {
                if (error) throw error;
                map.addImage('iconImage', image);
 
                // 图标位置坐标
                let features = [{
                    "type": "Feature",
                    "geometry": {
                    "type": "Point",
                    "coordinates": [116.469000,40.251706]
                  }
                }, {
                    "type": "Feature",
                    "geometry": {
                    "type": "Point",
                    "coordinates": [116.469000,40.351706]
                  }
                }]
 
          map.addSource('iconImage', {
              type: 'geojson',
              data: {
                type: 'FeatureCollection',
                features
              }
          });
        
        // 增加图片
        map.addLayer({
          id: "iconImage",
          type: "symbol",
          source: 'iconImage', // 对应addSource第一个参数名字
          layout: {
            "icon-image": "iconImage", // 对应addImage()第一个参数名字
            "icon-size": 0.1,//图标的大小
          },
        })
    }
},
mounted() {
    this.initMap()
}
}
</script>

官网也有示例:
添加链接描述
二、在地图上画线条

<template>
    <div>
         <div class="mapBOX" id="map" ref="basicMapbox"></div>
    </div>
</template>
 
<script>
let map;
 
import mapboxgl from 'mapbox-gl';
 
export default {
methods: {
    this.initMap(){
        let mapStyle = require('../../../static/style.json');// sytle.json看上一篇文章,或者使用官方的网址也可以:let mapStyle = "mapbox://styles/mapbox/streets-v11"
            map = new mapboxgl.Map({
            container: this.$refs.basicMapbox,
            style: mapStyle,
            // 中心点:北京市
            center: [116.469000,40.251706],
            zoom: 10,
            minZoom: 3,
            maxZoom: 15,
            fadeDuration: 100,
            antialias: true,
        });
 
        map.on('load', () => {
            map.addSource('lineSource', {
            type: 'geojson',
            data: {
                type: "FeatureCollection",
                features: [{
                    type: "Feature",
                    geometry: {
                    type: 'LineString',
                    coordinates: [
                      [116.469000,40.251706],
                      [116.469000,40.351706],
                      [117.469000,40.351706]
                    ],
                }
            },
            {
              type: 'Feature',
              geometry: {
                type: 'Point',
                coordinates: [116.469000,40.251706]
              }
            },
            {
              type: 'Feature',
              geometry: {
                type: 'Point',
                coordinates: [116.469000,40.351706]
              }
            },
            {
              type: 'Feature',
              geometry: {
                type: 'Point',
                coordinates: [117.469000,40.351706]
              }
            },
          ]
        }
      });
 
      // 增加线条
      map.addLayer({
        id: "lines",
        type: "line",
        source: "lineSource",
        layout: {
            line-cap: "round",
            line-join: "round",
        },
        paint: {
          "line-width": 3, // 线条宽度
          "line-opacity": 1, // 线条透明度
          "line-color": "#000000", // 线条颜色
        }
      });
 
      // 显示线路节点
      map.addLayer({
        id: "lineSources",
        type: "circle",
        source: "lineSource",
        paint: {
          "circle-radius": 6, // 圆角值
          "circle-color": "#000000" // 节点颜色 
        },
      })
    }
},
mounted() {
    this.initMap()
}
}
</script>

三、地图点击标记点弹窗
这里参考复制了部分代码:
添加链接描述
官网API:
添加链接描述

<template>
    <div>
         <div class="mapBOX" id="map" ref="basicMapbox"></div>
    </div>
</template>
 
<script>
let map;
 
import Vue from "vue";
import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css'; // 最近发现的问题,如果样式没出来,请加上这句
import InfoPopup from "./components/info-popup.vue";
export default {
components: { InfoPopup },
 
methods: {
    this.initMap(){
        let mapStyle = require('../../../static/style.json');// sytle.json看上一篇文章,或者使用官方的网址也可以:let mapStyle = "mapbox://styles/mapbox/streets-v11"
            map = new mapboxgl.Map({
            container: this.$refs.basicMapbox,
            style: mapStyle,
            // 中心点:北京市
            center: [116.469000,40.251706],
            zoom: 10,
            minZoom: 3,
            maxZoom: 15,
            fadeDuration: 100,
            antialias: true,
        });
 
        map.on('load', () => {
            this.openPopup()        
        });
    },
    // 地图标记点弹窗
    openPopup(coordinate = [116.469000,40.251706]) {
      let el = document.createElement('div')
      el.id = 'markerId'
      el.style.backgroundColor= '#6699ff'
      el.style.width = 20 + 'px'
      el.style.height = 20 + 'px'
      el.style.borderRadius = '50%'
 
      let marker = new mapboxgl.Marker(el).setLngLat(coordinate).setOffset([0, -19]).addTo(map) // 将标记添加到地图上
      this.currentMarkers.push(marker)
 
      // 添加弹窗
      const popDetail = Vue.extend(InfoPopup)
      let vm = new popDetail({
        propsData: {
          color: '#6699ff',
          name: 'xxx',
        },
      })
      vm.$mount() //挂载
      let popupTemp = vm.$el
 
      // 添加弹窗
      var popup = new mapboxgl.Popup({ closeButton: false, offset: 25, className: 'map-popup' }).setDOMContent(popupTemp)
      new mapboxgl.Marker(el)
        .setLngLat(coordinate)
        .setPopup(popup)
        .addTo(map)
 
    },
},
mounted() {
    this.initMap()
}
}
</script>

InfoPopup组件:

<!-- 地图弹窗 -->
<template>
    <div class="info-popup">
        <div class="info-popup-content">
            {{ name }}
        </div>
    </div>
</template>
 
<script>
export default {
    name: '',
    props: {
        // 显示名称
        name: {
            type: String,
            default: '名称'
        }
    },
    data() {
        return {
 
        }
    }
};
</script>
<style lang='less' scoped>
.info-popup {
    border-radius: 10px;
    font-family: "Microsoft YaHei";
}
</style>

四、再附上一些可能用到的方法

  1. 鼠标经过事件
map.on('mouseenter', 'addLayer的id值', (e) => {
    console.log('e', e);
});
  1. 鼠标点击事件
map.on('click', 'addLayer的id值', (e) => {
    console.log('e', e);
});
  1. 地图平移
// center为要平移的坐标,zoom为平移的缩放级别
map.flyTo({ center:[坐标], zoom: 9 });
父组件
// 添加弹窗
                    const popDetail = Vue.extend(PopupInfo)
                    let vm = new popDetail({
                        propsData: {
                            name,
                            details,
                        },
                        methods:{
                            closePopup(){
                                //触发关闭弹框
                                this.$emit('close-popup');
                            }
                        }
                    })
                    // 在父组件中监听子组件触发的事件
                    vm.$on('close-popup', () => {
                        // 在这里执行关闭弹框的操作
                        this.popup && this.popup.remove();
                    });
                    vm.$mount() //挂载
                    // 添加弹窗
                    this.popup = new maplibregl.Popup({ closeButton: false, offset: 25, className: 'map-popup' }).setDOMContent(vm.$el)
                    new maplibregl.Marker(ele)
                        .setLngLat(coord)
                        .setPopup(this.popup)
                        .addTo(this.map)
//子组件
<template>
    <div class="detail-popupInfo">
        <span class="detail-popupInfo__title" v-text="name"></span>
        <div class="detail-popupInfo__content" @onWheel="(e)=>e.stopPropagation()">
        <i class="el-icon-close detail-popupInfo__close" @click="close"></i>
        </div>
    </div>
</template>
<script>
export default {
    name: "PopupInfo",
    components: {},
    props: {
        name: {
            type: String,
            default: ''
        },
        details: {
            type: Array,
            default: []
        }
    },
    data() {
        return {
        };
    },
    created() {
    },
    mounted() {
    },
    beforeDestroy() {
    },
    methods: {
        close(){
            this.closePopup();
        }
    }
}
</script>
<style scoped lang="scss">
</style>

最后,react版本

// 详情弹窗
  let popEle = document.createElement('div');
  const popupMaker = new mapboxgl.Marker({ element: popEle, anchor: 'center', offset: [0, 0] });
  //子组件
  const DetailPopup = ({ name, details }) => {
    return (
      <div className="detail-popup">
        <span className="detail-popup__title">{name}</span>
        <div className="detail-popup__content" onWheel={(e) => e.stopPropagation()}>
          <CloseOutlined
            className="detail-popup__close"
            onClick={() => ReactDOM.unmountComponentAtNode(popEle)}
          />
          <article className="detail-popup__ul">
            {details.map((item, index) => (
              <p className="serial" key={index}>
                <span className="dot">●</span>
                <span className="name">{item.mnx}</span>
              </p>
            ))}
          </article>
        </div>
      </div>
    );
  };

// 飞线结束位置
  flyArr.forEach(({ name, coord }) => {
    const properties = flyArrData.features.map((item) => item.properties);
    const details = properties.find((item) => item.name === name)?.details || [];

    let ele = document.createElement('div');
    ele.innerHTML = `
      <div class="line-end-maker" >
        <div class="line-end-maker__title" >${name}</div>
        <div class="line-end-maker__point" />
      </div>
    `;
    new mapboxgl.Marker({ element: ele, anchor: 'center', offset: [0, 0] })
      .setLngLat(coord)
      .addTo(map);

    // 详情弹窗
    ele.addEventListener('click', () => {
      // 点击之后再添加到map上
      popupMaker.remove().setLngLat(coord).addTo(map);
      //父组件
      ReactDOM.unmountComponentAtNode(popEle);
      ReactDOM.render(<DetailPopup name={name} details={details} />, popEle);
    });
  });
GitHub 加速计划 / vu / vue
80
16
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:4 个月前 )
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 6 个月前
e428d891 Updated Browser Compatibility reference. The previous currently returns HTTP 404. 6 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐