最近做了一个web平台,其中有一个地图服务的模块,包含了一些常见的地图操作和轨迹功能,经讨论最终选择了openlayers4作为地图引擎,这里将开发过程中遇到的问题和解决方案贴出来供大家参考,小弟第一次写博客,有写的不对的地方请指正。
// 创建百度地图的数据源
function createBaiduSource(isSatellite) {
// 自定义分辨率和瓦片坐标系
var resolutions = [],
maxZoom = 18;
// 计算百度使用的分辨率
for (var i = 0; i <= maxZoom; i++) {
resolutions[i] = Math.pow(2, maxZoom - i);
}
var tilegrid = new ol.tilegrid.TileGrid({
origin: [0, 0], // 设置原点坐标
resolutions: resolutions // 设置分辨率
});
return new ol.source.TileImage({
projection: 'EPSG:3857',
tileGrid: tilegrid,
tileUrlFunction: function(tileCoord, pixelRatio, proj) {
var z = tileCoord[0],
x = tileCoord[1],
y = tileCoord[2];
// 百度瓦片服务url将负数使用M前缀来标识
if (x < 0) {
x = 'M' + (-x);
}
if (y < 0) {
y = 'M' + (-y);
}
var hash = (x << z) + y,
len = 5; // [0, 1, 2, 3, 4]
var index = hash % 5;
index = index < 0 ? index + 5 : index;
if (isSatellite) {
// 卫星地图
return 'http://shangetu' + index + '.map.bdimg.com/it/u=x=' + x + ';y=' + y + ';z=' + z + ';v=009;type=sate&fm=46&app=webearth2&v=009&udt=20171031'
} else {
// url最后的参数p=1时显示路网,p=0时不显示路网
return 'http://online' + index + '.map.bdimg.com/onlinelabel/?qt=tile&x=' + x + '&y=' + y + '&z=' + z + '&styles=pl&udt=20160426&scaler=1&p=1';
}
}
});
}
// 百度地图的矢量路网数据源
var baiduSource = createBaiduSource();
this.mapLayer = new ol.layer.Tile({
source: baiduSource
});
this.map = new ol.Map({
logo: getLogoElement(this.opts),
controls: ol.control.defaults({
attribution: this.opts.attribution, //右下角的地图信息控件
rotate: false, // 指北针控件
zoom: false // 缩放按钮控件
}).extend(getControls(this.opts)),
interactions: ol.interaction.defaults(),
layers: [
this.mapLayer,
this.geoPointLayer,
this.markerLayer,
this.lineLayer
],
view: new ol.View({
center: [104.06, 30.67],
projection: 'EPSG:4326',
zoom: this.opts.defaultZoom,
minZoom: this.opts.minZoom,
maxZoom: this.opts.mapType == 'baidu' ? this.opts.maxZoom_baidu : this.opts.maxZoom,
// 边界[minx, miny, maxx, maxy]
extent: util.isArray(this.opts.extent) && this.opts.extent.length == 4 ? this.opts.extent : [-180, -30, 180, 90]
}),
target: this.mapContainer
});
问题一: 这段代码直接以’EPSG:4326’投影初始化地图,但是某些层级时会出现异常,如图同时出现了两个层级
原因: projection参数错误,未正确理解’EPSG:4326’和’EPSG:3857’。
解释:‘EPSG:4326’指的是地理坐标系WGS84,’EPSG:3857’是由google团队推动形成的Web Mercator标准,4326的瓦片大小是512×512,3857是256×256。这里地图源的瓦片大小是256×256,与投影projection参数不匹配,所以出现图层加载异常。对坐标系有兴趣的朋友可以去坐标转换那些事儿查看更详细的介绍
解决方案一 以’EPSG:4326’投影初始化地图,将地图源换成瓦片大小是512×512的资源
解决方案二: 以默认的’EPSG:3857’投影初始化地图,将外部输入的地理坐标先转换成3857坐标,再使用,代码如下:
this.map = new ol.Map({
logo: getLogoElement(this.opts),
controls: ol.control.defaults({
attribution: this.opts.attribution, //右下角的地图信息控件
rotate: false, // 指北针控件
zoom: false // 缩放按钮控件
}).extend(getControls(this.opts)),
interactions: ol.interaction.defaults(),
layers: [
this.mapLayer,
this.geoPointLayer,
this.markerLayer,
this.lineLayer
],
view: new ol.View({
center: ol.proj.transform([104.06584974378, 30.65754338153], 'EPSG:4326', 'EPSG:3857'),
// projection: 'EPSG:3857',
zoom: this.opts.defaultZoom,
minZoom: this.opts.minZoom,
maxZoom: this.opts.mapType == 'baidu' ? this.opts.maxZoom_baidu : this.opts.maxZoom,
// 边界[minx, miny, maxx, maxy]
extent: (() => {
if(util.isArray(this.opts.extent) && this.opts.extent.length == 4){
return ol.proj.transformExtent(this.opts.extent, 'EPSG:4326', 'EPSG:3857');
}else{
return this.opts.defaultExtent;
}
})()
}),
target: this.mapContainer
});
问题二: 百度地图坐标加载偏移。经验证,地图源换成谷歌、高德地图瓦片后,定位点通过坐标系转换(从WGS84到GCJ02),百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系,均能正常显示,但是地图源换成百度地图后,定位点坐标发生偏移。尝试过多种方法,其中有一种自定义了百度投影,仍偏移几百米。路过的大神若有可行的解决方案,望告知,不胜感激!
问题三: 项目发布时,将开发版ol-debug.js切换成发布版ol.js后,ol.js报错,定位到的原因是:ol.geom.GeometryLayout未定义。不清楚是发布版ol.js的bug还是其他什么原因,网上也没有找到相关的说明。
解决方案: 手动定义ol.geom.GeometryLayout
ol.geom.GeometryLayout = {
XY: 'XY',
XYZ: 'XYZ',
XYM: 'XYM',
XYZM: 'XYZM'
};