const PI = Math.PI;
|
const X_PI = PI * 3000 / 180;
|
const EARTH_SEMI_MAJOR_AXIS = 6_378_245;
|
const EARTH_ECCENTRICITY_SQUARED = 0.006_693_421_622_965_943;
|
|
function outOfChina(longitude: number, latitude: number) {
|
return longitude < 72.004 || longitude > 137.8347 || latitude < 0.8293 || latitude > 55.8271;
|
}
|
|
function transformLatitude(longitude: number, latitude: number) {
|
let result = -100 + 2 * longitude + 3 * latitude + 0.2 * latitude * latitude
|
+ 0.1 * longitude * latitude + 0.2 * Math.sqrt(Math.abs(longitude));
|
result += (20 * Math.sin(6 * longitude * PI) + 20 * Math.sin(2 * longitude * PI)) * 2 / 3;
|
result += (20 * Math.sin(latitude * PI) + 40 * Math.sin(latitude / 3 * PI)) * 2 / 3;
|
result += (160 * Math.sin(latitude / 12 * PI) + 320 * Math.sin(latitude * PI / 30)) * 2 / 3;
|
return result;
|
}
|
|
function transformLongitude(longitude: number, latitude: number) {
|
let result = 300 + longitude + 2 * latitude + 0.1 * longitude * longitude
|
+ 0.1 * longitude * latitude + 0.1 * Math.sqrt(Math.abs(longitude));
|
result += (20 * Math.sin(6 * longitude * PI) + 20 * Math.sin(2 * longitude * PI)) * 2 / 3;
|
result += (20 * Math.sin(longitude * PI) + 40 * Math.sin(longitude / 3 * PI)) * 2 / 3;
|
result += (150 * Math.sin(longitude / 12 * PI) + 300 * Math.sin(longitude / 30 * PI)) * 2 / 3;
|
return result;
|
}
|
|
export function wgs84ToGcj02(longitude: number, latitude: number): [number, number] {
|
if (outOfChina(longitude, latitude)) return [longitude, latitude];
|
let deltaLatitude = transformLatitude(longitude - 105, latitude - 35);
|
let deltaLongitude = transformLongitude(longitude - 105, latitude - 35);
|
const radianLatitude = latitude / 180 * PI;
|
let magic = Math.sin(radianLatitude);
|
magic = 1 - EARTH_ECCENTRICITY_SQUARED * magic * magic;
|
const sqrtMagic = Math.sqrt(magic);
|
deltaLatitude = deltaLatitude * 180
|
/ ((EARTH_SEMI_MAJOR_AXIS * (1 - EARTH_ECCENTRICITY_SQUARED)) / (magic * sqrtMagic) * PI);
|
deltaLongitude = deltaLongitude * 180
|
/ (EARTH_SEMI_MAJOR_AXIS / sqrtMagic * Math.cos(radianLatitude) * PI);
|
return [longitude + deltaLongitude, latitude + deltaLatitude];
|
}
|
|
export function wgs84ToBd09(longitude: number, latitude: number): [number, number] {
|
const [gcjLongitude, gcjLatitude] = wgs84ToGcj02(longitude, latitude);
|
const z = Math.sqrt(gcjLongitude * gcjLongitude + gcjLatitude * gcjLatitude)
|
+ 0.00002 * Math.sin(gcjLatitude * X_PI);
|
const theta = Math.atan2(gcjLatitude, gcjLongitude) + 0.000003 * Math.cos(gcjLongitude * X_PI);
|
return [z * Math.cos(theta) + 0.0065, z * Math.sin(theta) + 0.006];
|
}
|
|
const SCRIPT_ID = "mom-baidu-map-jsapi";
|
const CALLBACK = "__momBaiduMapReady";
|
|
export function loadBaiduMap(apiKey: string): Promise<any> {
|
if (typeof window === "undefined" || typeof document === "undefined") {
|
return Promise.reject(new Error("当前运行环境不支持百度 WebGL 地图"));
|
}
|
const mapWindow = window as any;
|
if (mapWindow.BMapGL) return Promise.resolve(mapWindow.BMapGL);
|
if (mapWindow.__momBaiduMapPromise) return mapWindow.__momBaiduMapPromise;
|
mapWindow.__momBaiduMapPromise = new Promise((resolve, reject) => {
|
const timeout = window.setTimeout(() => reject(new Error("百度地图加载超时,请检查 AK、域名白名单和网络")), 15_000);
|
mapWindow[CALLBACK] = () => {
|
window.clearTimeout(timeout);
|
resolve(mapWindow.BMapGL);
|
delete mapWindow[CALLBACK];
|
};
|
if (document.getElementById(SCRIPT_ID)) return;
|
const script = document.createElement("script");
|
script.id = SCRIPT_ID;
|
script.src = `https://api.map.baidu.com/api?v=1.0&type=webgl&ak=${encodeURIComponent(apiKey)}&callback=${CALLBACK}`;
|
script.addEventListener("error", () => {
|
window.clearTimeout(timeout);
|
reject(new Error("百度地图加载失败,请检查 AK、域名白名单和网络"));
|
}, { once: true });
|
document.head.append(script);
|
});
|
return mapWindow.__momBaiduMapPromise;
|
}
|