OpenLayers 6 如何优雅的使用天地图WMTS服务“经纬度投影(CGCS2000)”和“球面墨卡托投影(EPSG:3857)”

最近google.com卫星图和bing卫星图相继有重大变动,常规方式已经没办法使用XYZ方式加载在线图了,于是我把目光转向了天地图。之前以为天地图是GCJ02加偏的资源,直到看到官网上这么一句话:









于是眼前一亮,申请了一个开发者API(过程很简单,略),搞起。

但是因为天地图在WMTS的基础上加了个key,没办法用getCapablities的方法加载,每次都需要自己配置长长一大堆参数,很烦,干脆封装了一个 函数,可以通过<地图类型>+<“投影”类型>的参数配置方式直接获得一个ol/layer/Tile类的图层,在OpenLayers 6.1.1版本下测试通过。个人感觉还挺好用的。

以下是源码:

/**
* @fileOverview 天地图WMTS服务API
* @author <a href=”https://blog.csdn.net/nudtcadet”>老胡</a>
* @version 1.0
*/
import { getWidth, getTopLeft } from 'ol/extent';
import WMTS from 'ol/tilegrid/WMTS';
import { WMTS as WMTSSource } from 'ol/source';
import TileLayer from 'ol/layer/Tile';
import { get as getProjection, getTransform } from 'ol/proj';
import { applyTransform } from 'ol/extent';
 
 
/**
* @description 获得一个OpenLayers框架下的ol/layer/Tile类型天地图图层
* @param {options} Object 初始化参数
* @param {options.type} String 与官方名称相同的图层类型
* @param {options.proj} String 与官方名称相同的投影类型
* @param {options.key} String 开发者秘钥
*/
export function getTianditu(options) {
        let layers = {
                '全球境界': 'ibo',
                '地形注记': 'cta',
                '地形晕渲': 'ter',
                '影像注记': 'cia',
                '影像底图': 'img',
                '矢量注记': 'cva',
                '矢量底图': 'vec'
        }
        let projs = {
                '经纬度投影': 'EPSG:4490',
                '球面墨卡托投影': 'EPSG:900913'
        }
        let matrixSets = {
                '经纬度投影': 'c',
                '球面墨卡托投影': 'w'
        }
        let projection = getProjection(projs[options.proj]);
        let projectionExtent = projection.getExtent();
        let origin = projectionExtent ? getTopLeft(projectionExtent) : [-180, 90];
        let fromLonLat = getTransform('EPSG:4326', projection);
        let width = projectionExtent ? getWidth(projectionExtent) : getWidth(applyTransform([-180.0, -90.0, 180.0, 90.0], fromLonLat));
        let resolutions = [];
        let matrixIds = [];
        for (let z = 1; z < 19; z++) {
                resolutions[z] = width / (256 * Math.pow(2, z));
                matrixIds[z] = z;
        };
        let wmtsTileGrid = new WMTS({
                origin: origin,
                resolutions: resolutions,
                matrixIds: matrixIds
        });
        let wmtsSource = new WMTSSource({
                url: "http://t0.tianditu.gov.cn/" + layers[options.type] + "_" + matrixSets[options.proj] + "/wmts?tk=" + options.key,
                layer: layers[options.type],
                version: '1.0.0',
                matrixSet: matrixSets[options.proj],
                format: 'tiles',
                projection: projection,
                requestEncoding: 'KVP',
                style: 'default',
                tileGrid: wmtsTileGrid
        });
        let wmtsLayer = new TileLayer({
                source: wmtsSource
        });
        return wmtsLayer
}

再放两个例子:

这个是使用CGCS2000坐标系的,网上有很多人使用OpenLayers加载不上这个坐标系,是因为通过Proj4这个库使用EPSG.io上的坐标代码有bug,Proj4.js的加载不上,改用WKT的数据就可以。
在这里插入图片描述

import { Map, View } from 'ol';
import { getTianditu } from './js/tianditu'
import { register } from 'ol/proj/proj4';
import proj4 from 'proj4';
 
proj4.defs("EPSG:4490", "GEOGCS[\"China Geodetic Coordinate System 2000\",DATUM[\"China_2000\",SPHEROID[\"CGCS2000\",6378137,298.257222101,AUTHORITY[\"EPSG\",\"1024\"]],AUTHORITY[\"EPSG\",\"1043\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4490\"]]");
register(proj4);
 
var map = new Map({
        target: "map",
        view: new View({
                center: [116.391478, 39.903185],
                // center: [11936406.337013, 3786384.633134],
                projection: "EPSG:4490",
                zoom: 5,
                maxZoom: 18,
                minZoom: 1
        })
});
var tdt = getTianditu({
        type: '矢量底图',
        // proj: '球面墨卡托投影',
        proj: '经纬度投影',
 
        key: '用你自己的key'
});
var zz = getTianditu({
        type: '矢量注记',
        // proj: '球面墨卡托投影',
        proj: '经纬度投影',
 
        key: '用你自己的key'
})
var jj = getTianditu({
        type: '全球境界',
        // proj: '球面墨卡托投影',
        proj: '经纬度投影',
 
        key: '用你自己的key'
})
map.addLayer(tdt)
map.addLayer(zz)
map.addLayer(jj)

下面这个是3857坐标系的:
在这里插入图片描述












import { Map, View } from 'ol';
import { getTianditu } from './js/tianditu'
import { register } from 'ol/proj/proj4';
import proj4 from 'proj4';
 
// proj4.defs("EPSG:4490", "GEOGCS[\"China Geodetic Coordinate System 2000\",DATUM[\"China_2000\",SPHEROID[\"CGCS2000\",6378137,298.257222101,AUTHORITY[\"EPSG\",\"1024\"]],AUTHORITY[\"EPSG\",\"1043\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4490\"]]");
// register(proj4);
 
var map = new Map({
        target: "map",
        view: new View({
                // center: [116.391478, 39.903185],
                center: [11936406.337013, 3786384.633134],
                // projection: "EPSG:4490",
                zoom: 5,
                maxZoom: 18,
                minZoom: 1
        })
});
var tdt = getTianditu({
        type: '矢量底图',
        proj: '球面墨卡托投影',
        // proj: '经纬度投影',
 
        key: '用你自己的key'
});
var zz = getTianditu({
        type: '矢量注记',
        proj: '球面墨卡托投影',
        // proj: '经纬度投影',
 
        key: '用你自己的key'
})
var jj = getTianditu({
        type: '全球境界',
        proj: '球面墨卡托投影',
        // proj: '经纬度投影',
 
        key: '用你自己的key'
})
map.addLayer(tdt)
map.addLayer(zz)
map.addLayer(jj)

图荒的问题暂时得到解决了,关键时刻还是要看国家队……