【Openlayers+百度地图】准确加载百度地图

地图展示

由于ol没有DB09的坐标系,当需要使用openlayers加载百度地图的瓦片资源时,地图的projection最好是DB09,如果使用EPSG:3857也是可以加载出底图的,但会出现点位偏移,位置不准确等问题,点位也会随着zoom变化而移动。

以下是通过DB:09的方式加载百度底图,然后再将需要展示的点位数据转为百度墨卡即可。

创建百度地图的source

/*
 * @Description:BaiDuSource.js
 * @Author: zm
 * @Date: 2024-07-16 14:06:26
 * @LastEditTime: 2024-09-11 15:32:37
 * @LastEditors: zm 1540588534@qq.com
 */
import { TileImage } from "ol/source";
import TileGrid from "ol/tilegrid/TileGrid";

export default class BaiDuDiTu extends TileImage {
  constructor(opt) {
    const options = opt || {};
    const tileGrid =
      options.tileGrid ||
      BaiDuDiTu.getTileGrid(options.projection || "EPSG:3857");
    const superOptions = {
      projection: options.projection || "EPSG:3857",
      tileGrid,
      tileUrlFunction: function (tileCoord) {
        if (!tileCoord) return "";
        let z = tileCoord[0];
        let x = tileCoord[1];
        let y = -tileCoord[2] - 1; //ol6版本有偏移问题
        // 对编号xy处理
        let baiduX = x < 0 ? "M" + -x : x;
        let baiduY = y < 0 ? "M" + -y : y;
        return (
          "/onlinelabel/?qt=tile&x=" +
          baiduX +
          "&y=" +
          baiduY +
          "&z=" +
          z +
          "&styles=pl&udt=20151021&scaler=1&p=1"
        );
      },
    };
    super(superOptions);
  }

  /**
   * @function BaiDuDiTu.getTileGrid
   * @description 获取瓦片网格
   * @param {Object} projection - 投影参考对象
   * @returns {ol.tilegrid.WMTS} 返回瓦片网格对象
   */
  static getTileGrid(projection) {
    if (projection === "EPSG:4326" || projection === "EPSG:4490") {
      return BaiDuDiTu.default4326TileGrid();
    }
    if (projection === "BD:09") {
      return BaiDuDiTu.defaultBD09TileGrid();
    }
    return BaiDuDiTu.default3857TileGrid();
  }

  /**
   * @function BaiDuDiTu.default4326TileGrid
   * @description 获取默认 4326 网格瓦片
   * @returns {ol.tilegrid.WMTS} 返回默认 4326 网格瓦片对象
   */
  static default4326TileGrid() {
    const tdtWgs84Resolutions = [];
    const matrixIds = [];
    for (let i = 1; i < 19; i += 1) {
      tdtWgs84Resolutions.push((0.703125 * 2) / 2 ** i);
      matrixIds.push(i);
    }
    const tileGird = new TileGrid({
      extent: [-180, -90, 180, 90],
      resolutions: tdtWgs84Resolutions,
      origin: [-180, 90],
      matrixIds,
      minZoom: 1,
    });
    return tileGird;
  }

  /**
   * @function Tianditu.default3857TileGrid
   * @description 获取默认 3857 网格瓦片
   * @returns {ol.tilegrid.WMTS} 返回默认 3857 网格瓦片对象
   */
  static default3857TileGrid() {
    const resolutions = [];
    const matrixIds = [];
    for (let i = 1; i < 19; i += 1) {
      resolutions[i] = Math.pow(2, 18 - i);
      matrixIds.push(i);
    }
    const tileGird = new TileGrid({
      resolutions,
      matrixIds,
      origin: [0, 0],
      minZoom: 1,
    });
    return tileGird;
  }
  /**
   * @function BaiDuDiTu.defaultBD09TileGrid
   * @description
   * @returns {ol.tilegrid.WMTS}
   */
  static defaultBD09TileGrid() {
    const resolutions = [];
    for (let i = 1; i < 19; i += 1) {
      resolutions[i] = Math.pow(2, 18 - i);
    }
    const tileGird = new TileGrid({
      resolutions,
      origin: [0, 0],
      minZoom: 1,
    });
    return tileGird;
  }
}

创建地图map

/*
 * @Description:BaiDuMap.js
 * @Author: zm
 * @Date: 2024-07-15 09:59:35
 * @LastEditTime: 2024-09-11 18:43:05
 * @LastEditors: zm 1540588534@qq.com
 */
import "ol/ol.css";
import Map from "ol/Map.js";
import View from "ol/View.js";
import TileLayer from "ol/layer/Tile.js";
import BaiDuDiTu from "@/common/map/baidu/BaiDuSource.js";
import { PROJECTION_DB09, getProjBD09 } from "@/common/map/projects.js";
import { BASEMAP_IMAGE_LAYER } from "@/common/map/layer-ids.js";
import { lngLatToMercator } from "./BD09.js";

const baiduMap = new Map({
  controls: [],
  layers: [
    new TileLayer({
      id: BASEMAP_IMAGE_LAYER,
      source: new BaiDuDiTu({ projection: PROJECTION_DB09 }),
      visible: true,
    }),
  ],
  view: new View({
    projection: getProjBD09(PROJECTION_DB09),
    center: lngLatToMercator([120.098926, 29.343227]),
    maxZoom: 20,
    minZoom: 5,
    zoom: 8,
  }),
});

export default baiduMap;

在vue组件中使用

TheHomeGis.vue
<div :class="$style['map']" id="BaiDuMap"></div>

绑定容器即可

import baiduMap from "@/common/map/baidu/BaiDuMap.js";

  mounted() {
    this.baiduMap.setTarget("BaiDuMap");
  },
  beforeDestroy() {
    this.baiduMap.setTarget("");
	}

引用的其他文件

/*
 * @Description:@/common/map/projects.js
 * @Author: zm
 * @Date: 2024-09-05 16:35:23
 * @LastEditTime: 2024-09-12 19:34:15
 * @LastEditors: zm 1540588534@qq.com
 */
import { get as ProjGet, addProjection, Projection } from "ol/proj";

export const PROJECTION_4326 = "EPSG:4326";
export const PROJECTION_3857 = "EPSG:3857";
export const PROJECTION_DB09 = "BD:09";
export const getProjBD09 = (projCode) => {
  let projection = ProjGet(projCode);
  if (projection) {
    return projection;
  }
  let projBD09 = new Projection({
    code: "BD:09",
    extent: [-20037726.37, -11708041.66, 20037726.37, 12474104.17],
    units: "m",
    axisOrientation: "neu",
    global: false,
  });
  addProjection(projBD09);
  return projection;
};

export const BASEMAP_IMAGE_LAYER = 'BASEMAP_IMAGE_LAYER';

BD09.js

/* eslint-disable no-redeclare */
/* eslint-disable no-undef */
/* eslint-disable no-useless-escape */
var MCBAND = [12890594.86, 8362377.87, 5591021, 3481989.83, 1678043.12, 0];
var LLBAND = [75, 60, 45, 30, 15, 0];
var MC2LL = [
  [
    1.410526172116255e-8, 0.00000898305509648872, -1.9939833816331,
    200.9824383106796, -187.2403703815547, 91.6087516669843, -23.38765649603339,
    2.57121317296198, -0.03801003308653, 17337981.2,
  ],
  [
    -7.435856389565537e-9, 0.000008983055097726239, -0.78625201886289,
    96.32687599759846, -1.85204757529826, -59.36935905485877, 47.40033549296737,
    -16.50741931063887, 2.28786674699375, 10260144.86,
  ],
  [
    -3.030883460898826e-8, 0.00000898305509983578, 0.30071316287616,
    59.74293618442277, 7.357984074871, -25.38371002664745, 13.45380521110908,
    -3.29883767235584, 0.32710905363475, 6856817.37,
  ],
  [
    -1.981981304930552e-8, 0.000008983055099779535, 0.03278182852591,
    40.31678527705744, 0.65659298677277, -4.44255534477492, 0.85341911805263,
    0.12923347998204, -0.04625736007561, 4482777.06,
  ],
  [
    3.09191371068437e-9, 0.000008983055096812155, 0.00006995724062,
    23.10934304144901, -0.00023663490511, -0.6321817810242, -0.00663494467273,
    0.03430082397953, -0.00466043876332, 2555164.4,
  ],
  [
    2.890871144776878e-9, 0.000008983055095805407, -3.068298e-8,
    7.47137025468032, -0.00000353937994, -0.02145144861037, -0.00001234426596,
    0.00010322952773, -0.00000323890364, 826088.5,
  ],
];

var LL2MC = [
  [
    -0.0015702102444, 111320.7020616939, 1704480524535203, -10338987376042340,
    26112667856603880, -35149669176653700, 26595700718403920,
    -10725012454188240, 1800819912950474, 82.5,
  ],
  [
    0.0008277824516172526, 111320.7020463578, 647795574.6671607,
    -4082003173.641316, 10774905663.51142, -15171875531.51559,
    12053065338.62167, -5124939663.577472, 913311935.9512032, 67.5,
  ],
  [
    0.00337398766765, 111320.7020202162, 4481351.045890365, -23393751.19931662,
    79682215.47186455, -115964993.2797253, 97236711.15602145,
    -43661946.33752821, 8477230.501135234, 52.5,
  ],
  [
    0.00220636496208, 111320.7020209128, 51751.86112841131, 3796837.749470245,
    992013.7397791013, -1221952.21711287, 1340652.697009075, -620943.6990984312,
    144416.9293806241, 37.5,
  ],
  [
    -0.0003441963504368392, 111320.7020576856, 278.2353980772752,
    2485758.690035394, 6070.750963243378, 54821.18345352118, 9540.606633304236,
    -2710.55326746645, 1405.483844121726, 22.5,
  ],
  [
    -0.0003218135878613132, 111320.7020701615, 0.00369383431289,
    823725.6402795718, 0.46104986909093, 2351.343141331292, 1.58060784298199,
    8.77738589078284, 0.37238884252424, 7.45,
  ],
];

// eslint-disable-next-line no-unused-vars
// 百度经纬度转百度墨卡托
export function lngLatToMercator(T) {
  var c = new cd(T[0], T[1]);
  var r = convertLL2MC(c);
  return [r.lng, r.lat];
}

// eslint-disable-next-line no-unused-vars
export function mercatorToLngLat(T) {
  var c = new cd(T[0], T[1]);
  var r = convertMC2LL(c);
  return [r.lng, r.lat];
}

export function convertLL2MC(T) {
  var cL, cN;
  T.lng = getLoop(T.lng, -180, 180);
  T.lat = getRange(T.lat, -74, 74);
  cL = new cd(T.lng, T.lat);
  for (var cM = 0; cM < LLBAND.length; cM++) {
    if (cL.lat >= LLBAND[cM]) {
      cN = LL2MC[cM];
      break;
    }
  }
  if (!cN) {
    for (var cM = LLBAND.length - 1; cM >= 0; cM--) {
      if (cL.lat <= -LLBAND[cM]) {
        cN = LL2MC[cM];
        break;
      }
    }
  }
  var cO = convertor(T, cN);
  var T = new cd(cO.lng.toFixed(2), cO.lat.toFixed(2));
  return T;
}

export function convertMC2LL(cL) {
  var cM, cO;
  cM = new cd(Math.abs(cL.lng), Math.abs(cL.lat));
  for (var cN = 0; cN < MCBAND.length; cN++) {
    if (cM.lat >= MCBAND[cN]) {
      cO = MC2LL[cN];
      break;
    }
  }
  var T = convertor(cL, cO);
  var cL = new cd(T.lng.toFixed(6), T.lat.toFixed(6));
  return cL;
}

function getRange(cM, cL, T) {
  if (cL != null) {
    cM = Math.max(cM, cL);
  }
  if (T != null) {
    cM = Math.min(cM, T);
  }
  return cM;
}

function getLoop(cM, cL, T) {
  while (cM > T) {
    cM -= T - cL;
  }
  while (cM < cL) {
    cM += T - cL;
  }
  return cM;
}

function convertor(cM, cN) {
  if (!cM || !cN) {
    return;
  }
  var T = cN[0] + cN[1] * Math.abs(cM.lng);
  var cL = Math.abs(cM.lat) / cN[9];
  var cO =
    cN[2] +
    cN[3] * cL +
    cN[4] * cL * cL +
    cN[5] * cL * cL * cL +
    cN[6] * cL * cL * cL * cL +
    cN[7] * cL * cL * cL * cL * cL +
    cN[8] * cL * cL * cL * cL * cL * cL;
  T *= cM.lng < 0 ? -1 : 1;
  cO *= cM.lat < 0 ? -1 : 1;
  return new cd(T, cO);
}

function cd(T, cL) {
  if (isNaN(T)) {
    T = bV(T);
    T = isNaN(T) ? 0 : T;
  }
  if (b3(T)) {
    T = parseFloat(T);
  }
  if (isNaN(cL)) {
    cL = bV(cL);
    cL = isNaN(cL) ? 0 : cL;
  }
  if (b3(cL)) {
    cL = parseFloat(cL);
  }
  this.lng = T;
  this.lat = cL;
}
cd.isInRange = function (T) {
  return T && T.lng <= 180 && T.lng >= -180 && T.lat <= 74 && T.lat >= -74;
};
cd.prototype.equals = function (T) {
  return T && lat == T.lat && lng == T.lng;
};

function bV(cN) {
  var cL = "";
  var cU,
    cS,
    cQ = "";
  var cT,
    cR,
    cP,
    cO = "";
  var cM = 0;
  var T = /[^A-Za-z0-9\+\/\=]/g;
  if (!cN || T.exec(cN)) {
    return cN;
  }
  cN = cN.replace(/[^A-Za-z0-9\+\/\=]/g, "");
  do {
    cT = cf.indexOf(cN.charAt(cM++));
    cR = cf.indexOf(cN.charAt(cM++));
    cP = cf.indexOf(cN.charAt(cM++));
    cO = cf.indexOf(cN.charAt(cM++));
    cU = (cT << 2) | (cR >> 4);
    cS = ((cR & 15) << 4) | (cP >> 2);
    cQ = ((cP & 3) << 6) | cO;
    cL = cL + String.fromCharCode(cU);
    if (cP != 64) {
      cL = cL + String.fromCharCode(cS);
    }
    if (cO != 64) {
      cL = cL + String.fromCharCode(cQ);
    }
    cU = cS = cQ = "";
    cT = cR = cP = cO = "";
  } while (cM < cN.length);
  return cL;
}

function b3(T) {
  return typeof T == "string";
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值