Skip to content

Instantly share code, notes, and snippets.

@ngbrown
Last active August 11, 2023 08:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ngbrown/f8bb039cacc56f65a5424d6577866b80 to your computer and use it in GitHub Desktop.
Save ngbrown/f8bb039cacc56f65a5424d6577866b80 to your computer and use it in GitHub Desktop.
Updated uplot-react
// Adapted from https://github.com/skalinichev/uplot-wrappers
// MIT license
import type { JSX } from "react";
import React, { useCallback, useEffect, useRef } from "react";
import uPlot from "uplot";
import { dataMatch, optionsUpdateState } from "./uplot-wrappers-common.js";
export default function UplotReact({
options,
data,
target,
onDelete,
onCreate,
resetScales = true,
className,
}: {
options: uPlot.Options;
data: uPlot.AlignedData;
target?: HTMLElement | ((self: uPlot, init: Function) => void);
onDelete?: (chart: uPlot) => void;
onCreate?: (chart: uPlot) => void;
resetScales?: boolean;
className?: string;
}): JSX.Element | null {
const chartRef = useRef<uPlot | null>(null);
const targetRef = useRef<HTMLDivElement>(null);
const propOptionsRef = useRef(options);
const propTargetRef = useRef(target);
const propDataRef = useRef(data);
const destroy = useCallback(
(chart: uPlot | null) => {
if (chart) {
onDelete?.(chart);
chart.destroy();
chartRef.current = null;
}
},
[onDelete]
);
const create = useCallback(() => {
const newChart = new uPlot(
propOptionsRef.current,
propDataRef.current,
propTargetRef.current || (targetRef.current as HTMLDivElement)
);
chartRef.current = newChart;
onCreate?.(newChart);
}, [onCreate]);
useEffect(() => {
create();
return () => {
destroy(chartRef.current);
};
}, [create, destroy]);
useEffect(() => {
if (propOptionsRef.current !== options) {
const optionsState = optionsUpdateState(propOptionsRef.current, options);
propOptionsRef.current = options;
if (!chartRef.current || optionsState === "create") {
destroy(chartRef.current);
create();
} else if (optionsState === "update") {
chartRef.current.setSize({
width: options.width,
height: options.height,
});
}
}
}, [options, create, destroy]);
useEffect(() => {
if (propDataRef.current !== data) {
if (!chartRef.current) {
propDataRef.current = data;
create();
} else if (!dataMatch(propDataRef.current, data)) {
if (resetScales) {
chartRef.current.setData(data, true);
} else {
chartRef.current.setData(data, false);
chartRef.current.redraw();
}
}
propDataRef.current = data;
}
}, [data, resetScales, create]);
useEffect(() => {
if (propTargetRef.current !== target) {
propTargetRef.current = target;
create();
}
const chart = chartRef.current;
return chart ? () => destroy(chart) : undefined;
}, [target, create, destroy]);
return target ? null : <div ref={targetRef} className={className}></div>;
}
export const AxisSideTop = 0;
export const AxisSideRight = 1;
export const AxisSideBottom = 2;
export const AxisSideLeft = 3;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment