- 新增 WorldMap 组件,支持 2D 世界地图视图 - 主页添加 2D/3D 视图切换按钮 - 实现确定性坐标偏移算法,分散同城用户位置 - 更新 heatmap 和 register API 使用坐标偏移
73 lines
2.3 KiB
TypeScript
73 lines
2.3 KiB
TypeScript
/**
|
|
* Generate a deterministic offset based on a unique identifier.
|
|
* This ensures the same ID always gets the same offset,
|
|
* allowing multiple users in the same city to be spread out
|
|
* while maintaining consistent positions.
|
|
*
|
|
* @param id - Unique identifier (e.g., claw ID)
|
|
* @param maxOffsetKm - Maximum offset in kilometers (default: 15km)
|
|
* @returns Object with lat and lng offsets in degrees
|
|
*/
|
|
export function generateDeterministicOffset(
|
|
id: string,
|
|
maxOffsetKm: number = 15
|
|
): { latOffset: number; lngOffset: number } {
|
|
// Simple hash function to convert string to number
|
|
let hash = 0;
|
|
for (let i = 0; i < id.length; i++) {
|
|
const char = id.charCodeAt(i);
|
|
hash = ((hash << 5) - hash) + char;
|
|
hash = hash & hash; // Convert to 32-bit integer
|
|
}
|
|
|
|
// Use the hash to generate two pseudo-random values between -1 and 1
|
|
// Using simple modulo arithmetic for determinism
|
|
const seed1 = Math.abs(hash % 10000) / 10000; // 0 to 1
|
|
const seed2 = Math.abs((hash >> 8) % 10000) / 10000; // 0 to 1
|
|
|
|
// Convert to -1 to 1 range with better distribution
|
|
const factor1 = (seed1 * 2 - 1);
|
|
const factor2 = (seed2 * 2 - 1);
|
|
|
|
// Convert km to degrees (approximate)
|
|
// 1 degree latitude ≈ 111km
|
|
// 1 degree longitude varies by latitude (cos(lat) * 111km)
|
|
// We use a rough average here
|
|
const kmPerDegree = 111;
|
|
const maxOffsetDegrees = maxOffsetKm / kmPerDegree;
|
|
|
|
return {
|
|
latOffset: factor1 * maxOffsetDegrees,
|
|
lngOffset: factor2 * maxOffsetDegrees,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Apply deterministic offset to coordinates.
|
|
* This spreads out users in the same city while keeping
|
|
* each user's position consistent.
|
|
*
|
|
* @param lat - Original latitude
|
|
* @param lng - Original longitude
|
|
* @param id - Unique identifier for deterministic offset
|
|
* @param maxOffsetKm - Maximum offset in kilometers
|
|
* @returns New coordinates with offset applied
|
|
*/
|
|
export function applyDeterministicOffset(
|
|
lat: number,
|
|
lng: number,
|
|
id: string,
|
|
maxOffsetKm: number = 15
|
|
): { lat: number; lng: number } {
|
|
const { latOffset, lngOffset } = generateDeterministicOffset(id, maxOffsetKm);
|
|
|
|
// Adjust longitude offset based on latitude
|
|
// (longitude degrees get smaller towards poles)
|
|
const lngCorrection = Math.cos((lat * Math.PI) / 180);
|
|
|
|
return {
|
|
lat: lat + latOffset,
|
|
lng: lng + lngOffset * lngCorrection,
|
|
};
|
|
}
|