@visx/grid 网格线组件完全指南:为 visx 图表添加横向、纵向与极坐标网格
2026/9/20 19:57:32 网站建设 项目流程

@visx/grid 网格线组件完全指南:为 visx 图表添加横向、纵向与极坐标网格

【免费下载链接】visx🐯 visx | visualization components项目地址: https://gitcode.com/gh_mirrors/vi/visx

@visx/grid是 visx 可视化组件库中专用于绘制图表网格线的包:<GridRows />渲染水平网格线、<GridColumns />渲染垂直网格线,而<Grid />可一次同时渲染两者。本文以 packages/visx-grid/Readme.md 为主线,结合仓库源码(types.ts、GridRows.tsx、GridColumns.tsx、Grid.tsx 等)深入讲解全部组件的属性、默认值与实现原理,读完你可以直接在 visx 折线图、柱状图、散点图中快速接入横纵网格,也可以在雷达图/玫瑰图中使用极坐标网格(GridAngle、GridRadial、GridPolar)。

包定位与核心组件

@visx/grid的职责非常单一——根据已有的 scale(比例尺)在指定宽度/高度范围内生成网格线。它自身不包含坐标轴,只负责网格背景。从 src/index.ts 可以确认该包对外导出的全部组件:

  • GridRows—— 水平网格线(横线)
  • GridColumns—— 垂直网格线(竖线)
  • Grid—— 横线 + 竖线的组合容器
  • GridAngle—— 极坐标角度网格线(从圆心向外辐射的射线)
  • GridRadial—— 极坐标径向网格线(同心圆弧)
  • GridPolar—— 极坐标网格的组合容器(角度线 + 径向线)

其中前三者服务于常见的直角坐标系图表(折线、柱状、散点、面积等),后三者服务于极坐标系图表(雷达图、玫瑰图等)。

安装

在 React 18 或 19 项目中安装:

npm install --save @visx/grid

根据 package.json,该包以 React 18/19 为 peerDependencies,运行时依赖@visx/curve@visx/group@visx/point@visx/scale@visx/shapeclassnames(这些依赖会在安装时自动带入)。包同时提供 CommonJS(lib/)与 ES Module(esm/)两种产物,且声明sideEffects: false,可安全参与 tree-shaking。

基本用法:Grid 组合横纵网格线

Readme 中的核心示例展示了最常用的方式——用一个<Grid />同时获得横纵两组网格线:

import { Grid } from '@visx/grid'; // 或者 // import * as Grid from '@visx/grid'; // <Grid.Grid /> const grid = ( <Grid xScale={xScale} yScale={yScale} width={xMax} height={yMax} numTicksRows={numTicksForHeight(height)} numTicksColumns={numTicksForWidth(width)} /> );

要点说明:

  • xScale/yScale分别是映射 x、y 坐标的 scale,可以是@visx/scale创建的 scale,也可以是原生 d3-scale(见 Grid.tsx 的类型定义GridScale)。
  • width/height决定网格线的绘制范围:横向线从左边界画到width,纵向线从上边界画到height
  • numTicksRows/numTicksColumns控制横、纵网格线的“近似”条数。注意源码注释特别强调:由于 d3 的 tick 算法,这个数值是近似的(约等于),需要精确控制时应改用tickValues
  • 上述示例中numTicksForHeight/numTicksForWidth是 visx 常用的辅助约定,即让网格线数量随绘图区域尺寸自适应(例如Math.floor(height / 100)),Readme 以占位函数形式给出,实践中可自行实现或用固定数字。

为什么 numTicks 是“近似值”?

看 GridRows.tsx 的实现:const ticks = tickValues ?? getTicks(scale, numTicks);。当不传tickValues时,网格线位置由@visx/scalegetTicks依据 d3 的scale.ticks(count)算法生成。d3 的 tick 算法会根据 scale 的 domain 自动把请求的 tick 数“圆整”到美观的数值(如 1、2、5 的倍数),因此实际条数可能与传入值略有出入。若你的场景(如网格线与坐标轴标签严格对齐)要求完全一致,请直接传入tickValues

GridRows 与 GridColumns:单独使用

当只需要一组方向的网格线时,可以单独使用<GridRows /><GridColumns />。二者实现几乎对称,区别仅在于:

  • GridRows接收scale(y 方向 scale)与width,横向绘制;每条线的 y 坐标由scale(d)计算,x 从 0 到width
  • GridColumns接收scale(x 方向 scale)与height,纵向绘制;每条线的 x 坐标由scale(d)计算,y 从 0 到height

两个组件的默认值(见各自源码的组件签名)完全一致:top = 0left = 0stroke = '#eaf0f6'(浅蓝灰)、strokeWidth = 1numTicks = 10

import { GridRows, GridColumns } from '@visx/grid'; // 只画横向网格线 <GridRows scale={yScale} width={xMax} numTicks={5} stroke="#eee" /> // 只画纵向网格线 <GridColumns scale={xScale} height={yMax} numTicks={5} />

内部实现:从 tick 到 SVG Line

以 GridRows.tsx 为例,渲染流程为:

  1. ticks = tickValues ?? getTicks(scale, numTicks)得到刻度值数组;
  2. 计算偏移scaleOffset = (offset ?? 0) + getScaleBandwidth(scale) / 2
  3. 对每个 tick,y = coerceNumber(scale(d)) ?? 0 + scaleOffset,构建from/to两个Point(来自@visx/point),横跨[0, width]
  4. @visx/shape<Line />逐条渲染,外层包裹@visx/group<Group className="visx-rows" />

值得注意的两点实现细节:

  • band 类 scale 的自动居中getScaleBandwidth(见 utils/getScaleBandwidth.ts)检测 scale 是否具有bandwidth()方法(如scaleBand),有则取带宽的一半作为偏移,让网格线落在 band 的中间而不是边缘。这样在使用scaleBand做柱状图时,网格线会与柱子中心对齐。
  • scale 输出非数字的容错coerceNumber保证即使 scale 输出undefined(某些 scale 在 domain 外会返回 undefined),也回退为 0,避免渲染崩溃。类型层面由GridScaleOutput = number | NumberLike | undefined(见 types.ts)承接。

通用属性(CommonGridProps)速查

GridRowsGridColumns及极坐标组件共同继承CommonGridProps(定义于 types.ts):

属性类型默认值说明
classNamestring应用到线组<g>元素的类名
children({ lines }) => ReactNode自定义渲染函数,接收{ lines: GridLines }覆盖默认的<Line>渲染
top/leftnumber0对网格组容器<g>的整体平移偏移(像素)
strokestring'#eaf0f6'网格线描边颜色
strokeWidthstring \| number1网格线描边粗细
strokeDasharraystring网格线虚线样式,如'4,4'
numTicksnumber10网格线近似条数(d3 算法会圆整,见上文)
lineStyleCSSProperties应用到每条网格线的 style 样式对象
offsetnumber每条网格线的像素平移量(Rows 平移 y、Columns 平移 x),叠加在 band 居中偏移之上

children渲染函数的lines数据结构为GridLines(见 types.ts):数组元素包含from: { x?, y? }to: { x?, y? }index,你可以完全自定义网格线的渲染方式(例如换成<circle>或其他标记)。

此外,GridRowsProps/GridColumnsProps还接受tickValues?: ScaleInput<Scale>[]——传入精确刻度值数组,指定后覆盖numTicks。同时由于类型定义中AllGridRowsProps/AllGridColumnsProps继承了@visx/shapeLinePropsSVGLineElement的原生属性(见 GridRows.tsx),你还可以直接透传vectorEffectopacity等任意 SVG 属性到每条线上。

Grid 组合组件的专属属性

<Grid />内部正是把GridRows(用yScale)与GridColumns(用xScale)组合进同一个<Group className="visx-grid">(见 Grid.tsx)。除继承通用属性外,它提供成对的前缀属性,让横、纵两组网格线可以独立定制:

属性说明
xScale/yScale必填,分别映射 x(Columns)与 y(Rows)坐标
xOffset/yOffset对 Columns 线做 x 平移 / 对 Rows 线做 y 平移
numTicksRows/numTicksColumns横、纵网格线近似条数
rowLineStyle/columnLineStyle分别应用到 Rows / Columns 的 style 对象
rowTickValues/columnTickValues横、纵网格线的精确刻度值数组,优先于 numTicks*

Grid还透传classNamestrokestrokeWidthstrokeDasharray等公共属性给两组线;restProps也会一并透传给内部的 Rows 与 Columns,因此适合把vectorEffect="non-scaling-stroke"这类 SVG 属性一次性应用到全部网格线。

典型用法(让横纵网格线拥有不同样式):

<Grid xScale={xScale} yScale={yScale} width={width} height={height} stroke="#ddd" strokeWidth={1} numTicksRows={8} numTicksColumns={12} rowLineStyle={{ strokeDasharray: '4,4' }} columnLineStyle={{ strokeDasharray: '2,2' }} />

极坐标网格:GridAngle、GridRadial 与 GridPolar

除直角坐标网格外,@visx/grid还提供完整的极坐标网格能力,通常用于雷达图、玫瑰图或径向条形图。

GridAngle:角度线(辐射射线)

GridAngle(见 GridAngle.tsx)根据角度 scale 从圆心向外绘制射线。除通用属性外还有:

  • innerRadius(默认0):射线起始半径;
  • outerRadius(必填):射线终止半径;
  • lineClassName:应用到所有角度线的类名。

实现上,每个 tick 的角度为scale(tick) - Math.PI / 2(把 d3 角度 scale 的起始方向对齐到 12 点钟方向),再经 utils/polarToCartesian.ts 转换为直角坐标的起点与终点,最后用<Line />渲染。

<GridAngle scale={angleScale} innerRadius={0} outerRadius={radius} numTicks={12} stroke="#ddd" />

GridRadial:径向线(同心圆弧)

GridRadial(见 GridRadial.tsx)根据径向 scale 绘制同心圆弧,内部使用@visx/shape<Arc />渲染。专属属性:

  • startAngle(默认0)/endAngle(默认2 * Math.PI):圆弧的起止角度(弧度);
  • arcThickness:若指定,则每条圆弧会具有该厚度(用于填充场景),此时内半径由scale(radius - arcThickness)计算;
  • fill(默认'transparent')/fillOpacity(默认1):圆弧填充色与不透明度;
  • lineClassName:应用到所有径向弧线的类名。

一个实现细节:当不指定arcThickness时,内半径取Math.min(...scale.domain()),即弧线贴紧 domain 最小值,形成常见的“蛛网”式同心圆。

GridPolar:极坐标组合

GridPolar(见 GridPolar.tsx)是GridAngle+GridRadial的组合容器,专门为极坐标成对属性,例如scaleAngle/scaleRadialinnerRadius/outerRadiusnumTicksAngle/numTicksRadialtickValuesAngle/tickValuesRadialstrokeAngle/strokeRadialstrokeWidthAngle/strokeWidthRadialstrokeDasharrayAngle/strokeDasharrayRadiallineStyleAngle/lineStyleRadialclassNameAngle/classNameRadiallineClassNameAngle/lineClassNameRadialfillRadialarcThicknessstartAngle/endAngle等,几乎为每个内部组件属性都提供了带Angle/Radial后缀的独立版本,便于分别定制射线与圆弧。

<GridPolar scaleAngle={angleScale} scaleRadial={radialScale} innerRadius={0} outerRadius={radius} numTicksAngle={12} numTicksRadial={5} strokeAngle="#bbb" strokeRadial="#ddd" />

测试覆盖与进一步探索

该包在 test/ 目录下为每个组件都配备了单元测试(Grid.test.tsxGridRows.test.tsxGridColumns.test.tsxGridAngle.test.tsxGridRadial.test.tsxGridPolar.test.tsx以及utils.test.ts),可在packages/visx-grid目录下通过 vitest 运行。阅读这些测试是理解各组件边界行为(如默认值、tickValues优先级、children 自定义渲染)的捷径。

若想看到网格线的实际应用,可参考同仓库的@visx/xychart(packages/visx-xychart)与@visx/chart(packages/visx-chart)等更上层封装,它们内部即基于此类基础网格组件构建。visx 的网格组件与 packages/visx-axis 的坐标轴组件配合使用,即可快速搭建出带完整坐标参考系的专业图表。

【免费下载链接】visx🐯 visx | visualization components项目地址: https://gitcode.com/gh_mirrors/vi/visx

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询