diff --git a/packages/grafana-ui/src/components/RadialGauge/RadialArcPath.tsx b/packages/grafana-ui/src/components/RadialGauge/RadialArcPath.tsx index b08085af48e..d89ec94cc58 100644 --- a/packages/grafana-ui/src/components/RadialGauge/RadialArcPath.tsx +++ b/packages/grafana-ui/src/components/RadialGauge/RadialArcPath.tsx @@ -1,4 +1,4 @@ -import { useId, useMemo, memo } from 'react'; +import { useId, memo, HTMLAttributes } from 'react'; import { FieldDisplay } from '@grafana/data'; @@ -48,53 +48,36 @@ export const RadialArcPath = memo( const theme = useTheme2(); const id = useId(); - const gradientStops = useMemo(() => { - if (gradientMode === 'none') { - return []; - } - return buildGradientColors(gradientMode, theme, fieldDisplay, fieldDisplay.display.color); - }, [gradientMode, fieldDisplay, theme]); + const gradientStops = buildGradientColors(gradientMode, theme, fieldDisplay, fieldDisplay.display.color); - const { guideDotColors, endpointColors } = useMemo(() => { - if (!showGuideDots || gradientStops.length === 0) { - return { - guideDotStartColor: undefined, - guideDotEndColor: undefined, - }; - } - return { - guideDotColors: getGuideDotColors(gradientStops, fieldDisplay.display.percent ?? 0), - endpointColors: - shape === 'circle' ? getEndpointColors(gradientStops, fieldDisplay.display.percent ?? 1) : undefined, - }; - }, [showGuideDots, fieldDisplay, gradientStops, shape]); + let guideDotColors: [string, string] | undefined; + let endpointColors: [string, string] | undefined; - const bgDivStyle = useMemo(() => { - const baseStyles = { width: '100%', height: '100%' }; - if (color) { - return { backgroundColor: color, ...baseStyles }; + if (showGuideDots && gradientStops.length > 0) { + guideDotColors = getGuideDotColors(gradientStops, fieldDisplay.display.percent); + if (shape === 'circle') { + endpointColors = getEndpointColors(gradientStops, fieldDisplay.display.percent); } - const gradientCss = getGradientCss(gradientStops, shape); - return { backgroundImage: gradientCss, ...baseStyles }; - }, [color, gradientStops, shape]); + } + + const bgDivStyle: HTMLAttributes['style'] = { width: '100%', height: '100%' }; + if (color) { + bgDivStyle.backgroundColor = color; + } else { + bgDivStyle.backgroundImage = getGradientCss(gradientStops, shape); + } const { radius, centerX, centerY, barWidth } = dimensions; - const path = useMemo( - () => drawRadialArcPath(angle, arcLengthDeg, dimensions, roundedBars), - [angle, arcLengthDeg, dimensions, roundedBars] - ); + const path = drawRadialArcPath(angle, arcLengthDeg, dimensions, roundedBars); - const { x1, x2, y1, y2 } = useMemo(() => { - const startRadians = toRad(angle); - const endRadians = toRad(angle + arcLengthDeg); + const startRadians = toRad(angle); + const endRadians = toRad(angle + arcLengthDeg); - let x1 = centerX + radius * Math.cos(startRadians); - let y1 = centerY + radius * Math.sin(startRadians); - let x2 = centerX + radius * Math.cos(endRadians); - let y2 = centerY + radius * Math.sin(endRadians); - return { x1, y1, x2, y2 }; - }, [angle, arcLengthDeg, centerX, centerY, radius]); + const x1 = centerX + radius * Math.cos(startRadians); + const y1 = centerY + radius * Math.sin(startRadians); + const x2 = centerX + radius * Math.cos(endRadians); + const y2 = centerY + radius * Math.sin(endRadians); const dotRadius = Math.min((barWidth / 2) * DOT_RADIUS_FACTOR, MAX_DOT_RADIUS); diff --git a/packages/grafana-ui/src/components/RadialGauge/RadialBarSegmented.tsx b/packages/grafana-ui/src/components/RadialGauge/RadialBarSegmented.tsx index 522036377c2..d86baa5d1b5 100644 --- a/packages/grafana-ui/src/components/RadialGauge/RadialBarSegmented.tsx +++ b/packages/grafana-ui/src/components/RadialGauge/RadialBarSegmented.tsx @@ -45,6 +45,7 @@ export const RadialBarSegmented = memo( const value = fieldDisplay.display.numeric; const angleBetweenSegments = getAngleBetweenSegments(segmentSpacing, segmentCount, angleRange); const segmentArcLengthDeg = angleRange / segmentCountAdjusted - angleBetweenSegments; + const displayProcessor = getFieldDisplayProcessor(fieldDisplay); for (let i = 0; i < segmentCountAdjusted; i++) { const angleValue = min + ((max - min) / segmentCountAdjusted) * i; @@ -53,7 +54,7 @@ export const RadialBarSegmented = memo( if (angleValue >= value) { segmentColor = theme.colors.action.hover; } else if (gradientMode === 'none') { - segmentColor = getFieldDisplayProcessor(fieldDisplay)(angleValue).color ?? FALLBACK_COLOR; + segmentColor = displayProcessor(angleValue).color ?? FALLBACK_COLOR; } segments.push( diff --git a/packages/grafana-ui/src/components/RadialGauge/RadialSparkline.tsx b/packages/grafana-ui/src/components/RadialGauge/RadialSparkline.tsx index 4603426e8f9..67969fd3208 100644 --- a/packages/grafana-ui/src/components/RadialGauge/RadialSparkline.tsx +++ b/packages/grafana-ui/src/components/RadialGauge/RadialSparkline.tsx @@ -1,3 +1,5 @@ +import { memo, useMemo } from 'react'; + import { FieldDisplay, GrafanaTheme2, FieldConfig } from '@grafana/data'; import { GraphFieldConfig, GraphGradientMode, LineInterpolation } from '@grafana/schema'; @@ -22,36 +24,43 @@ const SPARKLINE_TOP_OFFSET_DIVISOR_CIRCLE = 4; const SPARKLINE_TOP_OFFSET_DIVISOR_CIRCLE_NAME_AND_VALUE = 3.3; const SPARKLINE_SPACING = 8; -export function RadialSparkline({ sparkline, dimensions, theme, color, shape, textMode }: RadialSparklineProps) { - const { radius, barWidth } = dimensions; +export const RadialSparkline = memo( + ({ sparkline, dimensions, theme, color, shape, textMode }: RadialSparklineProps) => { + const { radius, barWidth } = dimensions; - if (!sparkline) { - return null; + const showNameAndValue = textMode === 'value_and_name'; + const height = radius / (showNameAndValue ? SPARKLINE_HEIGHT_DIVISOR_NAME_AND_VALUE : SPARKLINE_HEIGHT_DIVISOR); + const width = radius * (shape === 'gauge' ? SPARKLINE_WIDTH_FACTOR_ARC : SPARKLINE_WIDTH_FACTOR_CIRCLE) - barWidth; + const topPos = + shape === 'gauge' + ? dimensions.gaugeBottomY - height - SPARKLINE_SPACING + : `calc(50% + ${radius / (showNameAndValue ? SPARKLINE_TOP_OFFSET_DIVISOR_CIRCLE_NAME_AND_VALUE : SPARKLINE_TOP_OFFSET_DIVISOR_CIRCLE)}px)`; + + const config: FieldConfig = useMemo( + () => ({ + color: { + mode: 'fixed', + fixedColor: color ?? 'blue', + }, + custom: { + gradientMode: GraphGradientMode.Opacity, + fillOpacity: 40, + lineInterpolation: LineInterpolation.Smooth, + }, + }), + [color] + ); + + if (!sparkline) { + return null; + } + + return ( +
+ +
+ ); } +); - const showNameAndValue = textMode === 'value_and_name'; - const height = radius / (showNameAndValue ? SPARKLINE_HEIGHT_DIVISOR_NAME_AND_VALUE : SPARKLINE_HEIGHT_DIVISOR); - const width = radius * (shape === 'gauge' ? SPARKLINE_WIDTH_FACTOR_ARC : SPARKLINE_WIDTH_FACTOR_CIRCLE) - barWidth; - const topPos = - shape === 'gauge' - ? dimensions.gaugeBottomY - height - SPARKLINE_SPACING - : `calc(50% + ${radius / (showNameAndValue ? SPARKLINE_TOP_OFFSET_DIVISOR_CIRCLE_NAME_AND_VALUE : SPARKLINE_TOP_OFFSET_DIVISOR_CIRCLE)}px)`; - - const config: FieldConfig = { - color: { - mode: 'fixed', - fixedColor: color ?? 'blue', - }, - custom: { - gradientMode: GraphGradientMode.Opacity, - fillOpacity: 40, - lineInterpolation: LineInterpolation.Smooth, - }, - }; - - return ( -
- -
- ); -} +RadialSparkline.displayName = 'RadialSparkline'; diff --git a/packages/grafana-ui/src/components/RadialGauge/colors.ts b/packages/grafana-ui/src/components/RadialGauge/colors.ts index c390e57d09d..b15117f7b9f 100644 --- a/packages/grafana-ui/src/components/RadialGauge/colors.ts +++ b/packages/grafana-ui/src/components/RadialGauge/colors.ts @@ -172,7 +172,7 @@ const getGuideDotColor = (color: string): string => { return colorManipulator.getContrastRatio(darkColor, color) >= CONTRAST_THRESHOLD_MAX ? darkColor : lightColor; }; -export function getGuideDotColors(gradientStops: GradientStop[], percent: number): [string, string] { +export function getGuideDotColors(gradientStops: GradientStop[], percent = 1): [string, string] { const [startColor, endColor] = getEndpointColors(gradientStops, percent); return [getGuideDotColor(startColor), getGuideDotColor(endColor)]; }