fix: update logic for handling data for uplot charts (#4131)

* fix: update logic for handling data for uplot charts

* fix: hide tooltip if no tooltip values present

* fix: remove console log
This commit is contained in:
Yunus M 2023-12-01 17:08:24 +05:30 committed by GitHub
parent b616dca52d
commit 3e29161fea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 95 additions and 128 deletions

View File

@ -107,48 +107,8 @@ function RightContainer({
}
/>
{/* <TextContainer>
<Typography>Stacked Graphs :</Typography>
<Switch
checked={stacked}
onChange={(): void => {
setStacked((value) => !value);
}}
/>
</TextContainer> */}
{/* <Title light={'true'}>Fill Opacity: </Title> */}
{/* <Slider
value={parseInt(opacity, 10)}
marks={{
0: '0',
33: '33',
66: '66',
100: '100',
}}
onChange={(number): void => onChangeHandler(setOpacity, number.toString())}
step={1}
/> */}
{/* <Title light={'true'}>Null/Zero values: </Title>
<NullButtonContainer>
{nullValueButtons.map((button) => (
<Button
type={button.check === selectedNullZeroValue ? 'primary' : 'default'}
key={button.name}
onClick={(): void =>
onChangeHandler(setSelectedNullZeroValue, button.check)
}
>
{button.name}
</Button>
))}
</NullButtonContainer> */}
<Space style={{ marginTop: 10 }} direction="vertical">
<Typography>Fill span gaps</Typography>
<Typography>Fill gaps</Typography>
<Switch
checked={isFillSpans}

View File

@ -29,6 +29,8 @@ const generateTooltipContent = (
): HTMLElement => {
const container = document.createElement('div');
container.classList.add('tooltip-container');
const overlay = document.getElementById('overlay');
let tooltipCount = 0;
let tooltipTitle = '';
const formattedData: Record<string, UplotTooltipDataProps> = {};
@ -49,28 +51,40 @@ const generateTooltipContent = (
const { metric = {}, queryName = '', legend = '' } =
seriesList[index - 1] || {};
const value = data[index][idx];
const label = getLabelName(metric, queryName || '', legend || '');
const value = data[index][idx] || 0;
const tooltipValue = getToolTipValue(value, yAxisUnit);
if (value) {
const tooltipValue = getToolTipValue(value, yAxisUnit);
const dataObj = {
show: item.show || false,
color: colors[(index - 1) % colors.length],
label,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
focus: item?._focus || false,
value,
tooltipValue,
textContent: `${label} : ${tooltipValue}`,
};
const dataObj = {
show: item.show || false,
color: colors[(index - 1) % colors.length],
label,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
focus: item?._focus || false,
value,
tooltipValue,
textContent: `${label} : ${tooltipValue}`,
};
formattedData[label] = dataObj;
tooltipCount += 1;
formattedData[label] = dataObj;
}
}
});
}
// Show tooltip only if atleast only series has a value at the hovered timestamp
if (tooltipCount <= 0) {
if (overlay && overlay.style.display === 'block') {
overlay.style.display = 'none';
}
return container;
}
const sortedData: Record<
string,
UplotTooltipDataProps
@ -116,8 +130,6 @@ const generateTooltipContent = (
});
}
const overlay = document.getElementById('overlay');
if (overlay && overlay.style.display === 'none') {
overlay.style.display = 'block';
}

View File

@ -1,44 +1,65 @@
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { QueryData } from 'types/api/widgets/getQuery';
// eslint-disable-next-line sonarjs/cognitive-complexity
function fillMissingTimestamps(
sortedTimestamps: number[],
subsetArray: any[],
fillSpans: boolean | undefined,
): any[] {
const filledArray = [];
function getXAxisTimestamps(seriesList: QueryData[]): number[] {
const timestamps = new Set();
let subsetIndex = 0;
// eslint-disable-next-line no-restricted-syntax
for (const timestamp of sortedTimestamps) {
if (
subsetIndex < subsetArray.length &&
timestamp === subsetArray[subsetIndex][0]
) {
// Timestamp is present in subsetArray
const seriesPointData = subsetArray[subsetIndex];
seriesList.forEach((series: { values: [number, string][] }) => {
series.values.forEach((value) => {
timestamps.add(value[0]);
});
});
if (
seriesPointData &&
Array.isArray(seriesPointData) &&
seriesPointData.length > 0 &&
seriesPointData[1] !== 'NaN'
) {
filledArray.push(subsetArray[subsetIndex]);
} else {
const value = fillSpans ? 0 : null;
filledArray.push([seriesPointData[0], value]);
}
const timestampsArr: number[] | unknown[] = Array.from(timestamps) || [];
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return timestampsArr.sort((a, b) => a - b);
}
subsetIndex += 1;
} else {
// Timestamp is missing in subsetArray, fill with [timestamp, 0]
function fillMissingXAxisTimestamps(
timestampArr: number[],
data: any[],
fillSpans: boolean,
): any {
// Generate a set of all timestamps in the range
const allTimestampsSet = new Set(timestampArr);
const processedData = JSON.parse(JSON.stringify(data));
// Fill missing timestamps with null values
processedData.forEach((entry: { values: (number | null)[][] }) => {
const existingTimestamps = new Set(entry.values.map((value) => value[0]));
const missingTimestamps = Array.from(allTimestampsSet).filter(
(timestamp) => !existingTimestamps.has(timestamp),
);
missingTimestamps.forEach((timestamp) => {
const value = fillSpans ? 0 : null;
filledArray.push([timestamp, value]);
}
}
return filledArray;
entry.values.push([timestamp, value]);
});
entry.values.forEach((v) => {
if (Number.isNaN(v[1])) {
const replaceValue = fillSpans ? 0 : null;
// eslint-disable-next-line no-param-reassign
v[1] = replaceValue;
} else if (v[1] !== null) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line no-param-reassign
v[1] = parseFloat(v[1]);
}
});
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
entry.values.sort((a, b) => a[0] - b[0]);
});
return processedData.map((entry: { values: [number, string][] }) =>
entry.values.map((value) => value[1]),
);
}
export const getUPlotChartData = (
@ -46,43 +67,12 @@ export const getUPlotChartData = (
fillSpans?: boolean,
): any[] => {
const seriesList = apiResponse?.data?.result || [];
const uPlotData = [];
// this helps us identify the series with the max number of values and helps define the x axis - timestamps
const xSeries = seriesList.reduce(
(maxObj, currentObj) =>
currentObj.values.length > maxObj.values.length ? currentObj : maxObj,
seriesList[0],
const timestampArr = getXAxisTimestamps(seriesList);
const yAxisValuesArr = fillMissingXAxisTimestamps(
timestampArr,
seriesList,
fillSpans || false,
);
// sort seriesList
for (let index = 0; index < seriesList.length; index += 1) {
seriesList[index]?.values?.sort((a, b) => a[0] - b[0]);
}
const timestampArr = xSeries?.values?.map((v) => v[0]);
// timestamp
uPlotData.push(timestampArr);
// for each series, push the values
seriesList.forEach((series) => {
const updatedSeries = fillMissingTimestamps(
timestampArr,
series?.values || [],
fillSpans,
);
const seriesData =
updatedSeries?.map((v) => {
if (v[1] === null) {
return v[1];
}
return parseFloat(v[1]);
}) || [];
uPlotData.push(seriesData);
});
return uPlotData;
return [timestampArr, ...yAxisValuesArr];
};

View File

@ -42,6 +42,11 @@ body {
border-radius: 50%;
}
}
&.u-off {
text-decoration: line-through;
text-decoration-thickness: 3px;
}
}
}