OpenLayers中栅格瓦片投影底图切换的实现

1.综述

WebGIS中渲染地图时,要经常使用瓦片地图(tiled web map)。绝大多数瓦片地图使用的是EPSG:3857墨卡托投影,也有个别瓦片地图使用EPSG:4326投影。瓦片地图按比例尺从小到大划分,可分为22个级别(z)。每个级别中的所有瓦片都会拼接成一幅世界地图。当级别数为0的时候,一个瓦片囊括了整幅世界地图。级别数越大,能够显示的地理内容会更丰富。瓦片的横向索引(x)和纵向索引(y)的起始位置分别在最左边和最上边,数值均为0,并分别向右和向下+1递增。假设某一级别的级别数为z,则该级别的横向索引总数和纵向索引总数为2^{z}

以下表格展示了瓦片地图中的x、y、z参数。

瓦片地图中的重要参数
参数 描述
z 瓦片地图的级别,最小值为0。级别数越大,比例尺就越大,瓦片数就越多,显示的各个地理要素越丰富
x 瓦片的横向索引,最小值为0。起始位置在最左边,向右+1递增。
y 瓦片的纵向索引,最小值为0。起始位置在最上边,向下+1递增。

瓦片地图按数据显示结构,可以划分为两种形式:一个是矢量瓦片(Vector Tiles),另一个是栅格瓦片(Raster Tiles)。矢量瓦片主要为pbf格式,虽然能精确描述地理要素,但如果在大比例尺展示的情况下,会引发性能上的问题。而栅格瓦片是以图片的形式描述地理数据,尽管会有一些缺点(某些情况下地图要素和地图注记无法分离;一定时间范围内数据无法实时更新),但在显示的时候,第一次加载多个瓦片,第二次直接引用缓存。因此,一些主流的地理信息页面经常使用栅格瓦片作为地理底图。

2.具体实践

下面以OpenLayers为例,来实现地理底图的切换。实现页面如下:

不同的栅格瓦片的展示界面

首先,引用Openlayer的第三方插件。

<link rel="stylesheet" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" type="text/css">
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>

其次,在body标签里添加地图显示容器map,以及地理底图的下拉菜单。

<body>
    <div id="map" class="map"></div>
    <ul class="buttons">
    	<li onclick="tileClick(this)">OpenLayers默认地图</li>
    	<li onclick="tileClick(this)">谷歌地图</li>
    	<li onclick="tileClick(this)">天地图</li>
    	<li onclick="tileClick(this)">ArcGIS影像地图</li>
    </ul>
</body>

其次,为各个组件定义CSS样式。为了使菜单在地图上显示,position设为绝对值。

        .map {
    		width: 100%;
    		height: 100%;
    		position: relative;
    	}
    	
    	.buttons {
    		position: absolute;
    		left: 0px; top: 0px;
    		float: left;
    		margin: 0px;
    		padding: 0px;
    	}
    	
    	.buttons > li {
    		background: #990033;
    		list-style-type: none;
    		height: 25px;
    		color: white;
    		padding: 5px;
    	}
    	body {
    		margin: 0px;
    	}

最后开始在script里面编写代码了。

首先,定义栅格瓦片名称及服务路径,和地图图层。并假定当显示谷歌地图的时候就显示,其他底图则隐藏。x、y、z参数的含义前面已经提到了,这里不再赘述。

		var mapSources = {
			OpenLayers默认地图: "https://a.tile.openstreetmap.org/{z}/{x}/{y}.png",
			谷歌地图: "http://mt2.google.cn/vt/lyrs=m&scale=1&hl=zh-CN&gl=cn&x={x}&y={y}&z={z}",
			天地图: "http://t4.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}",
			ArcGIS影像地图: "https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"
		};
		
		var layers = [];
		for (var l in mapSources) {
			let visible = false;
			if (l === "谷歌地图")
				visible = true;
			layers.push(new ol.layer.Tile({
				visible: visible,
			    title: l,
			    source: new ol.source.XYZ({
			        url: mapSources[l]
			    })
			}));
		}

接下来,为下拉菜单添加点击事件,当用户点击某个下拉菜单时,能够控制图层的显示。

                function tileClick(e) {
			for (let l = 0; l < layers.length; l++) {
			if (layers[l].values_.title === e.innerText)
				layers[l].setVisible(true);
			else
				layers[l].setVisible(false);
			}
		}

最后,为id为map的div控件设置地图展示的容器、图层、缩放的级别等。

		var map = new ol.Map({
			layers: layers,
			target: "map",
			view: new ol.View({
				center: [0, 0],
				zoom: 1
			})
		});

完整的代码如下:

<!DOCTYPE html>
<html>
  <head>
    <title>栅格瓦片切换</title>
	<meta charset="utf-8">
    <meta name="keywords" content="keyword1,keyword2,keyword3">
    <meta name="description" content="this is my page">
    <meta name="content-type" content="text/html; charset=UTF-8">
    <link rel="stylesheet" href="OpenLayers/v5.2.0-dist/ol.css" type="text/css">
    <style>
    	.map {
    		width: 100%;
    		height: 100%;
    		position: relative;
    	}
    	
    	.buttons {
    		position: absolute;
    		left: 0px; top: 0px;
    		float: left;
    		margin: 0px;
    		padding: 0px;
    	}
    	
    	.buttons > li {
    		background: #990033;
    		list-style-type: none;
    		height: 25px;
    		color: white;
    		padding: 5px;
    	}
    	body {
    		margin: 0px;
    	}
    </style>

  </head>
  
  <body>
    <div id="map" class="map"></div>
    <ul class="buttons">
    	<li onclick="tileClick(this)">OpenLayers默认地图</li>
    	<li onclick="tileClick(this)">谷歌地图</li>
    	<li onclick="tileClick(this)">天地图</li>
    	<li onclick="tileClick(this)">ArcGIS影像地图</li>
    </ul>
  </body>
	<script src="OpenLayers/v5.2.0-dist/ol.js"></script>
	<script type="text/javascript">
		var mapSources = {
			OpenLayers默认地图: "https://a.tile.openstreetmap.org/{z}/{x}/{y}.png",
			谷歌地图: "http://mt2.google.cn/vt/lyrs=m&scale=1&hl=zh-CN&gl=cn&x={x}&y={y}&z={z}",
			天地图: "http://t4.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}",
			ArcGIS影像地图: "https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"
		};
		
		var layers = [];
		for (var l in mapSources) {
			let visible = false;
			if (l === "谷歌地图")
				visible = true;
			layers.push(new ol.layer.Tile({
				visible: visible,
			    title: l,
			    source: new ol.source.XYZ({
			        url: mapSources[l]
			    })
			}));
		}
		
		function tileClick(e) {
			for (let l = 0; l < layers.length; l++) {
			if (layers[l].values_.title === e.innerText)
				layers[l].setVisible(true);
			else
				layers[l].setVisible(false);
			}
		}
		
		var map = new ol.Map({
			layers: layers,
			target: "map",
			view: new ol.View({
				center: [0, 0],
				zoom: 1
			})
		});
	</script>
</html>

参考链接:

  1. 瓦片的定义(英文):https://wiki.openstreetmap.org/wiki/Tiles
  2. OpenLayers实例库(英文):http://openlayers.org/en/latest/examples/

猜你喜欢

转载自blog.csdn.net/weixin_38307752/article/details/84482251