Files
test-map-distance/public/index.ts
2026-01-09 22:54:07 +08:00

133 lines
3.7 KiB
TypeScript

// deno run -A https://kevisual.xiongxiao.me/root/test-map-distance/index.ts?a=1
import path from 'node:path';
import fs from 'node:fs';
/**
* 手动读取 .env 文件
*/
function loadEnv() {
const envPath = path.resolve(process.cwd(), '.env');
if (!fs.existsSync(envPath)) {
return {};
}
const content = fs.readFileSync(envPath, 'utf-8');
const env: Record<string, string> = {};
for (const line of content.split('\n')) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) continue;
const [key, ...valueParts] = trimmed.split('=');
if (key && valueParts.length > 0) {
env[key.trim()] = valueParts.join('=').trim();
}
}
return env;
}
const env = loadEnv();
const AMAP_KEY = env.AMAP_KEY || '';
if (!AMAP_KEY) {
throw new Error('请在环境变量中设置 AMAP_KEY');
}
/**
* 地理编码:将地址转换为经纬度
*/
async function geocode(address: string): Promise<{ lng: number; lat: number } | null> {
const url = `https://restapi.amap.com/v3/geocode/geo?address=${encodeURIComponent(address)}&key=${AMAP_KEY}`;
const res = await fetch(url).then(r => r.json());
if (res.status === '1' && res.geocodes?.length > 0) {
const [lng, lat] = res.geocodes[0].location.split(',').map(Number);
return { lng, lat };
}
return null;
}
/**
* 计算两点间的直线距离(米)
*/
function calculateDistance(
from: { lng: number; lat: number },
to: { lng: number; lat: number }
): number {
const R = 6371000; // 地球半径(米)
const dLat = (to.lat - from.lat) * Math.PI / 180;
const dLng = (to.lng - from.lng) * Math.PI / 180;
const a =
Math.sin(dLat / 2) ** 2 +
Math.cos(from.lat * Math.PI / 180) *
Math.cos(to.lat * Math.PI / 180) *
Math.sin(dLng / 2) ** 2;
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
/**
* 主函数:计算两个地址间的距离
*/
async function getDistance(fromAddress: string, toAddress: string) {
const [from, to] = await Promise.all([
geocode(fromAddress),
geocode(toAddress)
]);
if (!from || !to) {
throw new Error('地址解析失败');
}
const distance = calculateDistance(from, to);
return {
from,
to,
distanceMeters: distance,
distanceKm: (distance / 1000).toFixed(2)
};
}
// 使用示例
// getDistance('北京市', '上海市').then(console.log);
// const fromAddress = '北京市朝阳区望京SOHO';
// const toAddress = '杭州市西湖区雅仕苑';
const addressPath = path.resolve(process.cwd(), 'address.json');
type Address = {
from: string;
to: string;
}
let addressJson: Address[];
// 读取 address.json 文件
const addressData = fs.readFileSync(addressPath, 'utf-8');
try {
addressJson = JSON.parse(addressData) as Address[];
} catch (error) {
console.error('无法解析 address.json 文件,请确保其为有效的 JSON 格式');
process.exit(1);
}
if (!Array.isArray(addressJson)) {
console.error('address.json 文件格式错误,应为地址对象数组');
process.exit(1);
}
const results: any[] = [];
for (const addr of addressJson) {
try {
// 计算距离
const result = await getDistance(addr.from, addr.to);
results.push({
from: addr.from,
to: addr.to,
distanceMeters: result.distanceMeters,
distanceKm: result.distanceKm,
});
console.log(`地址对 (${addr.from} -> ${addr.to}) 的距离为: ${result.distanceKm} 公里`);
} catch (error) {
console.error(`计算地址对 (${addr.from} -> ${addr.to}) 距离时出错:`, error);
}
}
// 将结果写入 distance-results.json 文件
const resultPath = path.resolve(process.cwd(), 'distance-results.json');
fs.writeFileSync(resultPath, JSON.stringify(results, null, 2), 'utf-8');
console.log(`距离结果已保存到 ${resultPath}`);