Openlayers 实战 - 地图视野(View)- 图层 -(layer)- 资源(source)显示等级设置。
- 问题原因
- 核心代码
- 完整代码:
- 在线示例
在以往的项目维护中,出现一个问题,使用最新高清底图发现,设置地图最大等级(21级)之后,地图虽然可以渲染 21 级图层,但是并没有请求 21 级图层瓦片数据。
思考之后,认为是地图等级参数限制,经过调试发现问题所在不仅于此,后来解决问题,这里记录一下。
本文包括问题原因、问题解决核心代码以及在线示例。
问题原因
地图图层想要设置缩放等级,需要三个条件:
1. 地图视野 View 对象设置 minzoom maxzoom 参数。
2. 图层 layer 对象设置 minzoom maxzoom 参数。
3. 资源 source 设置分辨率 tileGrid-resolutions 参数。
三个条件缺一不可,以下分别设置部分对象属性出现的问题:
1.只设置地图,不设置图层,地图可以放大,但是不会请求资源;由于图层没有资源,会显示空白。
PS: 下图额外加载了一个显示 zoom 的图层。
2. 只设置图层,不设置地图,地图不能继续放大,因此也不会加载高等级图层瓦片。
3. 设置地图以及图层,不设置资源,地图和图层可以放大,但是不会请求资源,只是图片放大了,看起来会模糊。
4. 地图视野、图层、资源同时设置,会正常请求相应的数据。
核心代码
这里放上控制地图视野(View)、图层(Layer)、资源(Source)对象缩放等级的代码:
其中加载了一个显示瓦片索引的图层,用来查看图层瓦片请求情况:瓦片索引的图层
// 地图视野等级设置
function viewZoom() {
view.setMaxZoom(maxZoom);
view.setZoom(defaultMaxZoom + 1);
}
// 图层等级设置
function layerZoom() {
layer.setMaxZoom(maxZoom);
}
// 图层资源等级设置
function sourceZoom() {
layer.setSource(getOptional(getUrl(),maxZoom))
}
// 还原所有缩放等级
function restoreZoom() {
view.setMaxZoom(defaultMaxZoom);
layer.setMaxZoom(defaultMaxZoom);
layer.setSource(getOptional(getUrl(),defaultMaxZoom))
view.setZoom(defaultMaxZoom);
}
完整代码:
<html lang="en">
<head>
<meta charset="utf-8">
<!--注意:openlayers 原版的比较慢,这里引起自己服务器版-->
<link rel="stylesheet" href="http://openlayers.vip/examples/css/ol.css" type="text/css">
<style>
/* 注意:这里必须给高度,否则地图初始化之后不显示;一般是计算得到高度,然后才初始化地图 */
.map {
height: 400px;
width: 100%;
float: left;
}
</style>
<!--注意:openlayers 原版的比较慢,这里引起自己服务器版-->
<script src="http://openlayers.vip/examples/resources/ol.js"></script>
<title>OpenLayers example</title>
</head>
<body>
<h2>View Layer Zoom</h2>
<!--地图容器,需要指定 id -->
<div id="map" class="map"></div>
<script type="text/javascript">
// 自己的tk
let TK = '2b7cbf61123cbe4e9ec6267a87e7442f';
// 默认地图等级
const defaultMaxZoom = 14;
// 设置新的最大等级
const maxZoom = 18;
// 定位测试等级
const moveToZoom = 16;
// 获取天地图资源地址
let getUrl = function (type = 'IMG_C') {
let url = 'http://t{randomNumber}.tianditu.gov.cn/DataServer?T={type}&x={x}&y={y}&l={z}';
url = url.replace('{randomNumber}', Math.round(Math.random() * 7).toString());
url = url.replace('{type}', type);
url = url + "&tk=" + TK;
return url;
}
// 获取分辨率数组
let getResolutionsExpert = function (size, maxZoom = defaultMaxZoom) {
let resolutions = new Array(maxZoom);
let matrixIds = new Array(maxZoom);
for (let z = 0; z < maxZoom + 1; ++z) {
//分辨率
resolutions[z] = size / Math.pow(2, z);
//放大等级
matrixIds[z] = z;
}
return resolutions;
}
// 获取图层资源对象
let getOptional = function (url, maxZoom) {
let projection = ol.proj.get('EPSG:4326');
let projectionExtent = projection.getExtent();
let size = ol.extent.getWidth(projectionExtent) / 256;
return new ol.source.XYZ({
crossOrigin: 'anonymous',
wrapX: true,
//切片xyz获取方法
tileUrlFunction: function (tileCoord) {
const z = tileCoord[0];
const x = tileCoord[1];
let y = tileCoord[2];
let completeUrl = url.replace('{z}', z.toString())
.replace('{y}', y.toString())
.replace('{x}', x.toString());
return completeUrl;
},
//坐标系
projection: projection,
tileGrid: new ol.tilegrid.TileGrid({
origin: ol.extent.getTopLeft(projectionExtent),
tileSize: [256, 256],
//分辨率数组 天地图为 1.40625
resolutions: getResolutionsExpert(size, maxZoom)
}),
})
}
// 初始图层资源对象
const source = getOptional(getUrl());
//影像图
function getIMG_CLayer() {
let layer = new ol.layer.Tile({
name: "天地图影像图层",
source: source,
maxZoom: defaultMaxZoom,
minZoom: 1,
});
return layer;
}
// 地图视野对象
const view = new ol.View({
projection: "EPSG:4326",
// 定位
center: [116, 39],
// 缩放
zoom: defaultMaxZoom,
maxZoom: defaultMaxZoom,
minZoom: 1,
});
// 图层对象
const layer = getIMG_CLayer();
// 网格图层参数
const size = 256;
const canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
const context = canvas.getContext('2d');
context.strokeStyle = 'white';
context.textAlign = 'center';
context.font = '40px sans-serif';
const lineHeight = 15;
// 地图对象
const map = new ol.Map({
// 地图容器
target: 'map',
// 地图图层,比如底图、矢量图等
layers: [
layer,
// 添加网格图层,显示等级:Z
new ol.layer.WebGLTile({
source: new ol.source.DataTile({
loader: function (z, x, y) {
const half = size / 2;
context.clearRect(0, 0, size, size);
context.fillStyle = 'rgba(100, 100, 100, 0.1)';
context.fillRect(0, 0, size, size);
context.fillStyle = 'white';
context.fillText(`z: ${z}`, half, half + lineHeight);
// context.fillText(`x: ${x}`, half, half);
// context.fillText(`y: ${y}`, half, half + lineHeight);
context.strokeRect(0, 0, size, size);
const data = context.getImageData(0, 0, size, size).data;
// converting to Uint8Array for increased browser compatibility
return new Uint8Array(data.buffer);
},
// disable opacity transition to avoid overlapping labels during tile loading
transition: 0,
}),
}),
],
// 地图视野
view: view
});
// 地图视野等级设置
function viewZoom() {
view.setMaxZoom(maxZoom);
view.setZoom(defaultMaxZoom + 1);
}
// 图层等级设置
function layerZoom() {
layer.setMaxZoom(maxZoom);
}
// 图层资源等级设置
function sourceZoom() {
layer.setSource(getOptional(getUrl(),maxZoom))
}
// 还原所有缩放等级
function restoreZoom() {
view.setMaxZoom(defaultMaxZoom);
layer.setMaxZoom(defaultMaxZoom);
layer.setSource(getOptional(getUrl(),defaultMaxZoom))
view.setZoom(defaultMaxZoom);
}
</script>
<button id="viewZoom" onClick="viewZoom()">设置地图缩放等级(不改变 layer 和 source)</button>
<button id="layerZoom" onClick="layerZoom()">设置图层缩放等级(不改变 map 和 source)</button>
<button id="sourceZoom" onClick="sourceZoom()">设置资源缩放等级(不改变 map 和 layer)</button>
<button id="restoreZoom" onClick="restoreZoom()">还原所有缩放等级</button>
</body>
</html>
在线示例
在线示例:Openlayers 显示等级设置