zhangwencui
8 天以前 dab35bff798cfce2ddf7e8a67e4e1cdb144f5b4c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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;
}