export const coordinateInputPattern = /^-?\d+(\.\d{0,6})?$/; const coordinateRanges = { longitude: { label: '经度', min: -180, max: 180, }, latitude: { label: '纬度', min: -90, max: 90, }, }; /** WGS-84 → GCJ-02(高德)偏移算法常量 */ const WGS84_TO_GCJ02_PI = Math.PI; const WGS84_TO_GCJ02_A = 6378245.0; const WGS84_TO_GCJ02_EE = 0.00669342162296594323; const isOutOfChina = (longitude, latitude) => longitude < 72.004 || longitude > 137.8347 || latitude < 0.8293 || latitude > 55.8271; const transformLatitude = (longitude, latitude) => { let result = -100.0 + 2.0 * longitude + 3.0 * latitude + 0.2 * latitude * latitude + 0.1 * longitude * latitude + 0.2 * Math.sqrt(Math.abs(longitude)); result += ((20.0 * Math.sin(6.0 * longitude * WGS84_TO_GCJ02_PI) + 20.0 * Math.sin(2.0 * longitude * WGS84_TO_GCJ02_PI)) * 2.0) / 3.0; result += ((20.0 * Math.sin(latitude * WGS84_TO_GCJ02_PI) + 40.0 * Math.sin((latitude / 3.0) * WGS84_TO_GCJ02_PI)) * 2.0) / 3.0; result += ((160.0 * Math.sin((latitude / 12.0) * WGS84_TO_GCJ02_PI) + 320 * Math.sin((latitude * WGS84_TO_GCJ02_PI) / 30.0)) * 2.0) / 3.0; return result; }; const transformLongitude = (longitude, latitude) => { let result = 300.0 + longitude + 2.0 * latitude + 0.1 * longitude * longitude + 0.1 * longitude * latitude + 0.1 * Math.sqrt(Math.abs(longitude)); result += ((20.0 * Math.sin(6.0 * longitude * WGS84_TO_GCJ02_PI) + 20.0 * Math.sin(2.0 * longitude * WGS84_TO_GCJ02_PI)) * 2.0) / 3.0; result += ((20.0 * Math.sin(longitude * WGS84_TO_GCJ02_PI) + 40.0 * Math.sin((longitude / 3.0) * WGS84_TO_GCJ02_PI)) * 2.0) / 3.0; result += ((150.0 * Math.sin((longitude / 12.0) * WGS84_TO_GCJ02_PI) + 300.0 * Math.sin((longitude / 30.0) * WGS84_TO_GCJ02_PI)) * 2.0) / 3.0; return result; }; /** * WGS-84(GPS / LBS)转 GCJ-02(高德/国测局),供高德地图绘制使用。 * 中国境外坐标不做偏移,原样返回。 * @param {number} longitude * @param {number} latitude * @returns {[number, number]} [经度, 纬度] */ export const wgs84ToGcj02 = (longitude, latitude) => { const lng = Number(longitude); const lat = Number(latitude); if (!Number.isFinite(lng) || !Number.isFinite(lat) || isOutOfChina(lng, lat)) { return [lng, lat]; } let dLat = transformLatitude(lng - 105.0, lat - 35.0); let dLng = transformLongitude(lng - 105.0, lat - 35.0); const radLat = (lat / 180.0) * WGS84_TO_GCJ02_PI; let magic = Math.sin(radLat); magic = 1 - WGS84_TO_GCJ02_EE * magic * magic; const sqrtMagic = Math.sqrt(magic); dLat = (dLat * 180.0) / (((WGS84_TO_GCJ02_A * (1 - WGS84_TO_GCJ02_EE)) / (magic * sqrtMagic)) * WGS84_TO_GCJ02_PI); dLng = (dLng * 180.0) / ((WGS84_TO_GCJ02_A / sqrtMagic) * Math.cos(radLat) * WGS84_TO_GCJ02_PI); return [lng + dLng, lat + dLat]; }; export const normalizeCoordinateInput = value => { const rawValue = String(value ?? '').replace(/[^\d.-]/g, ''); const isNegative = rawValue.startsWith('-'); const unsignedValue = rawValue.replace(/-/g, ''); if (!unsignedValue) { return isNegative ? '-' : ''; } const [integerPart, ...decimalParts] = unsignedValue.split('.'); const sign = isNegative ? '-' : ''; if (!decimalParts.length) { return `${sign}${integerPart}`; } return `${sign}${integerPart || '0'}.${decimalParts.join('').slice(0, 6)}`; }; export const isCoordinateInput = value => { if (value === undefined || value === null || value === '') { return true; } return coordinateInputPattern.test(String(value)); }; export const getCoordinateValidationMessage = (value, type, required = false) => { const range = coordinateRanges[type]; if (!range) { return ''; } if (value === undefined || value === null || value === '') { return required ? `${range.label}不能为空` : ''; } if (!isCoordinateInput(value)) { return `${range.label}最多保留6位小数`; } const numberValue = Number(value); if (numberValue < range.min || numberValue > range.max) { return `${range.label}范围为 ${range.min} 到 ${range.max}`; } return ''; };