UNPKG

leaflet-coord-converter-xiaoai

Version:

一个 Leaflet 坐标转换插件,支持GPS84、GCJ02、BD09坐标系之间的转换,提供简单易用的 API 和完整的 TypeScript 类型定义。

188 lines (187 loc) 6.83 kB
import r from "leaflet"; r.CoordConverter = class { constructor() { this.pi = Math.PI, this.a = 6378245, this.ee = 0.006693421622965943, this.x_pi = this.pi * 3e3 / 180, this.R = 6378137; } /** * 百度坐标转GPS84坐标 * @param {number} lng 经度 * @param {number} lat 纬度 * @returns {Object} {lng, lat} */ bd09ToGps84(o, t) { const s = this.bd09ToGcj02(o, t); return this.gcj02ToGps84(s.lng, s.lat); } /** * GPS84坐标转百度坐标 * @param {number} lng 经度 * @param {number} lat 纬度 * @returns {Object} {lng, lat} */ gps84ToBd09(o, t) { const s = this.gps84ToGcj02(o, t); return this.gcj02ToBd09(s.lng, s.lat); } /** * GPS84坐标转火星坐标(GCJ02) * @param {number} lng 经度 * @param {number} lat 纬度 * @returns {Object} {lng, lat} */ gps84ToGcj02(o, t) { let s = this._transformLat(o - 105, t - 35), i = this._transformLng(o - 105, t - 35); const h = t / 180 * this.pi; let n = Math.sin(h); n = 1 - this.ee * n * n; const a = Math.sqrt(n); s = s * 180 / (this.a * (1 - this.ee) / (n * a) * this.pi), i = i * 180 / (this.a / a * Math.cos(h) * this.pi); const e = t + s; return { lng: o + i, lat: e }; } /** * 火星坐标(GCJ02)转GPS84坐标 * @param {number} lng 经度 * @param {number} lat 纬度 * @returns {Object} {lng, lat} */ gcj02ToGps84(o, t) { const s = this._transform(o, t), i = o * 2 - s.lng, h = t * 2 - s.lat; return { lng: i, lat: h }; } /** * 火星坐标(GCJ02)转百度坐标 * @param {number} lng 经度 * @param {number} lat 纬度 * @returns {Object} {lng, lat} */ gcj02ToBd09(o, t) { const s = Math.sqrt(o * o + t * t) + 2e-5 * Math.sin(t * this.x_pi), i = Math.atan2(t, o) + 3e-6 * Math.cos(o * this.x_pi), h = s * Math.cos(i) + 65e-4, n = s * Math.sin(i) + 6e-3; return { lng: h, lat: n }; } /** * 百度坐标转火星坐标(GCJ02) * @param {number} lng 经度 * @param {number} lat 纬度 * @returns {Object} {lng, lat} */ bd09ToGcj02(o, t) { const s = o - 65e-4, i = t - 6e-3, h = Math.sqrt(s * s + i * i) - 2e-5 * Math.sin(i * this.x_pi), n = Math.atan2(i, s) - 3e-6 * Math.cos(s * this.x_pi), a = h * Math.cos(n), e = h * Math.sin(n); return { lng: a, lat: e }; } /** * 批量转换坐标数组 * @param {Array} coords 坐标数组 [{lng, lat}, ...] * @param {string} fromType 源坐标系类型 'gps84'|'gcj02'|'bd09' * @param {string} toType 目标坐标系类型 'gps84'|'gcj02'|'bd09' * @returns {Array} 转换后的坐标数组 */ convertArray(o, t, s) { if (t === s) return o; const i = { gps84_gcj02: this.gps84ToGcj02.bind(this), gps84_bd09: this.gps84ToBd09.bind(this), gcj02_gps84: this.gcj02ToGps84.bind(this), gcj02_bd09: this.gcj02ToBd09.bind(this), bd09_gps84: this.bd09ToGps84.bind(this), bd09_gcj02: this.bd09ToGcj02.bind(this) }, h = `${t}_${s}`, n = i[h]; if (!n) throw new Error(`不支持的转换类型: ${t} -> ${s}`); return o.map((a) => n(a.lng, a.lat)); } /** * 私有方法:坐标变换 */ _transform(o, t) { let s = this._transformLat(o - 105, t - 35), i = this._transformLng(o - 105, t - 35); const h = t / 180 * this.pi; let n = Math.sin(h); n = 1 - this.ee * n * n; const a = Math.sqrt(n); s = s * 180 / (this.a * (1 - this.ee) / (n * a) * this.pi), i = i * 180 / (this.a / a * Math.cos(h) * this.pi); const e = t + s; return { lng: o + i, lat: e }; } /** * 私有方法:纬度变换 */ _transformLat(o, t) { let s = -100 + 2 * o + 3 * t + 0.2 * t * t + 0.1 * o * t + 0.2 * Math.sqrt(Math.abs(o)); return s += (20 * Math.sin(6 * o * this.pi) + 20 * Math.sin(2 * o * this.pi)) * 2 / 3, s += (20 * Math.sin(t * this.pi) + 40 * Math.sin(t / 3 * this.pi)) * 2 / 3, s += (160 * Math.sin(t / 12 * this.pi) + 320 * Math.sin(t * this.pi / 30)) * 2 / 3, s; } /** * 私有方法:经度变换 */ _transformLng(o, t) { let s = 300 + o + 2 * t + 0.1 * o * o + 0.1 * o * t + 0.1 * Math.sqrt(Math.abs(o)); return s += (20 * Math.sin(6 * o * this.pi) + 20 * Math.sin(2 * o * this.pi)) * 2 / 3, s += (20 * Math.sin(o * this.pi) + 40 * Math.sin(o / 3 * this.pi)) * 2 / 3, s += (150 * Math.sin(o / 12 * this.pi) + 300 * Math.sin(o / 30 * this.pi)) * 2 / 3, s; } }; r.coordConverter = new r.CoordConverter(); r.coordConvert = function() { return r.coordConverter; }; r.GridLayer.include({ _setZoomTransform: function(o, t, s) { let i = t; i != null && this.options && (this.options.currentType === "gps84" && (this.options.coordType === "gcj02" ? i = r.coordConverter.gps84ToGcj02( t.lng, t.lat ) : this.options.coordType === "bd09" && (i = r.coordConverter.gps84ToBd09( t.lng, t.lat ))), this.options.currentType === "gcj02" && (this.options.coordType === "gps84" ? i = r.coordConverter.gcj02ToGps84( t.lng, t.lat ) : this.options.coordType === "bd09" && (i = r.coordConverter.gcj02ToBd09( t.lng, t.lat ))), this.options.currentType === "bd09" && (this.options.coordType === "gps84" ? i = r.coordConverter.bd09ToGps84( t.lng, t.lat ) : this.options.coordType === "gcj02" && (i = r.coordConverter.bd09ToGcj02( t.lng, t.lat )))); const h = this._map.getZoomScale(s, o.zoom), n = o.origin.multiplyBy(h).subtract(this._map._getNewPixelOrigin(i, s)).round(); r.Browser.any3d ? r.DomUtil.setTransform(o.el, n, h) : r.DomUtil.setPosition(o.el, n); }, _getTiledPixelBounds: function(o) { let t = o; t != null && this.options && this.options.currentType === "gps84" && (this.options.coordType === "gcj02" ? t = r.coordConverter.gps84ToGcj02( o.lng, o.lat ) : this.options.coordType === "bd09" && (t = r.coordConverter.gps84ToBd09( o.lng, o.lat ))), this.options.currentType === "gcj02" && (this.options.coordType === "gps84" ? t = r.coordConverter.gcj02ToGps84( o.lng, o.lat ) : this.options.coordType === "bd09" && (t = r.coordConverter.gcj02ToBd09(o.lng, o.lat))), this.options.currentType === "bd09" && (this.options.coordType === "gps84" ? t = r.coordConverter.bd09ToGps84(o.lng, o.lat) : this.options.coordType === "gcj02" && (t = r.coordConverter.bd09ToGcj02(o.lng, o.lat))); const s = this._map, i = s._animatingZoom ? Math.max(s._animateToZoom, s.getZoom()) : s.getZoom(), h = s.getZoomScale(i, this._tileZoom), n = s.project(t, this._tileZoom).floor(), a = s.getSize().divideBy(h * 2); return new r.Bounds( n.subtract(a), n.add(a) ); } }); const d = r.CoordConverter; export { d as default };