Add option to start Y axis at zero

Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
Julius Volz 2024-09-13 16:52:27 +02:00
parent b93ed7bd17
commit 55e54640f5
6 changed files with 58 additions and 0 deletions

View file

@ -24,6 +24,7 @@ export interface GraphProps {
resolution: GraphResolution; resolution: GraphResolution;
showExemplars: boolean; showExemplars: boolean;
displayMode: GraphDisplayMode; displayMode: GraphDisplayMode;
startYAtZero: boolean;
retriggerIdx: number; retriggerIdx: number;
onSelectRange: (start: number, end: number) => void; onSelectRange: (start: number, end: number) => void;
} }
@ -36,6 +37,7 @@ const Graph: FC<GraphProps> = ({
resolution, resolution,
showExemplars, showExemplars,
displayMode, displayMode,
startYAtZero,
retriggerIdx, retriggerIdx,
onSelectRange, onSelectRange,
}) => { }) => {
@ -182,6 +184,7 @@ const Graph: FC<GraphProps> = ({
width={width} width={width}
showExemplars={showExemplars} showExemplars={showExemplars}
displayMode={displayMode} displayMode={displayMode}
startYAtZero={startYAtZero}
onSelectRange={onSelectRange} onSelectRange={onSelectRange}
/> />
</Box> </Box>

View file

@ -7,8 +7,12 @@ import {
SegmentedControl, SegmentedControl,
Stack, Stack,
Skeleton, Skeleton,
ActionIcon,
Popover,
Checkbox,
} from "@mantine/core"; } from "@mantine/core";
import { import {
IconAdjustmentsHorizontal,
IconChartAreaFilled, IconChartAreaFilled,
IconChartLine, IconChartLine,
IconGraph, IconGraph,
@ -37,6 +41,7 @@ import ErrorBoundary from "../../components/ErrorBoundary";
import ASTNode from "../../promql/ast"; import ASTNode from "../../promql/ast";
import serializeNode from "../../promql/serialize"; import serializeNode from "../../promql/serialize";
import ExplainView from "./ExplainViews/ExplainView"; import ExplainView from "./ExplainViews/ExplainView";
import { actionIconStyle } from "../../styles";
export interface PanelProps { export interface PanelProps {
idx: number; idx: number;
@ -290,6 +295,34 @@ const QueryPanel: FC<PanelProps> = ({ idx, metricNames }) => {
// }, // },
]} ]}
/> />
<Popover position="bottom" withArrow shadow="md">
<Popover.Target>
<ActionIcon variant="light" color="gray" size={32}>
<IconAdjustmentsHorizontal
style={actionIconStyle}
stroke={1.5}
/>
</ActionIcon>
</Popover.Target>
<Popover.Dropdown p="lg">
<Checkbox
size="xs"
checked={panel.visualizer.startYAtZero}
label="Start Y axis at 0"
onChange={(event) =>
dispatch(
setVisualizer({
idx,
visualizer: {
...panel.visualizer,
startYAtZero: event.currentTarget.checked,
},
})
)
}
/>
</Popover.Dropdown>
</Popover>
</Group> </Group>
</Group> </Group>
<Space h="lg" /> <Space h="lg" />
@ -301,6 +334,7 @@ const QueryPanel: FC<PanelProps> = ({ idx, metricNames }) => {
resolution={panel.visualizer.resolution} resolution={panel.visualizer.resolution}
showExemplars={panel.visualizer.showExemplars} showExemplars={panel.visualizer.showExemplars}
displayMode={panel.visualizer.displayMode} displayMode={panel.visualizer.displayMode}
startYAtZero={panel.visualizer.startYAtZero}
retriggerIdx={retriggerIdx} retriggerIdx={retriggerIdx}
onSelectRange={onSelectRange} onSelectRange={onSelectRange}
/> />

View file

@ -24,6 +24,7 @@ export interface UPlotChartProps {
width: number; width: number;
showExemplars: boolean; showExemplars: boolean;
displayMode: GraphDisplayMode; displayMode: GraphDisplayMode;
startYAtZero: boolean;
onSelectRange: (start: number, end: number) => void; onSelectRange: (start: number, end: number) => void;
} }
@ -34,6 +35,7 @@ const UPlotChart: FC<UPlotChartProps> = ({
range: { startTime, endTime, resolution }, range: { startTime, endTime, resolution },
width, width,
displayMode, displayMode,
startYAtZero,
onSelectRange, onSelectRange,
}) => { }) => {
const [options, setOptions] = useState<uPlot.Options | null>(null); const [options, setOptions] = useState<uPlot.Options | null>(null);
@ -60,6 +62,7 @@ const UPlotChart: FC<UPlotChartProps> = ({
width, width,
data, data,
useLocalTime, useLocalTime,
startYAtZero,
theme === "light", theme === "light",
onSelectRange onSelectRange
); );
@ -81,6 +84,7 @@ const UPlotChart: FC<UPlotChartProps> = ({
useLocalTime, useLocalTime,
theme, theme,
onSelectRange, onSelectRange,
startYAtZero,
]); ]);
if (options === null || processedData === null) { if (options === null || processedData === null) {

View file

@ -289,6 +289,7 @@ export const getUPlotOptions = (
width: number, width: number,
result: RangeSamples[], result: RangeSamples[],
useLocalTime: boolean, useLocalTime: boolean,
startYAtZero: boolean,
light: boolean, light: boolean,
onSelectRange: (_start: number, _end: number) => void onSelectRange: (_start: number, _end: number) => void
): uPlot.Options => ({ ): uPlot.Options => ({
@ -329,6 +330,16 @@ export const getUPlotOptions = (
focus: { focus: {
alpha: 1, alpha: 1,
}, },
scales: startYAtZero
? {
y: {
range: (_u, _min, max) => {
const minMax = uPlot.rangeNum(0, max, 0.1, true);
return [0, minMax[1]];
},
},
}
: undefined,
axes: [ axes: [
// X axis (time). // X axis (time).
{ {

View file

@ -63,6 +63,9 @@ export const decodePanelOptionsFromURLParams = (query: string): Panel[] => {
panel.visualizer.displayMode = panel.visualizer.displayMode =
value === "1" ? GraphDisplayMode.Stacked : GraphDisplayMode.Lines; value === "1" ? GraphDisplayMode.Stacked : GraphDisplayMode.Lines;
}); });
decodeSetting("start_y_at_zero", (value) => {
panel.visualizer.startYAtZero = value === "1";
});
decodeSetting("show_exemplars", (value) => { decodeSetting("show_exemplars", (value) => {
panel.visualizer.showExemplars = value === "1"; panel.visualizer.showExemplars = value === "1";
}); });
@ -171,6 +174,7 @@ export const encodePanelOptionsToURLParams = (
} }
addParam(idx, "display_mode", p.visualizer.displayMode); addParam(idx, "display_mode", p.visualizer.displayMode);
addParam(idx, "start_y_at_zero", p.visualizer.startYAtZero ? "1" : "0");
addParam(idx, "show_exemplars", p.visualizer.showExemplars ? "1" : "0"); addParam(idx, "show_exemplars", p.visualizer.showExemplars ? "1" : "0");
}); });

View file

@ -58,6 +58,7 @@ export interface Visualizer {
resolution: GraphResolution; resolution: GraphResolution;
displayMode: GraphDisplayMode; displayMode: GraphDisplayMode;
showExemplars: boolean; showExemplars: boolean;
startYAtZero: boolean;
} }
export type Panel = { export type Panel = {
@ -86,6 +87,7 @@ export const newDefaultPanel = (): Panel => ({
resolution: { type: "auto", density: "medium" }, resolution: { type: "auto", density: "medium" },
displayMode: GraphDisplayMode.Lines, displayMode: GraphDisplayMode.Lines,
showExemplars: false, showExemplars: false,
startYAtZero: false,
}, },
}); });