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

React Highchart如何反转Tooltip中的数据显示顺序

问题描述

我用Highcharts渲染条形图,当前Tooltip里的内容是“Follow”在前、“Lead”在后,需要反转这个顺序,改成“Lead”在前、“Follow”在后,且对应各自的数据值。

现有代码

App.js

import {
  DummyData,
  PercentageBarChart,
} from "./Component/Sparkline/ChartCollection";
function App() {
  const mapperValue = (chartDetails, header) => {
    switch (chartDetails.type) {
      case "area": {
        const options = {
          series: [
            {
              data: chartDetails.data,
              pointStart: 1,
            },
          ],
          tooltip: {
            headerFormat: `<span style="font-size:10px">${header}, Q{point.x}: </span><br/>`,
            pointFormat: "<b>{point.y}.000</b> USD",
          },
          chart: {
            type: chartDetails.type,
          },
        };
        return <SparkLine options={options} />;
      }
      case "bar": {
        const color =
          chartDetails?.stacked === "normal"
            ? ["#B5E3D8", "#66C8C2", "#118C7D", "#004C45"]
            : ["#F5E887", "#00A499"];
        const series = chartDetails.data.map((item, index) => {
          return {
            ...item,
            color: color[index],
          };
        });
        const options = PercentageBarChart({
          series,
          stacked: chartDetails?.stacked || "percentage",
          dataLabel: chartDetails?.dataLabel,
          name: header,
        });

        return (
            <SparkLine options={options} />
        );
      }
      default:
        return chartDetails.data.map((item) => {
          return `${item.name} || `;
        });
    }
  };
}

ChartCollection.js

export const DummyData = [
  {
    name: "AON",
    lead_follow: {
      type: "bar",
      data: [
        { name: "Follow", data: [72] },
        { name: "Lead", data: [28] },
      ],
      dataLabel: {
        visible: true,
      },
    },
    types: {
      type: "bar",
      stacked: "normal",
      data: [
        { name: "Open", data: [45] },
        { name: "Deleg", data: [120] },
        { name: "Pool", data: [31] },
      ],
      dataLabel: {
        visible: false,
      },
    },
    avg_cost_acquisition: 35,
    avg_cost_brokerage: 23,
  },
];
const disableDataLabel = ["Follow", "Lead"];
export const PercentageBarChart = (props) => {
  props.series.forEach((seriesItem) => {
    if (disableDataLabel.includes(seriesItem.name)) {
      seriesItem.dataLabels = {
        enabled: false,
      };
    }
  });

  const plotOptions =
    props.stacked === "percentage"
      ? {
          bar: {
            stacking: "percent",
            dataLabels: {
              enabled: props.dataLabel.visible,
              format: "{point.y:.0f}%",
              x: props?.series?.dataLabel?.x || null,
              y: props?.series?.dataLabel?.y || null,
              verticalAlign: "middle",
              inside: false,
              style: {
                fontSize: "0.75rem",
                textOutline: "0px",
              },
            },
          },
        }
      : {
          series: {
            stacking: "normal",
            dataLabels: {
              enabled: props.dataLabel.visible,
              style: {
                fontSize: "0.75rem",
                textOutline: "0px",
              },
            },
          },
        };

  return {
    chart: {
      backgroundColor: "transparent",
      borderWidth: 0,
      type: "bar",
      margin: [2, 0, 2, 0],
      width: 200,
      height: 50,
      style: {
        overflow: "visible",
      },
      skipClone: true,
    },
    title: {
      text: null,
    },
    credits: {
      enabled: false,
    },
    yAxis: {
      endOnTick: false,
      startOnTick: false,
      labels: {
        enabled: false,
      },
      title: {
        text: null,
      },
      tickPositions: [0],
    },
    legend: {
      enabled: false,
      align: "left",
      x: 10,
      verticalAlign: "top",
      layout: "horizontal",
      y: 0,
    },
    tooltip: {
      headerFormat: `<span style="font-size:10px">${props.name}</span><br/>`,
      pointFormatter: function () {
        console.log("inside point formattor", this);
        var point = this,
          series = point.series;
        return `<div style="align-items: baseline">${series.name} <hr style="display:inline-block; position: relative; top: 5px; width:${point.y}px; height: 10px; font-size: 10px" color=${point.color}> <b>${point.y}</b><br /></div>`;
      },
    },
    plotOptions: plotOptions,
    series: props.series || [],
  };
};
我的尝试

我曾在App.js里修改代码,尝试添加反转后的series到options中,但没有效果:

//.......
const options = PercentageBarChart({
      series,
      stacked: chartDetails?.stacked || "percentage",
      dataLabel: chartDetails?.dataLabel,
      name: header,
    });

const modifiedOptions = JSON.parse(JSON.stringify(options));

modifiedOptions["tooltipSeries"] = [...series].reverse();
console.log({ modifiedOptions });
//......
解决方案

问题出在你自定义的tooltipSeries属性不是Highcharts的合法配置,Highcharts不会识别它。要反转Tooltip的展示顺序,需要修改tooltip的formatter函数(替换原来的pointFormatter),手动控制所有点的渲染顺序:

修改ChartCollection.js中PercentageBarChart的tooltip配置:

tooltip: {
  headerFormat: `<span style="font-size:10px">${props.name}</span><br/>`,
  formatter: function () {
    // 获取当前x轴对应的所有系列数据点
    const points = this.points;
    // 反转点的顺序,实现Lead在前、Follow在后
    const reversedPoints = [...points].reverse();
    // 生成每个点的HTML内容并拼接
    return reversedPoints.map(point => {
      return `<div style="align-items: baseline">${point.series.name} <hr style="display:inline-block; position: relative; top: 5px; width:${point.y}px; height: 10px; font-size: 10px" color=${point.color}> <b>${point.y}</b><br /></div>`;
    }).join('');
  },
},

这个方法的核心是利用Highcharts tooltip的formatter函数可以获取当前鼠标位置对应的所有系列点(this.points),将这个数组反转后再逐个生成HTML内容,既能保证Tooltip的顺序符合需求,又不会改变条形图本身的堆叠显示顺序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 05:26:02