我想根据条形的宽度动态地允许条形图上的标签 - 如果条形变薄,则标签看起来不太好并且经常重叠。然而,我真的不想搞乱一些低级的 SVG 元素操作,nivo 必须使用一些东西来计算条形的宽度;我可以使用同样的方法来确定标签是否合适。我期待 d3 直接给我一些东西,但我不知道。
所以我浏览了nivo的源代码,经过一些搜索,我找到了我正在寻找的东西(有点)这里:
const bandwidth = (indexScale.bandwidth() - innerPadding * (keys.length - 1)) / keys.length
这是分组条形图的版本(与堆叠相反,但在这种情况下它只是
= indexScale.bandwidth()
),其中 innerPadding
是组中条形之间的填充,keys
是用于单组。然而,indexScale
是一个用(我正在简化)createBandScale
创建的内部对象,你可以在here看到:
export const createBandScale = <Input extends StringValue>(
{ round = true }: ScaleBandSpec,
data: ComputedSerieAxis<Input>,
size: number,
axis: ScaleAxis
) => {
const scale = scaleBand<Input>()
.range(axis === 'x' ? [0, size] : [size, 0])
.domain(data.all)
.round(round)
return castBandScale<Input>(scale)
}
此功能可通过
@nivo/scales
获得,因此我可以将其用于我的目的。然而,在做了一些测试之后,我发现我的结果不对——计算似乎忽略了组之间的填充,因此我计算的宽度大于实际的条宽度;我不知道为什么会这样,也许这被认为是更进一步的事情,但出于我的目的,我只需要创建一个像这样的BandScale
:
const bandScale = createBandScale(
{ round: false },
{ all: xAxis },
totalWidth,
"x"
).paddingInner(padding) // << this is the important part
剩下的唯一挑战是计算 SVG 元素的总宽度,幸运的是 nivo 的代码库有这种钩子,但它不是包的一部分,所以我最终将它添加到我自己的代码中 - here 是钩子。