likes
comments
collection
share

关于离线地图方案的研究

作者站长头像
站长
· 阅读数 11

需求场景

- 在一般项目里我们使用第三方地图的时候比较多,如 高德地图、百度地图、腾讯地图等
- 在一些特殊系统需要部署到内网的环境下,有需要用到地图的时候,就需要自己搭建离线地图

搭建离线地图需要的东西

  1. 地图瓦片服务服务
  2. 地图基础库

地图瓦片服务服务

如今互联网地图的地图内容分为两种,一种是栅格瓦片,一种是矢量瓦片

栅格瓦片

栅格数据就是将空间分割成有规律的网格,每一个网格称为一个单元(像素),并在各单元上赋予相应的属性值来表示实体的一种数据形式。

点实体:由一个栅格像元来表示,如图所示,一个点对应着一个像元; 线实体:由一定方向上连接成串的相邻栅格像元表示; 面实体(区域):由具有相同属性的相邻栅格像元的块集合来表示; 栅格瓦片是预先在Server端制好固定的PNG和JPG图片集合,通俗说就是一张图片。

矢量瓦片

矢量数据是利用欧几里德几何学中点、线、面及其组合体来表示地理实体空间分布的一种数据组织方式。 矢量瓦片是将矢量数据通过不同的描述文件来组织和定义,在客户端实时解析数据和完成绘制。

对比

关于离线地图方案的研究

地图基础库

从网上找的几个地图基础库的对比

关于离线地图方案的研究

搭建流程-栅格瓦片

1. 获取离线地图瓦片

  • 下载离线地图瓦片,网上有很多方法、大部分收费 找个合适的工具真的难,找到一个能用的免费贡献出来了全能地图下载器
  • 链接:pan.baidu.com/s/18LiUAh1-…

关于离线地图方案的研究

关于离线地图方案的研究

*下载速度可能比较慢,下载量大的话有时候下不下来

2. 启动服务

可以直接在 \mapabc\roadmap 目录下用http-server启动

关于离线地图方案的研究

3. 使用 openlayers 加载地图

网上找的例子

<template>
  <div style="width: 100%;height: 100%">
    <div class="map" id="map"></div>
    <el-card id="popup" class="popup">
      <div class="popupContainer"></div>
    </el-card>
  </div>
</template>

<script>
import 'ol/ol.css';
import Map from 'ol/Map';
import Feature from 'ol/Feature';
import VectorSource from 'ol/source/Vector';
import Overlay from 'ol/Overlay';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import View from 'ol/View';
import {transform} from 'ol/proj';
import XYZ from 'ol/source/XYZ'
import Point from 'ol/geom/Point';
import GeoJSON from 'ol/format/GeoJSON';
import {Fill, Stroke, Icon, Style} from 'ol/style'
import markerImg from '@/assets/img/markerIcon.png'
export default {
  name: "openlayersMap",
  data () {
    return {
      mapObj: null,
      mapDom: null,
      mapPointList: [],
      pointLayerSource:null,
      pointLayer: null,
      markerIcon: markerImg
    }
  },
  mounted() {
    this.initMap()
  },
  methods: {
    // 清除地图 某些情况 地图容器会存在两个 导致地图无法正常显示 这个问题折腾了我半天。
    // 找了半天官方貌似也没有提供 对应的 api,自己动手了。
    mapClear (){
      if (this.mapDom) {
        this.mapDom.innerHTML = ''
        this.mapDom = null
      }
    },
    
    // 初始化地图
    initMap () {
      // 先尝试清除
      this.mapClear()
      // 获取地图容器
      this.mapDom = document.getElementById('map')

      // 初始化地图配置
      this.mapObj = new Map({
        target: this.mapDom, // 地图容器
        view: new View({
          center: [120.396255,36.307624], // 地图中心点
          zoom: 14, // 缩放
          projection: 'EPSG:4326' // 坐标系
        })
      })

      // 添加一个使用离线瓦片地图的层
      const offlineMapLayer = new TileLayer({
        source: new XYZ({
          url: 'http://172.16.0.214:8080' + '/{z}/{x}/{y}.png'  // 设置本地离线瓦片所在路径
        })
      })
      // 将图层添加到地图
      this.mapObj.addLayer(offlineMapLayer)

      // 加载地理坐标
      this.addPoint()
    },

    // 添加地理坐标
    addPoint () {
      this.delPointAll()
      // 地理坐标数组
      const pointData = [
        {longitude: 117.990969, latitude: 36.635013}
      ]

      pointData.map(item => {
        // 创建点
        const point = new Feature({
          geometry: new Point([item.longitude, item.latitude]),
          data: item
        })

        // 点的样式
        const iconStyle = new Style({
          image: new Icon({
            color: '#ffffff',
            crossOrigin: 'anonymous',
            src: this.markerIcon,
          }),
        })
        // 设置样式
        point.setStyle(iconStyle)
        // 保存到数据  方便删除
        this.mapPointList.push(point)
      })

      // 创建geojson据源
      this.pointLayerSource = new VectorSource({features: this.mapPointList})
      // 创建图层 并加载数据
      this.pointLayer = new VectorLayer({source: this.pointLayerSource})
      // 将图层添加地图上
      this.mapObj.addLayer(this.pointLayer)
    },

    // 地理点位删除
    delPointAll(){
      // 判断 删除的数据源是否存在
      if (this.pointLayerSource) {
        // 遍历删除
        this.mapPointList.map(item => {
          this.pointLayerSource.removeFeature(item)
        })

        // 删除图层 重置数据
        this.mapObj.removeLayer(this.pointLayer)
        this.pointLayerSource = null
        this.pointLayer = null
        this.mapPointList = []
      }
    }
  },
  beforeDestroy() {
    this.mapClear()
  }
}
</script>

<style scoped>
.map {
  width: 1000px;
  height: 90vh;
}
</style>

效果

关于离线地图方案的研究

搭建流程-矢量瓦片

1. 获取离线瓦片-格式 MBTiles

可以通过以下两种方式获取:

对比:
相同点:

-   数据源都为 OSM(OpenStreetMap) 数据

不同点:

-   前者不提供地图的样式,后者提供完整的地图样式
-   前者提供不同层级的细粒度的瓦片数据(未进行图层合并或者数据优化),后者提供完整的世界地图瓦片数据(数据已经整合且优化)
-   前者数据更新及时,后者提供免费的数据为三年前瓦片数据(收费的数据则较新)

* 第一个获取的不是MBTiles格式的,需要转化,第二个是直接获取 MBTiles 格式的,比较大,下载下来是全球的

方式1

1. 下载这一个中国地图的

关于离线地图方案的研究

2. 使用 tilemaker把它转化为 MBTiles 格式的文件

关于离线地图方案的研究

方式2

直接下载一个MBTiles,比较大,小的都50G

关于离线地图方案的研究

2. 使用 FoxGIS Server Lite 搭建一个矢量瓦片地图服务

文档 github

3. 启动 FoxGIS Server Lite 服务

关于离线地图方案的研究

4. 使用 mapbox-gl 加载地图

一个例子:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
        <style type="text/css">
            * {
                margin: 0;
                padding: 0;
            }
            html,
            body,
            #map {
                width: 100%;
                height: 100%;
            }
        </style>
        <link
            rel="stylesheet"
            href="http://localhost:1234/api/assets/mapbox-gl.css"
        />
        <script src="http://localhost:1234/api/assets/mapbox-gl.js"></script>
    </head>
    <body>
        <div id="map"></div>
    </body>
    <script>
        var map = new mapboxgl.Map({
            container: 'map', // container id
            style: 'http://localhost:1234/api/styles/style', // style URL
            center: [116.4, 39.9066], // starting position [lng, lat]
            zoom: 13, // starting zoom
        })
        // Create a new marker.
        const marker = new mapboxgl.Marker().setLngLat([116.4, 39.9066]).addTo(map)
    </script>
</html>

5. 效果

关于离线地图方案的研究