mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-10-14 15:41:33 +08:00

* refactor: added panel type histogram and basic setup done * feat: histogram for one query * refactor: multiple query support histogram * chore: typecorrection * refactor: done with legend part * refactor: legend change fix * refactor: fix the tooltip value for histogram * refactor: disable drag for histogram * fix: tsc * refactor: handled panel type change in edit mode * refactor: full view done (#4881) Co-authored-by: Rajat-Dabade <rajat@signoz.io> * [Feat]: Full view histogram (#4867) * refactor: added panel type histogram and basic setup done * feat: histogram for one query * refactor: multiple query support histogram * chore: typecorrection * refactor: done with legend part * refactor: legend change fix * refactor: fix the tooltip value for histogram * refactor: disable drag for histogram * fix: tsc * refactor: handled panel type change in edit mode * refactor: full view done --------- Co-authored-by: Rajat-Dabade <rajat@signoz.io> Co-authored-by: Yunus M <myounis.ar@live.com> * feat: histogram customisations (#5133) * feat: added bucket size and bucket width enhancements for histogram * fix: added handling for bucket size bucket count and combine into one series * fix: added bidirectional sync * fix: remove extra props from interfaces * fix: hide legends when merging all queries * fix: minor legend fixes * fix: build issues --------- Co-authored-by: Rajat-Dabade <rajat@signoz.io> Co-authored-by: Yunus M <myounis.ar@live.com> Co-authored-by: Vikrant Gupta <vikrant.thomso@gmail.com>
243 lines
6.3 KiB
TypeScript
243 lines
6.3 KiB
TypeScript
import { ThresholdProps } from 'container/NewWidget/RightContainer/Threshold/types';
|
|
import { convertValue } from 'lib/getConvertedValue';
|
|
import { isFinite } from 'lodash-es';
|
|
import { QueryDataV3 } from 'types/api/widgets/getQuery';
|
|
import uPlot from 'uplot';
|
|
|
|
function findMinMaxValues(data: QueryDataV3[]): [number, number] {
|
|
let min = Number.MAX_SAFE_INTEGER;
|
|
let max = Number.MIN_SAFE_INTEGER;
|
|
data?.forEach((entry) => {
|
|
entry.series?.forEach((series) => {
|
|
series.values.forEach((valueObj) => {
|
|
const value = parseFloat(valueObj.value);
|
|
if (isFinite(value)) {
|
|
min = Math.min(min, value);
|
|
max = Math.max(max, value);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
return [min, max];
|
|
}
|
|
|
|
function findMinMaxThresholdValues(
|
|
thresholds: ThresholdProps[],
|
|
yAxisUnit?: string,
|
|
): [number, number] {
|
|
let minThresholdValue =
|
|
thresholds[0].thresholdValue || Number.MAX_SAFE_INTEGER;
|
|
let maxThresholdValue =
|
|
thresholds[0].thresholdValue || Number.MIN_SAFE_INTEGER;
|
|
|
|
thresholds.forEach((entry) => {
|
|
const { thresholdValue, thresholdUnit } = entry;
|
|
if (thresholdValue === undefined) return;
|
|
const compareValue = convertValue(thresholdValue, thresholdUnit, yAxisUnit);
|
|
if (compareValue === null) return;
|
|
minThresholdValue = Math.min(minThresholdValue, compareValue);
|
|
maxThresholdValue = Math.max(maxThresholdValue, compareValue);
|
|
});
|
|
|
|
return [minThresholdValue, maxThresholdValue];
|
|
}
|
|
|
|
function getRange(
|
|
thresholds: ThresholdProps[],
|
|
series: QueryDataV3[],
|
|
yAxisUnit?: string,
|
|
): [number, number] {
|
|
const [minThresholdValue, maxThresholdValue] = findMinMaxThresholdValues(
|
|
thresholds,
|
|
yAxisUnit,
|
|
);
|
|
const [minSeriesValue, maxSeriesValue] = findMinMaxValues(series);
|
|
|
|
const min = Math.min(minThresholdValue, minSeriesValue);
|
|
let max = Math.max(maxThresholdValue, maxSeriesValue);
|
|
|
|
// this is a temp change, we need to figure out a generic way to better handle ranges based on yAxisUnit
|
|
if (yAxisUnit === 'percentunit' && max < 1) {
|
|
max = 1;
|
|
}
|
|
|
|
return [min, max];
|
|
}
|
|
|
|
function areAllSeriesEmpty(series: QueryDataV3[]): boolean {
|
|
return series.every((entry) => {
|
|
if (!entry.series) return true;
|
|
return entry.series.every((series) => series.values.length === 0);
|
|
});
|
|
}
|
|
|
|
function configSoftMinMax(
|
|
softMin: number | null,
|
|
softMax: number | null,
|
|
): { range: uPlot.Scale.Range } {
|
|
return {
|
|
range: {
|
|
min: {
|
|
soft: softMin !== null ? softMin : undefined,
|
|
mode: 2,
|
|
},
|
|
max: {
|
|
soft: softMax !== null ? softMax : undefined,
|
|
mode: 2,
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
export const getYAxisScale = ({
|
|
thresholds,
|
|
series,
|
|
yAxisUnit,
|
|
softMin,
|
|
softMax,
|
|
}: // eslint-disable-next-line sonarjs/cognitive-complexity
|
|
GetYAxisScale): { auto?: boolean; range?: uPlot.Scale.Range } => {
|
|
// Situation: thresholds and series data is absent
|
|
if (
|
|
(!thresholds || thresholds.length === 0) &&
|
|
(!series || areAllSeriesEmpty(series))
|
|
) {
|
|
// Situation: softMin is not null or softMax is null
|
|
if (softMin !== null && softMax === null) {
|
|
return configSoftMinMax(softMin, softMin + 100);
|
|
}
|
|
|
|
// Situation: softMin is null softMax is not null
|
|
if (softMin === null && softMax !== null) {
|
|
return configSoftMinMax(softMax - 100, softMax);
|
|
}
|
|
|
|
// Situation: softMin is not null and softMax is not null
|
|
if (softMin !== null && softMax !== null) {
|
|
return configSoftMinMax(softMin, softMax);
|
|
}
|
|
|
|
// Situation: softMin and softMax are null and no threshold and no series data
|
|
return { auto: true };
|
|
}
|
|
|
|
// Situation: thresholds are absent
|
|
if (!thresholds || thresholds.length === 0) {
|
|
if (softMax === softMin) {
|
|
return { auto: true };
|
|
}
|
|
|
|
// Situation: No thresholds data but series data is present
|
|
if (series && !areAllSeriesEmpty(series)) {
|
|
// Situation: softMin and softMax are null
|
|
if (softMin === null && softMax === null) {
|
|
return { auto: true };
|
|
}
|
|
|
|
// Situation: either softMin or softMax is not null
|
|
let [min, max] = findMinMaxValues(series);
|
|
|
|
if (softMin !== null) {
|
|
// Compare with softMin if it is not null
|
|
min = Math.min(min, softMin);
|
|
}
|
|
|
|
if (softMax !== null) {
|
|
// Compare with softMax if it is not null
|
|
max = Math.max(max, softMax);
|
|
}
|
|
|
|
if (min === max) {
|
|
// Min and Max value can be same if the value is same for all the series
|
|
return { auto: true };
|
|
}
|
|
|
|
return { auto: false, range: [min, max] };
|
|
}
|
|
|
|
// Situation: No thresholds data and series data is absent but either soft min and soft max is present
|
|
if (softMin !== null && softMax === null) {
|
|
return configSoftMinMax(softMin, softMin + 100);
|
|
}
|
|
|
|
if (softMin === null && softMax !== null) {
|
|
return configSoftMinMax(softMax - 100, softMax);
|
|
}
|
|
|
|
if (softMin !== null && softMax !== null) {
|
|
return configSoftMinMax(softMin, softMax);
|
|
}
|
|
|
|
return { auto: true };
|
|
}
|
|
|
|
if (!series || areAllSeriesEmpty(series)) {
|
|
// series data is absent but threshold is present
|
|
if (thresholds.length > 0) {
|
|
// Situation: thresholds are present and series data is absent
|
|
let [min, max] = findMinMaxThresholdValues(thresholds, yAxisUnit);
|
|
|
|
if (softMin !== null) {
|
|
// Compare with softMin if it is not null
|
|
min = Math.min(min, softMin);
|
|
}
|
|
|
|
if (softMax !== null) {
|
|
// Compare with softMax if it is not null
|
|
max = Math.max(max, softMax);
|
|
}
|
|
|
|
if (min === max) {
|
|
// Min and Max value can be same if the value is same for all the series
|
|
return { auto: true };
|
|
}
|
|
|
|
return { auto: false, range: [min, max] };
|
|
}
|
|
|
|
// Situation: softMin or softMax is not null
|
|
if (softMin !== null && softMax === null) {
|
|
return configSoftMinMax(softMin, softMin + 100);
|
|
}
|
|
|
|
if (softMin === null && softMax !== null) {
|
|
return configSoftMinMax(softMax - 100, softMax);
|
|
}
|
|
|
|
if (softMin !== null && softMax !== null) {
|
|
return configSoftMinMax(softMin, softMax);
|
|
}
|
|
|
|
return { auto: true };
|
|
}
|
|
|
|
// Situation: thresholds and series data are present
|
|
let [min, max] = getRange(thresholds, series, yAxisUnit);
|
|
|
|
if (softMin !== null) {
|
|
// Compare with softMin if it is not null
|
|
min = Math.min(min, softMin);
|
|
}
|
|
|
|
if (softMax !== null) {
|
|
// Compare with softMax if it is not null
|
|
max = Math.max(max, softMax);
|
|
}
|
|
|
|
if (min === max) {
|
|
// Min and Max value can be same if the value is same for all the series
|
|
return { auto: true };
|
|
}
|
|
|
|
return { auto: false, range: [min, max] };
|
|
};
|
|
|
|
export type GetYAxisScale = {
|
|
thresholds?: ThresholdProps[];
|
|
series?: QueryDataV3[];
|
|
yAxisUnit?: string;
|
|
softMin: number | null;
|
|
softMax: number | null;
|
|
};
|