OpenLayers 加载百度瓦片地图源(03)

发布时间:2026/7/30 20:22:54

OpenLayers 加载百度瓦片地图源(03) OpenLayers加载百度瓦片地图详解百度地图作为国内主流地图服务其瓦片坐标系与标准Web墨卡托投影存在差异。本文将详细介绍如何在OpenLayers中正确加载百度地图瓦片包括坐标转换原理、三种实现方案的对比以及实际使用中的注意事项。当前使用的OpenLayers版本{ol: ^10.9.0}一、百度地图瓦片特殊性分析1.1 坐标系差异百度地图使用BD09坐标系是在GCJ02坐标系基础上进一步加密的坐标系。而OpenLayers默认使用EPSG:3857Web墨卡托投影两者的差异导致直接加载百度瓦片会出现位置偏移。1.2 瓦片坐标规则百度地图的瓦片坐标规则与标准XYZ方案存在以下差异特性标准XYZ百度瓦片Y轴方向从上到下递增从下到上递增起始编号0开始1开始需要减1负数处理直接使用负数使用M前缀表示坐标系EPSG:3857BD09需转换1.3 核心转换公式在OpenLayers中加载百度瓦片的关键转换逻辑// OpenLayers坐标 → 百度瓦片坐标letbaiduY-openLayersY-1;letbaiduXopenLayersX0?M(-openLayersX):openLayersX;letfinalYbaiduY0?M(-baiduY):baiduY;二、实现方案详解2.1 XYZ Source方案推荐createBDXYZSource是基于ol/source/XYZ的实现也是目前推荐的方案importXYZfromol/source/XYZimportTileGridfromol/tilegrid/TileGridimport{getasolProjGet}fromol/projexportfunctioncreateBDXYZSource(options){if(!options.url){thrownewError(Tile: no url provided)}// 生成百度地图的分辨率数组0-18级constresolutions[]for(leti0;i19;i){resolutions[i]Math.pow(2,18-i)}// 创建自定义瓦片网格consttilegridnewTileGrid({origin:[0,0],resolutions:resolutions})const{url:tileUrl,...params}optionsreturnnewXYZ({...params,projection:olProjGet(EPSG:3857),tileGrid:tilegrid,// 核心自定义瓦片URL生成函数tileUrlFunction:(tileCoord,pixelRatio,projection){if(!tileCoord)return;letztileCoord[0]letxtileCoord[1]letytileCoord[2]// 坐标转换OpenLayers的y从上往下递增// 转换为百度的y从下往上递增且起始编号偏移1y-y-1// 处理负数百度要求用 M 前缀if(x0)xM(-x)if(y0)yM(-y)returnoptions.url.replace({x},x).replace({y},y).replace({z},z)}})}使用示例importMapfromol/MapimportViewfromol/ViewimportTileLayerfromol/layer/Tileimport{createBDXYZSource}from./BaiduSourceconstmapnewMap({target:map,layers:[newTileLayer({source:createBDXYZSource({url:http://online3.map.bdimg.com/onlinelabel/?qttilex{x}y{y}z{z}stylespludt20151021,crossOrigin:anonymous})})],view:newView({center:[116.404,39.915],// 北京市中心zoom:10,projection:EPSG:3857})})2.2 ImageTile Source方案新版本createBDImageTileSource是基于ol/source/ImageTile的实现这是OpenLayers新版本推荐的替代方案importImageTilefromol/source/ImageTileimportTileGridfromol/tilegrid/TileGridimport{getasolProjGet}fromol/projexportfunctioncreateBDImageTileSource(options){if(!options.url){thrownewError(Tile: no url provided)}// 生成分辨率数组constresolutions[]for(leti0;i19;i){resolutions[i]Math.pow(2,18-i)}// 创建瓦片网格consttilegridnewTileGrid({origin:[0,0],resolutions:resolutions})returnnewImageTile({...options,projection:olProjGet(EPSG:3857),tileGrid:tilegrid,// URL生成函数参数为(z, x, y)url:function(z,x,y){// 转换为百度所需的 y取反并减 1letbaiduY-y-1// 处理负数百度要求 M 前缀letbaiduXx0?M(-x):xletfinalYbaiduY0?M(-baiduY):baiduYreturnoptions.url.replace({x},baiduX).replace({y},finalY).replace({z},z)}})}使用示例constbaiduLayernewTileLayer({source:createBDImageTileSource({url:http://online3.map.bdimg.com/onlinelabel/?qttilex{x}y{y}z{z}stylespl,crossOrigin:anonymous})})2.3 TileImage Source方案已弃用createBDTileImageSource是基于ol/source/TileImage的实现该方案已被标记为弃用importTileImagefromol/source/TileImageimportTileGridfromol/tilegrid/TileGridimport{getasolProjGet}fromol/projexportfunctioncreateBDTileImageSource(options){if(!options.url){thrownewError(Tile: no url provided)}letresolutions[]for(leti0;i19;i){resolutions[i]Math.pow(2,18-i)}lettilegridnewTileGrid({origin:[0,0],resolutions:resolutions})returnnewTileImage({crossOrigin:anonymous,projection:olProjGet(EPSG:3857),tileGrid:tilegrid,tileUrlFunction:(tileCoord,pixelRatio,projection){if(!tileCoord)returnletztileCoord[0]letxtileCoord[1]lety-tileCoord[2]-1if(x0)xM-xif(y0)yM-yreturnoptions.url.replace({x},x).replace({y},y).replace({z},z)}})}注意TileImage在OpenLayers新版本中已被弃用建议迁移到XYZ或ImageTile方案。三、方案对比与选择建议3.1 三种方案对比方案数据源类型兼容性推荐度适用场景XYZ Sourceol/source/XYZOpenLayers 6.x⭐⭐⭐⭐⭐新项目首选API稳定ImageTile Sourceol/source/ImageTileOpenLayers 7.x⭐⭐⭐⭐新版本迁移官方推荐TileImage Sourceol/source/TileImage已弃用⭐⭐旧项目维护不推荐新使用3.2 选择建议新项目开发优先使用createBDXYZSourceAPI简洁且稳定升级OpenLayers版本可以考虑迁移到createBDImageTileSource维护旧项目如果当前使用TileImage且运行正常可以暂时保留但建议规划迁移四、百度地图瓦片URL配置4.1 常用瓦片服务地址百度地图提供多种样式瓦片服务// 标准地图瓦片constnormalUrlhttp://online{s}.map.bdimg.com/onlinelabel/?qttilex{x}y{y}z{z}stylespl// 卫星地图瓦片constsatelliteUrlhttp://shangetu{s}.map.bdimg.com/it/ux{x};y{y};z{z};v009;typesatefm46// 路网图层瓦片constroadUrlhttp://online{s}.map.bdimg.com/onlinelabel/?qttilex{x}y{y}z{z}stylessl// 深色主题瓦片constdarkUrlhttp://api{s}.map.bdimg.com/customimage/tile?x{x}y{y}z{z}udt20170428scale1akYOUR_AKcustomiddark4.2 缩放级别说明百度地图支持0-18级缩放对应的分辨率缩放级别分辨率像素/米说明0262144全球视图58192国家级10256城市级158街道级181建筑级五、常见问题与解决方案5.1 跨域问题问题描述控制台报错Access to image at http://... from origin ... has been blocked by CORS policy解决方案// 在创建Source时设置crossOrigincreateBDXYZSource({url:...,crossOrigin:anonymous// 关键配置})5.2 瓦片加载不显示可能原因坐标转换逻辑错误瓦片URL模板格式不正确缩放级别超出百度地图支持范围排查步骤// 1. 检查地图中心点坐标应为EPSG:3857格式console.log(map.getView().getCenter())// 2. 检查当前缩放级别console.log(map.getView().getZoom())// 3. 打印生成的瓦片URLconsole.log(生成的瓦片URL:,tileUrl)5.3 瓦片偏移问题问题描述地图加载正常但位置有明显偏移解决方案确保使用正确的坐标转换公式// 正确的转换公式letbaiduY-y-1// 不是 -y 或 -y 1六、总结6.1 核心要点回顾坐标转换是关键百度地图使用独特的瓦片坐标系必须进行正确的坐标转换推荐使用XYZ SourceAPI稳定兼容性好是新项目的首选方案注意跨域设置设置crossOrigin: anonymous解决跨域加载问题理解瓦片URL结构掌握百度地图瓦片服务的URL模板格式6.2 代码仓库本文示例代码已封装为可复用的工具函数完整实现可参考项目中的BaiduSource.js文件支持三种不同的数据源创建方式满足不同项目需求。完整代码// 官方推荐的替代方案是使用 ImageTile 数据源新版本importImageTilefromol/source/ImageTile// TileImage 数据源已被标记为弃用。旧版本importTileImagefromol/source/TileImageimportXYZfromol/source/XYZimportTileGridfromol/tilegrid/TileGridimport{getasolProjGet}fromol/projimportdebugfrom../debug/index.js/** * 使用 XYZ 创建百度地图瓦片数据源推荐版本 * * 百度地图瓦片采用自定义坐标系需要将 OpenLayers 的 EPSG:3857 坐标 * 转换为百度自有的瓦片坐标y 轴取反并 -1负数用 M 前缀。 * * param {Object} options - 配置参数 * param {string} options.url - 瓦片 URL 模板必须包含 {x} {y} {z} 占位符 * 示例: http://online{s}.map.bdimg.com/onlinelabel/?qttilex{x}y{y}z{z}stylespl * param {string} [options.crossOrigin] - 跨域策略设置为 anonymous 可解决跨域加载问题 * param {number} [options.minZoom0] - 最小缩放级别 * param {number} [options.maxZoom18] - 最大缩放级别 * param {number} [options.gutter] - 瓦片边缘像素扩展 * param {boolean} [options.reprojectionErrorThreshold0.5] - 重投影误差阈值 * returns {XYZ} 百度地图 XYZ 瓦片数据源 * example * createBDXYZSource({ * url: http://online{s}.map.bdimg.com/onlinelabel/?qttilex{x}y{y}z{z}stylespludt20151021, * crossOrigin: anonymous * }) */exportfunctioncreateBDXYZSource(options){if(!options.url){debug.error(Tile: no url provided)}constresolutions[]for(leti0;i19;i){resolutions[i]Math.pow(2,18-i)}consttilegridnewTileGrid({origin:[0,0],resolutions:resolutions})const{url:tileUrl,...params}optionsreturnnewXYZ({...params,projection:olProjGet(EPSG:3857),tileGrid:tilegrid,// 核心自定义瓦片URL生成函数 (url参数不要放进来否则不会触发tileUrlFunction函数)tileUrlFunction:(tileCoord,pixelRatio,projection){if(!tileCoord)return;letztileCoord[0];letxtileCoord[1];letytileCoord[2];// OpenLayers 的 y从上往下递增// 转换为百度的 y从下往上递增且起始编号偏移 1y-y-1;// 处理负数百度要求用 M 前缀if(x0)xM(-x);if(y0)yM(-y);returnoptions.url.replace({x},x).replace({y},y).replace({z},z)}})}/** * 使用ImageTile创建百度地图瓦片数据源新版本 * param {Object} options - 配置参数需包含 url 字段 * returns {ImageTile} */exportfunctioncreateBDImageTileSource(options){if(!options.url){debug.error(Tile: no url provided)}constresolutions[]for(leti0;i19;i){resolutions[i]Math.pow(2,18-i)}consttilegridnewTileGrid({origin:[0,0],resolutions:resolutions})returnnewImageTile({// crossOrigin: anonymous,...options,projection:olProjGet(EPSG:3857),tileGrid:tilegrid,url:function(z,x,y){// 转换为百度所需的 y取反并减 1letbaiduY-y-1;// 处理负数百度要求 M 前缀letbaiduXx0?M(-x):x;letfinalYbaiduY0?M(-baiduY):baiduY;returnoptions.url.replace({x},baiduX).replace({y},finalY).replace({z},z)}})}/** * 使用TileImage创建百度地图瓦片数据源(旧版本)已弃用 * param {Object} options - 配置参数需包含 url 字段 * returns {ImageTile} */exportfunctioncreateBDTileImageSource(options){if(!options.url){debug.error(Tile: no url provided)}letresolutions[]for(leti0;i19;i){resolutions[i]Math.pow(2,18-i)}lettilegridnewTileGrid({origin:[0,0],resolutions:resolutions})returnnewTileImage({crossOrigin:anonymous,projection:olProjGet(EPSG:3857),tileGrid:tilegrid,// 核心自定义瓦片URL生成函数tileUrlFunction:(tileCoord,pixelRatio,projection){if(!tileCoord)returnletztileCoord[0]letxtileCoord[1]lety-tileCoord[2]-1if(x0)xM-xif(y0)yM-yreturnoptions.url.replace({x},x).replace({y},y).replace({z},z)}})}

相关新闻