一. 数据加载

  1. OpenLayers的地图数据通过图层(Layer)进行组织渲染,通过数据源(Source)设置具体的地图数据来源。Layer可以看作渲染地图的容器,具体的数据需要通过Source设置,Source和Layer是一对一的关系,有一个Source必然需要有一个Layer。
  2. 地图数据根据数据源(Source)可分为Image、Tile、Vector三大类型的数据源,对应设置到地图图层(Layer)的Image、Tile、Vector三大类型的图层上,其中矢量图层Vector通过样式(Style)来设置矢量要素渲染的方式和外观。
  • Tile类是瓦片抽象基类,其子类作为各类瓦片数据的数据源。
  • Vector类是矢量数据源基类,为矢量图层提供具体的数据来源,包括直接组织或读取的矢量数据(Features)、远程数据源的矢量数据(即通过url设置数据源路径)等。
  • Image类是单一图像基类,其子类为画布(canvas)元素、服务器图片、单个静态图片、WMS单一图像等。

二. ol.source.Tile

        由于一些历史问题,多个服务提供商,多种标准等诸多原因,导致要支持世界上大多数的瓦片数据,需要针对这些差异(主要是瓦片坐标系不同、分辨率不同等)提供不同的Tile数据源支持,ol.source.Tile大致可以分为几类:

  • 在线服务的Source:如ol.source.BingMaps(微软提供的Bing在线地图数据)、ol.source.Stamen(Stamen提供的在线地图数据)等,在没有自己的地图服务器的情况下,可以直接使用它们。
  • 支持协议标准的Source:如ol.source.TileArcGISRest、ol.source.WMTS、ol.source.TileJSON等,如果要使用它们,要学习对应的协议,并且找到支持这些协议的服务器来提供数据源(服务器可以是地图服务商提供或自己搭建的地图服务器)。
  • ol.source.XYZ:目前很多地图服务都支持XYZ方式的请求,用途广泛,且简单易学。

三. 瓦片坐标系

        瓦片坐标系是瓦片地图的组织参考框架,规定了每一块瓦片的行号、列号以及层级数。OpenLayers提供了一个用于调试瓦片坐标系的ol.source.TileDebug类。借助这个类,可以清晰的看到每一个瓦片的坐标。

import React, { useEffect } from 'react';
import { Map, View } from 'ol';
import TileLayer from 'ol/layer/Tile';
import TileDebug from 'ol/source/TileDebug';
import { defaults } from 'ol/control';
import { fromLonLat } from 'ol/proj';
import OSM from 'ol/source/OSM';
import 'ol/ol.css';

export default function Index() {

  useEffect(() => {
    // 初始化地图
    initMap();
  }, [])

  /**
   * 初始化地图
   */
  const initMap = () => {
    let osmSource = new OSM();
    new Map({
      // 挂载到id为map的div容器上
      target: 'map',
      // 设置地图图层
      layers: [
        // 创建一个使用OpenStreetMap地图源的瓦片图层
        new TileLayer({ source: osmSource }),
        // 创建一个显示OpenStreetMap地图源的瓦片网格图层
        new TileLayer({
          source: new TileDebug({
            // Web墨卡托投影坐标系
            projection: 'EPSG:3857',
            // 获取OpenStreetMap地图源的瓦片坐标系
            tileGrid: osmSource.getTileGrid()
          })
        })
      ],
      // 设置地图视图
      view: new View({
        // 设置空间参考系统为'EPSG:3857'
        projection: 'EPSG:3857',
        // 地图的显示中心
        center: fromLonLat([0, 0]),
        // 地图的显示层级
        zoom: 3
      }),
      controls: defaults({
        // 移除归属控件
        attribution: false,
        // 移除缩放控件
        zoom: false,
        // 移除旋转控件
        rotate: false
      })
    })
  }

  return (<div>
    <div id='map' style={{ width: '100vw', height: '100vh' }}></div>
  </div>)
}

  • 第一个数字是层级z
  • 第二个数字是经度方向上的x(列号)
  • 第三个数字是纬度方向上的y(行号)

四. 分辨率

4.1 分辨率简介

  1. 分辨率的简单定义是屏幕上1像素表示的现实世界的地面实际距离。
  2. 以OpenStreetMap在线地图为例,层级0使用了一张瓦片,层级1使用了4张瓦片。通过计算可以知道层级0的整个地球图像为256×256像素大小,层级1的整个地球图像为512×512像素大小。而层级0和层级1表示的地球范围都是一样的(经度[-180°, 180°],纬度[-90°, 90°])。在层级0的时候,一个像素在水平方向表示360°÷256 = 1.40625°经度范围, 在竖直方向表示180°÷256 = 0.703125°的纬度范围。这两个数字就是分辨率,即一个像素表示的现实世界的范围,这个范围可能是度(地理坐标系统),可能是米(投影坐标系统)或其他单位。

4.2 Web墨卡托投影坐标系的分辨率

        在WebGIS中使用的在线瓦片地图采用Web墨卡托(Mercator)投影坐标系(OpenLayers默认使用EPSG:3857),经过投影后整个地球是一个正方形,范围为经度[-180°, 180°],纬度[-85°, 85°],单位为度。对应的Web墨卡托投影坐标系的范围为x[-20037508.3427892, 20037508.3427892]、y[-20037508.3427892, 20037508.3427892],x、y方向上的各层级瓦片地图分辨率计算公式可以归纳为:resolution = rang÷(256×2^z)。

  • rang:表示x方向或y方向上的整个范围,如20037508.3427892×2。
  • 256:表示一个瓦片的边长,单位为像素。
  • 2^z:表示在层级z下,x或y方向上的瓦片个数。

4.3 获取OpenLayers默认使用的分辨率

import React, { useRef, useState, useEffect } from 'react';
import { Map, View } from 'ol';
import TileLayer from 'ol/layer/Tile';
import { defaults } from 'ol/control';
import { fromLonLat } from 'ol/proj';
import OSM from 'ol/source/OSM';
import { unByKey } from 'ol/Observable';
import 'ol/ol.css';
import styles from './index.less';

export default function Index() {
  // 地图
  const map = useRef<any>();
  // 当前层级
  const [zoom, setZoom] = useState(3);
  // 当前分辨率
  const [resolution, setResolution] = useState(19567.8792);

  useEffect(() => {
    // 初始化地图
    initMap();
    // 绑定视图事件
    const resolutionChange = map.current.getView().on('change:resolution', resolutionChangeEvent);

    return () => {
      // 解绑视图事件
      unByKey(resolutionChange);
    }
  }, [])

  /**
   * 初始化地图
   */
  const initMap = () => {
    map.current = new Map({
      // 挂载到id为map的div容器上
      target: 'map',
      // 设置地图图层
      layers: [
        // 创建一个使用OpenStreetMap地图源的瓦片图层
        new TileLayer({ source: new OSM() })
      ],
      // 设置地图视图
      view: new View({
        // 设置空间参考系统为'EPSG:3857'
        projection: 'EPSG:3857',
        // 地图的显示中心
        center: fromLonLat([0, 0]),
        // 地图的显示层级
        zoom: zoom,
        // 设置缩放级别为整数
        constrainResolution: true,
        // 关闭无级别缩放地图
        smoothResolutionConstraint: false
      }),
      controls: defaults({
        // 移除归属控件
        attribution: false,
        // 移除缩放控件
        zoom: false,
        // 移除旋转控件
        rotate: false
      })
    })
  }

  /**
   * 分辨率改变事件
   */
  const resolutionChangeEvent = () => {
    let zoom = parseInt(map.current.getView().getZoom());
    let resolution = map.current.getView().getResolution().toFixed(4);
    setZoom(zoom);
    setResolution(resolution);
  }

  return (<div className={styles.mapCon}>
    <div id='map' className={styles.map}></div>
    <div className={styles.toolBar}>
      <span>层级:{zoom}</span>
      <span>分辨率:{resolution}</span>
    </div>
  </div>)
}

4.4 比例尺

  1. 比例尺是指地图上距离与实际距离的比例。
  2. 在计算地图比例尺时,需要用到地面分辨率与屏幕分辨率两个参数。屏幕分辨率是指屏幕上每英寸(1英寸=0.0254米)长度内包含的像素数量,默认是96。
  3. 计算公式为:比例尺=0.0254÷(分辨率×96)

4.5 OpenLayers默认分辨率、比例尺表

图像等级地图的宽高
(单位:像素)
地面分辨率
(单位:米 / 像素)
地图比例尺
(以96dpi为准)
151278,271.51701:295,829,355.45
2102439,135.75851:147,914,677.73
3204819,567.87921:73,957,338.86
440969,783.93961:36,978,669.43
581924,891.96981:18,489,334.72
616,3842,445.98491:9,244,667.36
732,7681,222.99251:4,622,333.68
865,536611.49621:2,311,166.84
9131,072305.74811:1,155,583.42
10262,144152.87411; 577,791.71
11524,28876.43701:288,895.85
121,048,57638.21851:144,447.93
132,097,15219.10931:72,223.96
144,194,3049.55461:36,111.98
158,388,6084.77731:18,055.99
1616,777,2162.38871:9,028.00
1733,554,4321.19431:4,514.00
1867,108,8640.59721:2,257.00
19134,271,7280.29861:1,128.50
20268,435,4560.14931:564.25
21536,870,9120.07461:282.12
221,073,741,8240.03731:141.06
232,147,483,6480.01871:70.53

参考文章:

OpenLayers教程八:多源数据加载之数据组织
OpenLayers教程九:多源数据加载之瓦片地图原理一
OpenLayers教程十:多源数据加载之瓦片地图原理二


离离千世
1 声望3 粉丝