vue中使用地图进行点、线、面绘制(vue + MineMap )

4,237 阅读5分钟

完成效果 代码地址

其实前端使用地图真的没有那么难,任何事物都是讲究方法的,前端使用地图也是一样的。

地图的一些基本知识

geoJson

维基百科这样介绍:GeoJSON是一种基于JSON的地理空间数据交换格式,它定义了几种类型JSON对象以及它们组合在一起的方法,以表示有关地理要素、属性和它们的空间范围的数据。

// 表示一个点
{
    "type": "Point", 
    "coordinates": [30, 10]
}

// 表示一个线
{
    "type": "LineString", 
    "coordinates": [
        [30, 10], [10, 30], [40, 40]
    ]
}

// 表示一个面(多边形)
{
    "type": "Polygon", 
    "coordinates": [
        [[30, 10], [40, 40], [20, 40], [10, 20], [30, 10]]
    ]
}

// 特殊的面 (特殊多边形)
{
    "type": "Polygon", 
    "coordinates": [
        [[35, 10], [45, 45], [15, 40], [10, 20], [35, 10]], 
        [[20, 30], [35, 35], [30, 20], [20, 30]]
    ]
}

地图的坐标系

  • 地球上同一个地理位置的经纬度,在不同的坐标系中,会有少许偏移,国内目前常见的坐标系主要分为三种:
    • 地球坐标系——WGS84:常见于 GPS 设备,Google 地图等国际标准的坐标体系。
    • 火星坐标系——GCJ-02:中国国内使用的被强制加密后的坐标体系,高德坐标就属于该种坐标体系。
    • 百度坐标系——BD-09:百度地图所使用的坐标体系,是在火星坐标系的基础上又进行了一次加密处理。
  • 其84坐标系内网使用较多,具有精度高,偏差小的特点。
  • 高德开放平台提供坐标转换api

在vue中加载地图

  • 高德、百度、腾讯地图文章很多了,咱看另一个地图minedata,四维图新旗下的地图,与bat的地图相比缺少一些知名度,但是因为他是商用地图。文档会比较完善。
  • 初始化一个vuecli项目(默认vue2.x, 其实3.x 套路也是一样的),清理下无用的代码。
  • 按照官网提示在项目的 index.html 中引入地图所需文件
  <!-- 引入MineMap API插件 抄官网的-->
  <link rel="stylesheet" href="https://minedata.cn/api/static/demo/js-api/zh/css/demo.css">
  <link rel="stylesheet" href="https://minedata.cn/minemapapi/v2.1.0/minemap.css">
  <script src="https://minedata.cn/minemapapi/v2.1.0/minemap.js"></script>
  • 创建一个 map.vue 文件,在app.vue的文件中当组件引入
  • map文件如下 官网例子
<template>
  <div class="box">
    <div id="map"></div>
  </div>
</template>

<script>
export default {
  name: "map",
  data() {
    return {
      mapObj: null
    }
  },
  mounted() {
    // dom 初始化完成才能加载地图
    this.initMap()
  },
  methods: {
    initMap() {
      let minemap = window.minemap
      minemap.domainUrl = 'https://minedata.cn';
      minemap.dataDomainUrl = ['https://datahive.minedata.cn', 'https://datahive01.minedata.cn', 'https://datahive02.minedata.cn', 'https://datahive03.minedata.cn', 'https://datahive04.minedata.cn'];
      minemap.spriteUrl = 'https://minedata.cn/minemapapi/v2.1.0/sprite/sprite';
      minemap.serviceUrl = 'https://mineservice.minedata.cn/service/';

      minemap.appKey = '16be596e00c44c86bb1569cb53424dc9';
      minemap.solution = 12877;

      this.mapObj = new minemap.Map({
        container: 'map', // 地图容器 对应 template 中,id 等于 map 的 div
        style: 'https://mineservice.minedata.cn/service/solu/style/id/12877', // 地图主题
        center: [116.46, 39.92], // 地图初始化中心点
        zoom: 10, // 地图初始化默认比例
        maxZoom: 17, // 最大比例
        minZoom: 3 // 最小比例
      });
    }
  }
}
</script>
vh
<style scoped>
.box {
  width: 100vw;
  height: 100vh;
}

#map {
  width: 100%;
  height: 100%;
}
</style>

在地图上加载一个点

	// 扩展上述方法 并在 initMap函数中调用
  addMarker () {
    let el = document.createElement('div');
    el.id = 'marker';
    el.style["background-image"] = "url(https://minedata.cn/api/static/demo/js-api/zh/images/park.png)";
    el.style["background-size"] = "cover";
    el.style.width = "50px";
    el.style.height = "50px";
    el.style["border-radius"] = "50%";

	// 添加一个信息窗体
    let popup = new minemap.Popup({offset: [0, -48]}).setText("我是一个固定信息窗体")

    new minemap.Marker(el, {offset: [-25, -50]})
    .setLngLat([116.46,39.92])
    .setPopup(popup) // 信息窗体绑定到marker
    .addTo(this.mapObj)
  }

在地图上加载多个点

  • 多个点与一个点其实没有本质的区别,不过在做大数据量(点位过万)点位展示时,本地图不建议使用 marker,会导致地图缩放等操作卡顿,咨询官方回复建议使用 geojson的方式自定义点位展示,他们做了优化。
  • 在其 MineMap for 2D API V2.0.0 上线 2019-12-02,存在addMarkers 方法,但是在 2.1.0 貌似是删除了这个方法。
// addMarkers 方法 需要在地图加载完成后使用
let vm = this
this.mapObj.on("load",function(){
  vm.addMarker()
  vm.addMarkers()
})

// 创建 addMarkers 方法,添加到 initMap 方法中使用
addMarkers() {
  let pointList = [
    [116.28841,39.895239],
    [116.351067,39.894712],
    [116.321026,39.916308]
  ]

  pointList.map((item,index) => {
    let el = document.createElement('div');
    el.id = 'marker';
    el.style["background-image"] = "url(https://minedata.cn/api/static/demo/js-api/zh/images/park.png)";
    el.style["background-size"] = "cover";
    el.style.width = "50px";
    el.style.height = "50px";
    el.style["border-radius"] = "50%";

    let popup = new minemap.Popup({offset: [0, -48]}).setText(`我是多个添加的marker${index} 信息窗体`)

    new minemap.Marker(el, {offset: [-25, -50]})
      .setLngLat(item)
      .setPopup(popup)
      .addTo(this.mapObj)
  })
}

在地图上加载一个线

  • 两点连成线
// addLine 方法 需要在地图加载完成后使用
let vm = this
this.mapObj.on("load",function(){
  vm.addMarker()
  vm.addMarkers()
  vm.addLine(vm.mapObj) // 传入地图实例
})
// 创建添加线的方法 addLine
addLine(map) {
  // 将线的geo数据 添加到地图的数据源
  map.addSource("arrowSource", {
    "type": "geojson",
    "data": {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "LineString",
        "coordinates": [
          [116.221462,39.873505],
          [116.585227,39.8822],
          [116.282574,39.728947]
        ]
      }
    }
  });

  // 将线的数据源添加到地图
  map.addLayer({
    "id": "line",
    "type": "line",
    "source": "arrowSource",
    "paint": {
      "line-color": "#15bbf2",
      "line-width": 4
    }
  })
}

// 同样将方法添加到 

在地图上加载一个面

  • 三点连成面
// addPolygon 方法 需要在地图加载完成后使用
let vm = this
this.mapObj.on("load",function(){
  vm.addMarker()
  vm.addMarkers()
  vm.addLine(vm.mapObj) // 传入地图实例
   vm.addPolygon(vm.mapObj) // 传入地图实例
})

// 创建addPolygon方法
addPolygon(map) {
  // 将面的geo数据 添加到地图的数据源
  map.addSource("fillSource", {
    "type": "geojson",
    "data": {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [116.25116,39.921311],
            [116.370465,39.931974],
            [116.28429,39.884702],
            [116.25116,39.921311],
          ]
        ]
      }
    }
  });


  map.addLayer({
    "id": "fillLayer",
    "type": "fill",
    "source": "fillSource",
    "layout": {
      "visibility": "visible",
    },
    "paint": {
      "fill-color": "#00ff00",
      "fill-opacity": 0.8,
      "fill-outline-color": "#ff0000"
    },
    "minzoom": 7,
    "maxzoom": 17.5
  });
}

切换地图主题颜色

  • 这个就比较简单了,一般官方都会提供相应的api的
// template
<div class="butBox">
  <button @click="setMapTheme(12877)">默认</button>
  <button @click="setMapTheme(12878)">深色</button>
</div>

// methods 中的 setMapTheme方法
setMapTheme(id) {
  if (this.mapObj) {
    this.mapObj.appKey = '16be596e00c44c86bb1569cb53424dc9';
    this.mapObj.solution = id;
    this.mapObj.setStyle('https://mineservice.minedata.cn/service/solu/style/id/' + id);
  }
}

后话

  • 有时候我们会有一个这样的需求,在地图上画出 各个省市区的范围,那么地图区划数据从哪里来呢?
  • 其实你明白了一种地图的使用,也大概就懂了其他地图的使用。而且主流地图的使用方式都是大同小异。
    • 要使用 你带先加载 sdk
    • 然后你要初始化地图
    • 然后在地图上做一些动作,做加载点 面 线
    • 有的地图会有图层的概念,有的则没有
  • 这一切的前提就是你需要认真阅读文档,一款给大众使用的地图 ,就决定了文档不会太难,不要说 leafletjs 那是真的需要认真看的。