mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-17 08:45:52 +08:00
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:
parent
b616dca52d
commit
3e29161fea
@ -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}
|
||||
|
@ -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';
|
||||
}
|
||||
|
@ -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];
|
||||
};
|
||||
|
@ -42,6 +42,11 @@ body {
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
&.u-off {
|
||||
text-decoration: line-through;
|
||||
text-decoration-thickness: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user