在做webgis应用过程中,难免遇到使用多种地图作为底图,比如天地图、谷歌地图、高德地图等,由于各地图使用的坐标系不一致,所以在动态切换底图时,通常需要处理地图容器中已存在的矢量数据,接下来我们以天地图和谷歌地图的切换,并保持地图容器中的矢量数据正常显示为例来说明。本文仅使用HTML+JS+CSS+Openlayers进行演示。
坐标系说明
天地图:天地图的坐标系为CGCS2000大地坐标系,在误差允许范围内,可以近似地认为等于WGS84坐标系
谷歌地图:谷歌地图坐标系在国内使用的是火星坐标系(gjc02)
所以在接下来的底图切换中,涉及到坐标系切换,使用的方法就是wgs84坐标系和gcj02坐标系之间进行切换。
磨刀不误砍柴工,我们先准备工具和数据:
- HBuilderX:用于编写前端代码的IDE,PS:笔者比较喜欢使用该IDE,可根据自己使用习惯选择;
- Openlayers:可以去官网下载,本文使用的Openlayers版本为V5.3.0;
- 一个用于演示的geojson数据:该数据主要用于演示底图切换时,geojson数据位置在地图上仍然处于相同位置。
一、使用HBuilderX新建项目MapSwitch,并复制Openlayers的JS和CSS到项目中
二、在index.html中书写本案例,具体见代码注释
第一、把天地图、谷歌地图和geojson测试数据分别定义,并加载到地图容器中;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Openlayers切换底图,并保持原有矢量数据显示</title>
<link rel="stylesheet" type="text/css" href="./ol/ol.css"/>
<style type="text/css">
</style>
</head>
<body>
<!-- 地图容器 -->
<div id="map" class="map"></div>
<script src="./ol/ol.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
//天地图的tk
var _tianditu_tk = 在天地图官网上进行申请;
//定义地图容器坐标系
var projection = ol.proj.get("EPSG:4326");
//天地图
var baselayer_tianditu_img = new ol.layer.Tile({
title: "天地图影像",
id:"baselayer_tianditu_img",
zIndex:0,
source: new ol.source.XYZ({
url: 'http://t{0-7}.tianditu.gov.cn/DataServer?T=img_c&x={x}&y={y}&l={z}&tk=' + _tianditu_tk,
projection: projection,
})
});
var baselayer_tianditu_cia = new ol.layer.Tile({
title: "天地图注记",
id:"baselayer_tianditu_cva",
zIndex:1,
source: new ol.source.XYZ({
url: 'http://t{0-7}.tianditu.gov.cn/DataServer?T=cia_c&x={x}&y={y}&l={z}&tk=' + _tianditu_tk,
projection: projection,
})
});
//谷歌地图
var baselayer_geogle = new ol.layer.Tile({
title: "谷歌地图",
id:"baselayer_geogle",
zIndex:0,
source: new ol.source.XYZ({
url: 'http://mt{0-3}.google.cn/maps/vt?lyrs=s,h@773&gl=cn&x={x}&y={y}&z={z}',
})
});
//定义geojson显示的样式
var style = new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.4)'
}),
stroke: new ol.style.Stroke({
color: '#319FD3',
width: 1
}),
text: new ol.style.Text({
fill: new ol.style.Fill({
color: '#d31417'
}),
font:'16px sans-serif',
overflow:true
})
});
//geojson矢量数据,用于演示
var geoJsonLayer = new ol.layer.Vector({
name:"矢量数据",
renderMode: 'image',
source: new ol.source.Vector({
url: 'cs.geojson',
format: new ol.format.GeoJSON()
}),
style: function(feature) {
style.getText().setText(feature.get('ZLDWMC'));
return style;
}
})
//创建视图
var view = new ol.View({
center: [116.20,39.56],//地图中心位置北京
projection: projection,
minZoom:4,
maxZoom:20,
zoom: 7//地图初始层级
})
//创建地图
var map = new ol.Map({
layers:[
//默认显示天地图
baselayer_tianditu_img,baselayer_tianditu_cia,
//显示geojson测试数据
geoJsonLayer
],
view: view,
target: 'map'
});
//地图渲染完成后的事件
map.once('rendercomplete',function() {
//把地图视图缩放到geojson测试数据视图范围内
viewFitLayer(geoJsonLayer);
})
//视图缩放至图层范围
function viewFitLayer(layer) {
var extent = layer.getSource().getExtent();
if(extent){
view.fit(extent,{
duration:1000,
easing:ol.easing.UpAndDown
});
}
}
</script>
</body>
</html>
效果如下:图中红色字体,蓝色边框就是我们的测试geojson里面的矢量数据构成的面。
第二、接下来,我们加入两个按钮,进行演示天地图和谷歌地图的切换
1、在body中加入两个天地图和谷歌地图两个按钮
<!-- 定义底图切换按钮 -->
<div class="btn">
<button data-id="tianditu" onclick="tianditu()">天地图</button>
<button data-id="geoglemap" onclick="geoglemap()">谷歌地图</button>
</div>
2、在head中对两个按钮进行修饰,让按钮在右上角
<style type="text/css">
.btn{
position: absolute;
right: 30px;
top: 30px;
}
.btn button{
font-size: 20px;
}
</style>
3、响应按钮事件,对地图进行切换
//定义当前底图的标识
var basemap = 0;//0标识天地图 1标识谷歌地图
//切换天地图
function tianditu() {
if(basemap == 0) {
return;
}
basemap = 0;
baseLayerChange();
//移除谷歌地图
map.removeLayer(baselayer_geogle);
//加入天地图
map.addLayer(baselayer_tianditu_img);
map.addLayer(baselayer_tianditu_cia);
}
//切换谷歌地图
function geoglemap(){
if(basemap == 1) {
return;
}
basemap = 1;
baseLayerChange();
//移除天地图
map.removeLayer(baselayer_tianditu_img);
map.removeLayer(baselayer_tianditu_cia);
//加入谷歌地图
map.addLayer(baselayer_geogle);
}
//底图切换逻辑,遍历出矢量数据中的坐标点,进行坐标转换
function baseLayerChange(){
//固定视图中心点
var center = view.getCenter();
center = transform4wgs84andgcj02(center);
view.setCenter(center);
var features = geoJsonLayer.getSource().getFeatures();
features.forEach((feature)=>{
var geo = feature.getGeometry();
var type = geo.getType();
var coords = geo.getCoordinates();
if("Point" == type){
coords = transform4wgs84andgcj02(coords);
geo.setCoordinates(coords);
feature.setGeometry(geo);
}
if("MultiPolygon" == type){
var newcoord = new Array();
var newcoord1 = new Array();
var newcoord2 = new Array();
coords.forEach((coord1)=>{
coord1.forEach((coord2)=>{
coord2.forEach((coord3)=>{
coord3 = transform4wgs84andgcj02(coord3);
newcoord2.push(coord3);
})
newcoord1.push(newcoord2);
})
newcoord.push(newcoord1);
})
geo.setCoordinates(newcoord);
feature.setGeometry(geo);
}
});
}
//wgs84和gcj02坐标点转换
function transform4wgs84andgcj02(coord){
//天地图
if(basemap == 0) {
coord = TRS.gcj02_to_wgs84_exact(coord);
}
//谷歌地图
if(basemap == 1) {
coord = TRS.wgs84_to_gcj02(coord);
}
return coord;
}
点击按钮,切换效果如下,实现了不同底图坐标系的动态切换,且正常显示矢量数据。
天地图
谷歌地图
本文项目源码下载
欢迎大家进行讨论,本文若有不足之处,敬请指出。