Skip to content

map-preview

使用高德地图、百度地图切片和openlayers实现广西街道地图离线使用。

切片下载和部署

  1. 请使用此工具进行切片下载:mapTileDownload

    下载的切片通常会很庞大,第 17、18、19 层级的文件数据量大、文件多,直接上传至服务器会非常缓慢,请使用压缩工具进行压缩 压缩也要根据电脑配置分多文件压缩,否则压缩到最后内存溢出失败了就白白压缩那么久了!通常 1-17 一个压缩包、18 分为一个或两个包,一个包大小为 4g-6g 左右大小

  2. 使用sftp上传文件到服务器:

    bash
    scp -r '/F:/地图切片/百度广西区域街道图/roadmap-1-17.7z' root@192.168.1.207:/data/daye01/map/
  3. 登录服务器,安装压缩工具7za

    bash
    yum install -y p7zip
  4. 解压缩上传的文件夹到指定目录:

    bash
    7za x 'roadmap-1-17.7z' -r -o./bmap
  5. 配置跨域资源访问,以nginx为例:

    若资源和客户端代码在同一服务上可忽略此操作

    为资源静态访问添加nginx配置:

    nginx
    location ^~ /map {
        # 处理以/map开头的请求
        add_header 'Access-Control-Allow-Headers' '*' always;
        add_header 'Access-Control-Allow-Origin' '*' always;
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin' '*' always;
            add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE' always;
            add_header 'Access-Control-Allow-Headers' '*' always;
            add_header 'Access-Control-Max-Age' 1728000 always;
            add_header 'Content-Length' 0;
            add_header 'Content-Type' 'text/plain; charset=utf-8';
            return 204;
        }
        root /data;
        expires 3d;
    }
  6. 之后就可以通过/map/bmap/{z}/{x}/{y}.png来访问切片了

demo-百度

js
/*定义百度地图分辨率与瓦片网格*/
const resolutions = [];
for (var i = 0; i <= 19; i++) {
  resolutions[i] = Math.pow(2, 18 - i);
}

// 创建百度地理坐标系,
const projBD09 = new ol.proj.Projection({
  // 坐标系代码
  code: 'BD:09',
  // 坐标系范围
  extent: [-180, -90, 180, 90],
  // 坐标系分辨率使用的单位
  units: 'degrees',
  // 用于确定坐标系的坐标轴方向
  axisOrientation: 'enu',
});
// 添加到openlayers支持的坐标系
ol.proj.addProjection(projBD09);
// 创建百度投影坐标系
const projBD09Meter = new ol.proj.Projection({
  // 坐标系代码
  code: 'BD:09-Meter',
  // 坐标系范围
  extent: [-20037726.37, -11708041.66, 20037726.37, 12474104.17],
  // 坐标系分辨率使用的单位
  units: 'm',
  // 用于确定坐标系的坐标轴方向
  axisOrientation: 'neu',
});
// 添加到openlayers支持的坐标系
ol.proj.addProjection(projBD09Meter);
// 定义百度投影坐标系和 BD:09 坐标系之间的转换规则
ol.proj.addCoordinateTransforms(
  'BD:09',
  'BD:09-Meter',
  function (coordinate) {
    return gcoord.transform(
      coordinate, // 经纬度坐标
      gcoord.BD09, // 当前坐标系
      gcoord.BD09Meter // 目标坐标系
    );
  },
  function (coordinate) {
    return gcoord.transform(
      coordinate, // 投影坐标
      gcoord.BD09Meter, // 当前坐标系
      gcoord.BD09 // 目标坐标系
    );
  }
);

/*加载百度地图离线瓦片不能用ol.source.XYZ,ol.source.XYZ针对谷歌地图(注意:是谷歌地图)而设计,而百度地图与谷歌地图使用了不同的投影、分辨率和瓦片网格。因此这里使用ol.source.TileImage来自行指定投影、分辨率、瓦片网格。*/
const tileGrid = new ol.tilegrid.TileGrid({
  origin: [0, 0],
  resolutions: resolutions,
});
// 创建百度坐标系切片资源
const bMapSources = new ol.source.TileImage({
  projection: 'BD:09-Meter',
  tileGrid: tileGrid,
  tileUrlFunction: function (tileCoord, pixelRatio, proj) {
    let z = tileCoord[0];
    let x = tileCoord[1];
    let y = -tileCoord[2] - 1;
    if (x < 0) x = 'M' + -x;
    if (y < 0) y = 'M' + -y;
    // return `http://111.12.91.15:28802/map/bmap/${z}/${x}/${y}.png`;
    return `https://maponline3.bdimg.com/tile/?qt=vtile&z=${z}&x=${x}&y=${y}&styles=pl&scaler=1&udt=20230616&from=jsapi3_0`;
  },
});
// 创建切片图层
const bdMapLayers = new ol.layer.Tile({
  source: bMapSources,
});
export default () => {
  const view = new ol.View({
    // 在百度地图jsapi中为了方便开发者,在底层将经纬度自动转换为墨卡托投影坐标,所以可以直接使用经纬度进行定位
    // 在使用openlayers的时候,需要手动对经纬度坐标进行转换,转换为百度的墨卡托投影坐标才能正确显示
    center: ol.proj.transform(
      [108.34171638707808, 22.818581259540537],
      'BD:09',
      'BD:09-Meter'
    ),
    zoom: 10, // 缩放
    maxZoom: 19,
    projection: 'BD:09-Meter',
    // 使用和百度切片资源设置的分辨率
    resolutions: bMapSources.getTileGrid().getResolutions(),
    // 设置缩放级别为整数
    constrainResolution: true,
    // 关闭无极缩放地图
    smoothResolutionConstraint: false,
  });
  return new ol.Map({
    target: 'map',
    layers: [bdMapLayers],
    view: view,
    controls: ol.control.defaults.defaults({
      zoom: true,
      rotate: true,
      attribution: true,
    }),
  });
};

demo-高德

js
// 百度坐标
const bdPoint = [108.34171638707808, 22.818581259540537];
// 转换为 GCJ02 坐标
export const GCJ02Point = gcoord.transform(
  bdPoint, // 经纬度坐标
  gcoord.BD09, // 当前坐标系
  gcoord.GCJ02 // 目标坐标系
);
// 创建 GCJ02 地理坐标系,
const GCJ02 = new ol.proj.Projection({
  // 坐标系代码
  code: 'GCJ:02',
  // 坐标系范围
  extent: [-180, -90, 180, 90],
  // 坐标系分辨率使用的单位
  units: 'degrees',
  // 用于确定坐标系的坐标轴方向
  axisOrientation: 'enu',
});
// 添加到openlayers支持的坐标系
ol.proj.addProjection(GCJ02);
// 定义GCJ02地理坐标系和web墨卡托投影坐标系之间的转换规则
ol.proj.addCoordinateTransforms(
  'GCJ:02',
  'EPSG:3857',
  function (coordinate) {
    // GCJ02火星坐标系转换为投影坐标系是使用经纬度直接转换,只有当前地理坐标系为WGS84时,经纬度可以被直接转换为EPSG:3857。
    // 若当前坐标系使用 GCJ02,算法会将GCJ02先转为WGS84,再转为EPSG:3857,所以这里将GCJ02视为WGS84进行直接转换
    return gcoord.transform(
      coordinate, // 经纬度坐标
      gcoord.WGS84, // 当前坐标系
      gcoord.EPSG3857 // 目标坐标系
    );
  },
  function (coordinate) {
    return gcoord.transform(
      coordinate, // 投影坐标
      gcoord.EPSG3857, // 当前坐标系
      gcoord.WGS84 // 目标坐标系
    );
  }
);

export default () => {
  const onlineUrl =
    'http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}';
  const offlineUrl = 'http://111.12.91.15:28802/map/amap' + '/{z}/{x}/{y}.png'; // 设置本地离线瓦片所在路径
  return new ol.Map({
    target: 'map',
    layers: [
      new ol.layer.Tile({
        source: new ol.source.XYZ({
          url: onlineUrl,
        }),
      }),
    ],
    view: new ol.View({
      center: ol.proj.transform(GCJ02Point, 'GCJ:02', 'EPSG:3857'),
      zoom: 10, // 缩放
    }),
    controls: ol.control.defaults.defaults({
      zoom: true,
      rotate: true,
      attribution: true,
    }),
  });
};