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

@wenle_2523097/agri-map

v2.0.2

Published

农业地图组件库 - 基于 Leaflet + React 的农业专用地图组件

Readme

agri-map-components

基于 Leaflet + React 的农业专用地图组件库,提供地块管理、标注点、道路、灌溉渠等农业场景常用组件。

特性

  • 🗺️ 地块管理 - 支持大规模地块数据渲染,提供绘制、剪辑、移动等编辑功能
  • 📍 标注点 - 多种预设图标,支持自定义 SVG 图标,提供新建、移动、删除编辑模式
  • 🛤️ 道路绘制 - 田间道路绘制与管理,支持距离显示
  • 💧 灌溉渠 - 灌溉渠绘制与流向箭头显示
  • 🌍 天地图 - 内置天地图图层支持
  • 📐 双向标尺 - 地图比例尺组件
  • 高性能 - 支持上万条地块数据渲染
  • 🛡️ 错误边界 - 内置 ErrorBoundary 组件,优雅处理渲染错误
  • 📊 性能监控 - 提供 usePerformanceMonitor Hook 监控组件性能

安装

npm install @wenle_2523097/agri-map
# 或
yarn add @wenle_2523097/agri-map

依赖版本

确保项目已安装以下依赖:

npm install leaflet@^1.9.4 react@>=18.0.0 react-dom@>=18.0.0

⚠️ 重要提示:

  • antd 为 peerDependency,按需安装:npm install antd@>=5.0.0
  • 本库已移除 react-leaflet 依赖,直接使用原生 Leaflet API,更轻量、更灵活

样式引入

组件库的 CSS 样式会自动注入到 DOM 中,无需手动引入。

// 只需引入 Leaflet 的基础样式即可
import 'leaflet/dist/leaflet.css';

// ✨ 组件库样式已自动注入,以下代码不再需要:
// import '@wenle_2523097/agri-map/dist/index.css'; // ❌ 已废弃

Breaking Change: 从 v1.4.0 开始,CSS 样式改为自动注入。如果你之前手动引入了 dist/index.css,请删除该导入,避免重复加载。

快速开始

// 引入 Leaflet 样式
import 'leaflet/dist/leaflet.css';
// ✨ CSS 已自动注入,无需引入

import { MapContainer, TianDiTuLayer, PlotLayer, Marker } from '@wenle_2523097/agri-map';

function App() {
  const plotData = [
    {
      id: 1,
      name: '地块A',
      type: 'farmland',
      status: 'planting',
      boundaries: [[30.0, 120.0], [30.0, 120.1], [30.1, 120.1], [30.1, 120.0]],
      area: 1000,
      crop: '水稻',
    },
  ];

  const markers = [
    { id: 1, position: [30.05, 120.05], title: '标注点1' },
  ];

  return (
    <div style={{ width: '100%', height: '100vh' }}>
      <MapContainer
        center={[30.0, 120.0]}
        zoom={12}
        theme="light"
        tianDiTuLayer={{ apiKey: 'your-tianditu-key' }}
        dualScaleControl
      >
        <PlotLayer dataSource={plotData} />
        <Marker dataSource={markers} />
      </MapContainer>
    </div>
  );
}

组件列表

PlotLayer 地块图层

高性能地块渲染组件,支持大规模数据。

import { PlotLayer, PlotData } from 'agri-map';

const plots: PlotData[] = [
  {
    id: 'plot-1',
    name: '农田A',
    type: 'farmland',
    status: 'planting',
    boundaries: [[30.0, 120.0], [30.0, 120.1], [30.1, 120.1], [30.1, 120.0]],
    area: 1000,
    crop: '水稻',
  },
];

<PlotLayer
  dataSource={plots}
  onClick={(data, layer) => console.log('点击地块:', data)}
  onContextMenu={(data, layer, e) => console.log('右键菜单:', data)}
  style={(data) => ({
    color: data.status === 'planting' ? '#4CAF50' : '#9E9E9E',
    fillColor: data.status === 'planting' ? '#81C784' : '#BDBDBD',
    fillOpacity: 0.6,
  })}
  editMode={['create', 'delete']}
  onCreate={(result) => console.log('新建地块:', result)}
  onDelete={(result) => console.log('删除地块:', result)}
  showLabel={true}
  labelFields={['name', 'area']}
/>

PlotLayer Props

| 属性 | 类型 | 默认值 | 说明 | | --------------- | ------------------------------ | ---------- | ------------ | | dataSource | PlotData[] | [] | 地块数据数组 | | onClick | (data, layer) => void | - | 点击回调 | | onContextMenu | (data, layer, event) => void | - | 右键菜单回调 | | style | (data) => PlotStyle | - | 动态样式函数 | | path | PathOptions | - | 默认路径样式 | | selectedPath | PathOptions | - | 选中样式 | | editMode | boolean \| string[] | false | 编辑模式 | | onCreate | (result) => void | - | 新建回调 | | onRedraw | (result) => void | - | 重绘回调 | | onClip | (result) => void | - | 剪辑回调 | | onMove | (result) => void | - | 移动回调 | | onDelete | (result) => void | - | 删除回调 | | showLabel | boolean \| 'all' | false | 显示标签 | | labelFields | string[] | ['name'] | 标签字段 |


Marker 标注点

地图标注点组件,支持多种图标和编辑功能。

import { Marker, MarkerData } from 'agri-map';

const markers: MarkerData[] = [
  { id: 1, position: [30.0, 120.0], title: '标注点1', description: '描述信息' },
  { id: 2, position: [30.1, 120.1], title: '标注点2', icon: 'drone' },
];

<Marker
  dataSource={markers}
  icon="point"
  iconSize={[48, 48]}
  animated={false}
  onClick={(item) => console.log('点击:', item)}
  editMode={['create', 'move', 'delete']}
  onCreate={(result) => console.log('新建:', result)}
/>

预设图标

  • point - 默认点位图标
  • position - 定位图标
  • position-red - 红色定位图标
  • drone - 无人机图标
  • down - 下载图标
  • marker-red/blue/green/orange/yellow - 彩色标记图标

自定义 SVG 图标

// 使用 SVG 字符串
<Marker svgIcon="<svg>...</svg>" />

// 使用 SVG 配置对象
<Marker svgIcon={{
  path: 'M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z',
  viewBox: '0 0 24 24',
  fill: '#e53935',
}} />

// 使用远程图标 URL
<Marker icon="https://example.com/icon.png" />

Marker Props

| 属性 | 类型 | 默认值 | 说明 | | ---------------- | -------------------------------- | ---------- | ---------------- | | dataSource | MarkerData[] | [] | 标注数据 | | icon | string \| SvgIconConfig | 'point' | 图标类型 | | iconSize | [number, number] | [48, 48] | 图标尺寸 | | animated | boolean | false | 是否动画 | | permanent | boolean | false | 永久显示提示 | | editMode | boolean \| string[] | false | 编辑模式 | | onCreate | (result) => void | - | 新建回调 | | onMove | (result) => void | - | 移动回调 | | onDelete | (result) => void | - | 删除回调 | | cluster | boolean \| MarkerClusterConfig | false | 聚合配置 | | onClusterClick | (count, markers) => void | - | 聚合气泡点击回调 | | icons | MarkerIconsConfig | - | 统一图标配置 |

聚合功能

Marker 组件支持标注点聚合,在小缩放级别下将相近的标注点聚合为气泡显示,提升大量标注点时的渲染性能。

// 启用默认聚合
<Marker
  dataSource={markers}
  cluster={true}
/>

// 自定义聚合配置
<Marker
  dataSource={markers}
  cluster={{
    radius: 60,        // 聚合半径(像素),默认 40
    maxZoom: 16,       // 最大聚合 zoom 级别,默认 18
    minPoints: 3,      // 最小聚合点数,默认 2
    onClickBehavior: 'expand',  // 点击行为:'zoom' 或 'expand'
  }}
  onClusterClick={(count, markers) => {
    console.log(`点击了包含 ${count} 个点的聚合`);
  }}
/>

// 自定义聚合气泡图标
<Marker
  dataSource={markers}
  cluster={true}
  icons={{
    cluster: {
      icon: 'marker-yellow',
      colors: ['#1890ff', '#faad14', '#ff4d4f'],
      animated: true,
      showCount: true,
    },
    default: { icon: 'point', iconSize: [32, 32] },
    selected: { icon: 'position-red' },
  }}
/>

MarkerClusterConfig

| 属性 | 类型 | 默认值 | 说明 | | ----------------- | -------------------- | -------- | ------------------------ | | radius | number | 40 | 聚合半径(像素) | | maxZoom | number | 18 | 聚合生效的最大 zoom 级别 | | minPoints | number | 2 | 最小聚合点数 | | onClickBehavior | 'zoom' \| 'expand' | 'zoom' | 点击聚合气泡后的行为 |

MarkerIconsConfig

| 属性 | 类型 | 说明 | | ---------- | ---------------------- | ------------------ | | default | MarkerIconItemConfig | 默认状态图标配置 | | selected | MarkerIconItemConfig | 选中状态图标配置 | | editing | MarkerIconItemConfig | 编辑中状态图标配置 | | cluster | ClusterIconConfig | 聚合气泡图标配置 |


Road 道路组件

田间道路绘制与管理组件。

import { Road, RoadData } from 'agri-map';

const roads: RoadData[] = [
  {
    id: 1,
    name: '田间道1号',
    points: [[30.0, 120.0], [30.1, 120.1], [30.2, 120.2]],
  },
];

<Road
  dataSource={roads}
  path={{ color: '#795548', weight: 3 }}
  showDistance={true}
  editMode={['create', 'edit', 'delete']}
  onCreate={(result) => console.log('新建道路:', result)}
/>

Road Props

| 属性 | 类型 | 默认值 | 说明 | | -------------- | --------------------- | ------- | -------- | | dataSource | RoadData[] | [] | 道路数据 | | path | PathOptions | - | 路径样式 | | showDistance | boolean | false | 显示距离 | | editMode | boolean \| string[] | false | 编辑模式 |


Irrigation 灌溉渠组件

灌溉渠绘制与流向显示组件。

import { Irrigation, IrrigationData } from 'agri-map';

const channels: IrrigationData[] = [
  {
    id: 1,
    name: '主干渠',
    points: [[30.0, 120.0], [30.1, 120.1]],
    inlet: true,
    outlet: false,
  },
];

<Irrigation
  dataSource={channels}
  path={{ color: '#2196F3', weight: 4 }}
  editMode={['create', 'edit', 'delete', 'reverse']}
  onCreate={(result) => console.log('新建渠道:', result)}
  onReverse={(result) => console.log('反转流向:', result)}
/>

Irrigation Props

| 属性 | 类型 | 默认值 | 说明 | | ------------ | --------------------- | ------- | ------------ | | dataSource | IrrigationData[] | [] | 灌溉渠数据 | | path | PathOptions | - | 路径样式 | | editMode | boolean \| string[] | false | 编辑模式 | | onReverse | (result) => void | - | 反转流向回调 |


TianDiTuLayer 天地图图层

天地图底图组件。

import { TianDiTuLayer, LAYER_TYPES } from 'agri-map';

// 矢量底图 + 标注
<TianDiTuLayer
  apiKey="your-tianditu-key"
  layerType="vector"
  showAnnotation={true}
/>

// 卫星影像
<TianDiTuLayer
  apiKey="your-tianditu-key"
  layerType="satellite"
/>

// 地形图
<TianDiTuLayer
  apiKey="your-tianditu-key"
  layerType="terrain"
/>

// 自定义叠加层
<TianDiTuLayer
  apiKey="your-tianditu-key"
  overlayUrl="https://your-server.com/overlay/{z}/{x}/{y}.png"
  overlayOpacity={0.5}
/>

TianDiTuLayer Props

| 属性 | 类型 | 默认值 | 说明 | | ---------------- | -------------------------------------- | ---------- | ---------------------- | | apiKey | string | - | 天地图 API Key(必填) | | layerType | 'vector' \| 'satellite' \| 'terrain' | 'vector' | 图层类型 | | showAnnotation | boolean | true | 显示标注 | | overlayUrl | string | - | 叠加瓦片 URL | | overlayOpacity | number | 1 | 叠加层透明度 |


DualScaleControl 双向标尺

地图比例尺组件,缩放控件固定在左下角。

import { DualScaleControl } from 'agri-map';

<DualScaleControl
  metric={true}
  imperial={false}
  showZoomControl={true}
  theme="light"
/>

ErrorBoundary 错误边界

捕获子组件树中的 JavaScript 错误,记录错误信息,并展示回退 UI。

import { ErrorBoundary } from 'agri-map';

// 基础用法
<ErrorBoundary>
  <MapContainer>
    <PlotLayer dataSource={plots} />
  </MapContainer>
</ErrorBoundary>

// 自定义回退 UI
<ErrorBoundary
  fallback={(error, reset) => (
    <div>
      <p>出错了:{error.message}</p>
      <button onClick={reset}>重试</button>
    </div>
  )}
>
  <YourComponent />
</ErrorBoundary>

// 带错误回调
<ErrorBoundary
  onError={(error, errorInfo) => {
    // 上报错误到监控服务
    logErrorToService(error, errorInfo);
  }}
>
  <YourComponent />
</ErrorBoundary>

ErrorBoundary Props

| 属性 | 类型 | 默认值 | 说明 | | ------------------------- | ------------------------------------------ | ------- | -------------------- | | fallback | ReactNode \| (error, reset) => ReactNode | - | 错误回退 UI | | onError | (error, errorInfo) => void | - | 错误回调 | | showDetailsInProduction | boolean | false | 生产环境显示错误详情 |


usePerformanceMonitor 性能监控 Hook

监控组件渲染性能和地图操作性能。

import { usePerformanceMonitor } from 'agri-map/hooks';

function PlotLayer({ dataSource }) {
  const {
    metrics,
    recordRenderPerformance,
    observeMapOperation,
    reportPerformance
  } = usePerformanceMonitor('PlotLayer', {
    enabled: true,
    reportToService: process.env.NODE_ENV === 'production',
    serviceUrl: '/api/performance',
  });

  useEffect(() => {
    console.log('渲染性能:', metrics);
  }, [metrics]);

  return <div>...</div>;
}

PerformanceMonitorConfig

| 属性 | 类型 | 默认值 | 说明 | | ----------------- | ------------------------- | ------- | ------------------ | | enabled | boolean | true | 是否启用监控 | | reportToService | boolean | false | 是否上报到监控服务 | | serviceUrl | string | - | 监控服务上报 URL | | extraData | Record<string, unknown> | - | 额外数据 |

返回值

| 属性 | 类型 | 说明 | | ------------------------- | -------------------------- | ---------------- | | metrics | PerformanceMetrics | 性能指标数据 | | getMetrics | () => PerformanceMetrics | 获取完整性能指标 | | recordRenderPerformance | (type) => void | 记录渲染性能 | | observeMapOperation | (map, name, op) => T | 观察地图操作性能 | | reportPerformance | () => void | 上报性能数据 |


MapContainer 地图容器

集成配置功能的地图容器组件,替代了原有的 ConfigProvider + react-leaflet MapContainer 组合。

import { MapContainer } from '@wenle_2523097/agri-map';

<MapContainer
  center={[30.0, 120.0]}
  zoom={12}
  theme="light"                        // 主题:'light' | 'dark'
  tianDiTuLayer={{                     // 天地图配置
    apiKey: 'your-tianditu-key',
    layerType: 'vector',
    showAnnotation: true,
  }}
  dualScaleControl                     // 显示双向标尺
  mapSizeHandler                       // 自动处理地图尺寸变化
>
  {/* 子组件 */}
</MapContainer>

MapContainer Props

| 属性 | 类型 | 默认值 | 说明 | | ------------------ | ---------------------------------- | --------- | -------------------- | | center | [number, number] | - | 地图中心点(必填) | | zoom | number | - | 缩放级别(必填) | | theme | 'light' \| 'dark' | 'light' | 主题 | | tianDiTuLayer | TianDiTuLayerConfig \| false | - | 天地图配置 | | dualScaleControl | boolean \| DualScaleControlProps | false | 双向标尺配置 | | mapSizeHandler | boolean | true | 自动处理地图尺寸变化 | | loading | boolean | false | 显示加载状态 | | children | ReactNode | - | 子组件 |

注意: MapContainer 同时支持所有原生 Leaflet 地图选项(如 minZoom, maxZoom, zoomControl 等)。


useMap Hook

获取地图实例的 Hook,用于在子组件中操作地图。API 与 react-leaflet 的 useMap 保持一致。

import { useMap } from '@wenle_2523097/agri-map';

function MyComponent() {
  const map = useMap();

  useEffect(() => {
    if (map) {
      map.setView([30.0, 120.0], 15);
    }
  }, [map]);

  return null;
}

useMapEvents Hook

同时监听多个地图事件的 Hook,API 与 react-leaflet 的 useMapEvents 保持一致。返回地图实例。

import { useMapEvents } from '@wenle_2523097/agri-map';

function MyComponent() {
  const map = useMapEvents({
    click: (e) => {
      console.log('点击位置:', e.latlng);
    },
    zoomend: () => {
      console.log('当前缩放级别:', map?.getZoom());
    },
    moveend: () => {
      console.log('当前中心点:', map?.getCenter());
    },
  });

  return null;
}

Icons 图标组件

内置 SVG 图标组件库。

import {
  Icons,
  PlotRedrawIcon,
  ClipIcon,
  MoveIcon,
  DeleteIcon,
  CancelIcon,
  SaveIcon,
  CreateIcon
} from 'agri-map';

// 使用方式一
<CreateIcon />

// 使用方式二
<Icons.Create />

类型定义

// 坐标点 [lat, lng]
type Coordinate = [number, number];

// 地块类型
type PlotType = 'farmland' | 'vegetable' | 'orchard' | 'forest' | 'grassland' | 'paddy' | 'greenhouse';

// 地块状态
type PlotStatus = 'cultivating' | 'fallow' | 'harvesting' | 'planting' | 'irrigating';

// 编辑模式
type PlotEditMode = 'idle' | 'redraw' | 'clip' | 'move' | 'create';

// 路径样式
interface PathOptions {
  color?: string;
  fillColor?: string;
  weight?: number;
  opacity?: number;
  fillOpacity?: number;
  dashArray?: string | number[];
  className?: string;
}

开发

# 安装依赖
npm install

# 开发模式
npm run dev

# 构建
npm run build

# 类型检查
npm run type-check

许可证

MIT