wip: progress on everything
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useId } from 'react';
|
||||
import { useId, useEffect } from 'react';
|
||||
|
||||
import { RadialColorDefs } from './RadialColorDefs';
|
||||
import { RadialShape } from './RadialGauge';
|
||||
@@ -11,7 +11,6 @@ export interface RadialArcPathPropsBase {
|
||||
arcLengthDeg: number;
|
||||
shape: RadialShape;
|
||||
color?: string;
|
||||
gradient?: string;
|
||||
glowFilter?: string;
|
||||
roundedBars?: boolean;
|
||||
showGuideDots?: boolean;
|
||||
|
||||
@@ -47,7 +47,6 @@ export function RadialBar({
|
||||
startAngle={startAngle}
|
||||
arcLengthDeg={angle}
|
||||
colorDefs={colorDefs}
|
||||
gradient={colorDefs.getGradientDef()}
|
||||
roundedBars={roundedBars}
|
||||
glowFilter={glowFilter}
|
||||
showGuideDots={roundedBars}
|
||||
@@ -56,7 +55,6 @@ export function RadialBar({
|
||||
shape={shape}
|
||||
/>
|
||||
</g>
|
||||
<defs>{colorDefs.getDefs()}</defs>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useTheme2 } from '../../themes/ThemeContext';
|
||||
|
||||
import { RadialArcPath } from './RadialArcPath';
|
||||
import { RadialColorDefs } from './RadialColorDefs';
|
||||
import { RadialShape } from './RadialGauge';
|
||||
import { RadialGradientMode, RadialShape } from './RadialGauge';
|
||||
import { GaugeDimensions } from './utils';
|
||||
|
||||
export interface RadialBarSegmentedProps {
|
||||
@@ -17,6 +17,7 @@ export interface RadialBarSegmentedProps {
|
||||
segmentCount: number;
|
||||
segmentSpacing: number;
|
||||
shape: RadialShape;
|
||||
gradientMode: RadialGradientMode;
|
||||
}
|
||||
export function RadialBarSegmented({
|
||||
fieldDisplay,
|
||||
@@ -28,6 +29,7 @@ export function RadialBarSegmented({
|
||||
segmentSpacing,
|
||||
colorDefs,
|
||||
shape,
|
||||
gradientMode,
|
||||
}: RadialBarSegmentedProps) {
|
||||
const segments: React.ReactNode[] = [];
|
||||
const theme = useTheme2();
|
||||
@@ -41,9 +43,13 @@ export function RadialBarSegmented({
|
||||
|
||||
for (let i = 0; i < segmentCountAdjusted; i++) {
|
||||
const angleValue = min + ((max - min) / segmentCountAdjusted) * i;
|
||||
// const angleColor = colorDefs.getSegmentColor(angleValue, i);
|
||||
const segmentAngle = startAngle + (angleRange / segmentCountAdjusted) * i + 0.01;
|
||||
const segmentColor = angleValue >= value ? theme.colors.action.hover : undefined;
|
||||
let segmentColor: string | undefined;
|
||||
if (angleValue >= value) {
|
||||
segmentColor = theme.colors.action.hover;
|
||||
} else if (gradientMode === 'none') {
|
||||
segmentColor = colorDefs.getSegmentColor(angleValue);
|
||||
}
|
||||
|
||||
segments.push(
|
||||
<RadialArcPath
|
||||
@@ -59,12 +65,7 @@ export function RadialBarSegmented({
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<g>{segments}</g>
|
||||
<defs>{colorDefs.getDefs()}</defs>
|
||||
</>
|
||||
);
|
||||
return <g>{segments}</g>;
|
||||
}
|
||||
|
||||
export function getAngleBetweenSegments(segmentSpacing: number, segmentCount: number, range: number) {
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
import {
|
||||
colorManipulator,
|
||||
DisplayProcessor,
|
||||
FALLBACK_COLOR,
|
||||
FieldDisplay,
|
||||
getFieldColorMode,
|
||||
GrafanaTheme2,
|
||||
} from '@grafana/data';
|
||||
import { colorManipulator, DisplayProcessor, FALLBACK_COLOR, FieldDisplay, GrafanaTheme2 } from '@grafana/data';
|
||||
|
||||
import { RadialGradientMode, RadialShape } from './RadialGauge';
|
||||
import { buildGradientColors } from './colors';
|
||||
@@ -29,98 +22,17 @@ const getGuideDotColor = (color: string): string => {
|
||||
};
|
||||
|
||||
export class RadialColorDefs {
|
||||
private colorToIds: Record<string, string> = {};
|
||||
private defs: React.ReactNode[] = [];
|
||||
|
||||
constructor(private options: RadialColorDefsOptions) {}
|
||||
|
||||
getSegmentColor(forValue: number, segmentIdx: number): string {
|
||||
getSegmentColor(forValue: number): string {
|
||||
const { displayProcessor } = this.options;
|
||||
const baseColor = displayProcessor(forValue).color ?? FALLBACK_COLOR;
|
||||
return this.getColor(baseColor, segmentIdx);
|
||||
}
|
||||
|
||||
getColor(baseColor: string, segmentIdx?: number): string {
|
||||
const { gradient, dimensions, gaugeId, fieldDisplay, shape } = this.options;
|
||||
|
||||
let id = `value-color-${baseColor}-${gaugeId}`;
|
||||
const forSegment = segmentIdx !== undefined;
|
||||
if (forSegment) {
|
||||
id += `-segment-${segmentIdx}`;
|
||||
}
|
||||
|
||||
if (this.colorToIds[id]) {
|
||||
return this.colorToIds[id];
|
||||
}
|
||||
|
||||
// If no gradient, just return the base color
|
||||
if (gradient === 'none') {
|
||||
this.colorToIds[id] = baseColor;
|
||||
return baseColor;
|
||||
}
|
||||
|
||||
const returnColor = (this.colorToIds[id] = `url(#${id})`);
|
||||
const colorModeId = fieldDisplay.field.color?.mode;
|
||||
const colorMode = getFieldColorMode(colorModeId);
|
||||
const valuePercent = fieldDisplay.display.percent ?? 0;
|
||||
|
||||
const gradientStops = this.getGradient(baseColor, forSegment);
|
||||
const stops = gradientStops.map((stop, i) => (
|
||||
<stop key={i} offset={`${(stop.percent * 100).toFixed(2)}%`} stopColor={stop.color} stopOpacity={1} />
|
||||
));
|
||||
|
||||
// circular gradients are a little awkward today. we don't exactly have the result we
|
||||
// want for continuous color modes, which would be to have the radial bar fill from the top
|
||||
// around the circle. But SVG doesn't support that kind of gradient on stroke paths out-of-the-box,
|
||||
// we'd need to implement something like https://gist.github.com/mbostock/4163057
|
||||
|
||||
// Handle continusous color modes first
|
||||
// If it's a segment color we don't want to do continuous gradients
|
||||
if (colorMode.isContinuous && colorMode.getColors && !forSegment) {
|
||||
this.defs.push(
|
||||
<linearGradient key={id} id={id} x1="0" y1="0" x2="0" y2="1">
|
||||
{stops}
|
||||
</linearGradient>
|
||||
);
|
||||
|
||||
return returnColor;
|
||||
}
|
||||
|
||||
// For value based colors we want to stay more true to the specific color
|
||||
// So a radial gradient that adds a bit of light and shade works best
|
||||
if (colorMode.isByValue) {
|
||||
const x2 = shape === 'circle' ? 0 : 1 / valuePercent;
|
||||
const y2 = shape === 'circle' ? 1 : 0;
|
||||
this.defs.push(
|
||||
<radialGradient key={id} id={id} x1="0" y1="0" x2={x2} y2={y2}>
|
||||
{stops}
|
||||
</radialGradient>
|
||||
);
|
||||
return returnColor;
|
||||
}
|
||||
|
||||
// For fixed / palette based color scales we can create a more fun
|
||||
// hue and light based linear gradient that we rotate/move with the value
|
||||
const x2 = shape === 'circle' ? 0 : dimensions.centerX + dimensions.radius;
|
||||
const y2 = shape === 'circle' ? dimensions.centerY + dimensions.radius : 0;
|
||||
|
||||
this.defs.push(
|
||||
<linearGradient key={id} id={id} x1="0" y1="0" x2={x2} y2={y2} gradientUnits="userSpaceOnUse">
|
||||
{stops}
|
||||
</linearGradient>
|
||||
);
|
||||
|
||||
return returnColor;
|
||||
return displayProcessor(forValue).color ?? FALLBACK_COLOR;
|
||||
}
|
||||
|
||||
getFieldBaseColor(): string {
|
||||
return this.options.fieldDisplay.display.color ?? FALLBACK_COLOR;
|
||||
}
|
||||
|
||||
getMainBarColor(): string {
|
||||
return this.getColor(this.getFieldBaseColor());
|
||||
}
|
||||
|
||||
getGradient(baseColor = this.getFieldBaseColor(), forSegment?: boolean): Array<{ color: string; percent: number }> {
|
||||
const { displayProcessor, gradient, fieldDisplay, theme } = this.options;
|
||||
return buildGradientColors(gradient, baseColor, theme, displayProcessor, fieldDisplay, forSegment);
|
||||
@@ -131,7 +43,7 @@ export class RadialColorDefs {
|
||||
const colorStrings = gradientStops.map((stop) => `${stop.color} ${(stop.percent * 100).toFixed(2)}%`);
|
||||
return this.options.shape === 'circle'
|
||||
? `conic-gradient(from 0deg, ${colorStrings.join(', ')})`
|
||||
: 'linear-gradient(90deg, ' + colorStrings.join(', ') + ')';
|
||||
: `linear-gradient(90deg, ${colorStrings.join(', ')})`;
|
||||
}
|
||||
|
||||
getEndpointColors(): [string, string] {
|
||||
@@ -157,8 +69,4 @@ export class RadialColorDefs {
|
||||
const [startColor, endColor] = this.getEndpointColors();
|
||||
return [getGuideDotColor(startColor), getGuideDotColor(endColor)];
|
||||
}
|
||||
|
||||
getDefs(): React.ReactNode[] {
|
||||
return this.defs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +156,7 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||
segmentSpacing={segmentSpacing}
|
||||
colorDefs={colorDefs}
|
||||
shape={shape}
|
||||
gradientMode={gradient}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
@@ -231,6 +232,7 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||
glowFilter={`url(#${glowFilterId})`}
|
||||
colorDefs={colorDefs}
|
||||
shape={shape}
|
||||
gradientMode={gradient}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { FieldDisplay, Threshold } from '@grafana/data';
|
||||
|
||||
import { useTheme2 } from '../../themes/ThemeContext';
|
||||
|
||||
import { RadialArcPath } from './RadialArcPath';
|
||||
import { RadialColorDefs } from './RadialColorDefs';
|
||||
import { RadialShape } from './RadialGauge';
|
||||
import { RadialGradientMode, RadialShape } from './RadialGauge';
|
||||
import { GaugeDimensions } from './utils';
|
||||
|
||||
export interface Props {
|
||||
@@ -16,6 +18,7 @@ export interface Props {
|
||||
glowFilter?: string;
|
||||
colorDefs: RadialColorDefs;
|
||||
thresholds: Threshold[];
|
||||
gradientMode: RadialGradientMode;
|
||||
}
|
||||
export function ThresholdsBar({
|
||||
dimensions,
|
||||
@@ -27,7 +30,9 @@ export function ThresholdsBar({
|
||||
colorDefs,
|
||||
thresholds,
|
||||
shape,
|
||||
gradientMode,
|
||||
}: Props) {
|
||||
const theme = useTheme2();
|
||||
const fieldConfig = fieldDisplay.field;
|
||||
const min = fieldConfig.min ?? 0;
|
||||
const max = fieldConfig.max ?? 100;
|
||||
@@ -59,6 +64,7 @@ export function ThresholdsBar({
|
||||
startAngle={currentStart}
|
||||
arcLengthDeg={lengthDeg}
|
||||
colorDefs={colorDefs}
|
||||
color={gradientMode === 'none' ? threshold.color : undefined}
|
||||
shape={shape}
|
||||
dimensions={thresholdDimensions}
|
||||
roundedBars={roundedBars}
|
||||
@@ -69,10 +75,5 @@ export function ThresholdsBar({
|
||||
currentStart += lengthDeg;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<g>{paths}</g>
|
||||
<defs>{colorDefs.getDefs()}</defs>
|
||||
</>
|
||||
);
|
||||
return <g>{paths}</g>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user