hejianhao
2026-05-06 6848964470be03b07d3f5ceb95e2325423502996
feat(map): 优化自动缩放逻辑,优先保证中心点可见至少3个点位

重构 `getAutoScaleBySites` 函数,新增中心点参数。当提供有效中心点时,算法会优先计算从该中心点向外至少能显示3个点位所需的缩放等级,提升地图初始视图的用户体验。对于高密度和低密度区域,也分别优化了局部精细视角和稀疏场景下的可见性逻辑。
3个文件已修改
108 ■■■■■ 已修改文件
src/pages/robotaxi/home/hooks/use-map-state.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/select-map-site/hooks/use-select-map-site.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/Robotaxi-public-method.ts 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/robotaxi/home/hooks/use-map-state.ts
@@ -42,7 +42,7 @@
      setElectronicAreaId(result.electronicAreaId);
      setMarkers(result.newMarkers);
      if (autoScaleAppliedCityCodeRef.current !== code) {
        const autoScale = getAutoScaleBySites(result?.sites || result?.newMarkers || []);
        const autoScale = getAutoScaleBySites(result?.sites || result?.newMarkers || [], lat, lng);
        if (typeof autoScale === 'number') {
          setMapScale((prev) => {
            const nextScale = Math.max(AUTO_SCALE_MIN, Math.min(AUTO_SCALE_MAX, autoScale));
src/robotaxi/pages/select-map-site/hooks/use-select-map-site.ts
@@ -91,7 +91,7 @@
        state.setStationSiteList(nextStationSites);
      }
      if (!state.autoScaleLockedRef.current) {
        const autoScale = getAutoScaleBySites(sites?.length > 0 ? sites : newMarkers);
        const autoScale = getAutoScaleBySites(sites?.length > 0 ? sites : newMarkers, lat, lng);
        if (typeof autoScale === 'number') {
          state.setMapScale((prev) => {
            const nextScale = Math.max(AUTO_SCALE_MIN, Math.min(AUTO_SCALE_MAX, autoScale));
src/utils/Robotaxi-public-method.ts
@@ -185,9 +185,9 @@
};
/**
 * 根据站点空间分布估算推荐缩放等级(站点越分散,缩放越小)。
 * 根据站点空间分布估算推荐缩放等级;如提供中心点,则优先保证从中心点往外至少可见 3 个点位。
 */
export const getAutoScaleBySites = (sites: any[]) => {
export const getAutoScaleBySites = (sites: any[], centerLat?: number, centerLng?: number) => {
  if (!Array.isArray(sites) || sites.length === 0) return null;
  const validSites = sites
    .map((site) => ({
@@ -208,6 +208,82 @@
    return 17;
  }; // 统一距离到缩放等级的映射规则
  const hasValidCenter = Number.isFinite(Number(centerLat)) && Number.isFinite(Number(centerLng)); // 是否提供了有效中心点
  /**
   * 基于中心点计算至少可见 3 个点位所需缩放等级。
   */
  const resolveScaleByCenterVisibleSites = () => {
    if (!hasValidCenter) return null;
    const visibleSiteCount = Math.min(validSites.length, 3); // 最多按最近 3 个点位估算
    if (visibleSiteCount <= 1) return 16;
    const sortedDistances = validSites
      .map((site) => getDistance(Number(centerLat), Number(centerLng), site.latitude, site.longitude))
      .filter((distance) => Number.isFinite(distance))
      .sort((a, b) => a - b);
    const targetRadius = sortedDistances[visibleSiteCount - 1]; // 取第 N 个最近点的半径,保证中心点往外至少覆盖 N 个点
    if (!Number.isFinite(targetRadius)) return null;
    const safeDiagonal = Math.max(targetRadius * 2 * 1.35, 300); // 预留边缘与卡片遮挡余量,避免第 3 个点卡边
    return resolveScaleByDiagonal(safeDiagonal);
  };
  const centerVisibleScale = resolveScaleByCenterVisibleSites(); // 中心点口径下的推荐缩放等级
  if (typeof centerVisibleScale === 'number') {
    return centerVisibleScale;
  }
  /**
   * 计算稀疏场景下“至少可见 3 个点位”所需的最大安全缩放等级。
   */
  const resolveSparseScaleForThreeVisibleSites = () => {
    if (validSites.length < 3) return null;
    const radiusNeedForThreeSites = validSites.reduce((maxRadius, baseSite) => {
      const neighborDistances = validSites
        .filter((site) => site !== baseSite)
        .map((site) => getDistance(baseSite.latitude, baseSite.longitude, site.latitude, site.longitude))
        .sort((a, b) => a - b);
      const radius = neighborDistances[1]; // 取第 2 个邻居距离,保证当前点周围至少覆盖 3 个点
      if (!Number.isFinite(radius)) return maxRadius;
      return Math.max(maxRadius, radius);
    }, 0); // 取所有基点中的最大值,保证任意基点都能满足 3 点可见
    if (radiusNeedForThreeSites <= 0) return null;
    return resolveScaleByDiagonal(radiusNeedForThreeSites * 2);
  };
  /**
   * 计算高密度场景下“精细视角至少可见 3 个点”的推荐缩放等级。
   */
  const resolveDenseScaleForThreeVisibleSites = () => {
    if (validSites.length < 3) return null;
    const denseAnchor = validSites.reduce((bestSite, currentSite) => {
      if (!bestSite) return currentSite;
      const currentNeighborDistances = validSites
        .filter((site) => site !== currentSite)
        .map((site) => getDistance(currentSite.latitude, currentSite.longitude, site.latitude, site.longitude))
        .sort((a, b) => a - b);
      const bestNeighborDistances = validSites
        .filter((site) => site !== bestSite)
        .map((site) => getDistance(bestSite.latitude, bestSite.longitude, site.latitude, site.longitude))
        .sort((a, b) => a - b);
      const currentRadius = currentNeighborDistances[1];
      const bestRadius = bestNeighborDistances[1];
      if (!Number.isFinite(bestRadius)) return currentSite;
      if (!Number.isFinite(currentRadius)) return bestSite;
      return currentRadius < bestRadius ? currentSite : bestSite;
    }, null as any); // 选择“第 3 个点最近”的簇中心,避免被远端离散点拉远
    if (!denseAnchor) return null;
    const denseNeighborDistances = validSites
      .filter((site) => site !== denseAnchor)
      .map((site) => getDistance(denseAnchor.latitude, denseAnchor.longitude, site.latitude, site.longitude))
      .sort((a, b) => a - b);
    const denseRadius = denseNeighborDistances[1];
    if (!Number.isFinite(denseRadius) || denseRadius <= 0) return null;
    return resolveScaleByDiagonal(denseRadius * 2);
  };
  const sparseScaleForThreeVisibleSites = resolveSparseScaleForThreeVisibleSites(); // 稀疏场景至少可见 3 点的最大缩放等级
  const denseScaleForThreeVisibleSites = resolveDenseScaleForThreeVisibleSites(); // 高密度场景局部精细视角的缩放等级
  const nearbyCounts = validSites.map((targetSite, targetIndex) => {
    return validSites.reduce((count, compareSite, compareIndex) => {
      if (targetIndex === compareIndex) return count; // 密度统计不包含自身
@@ -217,22 +293,18 @@
  }); // 每个点位在 1km 半径内的“邻居点”数量
  const maxNearbyCount = Math.max(...nearbyCounts);
  // 高密度区:1km 内点位 > 5(按邻居数统计),固定精细视角。
  if (maxNearbyCount > 5) return 17;
  // 高密度区:1km 内点位 >= 2(按邻居数统计),固定精细视角。
  if (maxNearbyCount >= 2) {
    if (typeof denseScaleForThreeVisibleSites === 'number') {
      return Math.min(17, denseScaleForThreeVisibleSites);
    }
    return 17;
  }
  // 低密度区:1km 内点位 < 2,自动缩小到至少可见 3 个点位。
  if (maxNearbyCount < 2 && validSites.length >= 3) {
    const radiusNeedForThreePoints = validSites.reduce((maxRadius, baseSite) => {
      const neighborDistances = validSites
        .filter((site) => site !== baseSite)
        .map((site) => getDistance(baseSite.latitude, baseSite.longitude, site.latitude, site.longitude))
        .sort((a, b) => a - b);
      const radius = neighborDistances[1]; // 包含 2 个邻居时即可在屏幕中达到 3 个点位
      if (!Number.isFinite(radius)) return maxRadius;
      return Math.max(maxRadius, radius);
    }, 0); // 取最大半径,确保低密度点位也能满足“至少 3 点可见”
    if (radiusNeedForThreePoints > 0) {
      return resolveScaleByDiagonal(radiusNeedForThreePoints * 2);
  if (maxNearbyCount < 2) {
    if (typeof sparseScaleForThreeVisibleSites === 'number') {
      return sparseScaleForThreeVisibleSites;
    }
  }