diff --git a/public/app/plugins/panel/heatmap-new/ColorScale.tsx b/public/app/plugins/panel/heatmap-new/ColorScale.tsx index 82064168b44..e21f231e94f 100644 --- a/public/app/plugins/panel/heatmap-new/ColorScale.tsx +++ b/public/app/plugins/panel/heatmap-new/ColorScale.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; import { css } from '@emotion/css'; import { GrafanaTheme2 } from '@grafana/data'; -import { useTheme2, VizTooltipContainer } from '@grafana/ui'; +import { useTheme2 } from '@grafana/ui'; type Props = { colorPalette: string[]; @@ -10,6 +10,7 @@ type Props = { // Show a value as string -- when not defined, the raw values will not be shown display?: (v: number) => string; + hoverValue?: number; }; type HoverState = { @@ -17,48 +18,63 @@ type HoverState = { value: number; }; -export const ColorScale = ({ colorPalette, min, max, display }: Props) => { +const LEFT_OFFSET = 2; + +export const ColorScale = ({ colorPalette, min, max, display, hoverValue }: Props) => { const [colors, setColors] = useState([]); - const [hover, setHover] = useState({ isShown: false, value: 0 }); - const [cursor, setCursor] = useState({ clientX: 0, clientY: 0 }); + const [scaleHover, setScaleHover] = useState({ isShown: false, value: 0 }); + const [percent, setPercent] = useState(null); + + const theme = useTheme2(); + const styles = getStyles(theme, colors); useEffect(() => { setColors(getGradientStops({ colorArray: colorPalette })); }, [colorPalette]); - const theme = useTheme2(); - const styles = getStyles(theme, colors); - const onScaleMouseMove = (event: React.MouseEvent) => { const divOffset = event.nativeEvent.offsetX; const offsetWidth = (event.target as any).offsetWidth as number; const normPercentage = Math.floor((divOffset * 100) / offsetWidth + 1); const scaleValue = Math.floor(((max - min) * normPercentage) / 100 + min); - setHover({ isShown: true, value: scaleValue }); - setCursor({ clientX: event.clientX, clientY: event.clientY }); + + setScaleHover({ isShown: true, value: scaleValue }); + setPercent(normPercentage); }; const onScaleMouseLeave = () => { - setHover({ isShown: false, value: 0 }); + setScaleHover({ isShown: false, value: 0 }); }; + useEffect(() => { + if (hoverValue != null) { + const percent = hoverValue / (max - min); + setPercent(percent * 100); + } + }, [hoverValue, min, max]); + return (
-
-
- {display && hover.isShown && ( - - {display(hover.value)} - - )} -
- {display && ( -
- {display(min)} - {display(max)} +
+ {display && (scaleHover.isShown || hoverValue !== undefined) && ( +
+
)}
+ {display && ( +
+ {percent != null && (scaleHover.isShown || hoverValue !== undefined) && ( + + {display(hoverValue || scaleHover.value)} + + )} +
+ {display(min)} + {display(max)} +
+
+ )}
); }; @@ -96,18 +112,36 @@ const getGradientStops = ({ colorArray, stops = 10 }: { colorArray: string[]; st const getStyles = (theme: GrafanaTheme2, colors: string[]) => ({ scaleWrapper: css` - margin: 0 16px; - padding-top: 4px; width: 100%; max-width: 300px; - color: #ccccdc; + margin-left: 25px; + padding: 10px 0; font-size: 11px; + opacity: 1; `, scaleGradient: css` background: linear-gradient(90deg, ${colors.join()}); - height: 6px; + height: 10px; `, - maxDisplay: css` - float: right; + legendValues: css` + display: flex; + justify-content: space-between; + `, + hoverValue: css` + position: absolute; + padding-top: 5px; + `, + followerContainer: css` + position: relative; + `, + follower: css` + position: absolute; + height: 14px; + width: 14px; + border-radius: 50%; + transform: translateX(-50%) translateY(-50%); + pointer-events: none; + border: 2px solid ${theme.colors.text.primary}; + margin-top: 5px; `, }); diff --git a/public/app/plugins/panel/heatmap-new/HeatmapPanel.tsx b/public/app/plugins/panel/heatmap-new/HeatmapPanel.tsx index ea0ce691456..6aea37d7ab3 100644 --- a/public/app/plugins/panel/heatmap-new/HeatmapPanel.tsx +++ b/public/app/plugins/panel/heatmap-new/HeatmapPanel.tsx @@ -99,9 +99,15 @@ export const HeatmapPanel: React.FC = ({ const { min, max } = reduceField({ field, reducers: [ReducerID.min, ReducerID.max] }); const display = field.display ? (v: number) => formattedValueToString(field.display!(v)) : (v: number) => `${v}`; + let hoverValue: number | undefined = undefined; + if (hover && info.heatmap.fields) { + const countField = info.heatmap.fields[2]; + hoverValue = countField?.values.get(hover.index); + } + return ( - + ); };