关于 React 如何自定义配置 HighCharts tooltip

news/2024/7/15 18:29:00 标签: javascript, react.js

前言

当我们结合 React 使用 highCharts 库时,存在一些特殊自定义的情况,比如针对 Tooltip 定制化样式。当然 highCharts 也提供了配置自定义 tooltip 的 formatter 方法,可以支持 html 元素。但是并不够灵活,对于配置复杂样式或组件复用情况下,并不友好。因此寻求新的思路,以下便是社区常用的一个方法,在此记录。

实现

Tooltip 组件封装

javascript">import {
  Chart,
  TooltipFormatterCallbackFunction,
  TooltipFormatterContextObject,
} from 'highcharts';
import { useEffect, useRef, useState } from 'react';
import ReactDOM from 'react-dom';

const generateTooltipId = (chartId: number) =>
  `highcharts-custom-tooltip-${chartId}`;

interface Props {
  chart: Chart | null;
  children(formatterContext: TooltipFormatterContextObject): JSX.Element;
}

export const Tooltip = ({ chart, children }: Props) => {
  const isInit = useRef(false);
  const [context, setContext] = useState<TooltipFormatterContextObject | null>(
    null
  );

  useEffect(() => {
    if (chart) {
      const formatter: TooltipFormatterCallbackFunction = function () {
        // Ensures that tooltip DOM container is rendered before React portal is created.
        if (!isInit.current) {
          isInit.current = true;

          setTimeout(() => {
            chart.tooltip.refresh.apply(chart.tooltip, [
              this.points ? this.points.map(({ point }) => point) : this.point,
            ]);
            chart.tooltip.hide(0);
          });
        }

        setContext(this);

        return `<div id="${generateTooltipId(chart.index)}"></div>`;
      };

      chart.update({
        tooltip: {
          formatter,
          useHTML: true,
        },
      });
    }
  }, [chart]);

  const node = chart && document.getElementById(generateTooltipId(chart.index));

  return node && context
    ? ReactDOM.createPortal(children(context), node)
    : null;
};

调用方式

javascript">import React, { useState, useCallback } from "react";
import Highcharts, { Chart as HighchartsChart } from "highcharts";
import HighchartsReact from "highcharts-react-official";
import { Tooltip } from "./Tooltip";

const options = {
  title: {
    text: "Custom tooltip as React component"
  },
  series: [
    {
      type: "line",
      data: [1, 22424242424, 3, 4, 5, 123123132]
    }
  ],
  tooltip: {
    useHTML: true
  }
};

export const Chart = () => {
  const [chart, setChart] = useState<HighchartsChart | null>(null);
  const callback = useCallback((chart: HighchartsChart) => {
    setChart(chart);
  }, []);

  return (
    <>
      <HighchartsReact
        highcharts={Highcharts}
        options={options}
        callback={callback}
      />

      <Tooltip chart={chart}>
        {(formatterContext) => {
          const { x, y } = formatterContext;
          return (
            <>
              <div>x: {x}</div>
              <div>y: {y}</div>
              <br />
              <button onClick={() => alert(`x: ${x}, y: ${y}`)}>Action</button>
            </>
          );
        }}
      </Tooltip>
    </>
  );
};

formatterContext 里包含以下常用的字段:

javascript">{
	points
	point
	series
	x
	y
}

这些字段在自定义 tooltip 组件时可以传参到组件中获取每个 point 的值。
除了 x,y 值外,可以自定义字段,在 series.keys 配置项中,配置如下:

javascript">keys: [
  'x',
  'y',
  'custom.A',
  'custom.B',
  'custom.C',
],
data:[[1, 2, 'A1', 'B1', 'C1'], [1, 2, 'A2', 'B2', 'C2']]

其值便可以在 formatterContext.point.options.custom.AformatterContext.point.options.custom.B 等方式获取。

总结

该实现方式最基本的原理是采用 React 的 createPortal 方法,在指定的元素下渲染子元素。可以理解为类似纯 js 的 getElementById('id').html(children(context))


http://www.niftyadmin.cn/n/5239326.html

相关文章

自动驾驶:传感器初始标定

手眼标定 机器人手眼标定AxxB&#xff08;eye to hand和eye in hand&#xff09;及平面九点法标定 Ax xB问题求解&#xff0c;旋转和平移分步求解法 手眼标定AXXB求解方法&#xff08;文献总结&#xff09; 基于靶的方法 相机标定 (1) ApriTag (2) 棋盘格&#xff1a;cv::f…

如何通过DB操作地理空间数据

从公众号转载&#xff0c;关注微信公众号掌握更多技术动态 --------------------------------------------------------------- 一、PostgreSQL PostgreSQL是一个强大的对象关系数据库管理系统&#xff08;ORDBMS&#xff09;。它是在BSD风格的许可下发布的&#xff0c;因此是自…

代码随想录刷题题Day5

刷题的第五天&#xff0c;希望自己能够不断坚持下去&#xff0c;迎来蜕变。&#x1f600;&#x1f600;&#x1f600; 刷题语言&#xff1a;C / Python Day5 任务 ● 哈希表理论基础 ● 242.有效的字母异位词 ● 349. 两个数组的交集 ● 202. 快乐数 ● 1. 两数之和 1 哈希表理…

SpringBoot之logback 在Linux系统上启动的时候,设置日志按日期分割并设置指定时间自动清除日志

一、在src/main/resources/下创建logback-spring.xml文件 <?xml version"1.0" encoding"UTF-8"?> <configuration><!-- 日志存放路径 --><property name"log.path" value"/home/xmmc/logs" /><!-- 日志…

JS的监听事件

在JavaScript中&#xff0c;你可以使用监听器来捕获和处理不同类型的事件。通过添加事件监听器&#xff0c;你可以指定当特定事件发生时要执行的函数。 以下是几种常见的监听事件的方法&#xff1a; 1. addEventListener()&#xff1a;用于在目标元素上添加事件监听器。它接受…

发明无止境:简单的螺丝钉也有复杂悠久的专利故事?

今天跟大家分享一个螺丝钉专利的故事。 我们从人类开始就有了连接和固定的需求。 最早期的时候&#xff0c;人类就想到了连接和固定最简单的办法就是用钉子把两个物体连接在一起&#xff0c;最早的时候用的是木钉或者楔子。用木钉和楔子的方式简单粗暴&#xff0c;成本也非常的…

【Vulnhub 靶场】【Prime (2021): 2】【简单 - 中等】【20210509】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/prime-2021-2,696/ 靶场下载&#xff1a;https://download.vulnhub.com/prime-2021/Prime-2.ova 靶场难度&#xff1a;简单 - 中等 发布日期&#xff1a;2021年5月9日 文件大小&#xff1a;3.7 GB 靶场作者&am…

微信小程序调用相机拍摄或手机相册

wx.chooseMedia(Object object) 功能描述 拍摄或从手机相册中选择图片或视频。