lightweight-charts实现表格随着时间范围切换数据展示

676 阅读2分钟

自定义hook:useHistoryChart

完整的hook代码

import { createChart } from "lightweight-charts";
let chart;
let lineSeriesYes;
let lineSeriesNo;

//  chart,lineSeriesYes,lineSeriesNo
const useHistoryChart = (
  historyPrice,
  isMobile,
  activeIndex,
  setActiveIndex,
  chartContainerRef,
  chartDataYes,
  setChartDataYes,
  chartDataNo,
  setChartDataNo
) => {
  //历史图表
  const [isTimeScaleActive, setIsTimeScaleActive] = useState(false);
  const [chartHeight, setChartHeight] = useState(370);

  useEffect(() => {
    // 首先要确保表格数据拿到 再去生成 不然会报undefined的错
    if (historyPrice && chartDataYes && chartDataNo) {
      // 如果表格没有生成才进入这个if判断 生成表格
      if (chartContainerRef.current) {
        if ((chartContainerRef.current as HTMLElement).childNodes.length == 0) {
          chart = createChart(chartContainerRef.current, {
            width: isMobile ? 366 : 900,
            height: chartHeight,
            handleScale: {
              mouseWheel: false,
              axisPressedMouseMove: false,
            },
            handleScroll: {
              pressedMouseMove: false,
              vertTouchDrag: false,
            },
            leftPriceScale: {
              borderVisible: false,
            },
            rightPriceScale: {
              visible: true,
              borderVisible: false,
            },
            timeScale: {
              borderVisible: false,
              timeVisible: true,
              tickMarkFormatter: (time, tickMarkType) => {
                const activeTimeScale = activeIndex;
                console.log("activeTimeScale", activeTimeScale);
                console.log("tickMarkType", tickMarkType);
                const date1 = new Date(time * 1000).toLocaleString("en-US", {
                  hour: "numeric",
                  minute: "numeric",
                  hour12: true,
                });
                const date2 = new Date(time * 1000).toLocaleString("en-US", {
                  month: "short",
                  day: "numeric",
                  hour12: true,
                });
                if (
                  activeTimeScale == 0 ||
                  activeTimeScale == 1 ||
                  activeTimeScale == 2
                ) {
                  return date1;
                } else {
                  return date2;
                }
              },
            },
            localization: {
              priceFormatter: (price) => {
                return "$" + price.toFixed(2);
              },
              timeFormatter: (time) => {
                const date = new Date(time * 1000).toLocaleString("en-US", {
                  month: "short",
                  day: "numeric",
                  year: "numeric",
                  hour: "numeric",
                  minute: "numeric",
                  hour12: true,
                });
                return date;
              },
            },
            layout: {
              fontFamily: "Heebo,sans-serif",
              textColor: "#fff",
              background: {
                color: "#0e1520",
              },
            },
            grid: {
              vertLines: {
                visible: false,
              },
              horzLines: {
                visible: false,
              },
            },
          });
          lineSeriesYes = chart?.addLineSeries({
            color: "#FF6933",
          });
          lineSeriesNo = chart?.addLineSeries({
            color: "#FF6933",
          });
        }
      }

      // 拿到数据后要做排成升序 才能传入setData
      const sortChartDataYes = chartDataYes?.sort((a, b) => a.time - b.time);
      lineSeriesYes?.setData(sortChartDataYes);

      let sortChartDataNo = chartDataNo?.sort((a, b) => a.time - b.time);
      lineSeriesNo?.setData(sortChartDataNo);

      chart?.applyOptions({
        timeScale: {
          // 时间提示 就是鼠标在表格线上滑动会展示对应的时间戳
          tickMarkFormatter: (time) => {
            const activeTimeScale = activeIndex;
            const date1 = new Date(time * 1000).toLocaleString("en-US", {
              second: "numeric",
              minute: "numeric",
              hour: "numeric",
              hour12: true,
            });
            const date2 = new Date(time * 1000).toLocaleString("en-US", {
              hour: "numeric",
              minute: "numeric",
              hour12: true,
            });
            const date3 = new Date(time * 1000).toLocaleString("en-US", {
              month: "short",
              weekday: "short",
              // hour12: true,
            });
            const date4 = new Date(time * 1000).toLocaleString("en-US", {
              month: "short",
              day: "numeric",
              // hour12: true,
            });
            if (activeTimeScale == 0) {
              return date1;
            } else if (activeTimeScale == 1 || activeTimeScale == 2) {
              return date2;
            } else if (activeTimeScale == 3) {
              return date3;
            } else {
              return date4;
            }
          },
        },
      });

      // left top title
      var toolTip = document.createElement("div");
      toolTip.className = "leftTopTitle";
      toolTip.id = "tooltip-id";
      (chartContainerRef.current as HTMLDivElement).appendChild(toolTip);
      toolTip.style.display = "block";
      toolTip.style.fontWeight = "500";
      toolTip.style.position = "absolute";
      toolTip.style.left = 20 + "px";
      toolTip.style.top = "-" + 8 + "px";
      toolTip.style.zIndex = "10";
      // get the title of the chart
      const setToolTip = () => {
        toolTip.innerHTML =
          `<div style="font-size: 16px; margin: 4px 0px; color:#FFF;">
          YES 
          </div>` +
          `<div style="font-size: 22px; margin: 4px 0px; color:#FFF" >` +
          0.5 +
          "$" +
          "</div>";
      };
      setToolTip();
      //update the title base on the mousemove
      chart?.subscribeCrosshairMove(function (param) {
        if (
          param === undefined ||
          param.time === undefined ||
          param.point.x < 0 ||
          param.point.x > 900 ||
          param.point.y < 0 ||
          param.point.y > 390
        ) {
          setToolTip();
        } else {
          const seriesData = param.seriesData;

          if (seriesData && seriesData.size > 0) {
            // Get the first entry
            const firstEntry = seriesData.values().next().value;
            if (firstEntry) {
              const yesValue = `${firstEntry.value}$`;
              console.log("yesValue", yesValue);
              toolTip.innerHTML =
                `<div style="font-size: 16px; margin: 4px 0px; color:#FFF;">
        YES 
        </div>` +
                `<div style="font-size: 22px; margin: 4px 0px; color:#FFF" >` +
                yesValue +
                "</div>";
            }
          }
        }
      });
      chart?.timeScale().fitContent();
    }
  }, [chartDataYes, chartDataNo, isTimeScaleActive, activeIndex]);

  function updateYesLine(chartDataYes, index = 0) {
    chartDataYes?.sort((a, b) => a.time - b.time);
    setChartDataYes(chartDataYes);
  }

  function updateNoLine(chartDataNo, index = 0) {
    // console.log("")
    chartDataNo?.sort((a, b) => a.time - b.time);
    setChartDataNo(chartDataNo);
  }
  // 点击时间范围的按钮会调用这个函数
  function handleChangeTimeScale(index) {
    console.log("handleChangeTimeScale index", index);
    if (activeIndex == index) {
      return;
    }
    setActiveIndex(index);
    setIsTimeScaleActive(true);
    updateYesLine(historyPrice[index]["price_list"]["option0"], index);
    updateNoLine(historyPrice[index]["price_list"]["option1"], index);
  }

  return { updateYesLine, updateNoLine, handleChangeTimeScale };
};
export default useHistoryChart;

使用hook

点击切换时间范围的时候数据没有对应更新 刚进来的时候表格没有生成 是因为chartDataYes没有值,所以chartDataYes变量要定义在hook的外面,从接口拿到数据就setchartDataYes

  interface ChartData {   
    time: number;
    value: number;
  }
  const [chartDataYes, setChartDataYes] = useState<ChartData[]>();
  const [chartDataNo, setChartDataNo] = useState<ChartData[]>();
  const chartContainerRef = useRef();
const { handleChangeTimeScale} =useHistoryChart(historyPrice, isMobile, activeIndex,setActiveIndex,chartContainerRef,chartDataYes, setChartDataYes,chartDataNo, setChartDataNo)

html

       {/*  表格 */}
                    <Box
                      width={{
                        xs: "360px",
                        sm: "500px",
                        md: "700px",
                        lg: "1000px",
                      }}
                    >
                      <div
                        className={styles.tableContainer}
                        id="tableContainer"
                        style={{ width: "100%" }}
                      >
                        <div
                          ref={chartContainerRef}
                          id="test-id"
                          style={{ position: "relative" }}
                        />
                      </div>
                    </Box>

                    <hr className={styles.horizontalLine} />
                    {/*  时间范围筛选按钮 */}
                    <ButtonGroup
                      variant="text"
                      aria-label="text button group"
                      className={styles.timeScaleBar}
                    >
                      <Button
                        className={`${
                          activeIndex == 0 ? styles.activeTimeScale : ""
                        } ${styles.timeScaleBtn}`}
                        // focusable="false"
                        // quaternary
                        // size="small"
                        onClick={() => handleChangeTimeScale(0)}
                      > 
                        1H
                      </Button>
                      <Button
                        className={`${
                          activeIndex == 1 ? styles.activeTimeScale : ""
                        } ${styles.timeScaleBtn}`}
                        onClick={() => handleChangeTimeScale(1)}
                      >
                        6H
                      </Button>
                      <Button
                        className={`${
                          activeIndex == 2 ? styles.activeTimeScale : ""
                        } ${styles.timeScaleBtn}`}
                        onClick={() => handleChangeTimeScale(2)}
                      >
                        1D
                      </Button>
                      <Button
                        className={`${
                          activeIndex == 3 ? styles.activeTimeScale : ""
                        } ${styles.timeScaleBtn}`}
                        onClick={() => handleChangeTimeScale(3)}
                      >
                        1W
                      </Button>
                      <Button
                        className={`${
                          activeIndex == 4 ? styles.activeTimeScale : ""
                        } ${styles.timeScaleBtn}`}
                        onClick={() => handleChangeTimeScale(4)}
                      >
                        1M
                      </Button>
                      <Button
                        className={`${
                          activeIndex == 5 ? styles.activeTimeScale : ""
                        } ${styles.timeScaleBtn}`}
                        onClick={() => handleChangeTimeScale(5)}
                      >
                        ALL
                      </Button>
                    </ButtonGroup>

点击时间范围后生成 然后再点击就不会切换线了 是因为变量的定义位置 lineSeriesYes会变成undefined 改变变量定义的位置即可,要定义在hook文件

let chart;
let lineSeriesYes;
let lineSeriesNo;

//  chart,lineSeriesYes,lineSeriesNo
const useHistoryChart = (
  historyPrice,
  isMobile,
。。。