change endpoint marks to be configurable
This commit is contained in:
Generated
+2
@@ -28,6 +28,7 @@ export interface Options extends common.SingleStatBaseOptions {
|
||||
barShape: ('flat' | 'rounded');
|
||||
barWidthFactor: number;
|
||||
effects: GaugePanelEffects;
|
||||
endpointMarker?: ('point' | 'glow' | 'none');
|
||||
segmentCount: number;
|
||||
segmentSpacing: number;
|
||||
shape: ('circle' | 'gauge');
|
||||
@@ -40,6 +41,7 @@ export const defaultOptions: Partial<Options> = {
|
||||
barShape: 'flat',
|
||||
barWidthFactor: 0.5,
|
||||
effects: {},
|
||||
endpointMarker: 'point',
|
||||
segmentCount: 1,
|
||||
segmentSpacing: 0.3,
|
||||
shape: 'gauge',
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useId, memo, HTMLAttributes } from 'react';
|
||||
import { useId, memo, HTMLAttributes, ReactElement } from 'react';
|
||||
|
||||
import { FieldDisplay } from '@grafana/data';
|
||||
|
||||
import { useTheme2 } from '../../themes/ThemeContext';
|
||||
|
||||
import { buildGradientColors, getEndpointColors, getGradientCss, getGuideDotColors } from './colors';
|
||||
import { RadialGradientMode, RadialShape, RadialGaugeDimensions } from './types';
|
||||
import { buildGradientColors, getBarEndcapColors, getGradientCss, getEndpointMarkerColors } from './colors';
|
||||
import { RadialShape, RadialGaugeDimensions } from './types';
|
||||
import { drawRadialArcPath, toRad } from './utils';
|
||||
|
||||
export interface RadialArcPathPropsBase {
|
||||
@@ -13,12 +13,13 @@ export interface RadialArcPathPropsBase {
|
||||
color?: string;
|
||||
dimensions: RadialGaugeDimensions;
|
||||
fieldDisplay: FieldDisplay;
|
||||
glowFilter?: string;
|
||||
gradientMode: RadialGradientMode;
|
||||
gradient?: boolean;
|
||||
roundedBars?: boolean;
|
||||
shape: RadialShape;
|
||||
showGuideDots?: boolean;
|
||||
endpointMarker?: 'point' | 'glow';
|
||||
startAngle: number;
|
||||
glowFilter?: string;
|
||||
endpointMarkerGlowFilter?: string;
|
||||
}
|
||||
|
||||
interface RadialArcPathPropsWithGuideDot extends RadialArcPathPropsBase {
|
||||
@@ -40,27 +41,18 @@ export const RadialArcPath = memo(
|
||||
color,
|
||||
dimensions,
|
||||
fieldDisplay,
|
||||
glowFilter,
|
||||
gradientMode,
|
||||
gradient,
|
||||
roundedBars,
|
||||
shape,
|
||||
showGuideDots,
|
||||
endpointMarker,
|
||||
startAngle: angle,
|
||||
glowFilter,
|
||||
endpointMarkerGlowFilter,
|
||||
}: RadialArcPathProps) => {
|
||||
const theme = useTheme2();
|
||||
const id = useId();
|
||||
|
||||
const gradientStops = buildGradientColors(gradientMode, theme, fieldDisplay, fieldDisplay.display.color);
|
||||
|
||||
let guideDotColors: [string, string] | undefined;
|
||||
let endpointColors: [string, string] | undefined;
|
||||
|
||||
if (showGuideDots && gradientStops.length > 0) {
|
||||
guideDotColors = getGuideDotColors(gradientStops, fieldDisplay.display.percent);
|
||||
if (shape === 'circle') {
|
||||
endpointColors = getEndpointColors(gradientStops, fieldDisplay.display.percent);
|
||||
}
|
||||
}
|
||||
const gradientStops = buildGradientColors(gradient, theme, fieldDisplay, fieldDisplay.display.color);
|
||||
|
||||
const bgDivStyle: HTMLAttributes<HTMLDivElement>['style'] = { width: '100%', height: '100%' };
|
||||
if (color) {
|
||||
@@ -76,12 +68,65 @@ export const RadialArcPath = memo(
|
||||
const startRadians = toRad(angle);
|
||||
const endRadians = toRad(angle + arcLengthDeg);
|
||||
|
||||
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 xStart = centerX + radius * Math.cos(startRadians);
|
||||
const yStart = centerY + radius * Math.sin(startRadians);
|
||||
const xEnd = centerX + radius * Math.cos(endRadians);
|
||||
const yEnd = centerY + radius * Math.sin(endRadians);
|
||||
|
||||
const dotRadius = Math.min((barWidth / 2) * DOT_RADIUS_FACTOR, MAX_DOT_RADIUS);
|
||||
const dotRadius =
|
||||
endpointMarker === 'point' ? Math.min((barWidth / 2) * DOT_RADIUS_FACTOR, MAX_DOT_RADIUS) : barWidth / 2;
|
||||
|
||||
let barEndcapColors: [string | undefined, string | undefined] | undefined;
|
||||
const endpointMarks: ReactElement[] = [];
|
||||
if (endpointMarker && gradientStops.length > 0) {
|
||||
switch (endpointMarker) {
|
||||
case 'point':
|
||||
const [pointColorStart, pointColorEnd] = getEndpointMarkerColors(gradientStops, fieldDisplay.display.percent);
|
||||
if (arcLengthDeg > DOT_START_MIN_ANGLE_DEG) {
|
||||
endpointMarks.push(
|
||||
<circle
|
||||
key="endpoint-marker-start"
|
||||
cx={xStart}
|
||||
cy={yStart}
|
||||
r={dotRadius}
|
||||
fill={pointColorStart}
|
||||
opacity={DOT_OPACITY}
|
||||
/>
|
||||
);
|
||||
}
|
||||
endpointMarks.push(
|
||||
<circle
|
||||
key="endpoint-marker-end"
|
||||
cx={xEnd}
|
||||
cy={yEnd}
|
||||
r={dotRadius}
|
||||
fill={pointColorEnd}
|
||||
opacity={DOT_OPACITY}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'glow':
|
||||
const xStartMark = centerX + radius * Math.cos(endRadians - 0.2);
|
||||
const yStartMark = centerY + radius * Math.sin(endRadians - 0.2);
|
||||
endpointMarks.push(
|
||||
<path
|
||||
d={['M', xStartMark, yStartMark, 'A', radius, radius, 0, 0, 1, xEnd, yEnd].join(' ')}
|
||||
fill="none"
|
||||
strokeWidth={barWidth}
|
||||
stroke={endpointMarkerGlowFilter}
|
||||
strokeLinecap={roundedBars ? 'round' : 'butt'}
|
||||
filter={glowFilter}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (shape === 'circle') {
|
||||
barEndcapColors = getBarEndcapColors(gradientStops, fieldDisplay.display.percent);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -100,14 +145,13 @@ export const RadialArcPath = memo(
|
||||
>
|
||||
<div style={bgDivStyle} />
|
||||
</foreignObject>
|
||||
{endpointColors && <circle cx={x1} cy={y1} r={barWidth / 2} fill={endpointColors[0]} />}
|
||||
{endpointColors && <circle cx={x2} cy={y2} r={barWidth / 2} fill={endpointColors[1]} />}
|
||||
{barEndcapColors?.[0] && <circle cx={xStart} cy={yStart} r={barWidth / 2} fill={barEndcapColors[0]} />}
|
||||
{barEndcapColors?.[1] && (
|
||||
<circle cx={xEnd} cy={yEnd} r={barWidth / 2} fill={barEndcapColors[1]} opacity={0.5} />
|
||||
)}
|
||||
</g>
|
||||
|
||||
{guideDotColors && arcLengthDeg > DOT_START_MIN_ANGLE_DEG && (
|
||||
<circle cx={x1} cy={y1} r={dotRadius} fill={guideDotColors[0]} opacity={DOT_OPACITY} />
|
||||
)}
|
||||
{guideDotColors && <circle cx={x2} cy={y2} r={dotRadius} fill={guideDotColors[1]} opacity={DOT_OPACITY} />}
|
||||
{endpointMarks}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,29 +3,33 @@ import { FieldDisplay } from '@grafana/data';
|
||||
import { useTheme2 } from '../../themes/ThemeContext';
|
||||
|
||||
import { RadialArcPath } from './RadialArcPath';
|
||||
import { RadialGradientMode, RadialShape, RadialGaugeDimensions } from './types';
|
||||
import { RadialShape, RadialGaugeDimensions } from './types';
|
||||
|
||||
export interface RadialBarProps {
|
||||
angle: number;
|
||||
angleRange: number;
|
||||
dimensions: RadialGaugeDimensions;
|
||||
fieldDisplay: FieldDisplay;
|
||||
glowFilter?: string;
|
||||
gradientMode: RadialGradientMode;
|
||||
gradient?: boolean;
|
||||
roundedBars?: boolean;
|
||||
endpointMarker?: 'point' | 'glow';
|
||||
shape: RadialShape;
|
||||
startAngle: number;
|
||||
glowFilter?: string;
|
||||
endpointMarkerGlowFilter?: string;
|
||||
}
|
||||
export function RadialBar({
|
||||
angle,
|
||||
angleRange,
|
||||
dimensions,
|
||||
fieldDisplay,
|
||||
glowFilter,
|
||||
gradientMode,
|
||||
gradient,
|
||||
roundedBars,
|
||||
endpointMarker,
|
||||
shape,
|
||||
startAngle,
|
||||
glowFilter,
|
||||
endpointMarkerGlowFilter,
|
||||
}: RadialBarProps) {
|
||||
const theme = useTheme2();
|
||||
return (
|
||||
@@ -36,7 +40,6 @@ export function RadialBar({
|
||||
fieldDisplay={fieldDisplay}
|
||||
color={theme.colors.action.hover}
|
||||
dimensions={dimensions}
|
||||
gradientMode="none"
|
||||
roundedBars={roundedBars}
|
||||
shape={shape}
|
||||
startAngle={startAngle + angle}
|
||||
@@ -44,15 +47,16 @@ export function RadialBar({
|
||||
{/** The colored bar */}
|
||||
<RadialArcPath
|
||||
arcLengthDeg={angle}
|
||||
color={gradientMode === 'none' ? fieldDisplay.display.color : undefined}
|
||||
color={gradient ? undefined : fieldDisplay.display.color}
|
||||
dimensions={dimensions}
|
||||
fieldDisplay={fieldDisplay}
|
||||
glowFilter={glowFilter}
|
||||
gradientMode={gradientMode}
|
||||
gradient={gradient}
|
||||
roundedBars={roundedBars}
|
||||
shape={shape}
|
||||
showGuideDots={roundedBars}
|
||||
endpointMarker={roundedBars ? endpointMarker : undefined}
|
||||
startAngle={startAngle}
|
||||
endpointMarkerGlowFilter={endpointMarkerGlowFilter}
|
||||
glowFilter={glowFilter}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -5,7 +5,7 @@ import { FALLBACK_COLOR, FieldDisplay } from '@grafana/data';
|
||||
import { useTheme2 } from '../../themes/ThemeContext';
|
||||
|
||||
import { RadialArcPath } from './RadialArcPath';
|
||||
import { RadialGradientMode, RadialShape, RadialGaugeDimensions } from './types';
|
||||
import { RadialShape, RadialGaugeDimensions } from './types';
|
||||
import {
|
||||
getAngleBetweenSegments,
|
||||
getFieldConfigMinMax,
|
||||
@@ -22,7 +22,7 @@ export interface RadialBarSegmentedProps {
|
||||
segmentCount: number;
|
||||
segmentSpacing: number;
|
||||
shape: RadialShape;
|
||||
gradientMode: RadialGradientMode;
|
||||
gradient?: boolean;
|
||||
}
|
||||
|
||||
export const RadialBarSegmented = memo(
|
||||
@@ -32,10 +32,10 @@ export const RadialBarSegmented = memo(
|
||||
startAngle,
|
||||
angleRange,
|
||||
glowFilter,
|
||||
gradient,
|
||||
segmentCount,
|
||||
segmentSpacing,
|
||||
shape,
|
||||
gradientMode,
|
||||
}: RadialBarSegmentedProps) => {
|
||||
const theme = useTheme2();
|
||||
|
||||
@@ -53,21 +53,21 @@ export const RadialBarSegmented = memo(
|
||||
let segmentColor: string | undefined;
|
||||
if (angleValue >= value) {
|
||||
segmentColor = theme.colors.action.hover;
|
||||
} else if (gradientMode === 'none') {
|
||||
} else if (!gradient) {
|
||||
segmentColor = displayProcessor(angleValue).color ?? FALLBACK_COLOR;
|
||||
}
|
||||
|
||||
segments.push(
|
||||
<RadialArcPath
|
||||
key={i}
|
||||
startAngle={segmentAngle}
|
||||
arcLengthDeg={segmentArcLengthDeg}
|
||||
color={segmentColor}
|
||||
dimensions={dimensions}
|
||||
fieldDisplay={fieldDisplay}
|
||||
color={segmentColor}
|
||||
shape={shape}
|
||||
glowFilter={glowFilter}
|
||||
arcLengthDeg={segmentArcLengthDeg}
|
||||
gradientMode={gradientMode}
|
||||
gradient={gradient}
|
||||
shape={shape}
|
||||
startAngle={segmentAngle}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { useTheme2 } from '../../themes/ThemeContext';
|
||||
import { Stack } from '../Layout/Stack/Stack';
|
||||
|
||||
import { RadialGauge, RadialGaugeProps } from './RadialGauge';
|
||||
import { RadialGradientMode, RadialShape, RadialTextMode } from './types';
|
||||
import { RadialShape, RadialTextMode } from './types';
|
||||
|
||||
interface StoryProps extends RadialGaugeProps {
|
||||
value: number;
|
||||
@@ -60,7 +60,7 @@ const meta: Meta<StoryProps> = {
|
||||
width: 200,
|
||||
height: 200,
|
||||
shape: 'circle',
|
||||
gradient: 'none',
|
||||
gradient: false,
|
||||
seriesCount: 1,
|
||||
segmentCount: 0,
|
||||
segmentSpacing: 0.2,
|
||||
@@ -77,7 +77,7 @@ const meta: Meta<StoryProps> = {
|
||||
roundedBars: { control: 'boolean' },
|
||||
sparkline: { control: 'boolean' },
|
||||
thresholdsBar: { control: 'boolean' },
|
||||
gradient: { control: { type: 'radio' } },
|
||||
gradient: { control: { type: 'boolean' } },
|
||||
seriesCount: { control: { type: 'range', min: 1, max: 20 } },
|
||||
segmentCount: { control: { type: 'range', min: 0, max: 100 } },
|
||||
segmentSpacing: { control: { type: 'range', min: 0, max: 1, step: 0.01 } },
|
||||
@@ -119,41 +119,17 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
<Stack direction={'column'} gap={3} wrap="wrap">
|
||||
<div>Bar width</div>
|
||||
<Stack direction="row" alignItems="center" gap={3} wrap="wrap">
|
||||
<RadialGaugeExample
|
||||
seriesName="0.1"
|
||||
value={args.value ?? 30}
|
||||
color="blue"
|
||||
gradient="auto"
|
||||
barWidthFactor={0.1}
|
||||
/>
|
||||
<RadialGaugeExample
|
||||
seriesName="0.4"
|
||||
value={args.value ?? 40}
|
||||
color="green"
|
||||
gradient="auto"
|
||||
barWidthFactor={0.4}
|
||||
/>
|
||||
<RadialGaugeExample
|
||||
seriesName="0.6"
|
||||
value={args.value ?? 60}
|
||||
color="red"
|
||||
gradient="auto"
|
||||
barWidthFactor={0.6}
|
||||
/>
|
||||
<RadialGaugeExample
|
||||
seriesName="0.8"
|
||||
value={args.value ?? 70}
|
||||
color="purple"
|
||||
gradient="auto"
|
||||
barWidthFactor={0.8}
|
||||
/>
|
||||
<RadialGaugeExample seriesName="0.1" value={args.value ?? 30} color="blue" gradient barWidthFactor={0.1} />
|
||||
<RadialGaugeExample seriesName="0.4" value={args.value ?? 40} color="green" gradient barWidthFactor={0.4} />
|
||||
<RadialGaugeExample seriesName="0.6" value={args.value ?? 60} color="red" gradient barWidthFactor={0.6} />
|
||||
<RadialGaugeExample seriesName="0.8" value={args.value ?? 70} color="purple" gradient barWidthFactor={0.8} />
|
||||
</Stack>
|
||||
<div>Effects</div>
|
||||
<Stack direction="row" alignItems="center" gap={3} wrap="wrap">
|
||||
<RadialGaugeExample value={args.value ?? 30} glowBar glowCenter color="blue" gradient="auto" />
|
||||
<RadialGaugeExample value={args.value ?? 40} glowBar glowCenter color="green" gradient="auto" />
|
||||
<RadialGaugeExample value={args.value ?? 60} glowBar glowCenter color="red" gradient="auto" roundedBars />
|
||||
<RadialGaugeExample value={args.value ?? 70} glowBar glowCenter color="purple" gradient="auto" roundedBars />
|
||||
<RadialGaugeExample value={args.value ?? 30} glowBar glowCenter color="blue" gradient />
|
||||
<RadialGaugeExample value={args.value ?? 40} glowBar glowCenter color="green" gradient />
|
||||
<RadialGaugeExample value={args.value ?? 60} glowBar glowCenter color="red" gradient roundedBars />
|
||||
<RadialGaugeExample value={args.value ?? 70} glowBar glowCenter color="purple" gradient roundedBars />
|
||||
</Stack>
|
||||
<div>Shape: Gauge & color scale</div>
|
||||
<Stack direction="row" alignItems="center" gap={3} wrap="wrap">
|
||||
@@ -161,14 +137,14 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
value={40}
|
||||
shape="gauge"
|
||||
width={250}
|
||||
gradient="auto"
|
||||
gradient
|
||||
colorScheme={FieldColorModeId.ContinuousGrYlRd}
|
||||
glowCenter={true}
|
||||
barWidthFactor={0.6}
|
||||
/>
|
||||
<RadialGaugeExample
|
||||
colorScheme={FieldColorModeId.ContinuousGrYlRd}
|
||||
gradient="auto"
|
||||
gradient
|
||||
width={250}
|
||||
value={90}
|
||||
barWidthFactor={0.6}
|
||||
@@ -184,7 +160,7 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
value={args.value ?? 70}
|
||||
color="blue"
|
||||
shape="gauge"
|
||||
gradient="auto"
|
||||
gradient
|
||||
sparkline={true}
|
||||
glowBar={true}
|
||||
glowCenter={true}
|
||||
@@ -194,7 +170,7 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
value={args.value ?? 30}
|
||||
color="green"
|
||||
shape="gauge"
|
||||
gradient="auto"
|
||||
gradient
|
||||
sparkline={true}
|
||||
glowBar={true}
|
||||
glowCenter={true}
|
||||
@@ -205,7 +181,7 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
color="red"
|
||||
shape="gauge"
|
||||
width={250}
|
||||
gradient="auto"
|
||||
gradient
|
||||
sparkline={true}
|
||||
glowBar={true}
|
||||
glowCenter={true}
|
||||
@@ -216,7 +192,7 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
color="red"
|
||||
width={250}
|
||||
shape="gauge"
|
||||
gradient="auto"
|
||||
gradient
|
||||
sparkline={true}
|
||||
glowBar={true}
|
||||
glowCenter={true}
|
||||
@@ -228,7 +204,7 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
<RadialGaugeExample
|
||||
value={args.value ?? 70}
|
||||
color="green"
|
||||
gradient="auto"
|
||||
gradient
|
||||
glowCenter={true}
|
||||
segmentCount={8}
|
||||
segmentSpacing={0.1}
|
||||
@@ -237,7 +213,7 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
<RadialGaugeExample
|
||||
value={args.value ?? 30}
|
||||
color="purple"
|
||||
gradient="auto"
|
||||
gradient
|
||||
segmentCount={30}
|
||||
glowCenter={true}
|
||||
barWidthFactor={0.6}
|
||||
@@ -245,7 +221,7 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
<RadialGaugeExample
|
||||
value={args.value ?? 50}
|
||||
color="red"
|
||||
gradient="auto"
|
||||
gradient
|
||||
segmentCount={40}
|
||||
glowCenter={true}
|
||||
barWidthFactor={1}
|
||||
@@ -267,7 +243,7 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
width={250}
|
||||
colorScheme={FieldColorModeId.ContinuousGrYlRd}
|
||||
shape="gauge"
|
||||
gradient="auto"
|
||||
gradient
|
||||
glowBar={true}
|
||||
glowCenter={true}
|
||||
segmentCount={40}
|
||||
@@ -280,7 +256,7 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
<RadialGaugeExample
|
||||
value={args.value ?? 70}
|
||||
colorScheme={FieldColorModeId.Thresholds}
|
||||
gradient="auto"
|
||||
gradient
|
||||
thresholdsBar={true}
|
||||
roundedBars={false}
|
||||
glowCenter={true}
|
||||
@@ -290,7 +266,7 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
value={args.value ?? 70}
|
||||
width={250}
|
||||
colorScheme={FieldColorModeId.Thresholds}
|
||||
gradient="auto"
|
||||
gradient
|
||||
glowCenter={true}
|
||||
thresholdsBar={true}
|
||||
roundedBars={false}
|
||||
@@ -301,7 +277,7 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
value={args.value ?? 70}
|
||||
width={250}
|
||||
colorScheme={FieldColorModeId.Thresholds}
|
||||
gradient="auto"
|
||||
gradient
|
||||
glowCenter={true}
|
||||
thresholdsBar={true}
|
||||
roundedBars={false}
|
||||
@@ -347,7 +323,6 @@ export const Temp: StoryFn<StoryProps> = (args) => {
|
||||
};
|
||||
|
||||
interface ExampleProps {
|
||||
gradient?: RadialGradientMode;
|
||||
color?: string;
|
||||
seriesName?: string;
|
||||
value?: number;
|
||||
@@ -356,6 +331,7 @@ interface ExampleProps {
|
||||
max?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
gradient?: boolean;
|
||||
glowBar?: boolean;
|
||||
glowCenter?: boolean;
|
||||
barWidthFactor?: number;
|
||||
@@ -373,7 +349,6 @@ interface ExampleProps {
|
||||
}
|
||||
|
||||
export function RadialGaugeExample({
|
||||
gradient = 'none',
|
||||
color,
|
||||
seriesName = 'Server A',
|
||||
value = 70,
|
||||
@@ -382,6 +357,7 @@ export function RadialGaugeExample({
|
||||
max = 100,
|
||||
width = 200,
|
||||
height = 200,
|
||||
gradient = false,
|
||||
glowBar = false,
|
||||
glowCenter = false,
|
||||
barWidthFactor = 0.4,
|
||||
|
||||
@@ -13,8 +13,8 @@ import { RadialScaleLabels } from './RadialScaleLabels';
|
||||
import { RadialSparkline } from './RadialSparkline';
|
||||
import { RadialText } from './RadialText';
|
||||
import { ThresholdsBar } from './ThresholdsBar';
|
||||
import { GlowGradient, MiddleCircleGlow } from './effects';
|
||||
import { RadialGradientMode, RadialShape, RadialTextMode } from './types';
|
||||
import { GlowGradient, MiddleCircleGlow, SpotlightGradient } from './effects';
|
||||
import { RadialShape, RadialTextMode } from './types';
|
||||
import { calculateDimensions, getValueAngleForValue } from './utils';
|
||||
|
||||
export interface RadialGaugeProps {
|
||||
@@ -25,7 +25,7 @@ export interface RadialGaugeProps {
|
||||
* Circle or gauge (partial circle)
|
||||
*/
|
||||
shape?: RadialShape;
|
||||
gradient?: RadialGradientMode;
|
||||
gradient?: boolean;
|
||||
/**
|
||||
* Bar width is always relative to size of the gauge.
|
||||
* But this gives you control over the width relative to size.
|
||||
@@ -37,6 +37,10 @@ export interface RadialGaugeProps {
|
||||
glowCenter?: boolean;
|
||||
roundedBars?: boolean;
|
||||
thresholdsBar?: boolean;
|
||||
/**
|
||||
* Specify if an endpoint marker should be shown at the end of the bar
|
||||
*/
|
||||
endpointMarker?: 'point' | 'glow';
|
||||
/**
|
||||
* Number of segments depends on size of gauge but this
|
||||
* factor 1-10 gives you relative control
|
||||
@@ -74,7 +78,7 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||
width = 256,
|
||||
height = 256,
|
||||
shape = 'circle',
|
||||
gradient = 'none',
|
||||
gradient = false,
|
||||
barWidthFactor = 0.4,
|
||||
glowBar = false,
|
||||
glowCenter = false,
|
||||
@@ -85,6 +89,7 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||
roundedBars = true,
|
||||
thresholdsBar = false,
|
||||
showScaleLabels = false,
|
||||
endpointMarker,
|
||||
onClick,
|
||||
values,
|
||||
} = props;
|
||||
@@ -120,8 +125,24 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||
showScaleLabels
|
||||
);
|
||||
|
||||
// FIXME: I want to move the ids for these filters into a context which the children
|
||||
// can reference via a hook, rather than passing them down as props
|
||||
const spotlightGradientId = `spotlight-${barIndex}-${gaugeId}`;
|
||||
const glowFilterId = `glow-${gaugeId}`;
|
||||
|
||||
if (endpointMarker === 'glow') {
|
||||
defs.push(
|
||||
<SpotlightGradient
|
||||
key={spotlightGradientId}
|
||||
id={spotlightGradientId}
|
||||
angle={angle + startAngle}
|
||||
dimensions={dimensions}
|
||||
roundedBars={roundedBars}
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (segmentCount > 1) {
|
||||
graphics.push(
|
||||
<RadialBarSegmented
|
||||
@@ -134,7 +155,7 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||
segmentCount={segmentCount}
|
||||
segmentSpacing={segmentSpacing}
|
||||
shape={shape}
|
||||
gradientMode={gradient}
|
||||
gradient={gradient}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
@@ -147,9 +168,11 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||
startAngle={startAngle}
|
||||
roundedBars={roundedBars}
|
||||
glowFilter={`url(#${glowFilterId})`}
|
||||
endpointMarkerGlowFilter={`url(#${spotlightGradientId})`}
|
||||
shape={shape}
|
||||
gradientMode={gradient}
|
||||
gradient={gradient}
|
||||
fieldDisplay={displayValue}
|
||||
endpointMarker={endpointMarker}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -210,7 +233,7 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||
roundedBars={roundedBars}
|
||||
glowFilter={`url(#${glowFilterId})`}
|
||||
shape={shape}
|
||||
gradientMode={gradient}
|
||||
gradient={gradient}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FieldDisplay, Threshold } from '@grafana/data';
|
||||
|
||||
import { RadialArcPath } from './RadialArcPath';
|
||||
import { RadialGaugeDimensions, RadialGradientMode, RadialShape } from './types';
|
||||
import { RadialGaugeDimensions, RadialShape } from './types';
|
||||
import { getFieldConfigMinMax } from './utils';
|
||||
|
||||
interface ThresholdsBarProps {
|
||||
@@ -14,7 +14,7 @@ interface ThresholdsBarProps {
|
||||
roundedBars?: boolean;
|
||||
glowFilter?: string;
|
||||
thresholds: Threshold[];
|
||||
gradientMode: RadialGradientMode;
|
||||
gradient?: boolean;
|
||||
}
|
||||
|
||||
export function ThresholdsBar({
|
||||
@@ -26,7 +26,7 @@ export function ThresholdsBar({
|
||||
glowFilter,
|
||||
thresholds,
|
||||
shape,
|
||||
gradientMode,
|
||||
gradient,
|
||||
}: ThresholdsBarProps) {
|
||||
const thresholdDimensions = {
|
||||
...dimensions,
|
||||
@@ -50,7 +50,7 @@ export function ThresholdsBar({
|
||||
}
|
||||
|
||||
const lengthDeg = valueDeg - currentStart + startAngle;
|
||||
const color = gradientMode === 'none' ? threshold.color : undefined;
|
||||
const color = gradient ? undefined : threshold.color;
|
||||
|
||||
paths.push(
|
||||
<RadialArcPath
|
||||
@@ -60,7 +60,7 @@ export function ThresholdsBar({
|
||||
dimensions={thresholdDimensions}
|
||||
fieldDisplay={fieldDisplay}
|
||||
glowFilter={glowFilter}
|
||||
gradientMode={gradientMode}
|
||||
gradient={gradient}
|
||||
roundedBars={roundedBars}
|
||||
shape={shape}
|
||||
startAngle={currentStart}
|
||||
|
||||
@@ -112,16 +112,12 @@ exports[`RadialGauge color utils buildGradientColors should return gradient colo
|
||||
exports[`RadialGauge color utils buildGradientColors should return gradient colors for fixed color mode in dark theme 1`] = `
|
||||
[
|
||||
{
|
||||
"color": "#030108",
|
||||
"color": "#210550",
|
||||
"percent": 0,
|
||||
},
|
||||
{
|
||||
"color": "#442299",
|
||||
"percent": 0.45,
|
||||
},
|
||||
{
|
||||
"color": "#442299",
|
||||
"percent": 0.55,
|
||||
"percent": 0.33,
|
||||
},
|
||||
{
|
||||
"color": "#ffffff",
|
||||
@@ -133,19 +129,15 @@ exports[`RadialGauge color utils buildGradientColors should return gradient colo
|
||||
exports[`RadialGauge color utils buildGradientColors should return gradient colors for fixed color mode in light theme 1`] = `
|
||||
[
|
||||
{
|
||||
"color": "#9689ca",
|
||||
"color": "#9181d3",
|
||||
"percent": 0,
|
||||
},
|
||||
{
|
||||
"color": "#442299",
|
||||
"percent": 0.45,
|
||||
"percent": 0.33,
|
||||
},
|
||||
{
|
||||
"color": "#442299",
|
||||
"percent": 0.55,
|
||||
},
|
||||
{
|
||||
"color": "#030108",
|
||||
"color": "#210550",
|
||||
"percent": 1,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -6,9 +6,9 @@ import { FieldColorModeId } from '@grafana/schema';
|
||||
import {
|
||||
buildGradientColors,
|
||||
colorAtGradientPercent,
|
||||
getEndpointColors,
|
||||
getBarEndcapColors,
|
||||
getEndpointMarkerColors,
|
||||
getGradientCss,
|
||||
getGuideDotColors,
|
||||
} from './colors';
|
||||
|
||||
export type DeepPartial<T> = {
|
||||
@@ -49,9 +49,16 @@ describe('RadialGauge color utils', () => {
|
||||
},
|
||||
});
|
||||
|
||||
it('should return the baseColor if gradientMode is none', () => {
|
||||
it('should return the baseColor if gradient is false-y', () => {
|
||||
expect(
|
||||
buildGradientColors('none', createTheme(), buildFieldDisplay(createField(FieldColorModeId.Fixed)), '#FF0000')
|
||||
buildGradientColors(false, createTheme(), buildFieldDisplay(createField(FieldColorModeId.Fixed)), '#FF0000')
|
||||
).toEqual([
|
||||
{ color: '#FF0000', percent: 0 },
|
||||
{ color: '#FF0000', percent: 1 },
|
||||
]);
|
||||
|
||||
expect(
|
||||
buildGradientColors(undefined, createTheme(), buildFieldDisplay(createField(FieldColorModeId.Fixed)), '#FF0000')
|
||||
).toEqual([
|
||||
{ color: '#FF0000', percent: 0 },
|
||||
{ color: '#FF0000', percent: 1 },
|
||||
@@ -59,18 +66,18 @@ describe('RadialGauge color utils', () => {
|
||||
});
|
||||
|
||||
it('uses the fallback color if no baseColor is set', () => {
|
||||
expect(
|
||||
buildGradientColors('none', createTheme(), buildFieldDisplay(createField(FieldColorModeId.Fixed)))
|
||||
).toEqual([
|
||||
{ color: FALLBACK_COLOR, percent: 0 },
|
||||
{ color: FALLBACK_COLOR, percent: 1 },
|
||||
]);
|
||||
expect(buildGradientColors(false, createTheme(), buildFieldDisplay(createField(FieldColorModeId.Fixed)))).toEqual(
|
||||
[
|
||||
{ color: FALLBACK_COLOR, percent: 0 },
|
||||
{ color: FALLBACK_COLOR, percent: 1 },
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it('should map threshold colors correctly (with baseColor if displayProcessor does not return colors)', () => {
|
||||
expect(
|
||||
buildGradientColors(
|
||||
'auto',
|
||||
true,
|
||||
createTheme(),
|
||||
buildFieldDisplay(createField(FieldColorModeId.Thresholds), {
|
||||
view: { getFieldDisplayProcessor: jest.fn(() => jest.fn(() => ({ color: '#444444' }))) },
|
||||
@@ -81,19 +88,14 @@ describe('RadialGauge color utils', () => {
|
||||
|
||||
it('should map threshold colors correctly (with baseColor if displayProcessor does not return colors)', () => {
|
||||
expect(
|
||||
buildGradientColors(
|
||||
'auto',
|
||||
createTheme(),
|
||||
buildFieldDisplay(createField(FieldColorModeId.Thresholds)),
|
||||
'#FF0000'
|
||||
)
|
||||
buildGradientColors(true, createTheme(), buildFieldDisplay(createField(FieldColorModeId.Thresholds)), '#FF0000')
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should return gradient colors for continuous color modes', () => {
|
||||
expect(
|
||||
buildGradientColors(
|
||||
'auto',
|
||||
true,
|
||||
createTheme(),
|
||||
buildFieldDisplay(createField(FieldColorModeId.ContinuousCividis)),
|
||||
'#00FF00'
|
||||
@@ -104,7 +106,7 @@ describe('RadialGauge color utils', () => {
|
||||
it.each(['dark', 'light'] as const)('should return gradient colors for by-value color mode in %s theme', (mode) => {
|
||||
expect(
|
||||
buildGradientColors(
|
||||
'auto',
|
||||
true,
|
||||
createTheme({ colors: { mode } }),
|
||||
buildFieldDisplay(createField(FieldColorModeId.ContinuousBlues))
|
||||
)
|
||||
@@ -114,7 +116,7 @@ describe('RadialGauge color utils', () => {
|
||||
it.each(['dark', 'light'] as const)('should return gradient colors for fixed color mode in %s theme', (mode) => {
|
||||
expect(
|
||||
buildGradientColors(
|
||||
'auto',
|
||||
true,
|
||||
createTheme({ colors: { mode } }),
|
||||
buildFieldDisplay(createField(FieldColorModeId.Fixed)),
|
||||
'#442299'
|
||||
@@ -168,14 +170,14 @@ describe('RadialGauge color utils', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getEndpointColors', () => {
|
||||
describe('getBarEndcapColors', () => {
|
||||
it('should return the first and last colors in the gradient', () => {
|
||||
const gradient = [
|
||||
{ color: '#ff0000', percent: 0 },
|
||||
{ color: '#00ff00', percent: 0.5 },
|
||||
{ color: '#0000ff', percent: 1 },
|
||||
];
|
||||
const [startColor, endColor] = getEndpointColors(gradient);
|
||||
const [startColor, endColor] = getBarEndcapColors(gradient);
|
||||
expect(startColor).toBe('#ff0000');
|
||||
expect(endColor).toBe('#0000ff');
|
||||
});
|
||||
@@ -186,22 +188,22 @@ describe('RadialGauge color utils', () => {
|
||||
{ color: '#00ff00', percent: 0.5 },
|
||||
{ color: '#0000ff', percent: 1 },
|
||||
];
|
||||
const [startColor, endColor] = getEndpointColors(gradient, 0.25);
|
||||
const [startColor, endColor] = getBarEndcapColors(gradient, 0.25);
|
||||
expect(startColor).toBe('#ff0000');
|
||||
expect(endColor).toBe('#808000');
|
||||
});
|
||||
|
||||
it('should handle gradients with only one colors', () => {
|
||||
const gradient = [{ color: '#ff0000', percent: 0 }];
|
||||
const [startColor, endColor] = getEndpointColors(gradient);
|
||||
const [startColor, endColor] = getBarEndcapColors(gradient);
|
||||
expect(startColor).toBe('#ff0000');
|
||||
expect(endColor).toBe('#ff0000');
|
||||
});
|
||||
|
||||
it('should throw an error when no colors are provided', () => {
|
||||
expect(() => {
|
||||
getEndpointColors([]);
|
||||
}).toThrow('getEndpointColors requires at least one color stop');
|
||||
getBarEndcapColors([]);
|
||||
}).toThrow('getBarEndcapColors requires at least one color stop');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -227,14 +229,14 @@ describe('RadialGauge color utils', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getGuideDotColors', () => {
|
||||
describe('getEndpointMarkerColors', () => {
|
||||
it('should return contrasting guide dot colors based on the gradient endpoints and percent', () => {
|
||||
const gradient = [
|
||||
{ color: '#000000', percent: 0 },
|
||||
{ color: '#ffffff', percent: 0.5 },
|
||||
{ color: '#ffffff', percent: 1 },
|
||||
];
|
||||
const [startDotColor, endDotColor] = getGuideDotColors(gradient, 0.35);
|
||||
const [startDotColor, endDotColor] = getEndpointMarkerColors(gradient, 0.35);
|
||||
expect(startDotColor).toBe('#fbfbfb');
|
||||
expect(endDotColor).toBe('#111217');
|
||||
});
|
||||
|
||||
@@ -3,16 +3,16 @@ import tinycolor from 'tinycolor2';
|
||||
import { colorManipulator, FALLBACK_COLOR, FieldDisplay, getFieldColorMode, GrafanaTheme2 } from '@grafana/data';
|
||||
import { FieldColorModeId } from '@grafana/schema';
|
||||
|
||||
import { GradientStop, RadialGradientMode, RadialShape } from './types';
|
||||
import { GradientStop, RadialShape } from './types';
|
||||
import { getFieldConfigMinMax, getFieldDisplayProcessor } from './utils';
|
||||
|
||||
export function buildGradientColors(
|
||||
gradientMode: RadialGradientMode,
|
||||
gradient = false,
|
||||
theme: GrafanaTheme2,
|
||||
fieldDisplay: FieldDisplay,
|
||||
baseColor = FALLBACK_COLOR
|
||||
): GradientStop[] {
|
||||
if (gradientMode === 'none') {
|
||||
if (!gradient) {
|
||||
return [
|
||||
{ color: baseColor, percent: 0 },
|
||||
{ color: baseColor, percent: 1 },
|
||||
@@ -67,16 +67,14 @@ export function buildGradientColors(
|
||||
|
||||
// for fixed colors and other modes, we create a simple two-color gradient
|
||||
// we set the highest contrast color second based on the theme.
|
||||
const darkerColor = tinycolor(baseColor).spin(5).darken(35).saturate(20);
|
||||
const darkerColor = tinycolor(baseColor).spin(5).darken(20).saturate(25);
|
||||
const lighterColor = tinycolor(baseColor)
|
||||
.spin(-5)
|
||||
.brighten(theme.isDark ? 30 : 15)
|
||||
.lighten(theme.isDark ? 35 : 15)
|
||||
.desaturate(10);
|
||||
.lighten(theme.isDark ? 35 : 15);
|
||||
return [
|
||||
{ color: theme.isDark ? darkerColor.toString() : lighterColor.toString(), percent: 0 },
|
||||
{ color: baseColor, percent: 0.45 },
|
||||
{ color: baseColor, percent: 0.55 },
|
||||
{ color: baseColor, percent: 0.33 },
|
||||
{ color: theme.isDark ? lighterColor.toString() : darkerColor.toString(), percent: 1 },
|
||||
];
|
||||
}
|
||||
@@ -138,9 +136,9 @@ export function colorAtGradientPercent(stops: GradientStop[], percent: number):
|
||||
return mixed;
|
||||
}
|
||||
|
||||
export function getEndpointColors(gradientStops: GradientStop[], percent = 1): [string, string] {
|
||||
export function getBarEndcapColors(gradientStops: GradientStop[], percent = 1): [string, string] {
|
||||
if (gradientStops.length === 0) {
|
||||
throw new Error('getEndpointColors requires at least one color stop');
|
||||
throw new Error('getBarEndcapColors requires at least one color stop');
|
||||
}
|
||||
|
||||
const startColor = gradientStops[0].color;
|
||||
@@ -173,7 +171,7 @@ const getGuideDotColor = (color: string): string => {
|
||||
return colorManipulator.getContrastRatio(darkColor, color) >= CONTRAST_THRESHOLD_MAX ? darkColor : lightColor;
|
||||
};
|
||||
|
||||
export function getGuideDotColors(gradientStops: GradientStop[], percent = 1): [string, string] {
|
||||
const [startColor, endColor] = getEndpointColors(gradientStops, percent);
|
||||
export function getEndpointMarkerColors(gradientStops: GradientStop[], percent = 1): [string, string] {
|
||||
const [startColor, endColor] = getBarEndcapColors(gradientStops, percent);
|
||||
return [getGuideDotColor(startColor), getGuideDotColor(endColor)];
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
|
||||
import { RadialGaugeDimensions } from './types';
|
||||
|
||||
export interface GlowGradientProps {
|
||||
@@ -57,3 +59,36 @@ export function MiddleCircleGlow({ dimensions, gaugeId, color }: CenterGlowProps
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function SpotlightGradient({
|
||||
id,
|
||||
dimensions,
|
||||
roundedBars,
|
||||
angle,
|
||||
theme,
|
||||
}: {
|
||||
id: string;
|
||||
dimensions: RadialGaugeDimensions;
|
||||
angle: number;
|
||||
roundedBars: boolean;
|
||||
theme: GrafanaTheme2;
|
||||
}) {
|
||||
if (theme.isLight) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const angleRadian = ((angle - 90) * Math.PI) / 180;
|
||||
|
||||
let x1 = dimensions.centerX + dimensions.radius * Math.cos(angleRadian - 0.2);
|
||||
let y1 = dimensions.centerY + dimensions.radius * Math.sin(angleRadian - 0.2);
|
||||
let x2 = dimensions.centerX + dimensions.radius * Math.cos(angleRadian);
|
||||
let y2 = dimensions.centerY + dimensions.radius * Math.sin(angleRadian);
|
||||
|
||||
return (
|
||||
<linearGradient x1={x1} y1={y1} x2={x2} y2={y2} id={id} gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0%" stopColor={'white'} stopOpacity={0.0} />
|
||||
<stop offset="95%" stopColor={'white'} stopOpacity={0.5} />
|
||||
{roundedBars && <stop offset="100%" stopColor={'white'} stopOpacity={roundedBars ? 0.7 : 1} />}
|
||||
</linearGradient>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
export type RadialGradientMode = 'none' | 'auto';
|
||||
export type RadialTextMode = 'auto' | 'value_and_name' | 'value' | 'name' | 'none';
|
||||
export type RadialShape = 'circle' | 'gauge';
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export function RadialBarPanel({
|
||||
width={width}
|
||||
height={height}
|
||||
barWidthFactor={options.barWidthFactor}
|
||||
gradient={options.effects?.gradient ? 'auto' : 'none'}
|
||||
gradient={options.effects?.gradient}
|
||||
glowBar={options.effects?.barGlow}
|
||||
glowCenter={options.effects?.centerGlow}
|
||||
roundedBars={options.barShape === 'rounded'}
|
||||
@@ -50,6 +50,7 @@ export function RadialBarPanel({
|
||||
alignmentFactors={valueProps.alignmentFactors}
|
||||
valueManualFontSize={options.text?.valueSize}
|
||||
nameManualFontSize={options.text?.titleSize}
|
||||
endpointMarker={options.endpointMarker !== 'none' ? options.endpointMarker : undefined}
|
||||
onClick={menuProps.openMenu}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -71,6 +71,22 @@ export const plugin = new PanelPlugin<Options>(RadialBarPanel)
|
||||
showIf: (options) => options.segmentCount === 1,
|
||||
});
|
||||
|
||||
builder.addRadio({
|
||||
path: 'endpointMarker',
|
||||
name: t('radialbar.config.endpoint-marker', 'Endpoint marker'),
|
||||
description: t('radialbar.config.endpoint-marker-description', 'Glow is only supported in dark mode.'),
|
||||
category,
|
||||
defaultValue: defaultOptions.endpointMarker,
|
||||
settings: {
|
||||
options: [
|
||||
{ value: 'point', label: t('radialbar.config.endpoint-marker-point', 'Point') },
|
||||
{ value: 'glow', label: t('radialbar.config.endpoint-marker-glow', 'Glow') },
|
||||
{ value: 'none', label: t('radialbar.config.endpoint-marker-none', 'None') },
|
||||
],
|
||||
},
|
||||
showIf: (options) => options.barShape === 'rounded' && options.segmentCount === 1,
|
||||
});
|
||||
|
||||
builder.addSliderInput({
|
||||
path: 'barWidthFactor',
|
||||
name: t('radialbar.config.bar-width', 'Bar width'),
|
||||
|
||||
@@ -28,7 +28,7 @@ composableKinds: PanelCfg: {
|
||||
GaugePanelEffects: {
|
||||
barGlow?: bool | *false
|
||||
centerGlow?: bool | *false
|
||||
gradient?: bool | *true
|
||||
gradient?: bool | *true
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
Options: {
|
||||
@@ -40,7 +40,8 @@ composableKinds: PanelCfg: {
|
||||
sparkline?: bool | *true
|
||||
shape: "circle" | *"gauge"
|
||||
barWidthFactor: number | *0.5
|
||||
barShape: "flat" | "rounded" | *"flat"
|
||||
barShape: "flat" | "rounded" | *"flat"
|
||||
endpointMarker?: "point" | "glow" | "none" | *"point"
|
||||
effects: GaugePanelEffects | *{}
|
||||
} @cuetsy(kind="interface")
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ export interface Options extends common.SingleStatBaseOptions {
|
||||
barShape: ('flat' | 'rounded');
|
||||
barWidthFactor: number;
|
||||
effects: GaugePanelEffects;
|
||||
endpointMarker?: ('point' | 'glow' | 'none');
|
||||
segmentCount: number;
|
||||
segmentSpacing: number;
|
||||
shape: ('circle' | 'gauge');
|
||||
@@ -38,6 +39,7 @@ export const defaultOptions: Partial<Options> = {
|
||||
barShape: 'flat',
|
||||
barWidthFactor: 0.5,
|
||||
effects: {},
|
||||
endpointMarker: 'point',
|
||||
segmentCount: 1,
|
||||
segmentSpacing: 0.3,
|
||||
shape: 'gauge',
|
||||
|
||||
Reference in New Issue
Block a user