在漫长的无果搜索结束后,我决定自己解决这个问题。
最小代码发布在this Github gist。
要解决的基本问题是任何标准 Recharts 工具提示都会收到以下信息:
- 鼠标指针当前所在的x值,在图表画布上以像素表示
- 最接近鼠标 x 值位置的所有数据系列的 y 值,以 y 轴实际单位(欧元、千克等)表示
因此,有必要为自定义工具提示提供图表画布上以像素表示的 y 轴鼠标位置信息。
然后,工具提示可以计算出最接近垂直鼠标位置的数据系列,并仅显示属于该数据系列的值。
以像素为单位提取 y 位置很棘手,因为 Recharts 每次重绘图表时都会更改像素和纵坐标值之间的映射。但是有一个图表组件必须非常了解这个映射,以便将自己放置在正确的垂直位置并显示相应的真实世界纵坐标值:这是 y 轴上的每个刻度。
问题是:我们如何插入 Recharts 绘图工作流程以了解映射?
方法如下:Recharts YAxis 组件的 tick 属性允许提供自定义 React 组件,尽管没有记录示例。
对于 Recharts 决定放置在 y 轴上的每个刻度,此自定义组件都会实例化一次。
通过反复试验,我发现我的自定义 Tick 组件具有以下属性:
{ x, y, payload, ...anyCustomPropertyAddedByMe }
其中x 和y 是刻度的笛卡尔坐标(画布像素),payload 就是这样一个对象:
{ coordinates, isShow, offset, tickCoord, value }
value 以实际 y 轴单位表示。
想法是找出每幅图中最低和最高刻度的(y, value)这对夫妇,并计算像素和实际值之间的转换因子。
这将允许自定义工具提示执行上述计算。
(严格来说,从每个图表重绘时实例化的前两个刻度中收集两对就足够了,但选择相距最远的两个会提供更高的精度)
整个算法分为三个部分:
-
tooltipCollector:这是一个 JavaScript 模块,提供两种方法:
-
collect(value, y),由自定义刻度调用,将所有对 (y, value) 存储在私有数组 _collection 中
-
maxAndMin(),由自定义工具提示调用,它读取 _collection 数组并返回集合中代表最低和最高刻度的几个项目(注意画布中的垂直像素值是上下颠倒的!)
-
一个CustomizedTick React 组件:
- 在其自定义属性中接收工具提示收集器
- 通过调用其
collect(y, value) 方法将其y 和payload.value 发送到收集器
- 返回一个非常简单的 JSX 刻度标记,它使用
y(将自身放置在正确的垂直位置)和 payload.value(向用户显示刻度指示的实际值)
-
a CustomTooltip React 组件:
- 在其自定义属性中接收工具提示收集器并调用其
maxAndMin() 方法
- 使用阈值验证(通过考虑其属性
coordinate.y)它是否足够接近图表数据系列之一;这可确保仅当鼠标光标非常靠近图形上的某个点时才绘制工具提示
- 修改其返回的 JSX 标记以仅包含与鼠标最接近的数据系列相关的值;如果图表中的更多点比阈值更接近,则工具提示将显示多个值
我的要点中的代码已被简化,以删除所有不必要的 JSX 标记。它提供了一个chart component,它使上述所有组件都起作用。
请注意,突出显示工具提示横坐标指向的所有数据系列的点的标准 Recharts 行为未更改。因此,最好在工具提示内容中放置一个颜色代码,以清楚地说明显示的值属于哪个数据系列。