OpenLayer3读取Geoserver切割的离线瓦片
目录
前言:
由于在网上搜索了很久都没有找到相关的东西,只能自己埋头研究,本文我付出了整整40个小时的心血来解读,希望大家若要转载一定要注上作者名及地址。
Geoserver的离线瓦片生成
主要的功能全在Tile Caching上,要注意的是,必须先设置好你所要的图层的坐标系(注:本例为了讲解改变了坐标系范围,建议不要改,以配合其他图层)。
- 在Gridsets下选择/新建一个坐标系分割模版,计算好范围后,选择add zoom level,添加完毕后保存(注意,这些参数非常重要,勿乱改)
- 在你的图层设置中,找到tile设置,更换为你的分割模版
- 进入Tile Layers中,新建/选择你的图层,选中Seed/Truncate(如果你事先做过,先选清空),进入界面后如图设置(第一项是线程,想快点就多,除了Gridset必须一致外,其他随你便)

- 完成后在你的geoserver默认数据文件夹内的gwc下找到你的图层文件,文件结构如下图
Geoserver瓦片分割原理
瓦片主要由xyz三部分组成,z是放大级别,x为水平轴,y为垂直轴(不同体系下的原点不同,在Geoserver中原点在图层的左下角,即xy轴就是最日常的笛卡尔,所以x可称为列号,y可称为行号)。

瓦片行列号计算
必要条件:地图范围(即上图红框)、当前级别分辨率、瓦片的范围
var deltaX = Math.ceil(((extent[2] - extent[0]) / resolutions[z]) / 256); //地图的宽度除以(当前分辨率*瓦片宽度)= 列数,向上取整
var deltaY = Math.ceil(((extent[3] - extent[1]) / resolutions[z]) / 256); //地图的长度除以(当前分辨率*瓦片长度)= 行数,向上取整
条件获取方式:最快的是在tile Layer里打开你的瓦片图层,右键查看源代码。

在程序中实现读取
/**
* 本文件用于调用geoserver切割的瓦片
* @author Wilson.Yan
* @version 2016.8.21
*/
//改变数字格式
function fix(str,length){
var temp = "00" + str.toString();
return temp.substr(temp.length-2,length);
}
//外部调用测试函数
function addLocal(){
//实例化地图
var map = new ol.Map({
target:'map',
layers:[], //空图层
view:new ol.View({
projection: new ol.proj.Projection({
code: 'EPSG:4610',
units: 'degrees', //一定要换成经纬度显示,不然根本没法计算
axisOrientation:'neu'
}),
zoom:0,
maxZoom:10,
minZoom:2, //较为特殊的地方,要注意
center:[100,35] //必填,不然不显示(待定)
})
});
var extent = [73.62,3.157730076656914,135.315902709961,53.80867363506534];//地图边框,在geoserver内查看
//gridset分辨率,geoserver内查看
var resolutions = [0.2388671875, 0.11943359375, 0.059716796875, 0.0298583984375, 0.01492919921875];
var url = './test_bou2_4l/{z}/{f}/{x}_{y}.png'; //初步的url
//定义数据源
var source = new ol.source.TileImage({
projection:ol.proj.get('EPSG:4610'),
tileSize:256,
maxZoom:4,
minZoom:0,
/* urls:getUrls(z,extent,resolutions),*/
tileGrid:new ol.tilegrid.TileGrid({
origin:[73.62,3.1577],//ol.extent.getBottomLeft() Geoserver瓦片原点在左下角
resolutions:resolutions, //5个
tileSize:[256, 256]
}),
tileUrlFunction:function(tileCoord){
var z = tileCoord[0];
var x = tileCoord[1];
var y = tileCoord[2];
var re = [z,x,y];
console.log(re);
switch(z){ //暂时没有太好的方法解决,只能用较笨的方法
case 0: //0级
return url.replace('{z}','EPSG_4610_0' + z.toString())
.replace('{f}','0_0')
.replace('{x}',fix(x,2))
.replace('{y}',fix(y,2));
break;
case 1: //1级
if(x<2){
return url.replace('{z}','EPSG_4610_0' + z.toString())
.replace('{f}','0_0')
.replace('{x}',fix(x,2))
.replace('{y}',fix(y,2));
}
else{
return url.replace('{z}','EPSG_4610_0' + z.toString())
.replace('{f}','1_0')
.replace('{x}',fix(x,2))
.replace('{y}',fix(y,2));
}
break;
case 2:
if(x<4){
return url.replace('{z}','EPSG_4610_0' + z.toString())
.replace('{f}','0_0')
.replace('{x}',fix(x,2))
.replace('{y}',fix(y,2));
}
else{
return url.replace('{z}','EPSG_4610_0' + z.toString())
.replace('{f}','1_0')
.replace('{x}',fix(x,2))
.replace('{y}',fix(y,2));
}
break;
case 3:
if(x==8){
if(y<4){
return url.replace('{z}','EPSG_4610_0' + z.toString())
.replace('{f}','2_0')
.replace('{x}',fix(x,2))
.replace('{y}',fix(y,2));
}
else{
return url.replace('{z}','EPSG_4610_0' + z.toString())
.replace('{f}','2_1')
.replace('{x}',fix(x,2))
.replace('{y}',fix(y,2));
}
}
else{
if(x<4){
if(y<4){
return url.replace('{z}','EPSG_4610_0' + z.toString())
.replace('{f}','0_0')
.replace('{x}',fix(x,2))
.replace('{y}',fix(y,2));
}
else{
return url.replace('{z}','EPSG_4610_0' + z.toString())
.replace('{f}','0_1')
.replace('{x}',fix(x,2))
.replace('{y}',fix(y,2));
}
}
else{
if(y<4){
return url.replace('{z}','EPSG_4610_0' + z.toString())
.replace('{f}','1_0')
.replace('{x}',fix(x,2))
.replace('{y}',fix(y,2));
}
else{
return url.replace('{z}','EPSG_4610_0' + z.toString())
.replace('{f}','1_1')
.replace('{x}',fix(x,2))
.replace('{y}',fix(y,2));
}
}
}
break;
case 4:
if(x==16){
if(y<8){
return url.replace('{z}','EPSG_4610_0' + z.toString())
.replace('{f}','2_0')
.replace('{x}',fix(x,2))
.replace('{y}',fix(y,2));
}
else{
return url.replace('{z}','EPSG_4610_0' + z.toString())
.replace('{f}','2_1')
.replace('{x}',fix(x,2))
.replace('{y}',fix(y,2));
}
}
else{
if(x<8){
if(y<8){
return url.replace('{z}','EPSG_4610_0' + z.toString())
.replace('{f}','0_0')
.replace('{x}',fix(x,2))
.replace('{y}',fix(y,2));
}
else{
return url.replace('{z}','EPSG_4610_0' + z.toString())
.replace('{f}','0_1')
.replace('{x}',fix(x,2))
.replace('{y}',fix(y,2));
}
}
else{
if(y<8){
return url.replace('{z}','EPSG_4610_0' + z.toString())
.replace('{f}','1_0')
.replace('{x}',fix(x,2))
.replace('{y}',fix(y,2));
}
else{
return url.replace('{z}','EPSG_4610_0' + z.toString())
.replace('{f}','1_1')
.replace('{x}',fix(x,2))
.replace('{y}',fix(y,2));
}
}
}
default:
return null;
}
}
});
//创建离线瓦片图层
var LocalLayer = new ol.layer.Tile({
extent:extent,
source:source,
name:'尼玛'
});
map.addLayer(LocalLayer);
/*//视图变换事件
view.on('change:resolution',function(){
z = view.getZoom();
source.setUrls(getUrls(z,extent,resolutions));
console.log(z);
map.removeLayer(LocalLayer);
map.addLayer(LocalLayer);
},this);*/
return map;
}
注意事项:
- 你自己也可以利用setUrls的方法进行调用(反正你已经知道了当前级别有多少行多少列,来个嵌套循环就搞定),但不会比tileUrlFunction更好用
- 视图的缩放级别不一定跟tile的缩放级别对应的上,你可以利用开发者工具进行比较(例如本文的视图为2时,才被识别成0)
- 目前还没有太好的解决geoserver生成的恶心文件名的好方法,大家有解决的可以告诉我一下
- 善用开发者工具
文件路径问题补充:
又经过8小时的奋战,基本解决了文件的问题。
首先是最麻烦的计算文件数目,因为要亲手画图的缘故,所以特别辛苦。(目前8级以内的都是每隔两个级别才扩充一次文件块的存储数量)
//--------计算文件数方法-------------//
function calFileNum(minZoom,maxZoom){
var fileDelta = new Array(maxZoom-minZoom+1);//每个文件夹的边数组
for(var i=0;i<=maxZoom;i++){
if(i%2==0){ //偶数
fileDelta[i] = Math.pow(2,i+2);
}
else{ //奇数
fileDelta[i] = fileDelta[i-1];
}
}
return fileDelta;
}
然后,在TileUrlFunction函数中改成新的方法
tileUrlFunction:function(tileCoord){
var z = tileCoord[0];
var x = tileCoord[1];
var y = tileCoord[2];
var tempFile = Math.sqrt(fileDel[z]); //边数
var tryx = Math.ceil((x+1)/tempFile) - 1; //x所在列(关键点)
var tryy = Math.ceil((y+1)/tempFile) - 1; //y所在行(关键点)
var file = tryx.toString() + '_' + tryy.toString();
var ss = url.replace('{z}','EPSG_4610_0' + z.toString()).replace('{f}',file).replace('{x}',fix(x,2)).replace('{y}',fix(y,2));
console.log(ss);
return ss;
}
转载自:https://blog.csdn.net/u013323965/article/details/52268113