Skip to content

Commit

Permalink
fix: wait for uPlot to be ready to setData or setSize [DET-5343] (#2283)
Browse files Browse the repository at this point in the history
  • Loading branch information
apizzini authored Apr 28, 2021
1 parent c367fc7 commit 76fe5c8
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 32 deletions.
45 changes: 27 additions & 18 deletions webui/react/src/components/UPlotChart.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React, { useEffect, useMemo, useRef, useState } from 'react';
import React, {
forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState,
} from 'react';
import { throttle } from 'throttle-debounce';
import uPlot, { AlignedData } from 'uplot';

Expand All @@ -12,36 +14,50 @@ export interface Options extends Omit<uPlot.Options, 'width'> {
interface Props {
data?: AlignedData;
options?: Options;
ref?: React.Ref<uPlot|undefined>;
}

const SCROLL_THROTTLE_TIME = 500;

const UPlotChart: React.FC<Props> = ({ data, options }: Props) => {
const UPlotChart: React.FC<Props> = forwardRef((
{ data, options }: Props,
ref?: React.Ref<uPlot|undefined>,
) => {
const [ chart, setChart ] = useState<uPlot>();
const chartDivRef = useRef<HTMLDivElement>(null);

const hasData: boolean = useMemo(() => {
// no x values
if (!data || data[0].length === 0) return false;
// series values length not matching x values length
data.forEach(dataSerie => {
if (dataSerie.length !== data[0].length) return false;
});
return true;
}, [ data ]);

/*
* Chart setup.
*/
useEffect(() => {
if (!chartDivRef.current || !options) return;
if (!chartDivRef.current || !hasData || !options) return;

const optionsExtended = uPlot.assign(
{
cursor: { drag: { dist: 5, uni: null, x: true, y: true } },
hooks: { ready: [ (chart: uPlot) => setChart(chart) ] },
width: chartDivRef.current.offsetWidth,
},
options,
);

const plotChart = new uPlot(optionsExtended as uPlot.Options, [ [] ], chartDivRef.current);
setChart(plotChart);

return () => {
setChart(undefined);
plotChart.destroy();
};
}, [ chartDivRef, options ]);
}, [ chartDivRef, hasData, options ]);

/*
* Chart data.
Expand All @@ -56,7 +72,7 @@ const UPlotChart: React.FC<Props> = ({ data, options }: Props) => {
*/
const resize = useResize(chartDivRef);
useEffect(() => {
if (!chart || !options?.height) return;
if (!chart || !options?.height || !resize.width) return;
chart.setSize({ height: options.height, width: resize.width });
}, [ chart, options?.height, resize ]);

Expand All @@ -83,18 +99,11 @@ const UPlotChart: React.FC<Props> = ({ data, options }: Props) => {
};
}, [ chart ]);

/*
* Don't plot the chart if there are no X values.
*/
const hasData: boolean = useMemo(() => {
return !!(data && data[0].length > 0);
}, [ data ]);

if (!hasData) {
return <Message title="No data to plot." type={MessageType.Empty} />;
}
useImperativeHandle(ref, () => chart, [ chart ]);

return <div ref={chartDivRef} />;
};
return hasData
? <div ref={chartDivRef} />
: <Message title="No data to plot." type={MessageType.Empty} />;
});

export default UPlotChart;
29 changes: 15 additions & 14 deletions webui/react/src/components/UPlotChart/tooltipsPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export const tooltipsPlugin = ({ getXTooltipHeader, getXTooltipYLabels }: Props
let tooltipEl: HTMLDivElement|null = null;

const _buildTooltipHtml = (uPlot: uPlot, idx: number): string => {
let hasValue = false;
let html = '';

let header: ChartTooltip = null;
Expand All @@ -43,8 +42,6 @@ export const tooltipsPlugin = ({ getXTooltipHeader, getXTooltipYLabels }: Props
const label = yLabels[i - 1] || null;
const valueRaw = uPlot.data[i][idx];

if (valueRaw) hasValue = true;

const cssClass = valueRaw ? css.valueY : css.valueYEmpty;
html += `<div class="${cssClass}">`
+ `<span class="${css.color}" style="background-color: ${glasbeyColor(i - 1)}"></span>`
Expand All @@ -53,7 +50,7 @@ export const tooltipsPlugin = ({ getXTooltipHeader, getXTooltipYLabels }: Props
+ '</div>';
});

return (hasValue ? html : '');
return html;
};

const _getTooltipLeftPx = (uPlot: uPlot, idx: number): number => {
Expand Down Expand Up @@ -115,25 +112,29 @@ export const tooltipsPlugin = ({ getXTooltipHeader, getXTooltipYLabels }: Props
barEl = document.createElement('div');
barEl.className = css.bar;
uPlot.root.querySelector('.u-over')?.appendChild(barEl);

},
setCursor: (uPlot: uPlot) => {
const { left, idx, top } = uPlot.cursor;

if (
(idx == null && displayedIdx)
|| !left || left < 0
|| !top || top < 0
) {
hide();
if (!left || left < 0 || !top || top < 0 || idx == null) {
if (displayedIdx) hide();
return;
}

if (idx != null && idx !== displayedIdx) {
showIdx(uPlot, idx);
if (idx !== displayedIdx) {
const hasXValue = !!uPlot.series.find((serie, serieId) => (
serie.scale !== 'x' && serie.show && !!uPlot.data[serieId][idx]
));
if (hasXValue) {
showIdx(uPlot, idx);
} else {
hide();
}
}

_updateTooltipVerticalPosition(uPlot, top);
if (displayedIdx) {
_updateTooltipVerticalPosition(uPlot, top);
}
},
},
};
Expand Down

0 comments on commit 76fe5c8

Please sign in to comment.