openlayers 默认的坐标系的原点在左上角,向上为y轴正方向,向右为x轴正方向。
也就是说,地图投影到一个平面后,平面的左边对应着地球的西边,也是x轴负方向;平面上面对应地图的北面,也是y轴正方向。
但是并不是所有的瓦片地图都采用这样的坐标系,例如百度地图,它是将坐标系原点设为地图视图的中心点,因此坐标是有正负的,负值添加了 'M’ 前缀作为区分。
<div id="baiduMap" style="width: 100%"></div>
<script>
// 百度地图层
var baiduMapLayer = new ol.layer.Tile({
source: new ol.source.XYZ({
tilePixelRatio: 2,
// 这里没有直接写url,而是通过tileUrlFunction去处理坐标系原点,再返回url。参数tileCoord为瓦片坐标
tileUrlFunction: function(tileCoord){
var z = tileCoord[0];
var x = tileCoord[1];
var y = tileCoord[2];
// 计算当前层级下瓦片总数的一半,用于定位整个地图的中心点;瓦片数量=2 * z;z为当前层级;openlayers是以 2的幂次方的速度 来缩放的;
var halfTileNum = Math.pow(2, z-1);
// 原点移到中心点后,计算xy方向上新的坐标位置
var baiduX = x - halfTileNum;
var baiduY = y + halfTileNum;
// 百度瓦片服务url将负数使用M前缀来标识
if (baiduX < 0) {
baiduX = 'M' + (-baiduX);
}
if (baiduY < 0) {
baiduY = 'M' + (-baiduY);
}
// 返回经过转换后,对应于百度在线瓦片的url
return 'http://online2.map.bdimg.com/onlinelabel/?qt=tile&x=' + baiduX + '&y=' + baiduY + '&z=' + z + '&styles=pl&udt=20160321&scaler=2&p=0';
}
})
});
// 创建地图
var map = new ol.Map({
layers: [
baiduMapLayer
],
view: new ol.View({
// 设置成都为地图中心
center: [104.06, 30.67],
projection: 'EPSG:4326',
zoom: 4
}),
target: 'baiduMap'
});
</script>```
可以发现,百度地图的坐标系向右为x正方向,向上为y正方向的坐标系,与数学上的笛卡尔坐标系一致。但是上面的代码中心点会有偏差,可能是openlayers 与 百度在线瓦片地图的分辨率对不上导致的,因此我们还需要重新定义分辨率。
```javascript
<div id="baiduMap2" style="width: 100%"></div>
<script>
// 自定义分辨率和瓦片坐标系
var resolutions = [];
var maxZoom = 18;
// 计算百度使用的分辨率
for(var i=0; i<=maxZoom; i++){
resolutions[i] = Math.pow(2, maxZoom-i); //计算每一层的分辨率,存进 resolutions 中
}
var tilegrid = new ol.tilegrid.TileGrid({
origin: [0,0], // 设置原点坐标
resolutions: resolutions // 设置分辨率
});
// 创建百度地图的数据源
var baiduSource = new ol.source.TileImage({
projection: 'EPSG:3857',
tileGrid: tilegrid,
tileUrlFunction: function(tileCoord, pixelRatio, proj){
var z = tileCoord[0];
var x = tileCoord[1];
var y = tileCoord[2];
// 百度瓦片服务url将负数使用M前缀来标识
if(x<0){
x = 'M' + (-x);
}
if(y<0){
y = 'M' + (-y);
}
return "http://online0.map.bdimg.com/onlinelabel/?qt=tile&x="+x+"&y="+y+"&z="+z+"&styles=pl&udt=20160426&scaler=1&p=0";
}
});
// 百度地图层
var baiduMapLayer2 = new ol.layer.Tile({
source: baiduSource
});
// 创建地图
new ol.Map({
layers: [
baiduMapLayer2
],
view: new ol.View({
// 设置成都为地图中心
center: [104.06, 30.67],
projection: 'EPSG:4326',
zoom: 4
}),
target: 'baiduMap2'
});
</script>
上面的代码用到了ol.tilegrid.TileGrid,这个是瓦片网格,在其中定义了坐标原点和每一层的分辨率;需要注意的是,它与笛卡尔坐标系一样,默认情况下,从左向右为x正方向,从下向上为y轴正方向。使用这个类可以重新定义 openlayers 的瓦片地图坐标系。