除了二维平面图、卫星图外,三维地图、手绘地图等新地图形式也开始出现在各应用中。手绘地图能够快速定制化的呈现出特定区域的路线、交通、建筑、景点等,对于景区导览、旅游观光和规划等场景,具有良好的应用前景。最近做了个关于手绘地图的项目,使用 openlayers 渲染,加载速度和渲染效果都很不错。
参考资料:
openlayers 文档地址:https://openlayers.org/en/latest/apidoc/
一、手绘地图绘制、参数设置
绘图人员绘制完地图并配准后,发布到 GeoServer(一款基于 java 的开源 GIS 工具集),需在 GeoServer 上设置好投影坐标系(EPSG:3857即墨卡托坐标系,EPSG:4326即WGS84坐标系)、地图瓦片格式、坐标轴范围、地图原点、地图层级、分辨率等参数,一般由后台人员设置。
注意:以上地图参数一般由后台人员通过接口传给前端,但有时传过来的数据可能不全,此时必须问清楚或者自己去 GeoServer 上看,加载地图时如果出现问题基本是因为漏了参数或者参数错误。
二、openlayers 加载手绘地图
1、项目引入 openlayers
首先npm 安装 openlayers
npm install ol
注意,在 vue 中必须逐一声明所需的 openlayers 库的对象和方法才能正常使用
import Map from 'ol/Map.js' // 无法像普通库那样直接 import ol from 'ol' 后调用里面的对象和方法
import View from 'ol/View.js'
import Vectors from 'ol/layer/Vector.js'
import { asString } from 'ol/color'
import { fromLonLat, Projection } from 'ol/proj.js'
2、加载手绘地图
手绘地图以 WMTS (Web Map Tile Service, Web 地图瓦片形式)加载,先创建一个类型为 WMTS 的图层资源,再将其放入创建的 Map 对象的图层资源集合中。
// 单独引入要使用的对象和方法
import Map from 'ol/Map.js'
import View from 'ol/View.js'
import { fromLonLat, Projection } from 'ol/proj.js'
import { WMTS, Vector } from 'ol/source.js'
import WMTSTileGrid from 'ol/tilegrid/WMTS.js'
import TileLayer from 'ol/layer/Tile.js'
/*配置 WMTS 图层资源参数
*@param{object} data 后台接口传过来的地图参数
*@return {object} 返回创建的 WMTS 图层资源对象
*/
initWMTSLayer(data) {
const projection = new Projection({ // 地图的投影坐标系
code: 'EPSG:4326', // 类型可以是墨卡托坐标系或WGS84坐标系
units: 'm', // 坐标单位
axisOrientation: 'neu' // 坐标轴方向
})
// 设置分辨率数组,这里后台传过来的是以逗号分隔的字符串
const resolutions = data.layerCoordinates.split(',').map(item => +item)
// 设置地图瓦片矩阵Id
const gridIds = data.gridsetIds.split(',').map(item => item.replace(/\s+/g, '')
const tilesGrid = new WMTSTileGrid({ // 地图瓦片网格对象
tileSize: [256, 256], // 瓦片大小
origin: [-2.003750834E7, 2.003750834E7], // 切片原点
resolutions: resolutions,
matrixIds: gridIds
}),
// 创建 WMTS 图层资源
const source = new WMTS({
url: data.url // 地图服务的地址
layer: data.layerName // 地图图层的名称
matrixSet: data.gridsetName // 地图瓦片矩阵
format: 'image/png' // 地图瓦片的格式,可以接口传过来也可以前端写死
projection: projection,
tileGrid: tilesGrid,
wrapX: true
})
return source
}
/*创建 Map 对象,将配置好的 WMTS 图层资源加入到图层合集中
*@param{object} data 后台接口传过来的地图参数
*/
initMap(data) {
const projection = new Projection({ // 地图的投影坐标系
code: 'EPSG:4326', // 类型可以是墨卡托坐标系或WGS84坐标系
units: 'm', // 坐标单位
axisOrientation: 'neu' // 坐标轴方向
})
// 设置地图可拖动的范围
const leftBottom = data.leftBottom.split(',')
const rightTop = data.rightTop.split(',')
// 创建地图对象
this.map = new Map({
target: 'map',
interactions: defaultInteractions({ // 禁止旋转
altShiftDragRotate: false,
pinchRotate: false
}),
view: new View({
center: data.center.split(','), // 设置地图中心坐标
zoom: data.minLevel || data.defaultLevel, // 设置地图打开默认的层级
minZoom: data.minLevel, // 设置最小缩放层级
maxZoom: data.maxLevel, // 设置最大缩放层级
projection: projection, // 设置投影坐标系
extent: [+leftBottom[0], +leftBottom[1], +rightTop[0], +rightTop[1]] // 拖动范围
}),
layers: [ // 将创建好的 WMTS 图层资源放入地图图层合集中
new TileLayer({
source: this.initWMTSLayer(data)
})
]
})
// 地图打开后移动到要显示的位置
this.map.getView().animate({
center: data.location.split(','), // 目标位置的坐标
duration: data.duration, // 移动动画时长
zoom: data.minLevel || data.defaultLevel // 地图缩放层级
})
}
以上,实现加载手绘地图后,移动至指定经纬度。
这样就完成了手绘地图底图的加载,后续如何为地图添加标注(含聚合标注)、覆盖物及路线等,可以查看我的另一篇文章:https://www.jianshu.com/p/4af2a52a0fc6