more cleanup, optimization

This commit is contained in:
Paul Marbach
2025-12-16 13:36:15 -05:00
parent 0b89c821ad
commit 6042dfef89
4 changed files with 65 additions and 72 deletions
@@ -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<HTMLDivElement>['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);
@@ -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(
@@ -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<GraphFieldConfig> = useMemo(
() => ({
color: {
mode: 'fixed',
fixedColor: color ?? 'blue',
},
custom: {
gradientMode: GraphGradientMode.Opacity,
fillOpacity: 40,
lineInterpolation: LineInterpolation.Smooth,
},
}),
[color]
);
if (!sparkline) {
return null;
}
return (
<div style={{ position: 'absolute', top: topPos }}>
<Sparkline height={height} width={width} sparkline={sparkline} theme={theme} config={config} />
</div>
);
}
);
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<GraphFieldConfig> = {
color: {
mode: 'fixed',
fixedColor: color ?? 'blue',
},
custom: {
gradientMode: GraphGradientMode.Opacity,
fillOpacity: 40,
lineInterpolation: LineInterpolation.Smooth,
},
};
return (
<div style={{ position: 'absolute', top: topPos }}>
<Sparkline height={height} width={width} sparkline={sparkline} theme={theme} config={config} />
</div>
);
}
RadialSparkline.displayName = 'RadialSparkline';
@@ -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)];
}