把地图数据画出来:Leaflet + 搜索 API 做商家分布图

做本地商家调研时,我拿到过一份 200 行的表格:商家名、评分、地址、排名。表格里看半天,看不出「哪片区域密、哪片区域空、我的店被谁围着」。后来把这些点画到地图上,问题十秒内一目了然------这就是地图可视化的价值:坐标数据放在表里是数字,放在地图上是格局。这篇用 Leaflet 把地图搜索端点的商家数据画成分布图。

数据从哪来

地图搜索端点返回的每个商家都带坐标字段:

  • latitude / longitude:纬度经度(可选字段,谷歌有时不给,要过滤)
  • name、rating、address、position(本地排名)
  • website_domain:用来标出「你的店」

技术选型:Leaflet

对比过几套方案后选了 Leaflet:体积小(几十 KB)、API 直白、社区插件多(聚合、热力都有)。底图用 OpenStreetMap 瓦片起步,不用申请 Key,开发阶段零门槛。

完整实现(React)

tsx 复制代码
"use client";
import { useEffect, useRef } from "react";

interface Place {
  name: string;
  position?: number;
  address?: string;
  latitude?: number;
  longitude?: number;
}

export function PlacesMap({ places }: { places: Place[] }) {
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    let map: any;

    (async () => {
      // Leaflet 依赖 window,必须动态引入(SSR 环境不能顶层 import)
      const L = (await import("leaflet")).default;
      await import("leaflet/dist/leaflet.css");
      await import("leaflet.markercluster");
      if (!ref.current) return;

      map = L.map(ref.current);
      L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
        attribution: "© OpenStreetMap contributors",
      }).addTo(map);

      const cluster = L.markerClusterGroup();   // 点多了自动聚合
      const points: [number, number][] = [];

      for (const p of places) {
        // 坐标是可选字段:没有就跳过,别画到 (0,0) 去
        if (p.latitude == null || p.longitude == null) continue;

        const color = (p.position ?? 99) <= 3 ? "#16a34a" : "#f59e0b"; // 前3名绿色
        const marker = L.circleMarker([p.latitude, p.longitude], {
          radius: 8,
          color,
          fillOpacity: 0.8,
        });
        marker.bindPopup(
          `<b>#${p.position ?? "-"} ${p.name}</b><br/>${p.address ?? ""}`
        );
        cluster.addLayer(marker);
        points.push([p.latitude, p.longitude]);
      }

      map.addLayer(cluster);
      if (points.length) map.fitBounds(points, { padding: [30, 30] });
    })();

    return () => map?.remove();   // 卸载时销毁,防重复初始化
  }, [places]);

  return <div ref={ref} style={{ height: 480, borderRadius: 8 }} />;
}

三个设计点:动态引入 (SSR 安全)、坐标过滤 (可选字段)、前 3 名绿色(一眼分清你和竞品)。

三个进阶效果

1. 标记自己的店。 从数据里找 website_domain 等于自己域名的条目,换成大号红色标记 + 常开 tooltip:

tsx 复制代码
const isMine = p.website_domain === "your-site.com";
const marker = L.circleMarker([p.latitude!, p.longitude!], {
  radius: isMine ? 12 : 8,
  color: isMine ? "#dc2626" : color,
});

2. 聚合开关。 上百个点时用 markerClusterGroup;想数密度时改用热力图插件(leaflet.heat),把 [lat, lng] 数组直接喂进去。

3. 按评分着色。 把 color 从「排名」换成「评分」档位(<4.0 红、4.0-4.5 黄、>4.5 绿),就是一张口碑分布图。

踩坑记录

坑 1:顶层 import L from "leaflet" 报 window is not defined。 Leaflet 依赖浏览器环境,Next.js 里要么 dynamic(() => import(...), { ssr: false }),要么像我上面一样在 useEffect 里动态 import。

坑 2:忘了引 leaflet.css。 结果瓦片错位、缩放按钮散架。Leaflet 的样式是必需的,不是可选装饰。

坑 3:没过滤空坐标。 latitude 缺失时传 undefined,marker 画到 (0,0)------几内亚湾上漂着一堆中国商家。过滤是硬要求。

坑 4:组件卸载没 map.remove()。 React 严格模式双执行下地图初始化两次,控制台警告 + 内存泄漏。清理函数里必须 remove。

坑 5:几百个点不开聚合。 页面卡顿、点叠成一坨。markerClusterGroup 一行接入。

坑 6:生产环境直接用 OSM 瓦片。 OSM 的公共瓦片有使用政策(限流量、要署名),上线前换商业瓦片服务或自建,别把 demo 配置带上生产。

工程清单

  1. Leaflet 动态引入,leaflet.css 必引
  2. 过滤空坐标,坐标字段是可选字段
  3. 用 circleMarker 按排名/评分上色,自己的店高亮
  4. 多点场景加 markercluster(或热力图)
  5. 卸载时 map.remove(),StrictMode 下别重复初始化
  6. 底图瓦片:开发用 OSM,生产换商业服务

地图可视化的收益,不在技术复杂度,而在「把数据变成决策」------同样一份商家数据,表格让人逐行读,地图让人一眼判断。做本地 SEO、渠道分析、门店选址,这张图值得花一个下午搭出来。

商家数据的坐标、排名、评分字段说明见 SerpBase 官方文档。你们的本地数据是怎么可视化的?表格、地图还是 Dashboard?评论区聊聊。

相关推荐
用户77833661321111 小时前
选 SERP API 别靠感觉:用 SerpBase 实测的评估脚本与判定标准
python·api
P1Browser12 小时前
浏览器指纹参数校验:时区、语言、分辨率的一致性原理
web安全·api·前端开发·跨境电商·环境隔离·浏览器指纹
system_error_x16 小时前
API的使用
api·oneapi
高频因子挖掘机17 小时前
分钟线跨午休后时间轴不连续,是数据错了还是 A 股交易时段本来如此?
后端·github·api
高频因子挖掘机19 小时前
多只股票的 K 线日期对不上怎么办?用 Pandas MultiIndex 处理时间序列对齐
后端·github·api
高频因子挖掘机19 小时前
行情 API 返回了数据,为什么量化策略仍然会出错?用分层设计隔离数据故障
后端·github·api
高频因子挖掘机1 天前
500只股票 × 多年日线:数据获取与本地存储如何分工?
后端·github·api
高频因子挖掘机1 天前
别急着搭数据平台:量化策略开发如何用最小闭环验证想法
后端·github·api
张张123y1 天前
# 后端第七课:FastAPI 实战入门(用刚学的 Python 写第一个 API 接口)
开发语言·python·mysql·api·fastapi
高频因子挖掘机2 天前
实时行情与分钟 K 线如何协同?Python 量化系统的数据管道设计实践
后端·github·api