You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nivo响应式柱状图自定义警告线页面缩放偏移问题求助

Nivo响应式柱状图警告线缩放偏移问题解决

问题背景

在Nivo响应式水平柱状图的每个条形上添加自定义警告级别线,页面缩放时警告线位置会偏移,无法保持在预期位置。

依赖版本

  • next: ~12.2.4
  • @nivo/bar: ~0.79.1
  • @nivo/core: ~0.78.0

原组件代码

import CardComponent from '@components/CardComponent';
import NivoWrapper from '@components/NivoWrapper';
import { ResponsiveBar } from '@nivo/bar';
import React from 'react';

const data = [
  {
    x: '0',
    name: 'weight5',
    current: 200,
    warningLevel: 100,
  },
  {
    x: '1',
    name: 'weight2',
    current: 300,
    warningLevel: 150,
  },
  {
    x: '2',
    name: 'weight3',
    current: 400,
    warningLevel: 200,
  },
  {
    x: '3',
    name: 'weight4',
    current: 500,
    warningLevel: 250,
  },
  {
    x: '4',
    name: 'weight5',
    current: 600,
    warningLevel: 300,
  },
];

const MarginTop = 0;
const Marginright = 24;
const Marginbottom = 24;
const Marginleft = 64;

function Line({ bars, xScale }) {
  return (
      {bars.map((bar: any) => {
        return (
          <line
            key={bar.key}
            y1={bar.absY}
            y2={bar.absY + bar.height}
            x1={xScale(bar.width - bar.data.data.warningLevel - bar.data.data.warningLevel)}
            x2={xScale(bar.width - bar.data.data.warningLevel - bar.data.data.warningLevel)}
            stroke="black"
          />
        );
      })}
  );
}

function PackageStockLevelChart() {
  return (
      <NivoWrapper>
        <ResponsiveBar
          data={data}
          indexBy="name"
          keys={['current']}
          layout="horizontal"
          enableLabel={false}
          axisLeft={{
            tickValues: 7,
          }}
          margin={{
            top: MarginTop, right: Marginright, bottom: Marginbottom, left: Marginleft,
          }}
          enableGridY={false}
          colors="green"
          legendLabel="legend label"
          legends=[{{
            dataFrom: 'keys',
            anchor: 'bottom-right',
            direction: 'column',
            itemWidth: 80,
            itemHeight: 16,
            translateY: -16,
          }}]
          layers={['axes', 'bars', Line, 'legends']}
        />
      </NivoWrapper>
  );
}

export default PackageStockLevelChart;

问题原因

  1. 坐标计算错误:原代码用bar.width结合警告级别计算x坐标,未利用Nivo提供的xScale比例尺做数值到像素的正确映射,缩放时图表数值范围和容器尺寸变化,自定义计算无法适配。
  2. JSX结构不合法:Line组件直接返回多个line元素数组,缺少外层包裹元素,不符合React组件返回要求。
  3. 语法错误:legends属性使用双大括号,导致语法异常。

解决方案

修正Line组件的坐标计算逻辑,使用Nivo比例尺正确映射警告级别数值,同时修复JSX结构和语法错误。

修正后的完整代码

import CardComponent from '@components/CardComponent';
import NivoWrapper from '@components/NivoWrapper';
import { ResponsiveBar } from '@nivo/bar';
import React from 'react';

const data = [
  {
    x: '0',
    name: 'weight5',
    current: 200,
    warningLevel: 100,
  },
  {
    x: '1',
    name: 'weight2',
    current: 300,
    warningLevel: 150,
  },
  {
    x: '2',
    name: 'weight3',
    current: 400,
    warningLevel: 200,
  },
  {
    x: '3',
    name: 'weight4',
    current: 500,
    warningLevel: 250,
  },
  {
    x: '4',
    name: 'weight5',
    current: 600,
    warningLevel: 300,
  },
];

const MarginTop = 0;
const Marginright = 24;
const Marginbottom = 24;
const Marginleft = 64;

function Line({ bars, xScale }) {
  return (
    <g>
      {bars.map((bar: any) => (
        <line
          key={bar.key}
          y1={bar.absY}
          y2={bar.absY + bar.height}
          x1={xScale(bar.data.warningLevel)}
          x2={xScale(bar.data.warningLevel)}
          stroke="black"
          strokeWidth={2}
        />
      ))}
    </g>
  );
}

function PackageStockLevelChart() {
  return (
    <NivoWrapper>
      <ResponsiveBar
        data={data}
        indexBy="name"
        keys={['current']}
        layout="horizontal"
        enableLabel={false}
        axisLeft={{
          tickValues: 7,
        }}
        margin={{
          top: MarginTop, right: Marginright, bottom: Marginbottom, left: Marginleft,
        }}
        enableGridY={false}
        colors="green"
        legendLabel="legend label"
        legends={[
          {
            dataFrom: 'keys',
            anchor: 'bottom-right',
            direction: 'column',
            itemWidth: 80,
            itemHeight: 16,
            translateY: -16,
          },
        ]}
        layers={['axes', 'bars', Line, 'legends']}
      />
    </NivoWrapper>
  );
}

export default PackageStockLevelChart;

关键修改点

  1. Line组件添加外层<g>标签:确保组件返回单个合法JSX元素,避免React渲染错误。
  2. 用xScale映射警告级别:直接将bar.data.warningLevel传入xScale,该比例尺由Nivo根据当前图表数值范围和容器尺寸自动计算,缩放时实时更新,保证警告线位置始终匹配警告级别数值。
  3. 修复legends语法错误:将双大括号改为单大括号,符合React属性传递规范。
  4. 可选优化:添加strokeWidth让警告线更清晰。

内容的提问来源于stack exchange,提问作者Adam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 02:25:40