npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@suxiong/react-dotted-map

v1.0.1

Published

A React library for rendering interactive dotted maps with GeoJSON support

Readme

React Dotted Map

npm version License: MIT Deploy Status

一个高性能的 React 点阵地图渲染库,支持基于 GeoJSON 数据的交互式地图可视化。

🎮 在线演示 Playground

✨ 特性

  • 🗺️ GeoJSON 原生支持 - 完全兼容标准 GeoJSON 格式
  • 🎨 混合渲染模式 - Canvas 渲染基础地图(高性能) + SVG 渲染交互元素(灵活性)
  • 🌍 内置世界地图数据 - 开箱即用的全球地图 GeoJSON 数据
  • 🎯 多种使用模式 - 组件、Hooks、Render Props 三种灵活方式
  • 📍 Pin 点管理 - 简单易用的地点标记系统,支持自定义样式和交互
  • 🎪 多种网格布局 - 支持 Square、Diagonal、Vertical 三种网格模式
  • 🔷 多种形状 - Circle 和 Hexagon 两种点阵形状
  • 🎨 按国家着色 - 支持为不同国家/区域设置不同颜色
  • 🌐 地图投影 - 基于 Proj4 的 Google Mercator 投影
  • ⚡ TypeScript - 完整的类型定义和类型安全
  • 🎭 高度可定制 - 丰富的配置选项和样式定制能力

📦 安装

npm install @suxiong/react-dotted-map

或使用其他包管理器:

yarn add @suxiong/react-dotted-map
pnpm add @suxiong/react-dotted-map
bun add @suxiong/react-dotted-map

🚀 快速开始

1. 基础组件用法

最简单的使用方式,使用内置地图数据快速渲染:

import { DottedMap } from "@suxiong/react-dotted-map";
import { geojsonWorld } from "@suxiong/react-dotted-map";
import { useMapFactory } from "@suxiong/react-dotted-map";

function App() {
  const map = useMapFactory({
    height: 400,
    width: 800,
    grid: "square",
    spacing: 2,
    geojsonWorld,
  });

  return (
    <DottedMap
      map={map}
      shape="circle"
      color="#3b82f6"
      backgroundColor="#f3f4f6"
      radius={1}
    />
  );
}

2. Render Props 模式 - 添加自定义 Pin 点

使用 render props 获得完整控制权,添加交互式 Pin 点:

import { DottedMap } from "@suxiong/react-dotted-map";
import { geojsonWorld } from "@suxiong/react-dotted-map";
import { useMapFactory } from "@suxiong/react-dotted-map";

function App() {
  const map = useMapFactory({
    height: 400,
    width: 800,
    grid: "square",
    spacing: 2,
    geojsonWorld,
  });

  return (
    <DottedMap map={map}>
      {(instance) => {
        // 添加自定义 Pin 点
        instance.addPin({
          lat: 40.7128,
          lng: -74.006,
          data: { city: "New York" },
          svgOptions: { color: "#ef4444", radius: 2 },
        });

        instance.addPin({
          lat: 51.5074,
          lng: -0.1278,
          data: { city: "London" },
          svgOptions: { color: "#10b981", radius: 2 },
        });

        return (
          <div
            dangerouslySetInnerHTML={{
              __html: instance.getSVG({
                shape: "circle",
                backgroundColor: "#1f2937",
                color: "#9ca3af",
              }),
            }}
          />
        );
      }}
    </DottedMap>
  );
}

3. Hook 模式 - 完全自定义渲染

使用 Hook 获得最大灵活性,完全控制渲染过程:

import { useDottedMap } from "@suxiong/react-dotted-map";
import { useMapFactory } from "@suxiong/react-dotted-map";
import { geojsonWorld } from "@suxiong/react-dotted-map";

function App() {
  const map = useMapFactory({
    height: 400,
    width: 800,
    grid: "square",
    spacing: 2,
    geojsonWorld,
  });

  const instance = useDottedMap(map);

  // 添加 Pin 点
  instance.addPin({
    lat: 40.7128,
    lng: -74.006,
    data: { city: "New York" },
    svgOptions: { color: "#ef4444", radius: 3 },
  });

  return (
    <div
      dangerouslySetInnerHTML={{
        __html: instance.getSVG({
          shape: "hexagon",
          color: "#60a5fa",
          radius: 1.5,
        }),
      }}
    />
  );
}

4. 按国家过滤和着色

渲染特定国家,并为不同国家设置不同颜色:

import { DottedMap } from "@suxiong/react-dotted-map";
import { geojsonWorld, geojsonByCountry } from "@suxiong/react-dotted-map";
import { useMapFactory } from "@suxiong/react-dotted-map";

function App() {
  const countryColors = {
    USA: "#ef4444",
    CHN: "#3b82f6",
    JPN: "#10b981",
    GBR: "#f59e0b",
  };

  const map = useMapFactory({
    height: 400,
    width: 800,
    grid: "square",
    spacing: 2,
    countries: ["USA", "CHN", "JPN", "GBR"],
    geojsonWorld,
    geojsonByCountry,
    countryColors,
  });

  return (
    <DottedMap
      map={map}
      shape="circle"
      backgroundColor="#f9fafb"
      radius={1}
      countryColors={countryColors}
    />
  );
}

📖 API 文档

Components

<DottedMap>

主地图组件,支持两种渲染模式:

自动渲染模式(不使用 children):

<DottedMap
  map={mapConfig}
  shape="circle"
  color="#3b82f6"
  backgroundColor="#f3f4f6"
  radius={1}
  countryColors={{ USA: "#ef4444" }}
/>

Render Props 模式(使用 children 函数):

<DottedMap map={mapConfig}>
  {(instance) => {
    instance.addPin({ lat: 40, lng: -74 });
    return <div dangerouslySetInnerHTML={{ __html: instance.getSVG() }} />;
  }}
</DottedMap>
Props

| 属性 | 类型 | 默认值 | 说明 | | ----------------- | ------------------------ | ---------------- | ------------------------------------------- | | map | MapConfig | 必需 | 地图配置对象(由 useMapFactory 生成) | | shape | 'circle' \| 'hexagon' | 'circle' | 点阵形状 | | color | string | 'currentColor' | 点阵颜色 | | backgroundColor | string | 'transparent' | 背景颜色 | | radius | number | 0.5 | 点阵大小 | | countryColors | Record<string, string> | - | 按国家代码设置颜色 | | avoidOuterPins | boolean | false | 避免在边界外添加 Pin 点 | | polygon | PolygonType | - | 自定义多边形边界 | | children | function | - | Render props 函数,接收 DottedMapInstance |

<Pin>

单独的 Pin 点组件(用于 SVG 渲染):

<Pin
  x={100}
  y={200}
  shape="circle"
  radius={2}
  color="#ef4444"
  onClick={() => console.log("Clicked!")}
/>
Props

| 属性 | 类型 | 默认值 | 说明 | | -------------- | ----------------------- | ---------------- | ------------ | | x | number | 必需 | 屏幕 X 坐标 | | y | number | 必需 | 屏幕 Y 坐标 | | shape | 'circle' \| 'hexagon' | 'circle' | 形状 | | radius | number | 0.5 | 大小 | | color | string | 'currentColor' | 颜色 | | svgOptions | SvgOptions | - | 覆盖样式选项 | | onClick | function | - | 点击事件处理 | | onMouseEnter | function | - | 鼠标悬停事件 | | onMouseLeave | function | - | 鼠标离开事件 |

Hooks

useMapFactory(params)

生成地图配置对象的 Hook,处理 GeoJSON 数据并生成点阵地图。

const map = useMapFactory({
  height: 400,
  width: 800,
  grid: "square",
  spacing: 2,
  geojsonWorld,
  countries: ["USA", "CHN"],
  geojsonByCountry,
  countryColors: { USA: "#ef4444" },
});
参数

| 属性 | 类型 | 默认值 | 说明 | | ------------------ | -------------------------------------- | ------------ | ---------------------------------- | | height | number | - | 地图高度(与 width 至少提供一个) | | width | number | - | 地图宽度(与 height 至少提供一个) | | grid | 'square' \| 'diagonal' \| 'vertical' | 'vertical' | 网格类型 | | spacing | number | 2 | 点阵间距 | | countries | string[] | - | 要显示的国家代码列表 | | region | BoundingBox | - | 自定义地图区域边界 | | geojsonWorld | FeatureCollection | - | 世界地图 GeoJSON 数据 | | geojsonByCountry | Record<string, Feature> | - | 按国家分组的 GeoJSON | | countryColors | Record<string, string> | - | 国家颜色映射 |

返回值

MapConfig 对象,包含生成的地图点阵数据和配置。

useDottedMap(map, avoidOuterPins?, polygon?)

管理地图实例和 Pin 点的 Hook。

const instance = useDottedMap(map);

instance.addPin({
  lat: 40.7128,
  lng: -74.006,
  data: { city: "New York" },
  svgOptions: { color: "#ef4444", radius: 2 },
});

const svg = instance.getSVG({ shape: "circle", color: "#3b82f6" });
参数

| 参数 | 类型 | 默认值 | 说明 | | ---------------- | ------------- | -------- | ----------------------- | | map | MapConfig | 必需 | 地图配置对象 | | avoidOuterPins | boolean | false | 避免在边界外添加 Pin 点 | | polygon | PolygonType | - | 自定义多边形边界 |

返回值 - DottedMapInstance

| 方法 | 类型 | 说明 | | -------------------- | ----------------------------------------------------------------- | ----------------------------- | | addPin(params) | (params: AddPinParams) => PinPoint \| undefined | 添加 Pin 点 | | getPin(params) | (params: { lat: number; lng: number }) => PinPoint \| undefined | 获取指定坐标的 Pin 点 | | getPoints() | () => PinPoint[] | 获取所有点(基础 + 用户添加) | | getBasePoints() | () => PinPoint[] | 获取基础地图点 | | getUserPins() | () => PinPoint[] | 获取用户添加的 Pin 点 | | getSVG(params?) | (params?: GetSVGParams) => string | 生成 SVG 字符串 | | drawCanvas(params) | (params: DrawCanvasParams) => void | 在 Canvas 上绘制地图 | | image | { region?: string; width: number; height: number } | 地图尺寸信息 |

数据导出

库内置了世界地图 GeoJSON 数据:

import {
  geojsonWorld, // 完整世界地图 FeatureCollection
  geojsonByCountry, // 按国家代码索引的 Feature 对象
  getAvailableCountries, // 获取所有可用国家代码
  getCountryFeature, // 根据代码获取国家 Feature
} from "@suxiong/react-dotted-map";

// 查看所有可用国家
const countries = getAvailableCountries();
console.log(countries); // ['USA', 'CHN', 'JPN', ...]

// 获取特定国家数据
const usaFeature = getCountryFeature("USA");

Service 函数

库还导出了底层服务函数,供高级用户直接使用:

import {
  generateMap, // 生成地图配置
  generateMapJSON, // 生成地图配置 JSON
  createMapCacheKey, // 创建地图缓存键
  drawMapOnCanvas, // Canvas 渲染
  drawPoint, // 绘制单个点
  generateMapSVG, // SVG 生成
  generatePinSVG, // Pin SVG 生成
  geojsonToMultiPolygons, // GeoJSON 转换
  computeGeojsonBox, // 计算 GeoJSON 边界框
  projectCoordinates, // 坐标投影
  isPointInPolygon, // 点是否在多边形内
  latLngToScreenCoords, // 经纬度转屏幕坐标
  screenCoordsToLatLng, // 屏幕坐标转经纬度
} from "@suxiong/react-dotted-map";

TypeScript 类型

import type {
  MapConfig,
  PinPoint,
  GridType,
  ShapeType,
  SvgOptions,
  AddPinParams,
  GetSVGParams,
  DrawCanvasParams,
  DottedMapInstance,
  PolygonType,
  ScreenCoords,
  BoundingBox,
  MapGenerationParams,
} from "@suxiong/react-dotted-map";

🎨 使用场景

场景 1: 数据可视化

展示全球用户分布:

function UserDistribution({ users }) {
  const map = useMapFactory({
    height: 500,
    width: 1000,
    grid: "square",
    spacing: 2,
    geojsonWorld,
  });

  return (
    <DottedMap map={map}>
      {(instance) => {
        users.forEach((user) => {
          instance.addPin({
            lat: user.latitude,
            lng: user.longitude,
            data: user,
            svgOptions: {
              color: user.isPremium ? "#f59e0b" : "#60a5fa",
              radius: 2,
            },
          });
        });

        return (
          <div
            dangerouslySetInnerHTML={{
              __html: instance.getSVG({
                backgroundColor: "#f9fafb",
                color: "#d1d5db",
              }),
            }}
          />
        );
      }}
    </DottedMap>
  );
}

场景 2: 交互式地图

带有悬停和点击交互:

function InteractiveMap() {
  const [selectedCity, setSelectedCity] = useState(null);
  const map = useMapFactory({ height: 400, width: 800, geojsonWorld });

  const cities = [
    { name: "New York", lat: 40.7128, lng: -74.006 },
    { name: "London", lat: 51.5074, lng: -0.1278 },
    { name: "Tokyo", lat: 35.6762, lng: 139.6503 },
  ];

  return (
    <div>
      <DottedMap map={map}>
        {(instance) => {
          cities.forEach((city) => {
            instance.addPin({
              lat: city.lat,
              lng: city.lng,
              data: city,
              svgOptions: {
                color: selectedCity === city.name ? "#ef4444" : "#3b82f6",
                radius: selectedCity === city.name ? 3 : 2,
              },
            });
          });

          return (
            <div
              onClick={() => console.log("Map clicked")}
              dangerouslySetInnerHTML={{
                __html: instance.getSVG(),
              }}
            />
          );
        }}
      </DottedMap>
      {selectedCity && <div>Selected: {selectedCity}</div>}
    </div>
  );
}

场景 3: 区域对比

对比不同国家或区域:

function RegionComparison() {
  const countryColors = {
    USA: "#ef4444",
    CHN: "#3b82f6",
    IND: "#10b981",
    BRA: "#f59e0b",
  };

  const map = useMapFactory({
    height: 400,
    width: 800,
    grid: "square",
    spacing: 2,
    countries: Object.keys(countryColors),
    geojsonWorld,
    geojsonByCountry,
    countryColors,
  });

  return (
    <div>
      <DottedMap
        map={map}
        shape="hexagon"
        radius={1.5}
        countryColors={countryColors}
      />
      <div style={{ display: "flex", gap: "16px", marginTop: "16px" }}>
        {Object.entries(countryColors).map(([country, color]) => (
          <div key={country} style={{ display: "flex", alignItems: "center" }}>
            <div
              style={{
                width: 16,
                height: 16,
                backgroundColor: color,
                marginRight: 8,
              }}
            />
            <span>{country}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

🏗️ 架构设计

本库采用分层架构设计,确保代码的可维护性和可测试性:

架构层次

┌─────────────────────────────────────┐
│         UI Layer (React)            │  ← Components (DottedMap, Pin)
├─────────────────────────────────────┤
│       Hook Layer (React)            │  ← Hooks (useDottedMap, useMapFactory)
├─────────────────────────────────────┤
│    Service Layer (Pure Logic)       │  ← Services (mapGenerator, canvas, svg)
├─────────────────────────────────────┤
│      Data Layer (GeoJSON)           │  ← countries.geo.json
└─────────────────────────────────────┘
  • UI Layer: 纯展示组件,无业务逻辑
  • Hook Layer: 状态管理和副作用处理
  • Service Layer: 纯函数业务逻辑,可独立测试
  • Data Layer: 静态 GeoJSON 数据

渲染策略

采用混合渲染策略,平衡性能和交互性:

  • Canvas 层: 渲染基础地图点阵(数千个点,高性能)
  • SVG 层: 渲染用户添加的 Pin 点(支持交互、样式定制)

⚙️ 高级用法

自定义 GeoJSON 数据

使用自己的 GeoJSON 数据:

import customGeoJSON from "./my-regions.geo.json";

const map = useMapFactory({
  height: 400,
  width: 800,
  geojsonWorld: customGeoJSON,
});

自定义区域边界

限制地图到特定经纬度范围:

const map = useMapFactory({
  height: 400,
  width: 800,
  region: {
    lat: { min: 20, max: 50 },
    lng: { min: -130, max: -60 },
  },
  geojsonWorld,
});

缓存地图配置

避免重复生成相同的地图:

import { generateMapJSON, createMapCacheKey } from "@suxiong/react-dotted-map";

const params = { height: 400, width: 800, geojsonWorld };
const cacheKey = createMapCacheKey(params);

// 检查缓存
let mapJSON = localStorage.getItem(cacheKey);
if (!mapJSON) {
  mapJSON = generateMapJSON(params);
  localStorage.setItem(cacheKey, mapJSON);
}

const map = JSON.parse(mapJSON);

🔧 开发

# 安装依赖
npm install

# 开发模式(带示例)
npm run dev

# 构建库
npm run build

# 构建演示站点
npm run build:demo

# 代码检查
npm run lint

# 预览构建结果
npm run preview

📄 许可证

MIT © suxiong

🤝 贡献

欢迎贡献!请随时提交 Issue 或 Pull Request。

🔗 相关链接

📝 更新日志

1.0.0

  • 🎉 首次发布
  • ✨ 支持 Canvas 和 SVG 混合渲染
  • ✨ 内置世界地图 GeoJSON 数据
  • ✨ 多种使用模式(组件、Hooks、Render Props)
  • ✨ 按国家过滤和着色
  • ✨ 完整的 TypeScript 支持