mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Timeline: Use theme getContrastText to calculate value color based on background color (#34072)
* Timeline: Use theme getContrastText to calculate value color based on background color * Changed back to using the old functions fill, and stroke
This commit is contained in:
parent
36c4083264
commit
917a9ace57
@ -73,7 +73,7 @@ export interface ThemeHoverStrengh {}
|
||||
/** @beta */
|
||||
export interface ThemeColors extends ThemeColorsBase<ThemeRichColor> {
|
||||
/** Returns a text color for the background */
|
||||
getContrastText(background: string): string;
|
||||
getContrastText(background: string, threshold?: number): string;
|
||||
/* Brighten or darken a color by specified factor (0-1) */
|
||||
emphasize(color: string, amount?: number): string;
|
||||
}
|
||||
@ -255,11 +255,9 @@ export function createColors(colors: ThemeColorsInput): ThemeColors {
|
||||
...other
|
||||
} = colors;
|
||||
|
||||
function getContrastText(background: string) {
|
||||
function getContrastText(background: string, threshold: number = contrastThreshold) {
|
||||
const contrastText =
|
||||
getContrastRatio(background, dark.text.maxContrast) >= contrastThreshold
|
||||
? dark.text.maxContrast
|
||||
: light.text.maxContrast;
|
||||
getContrastRatio(background, dark.text.maxContrast) >= threshold ? dark.text.maxContrast : light.text.maxContrast;
|
||||
// todo, need color framework
|
||||
return contrastText;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { FIXED_UNIT } from '@grafana/ui/src/components/GraphNG/GraphNG';
|
||||
import { Quadtree, Rect, pointWithin } from 'app/plugins/panel/barchart/quadtree';
|
||||
import { distribute, SPACE_BETWEEN } from 'app/plugins/panel/barchart/distribute';
|
||||
import { TimelineMode } from './types';
|
||||
import { TimeRange } from '@grafana/data';
|
||||
import { GrafanaTheme2, TimeRange } from '@grafana/data';
|
||||
import { BarValueVisibility } from '@grafana/ui';
|
||||
|
||||
const { round, min, ceil } = Math;
|
||||
@ -12,8 +12,6 @@ const pxRatio = devicePixelRatio;
|
||||
|
||||
const laneDistr = SPACE_BETWEEN;
|
||||
|
||||
const font = Math.round(10 * pxRatio) + 'px Roboto';
|
||||
|
||||
type WalkCb = (idx: number, offPx: number, dimPx: number) => void;
|
||||
|
||||
function walk(rowHeight: number, yIdx: number | null, count: number, dim: number, draw: WalkCb) {
|
||||
@ -33,12 +31,13 @@ export interface TimelineCoreOptions {
|
||||
numSeries: number;
|
||||
rowHeight: number;
|
||||
colWidth?: number;
|
||||
theme: GrafanaTheme2;
|
||||
showValue: BarValueVisibility;
|
||||
isDiscrete: (seriesIdx: number) => boolean;
|
||||
|
||||
colorLookup: (seriesIdx: number, value: any) => string;
|
||||
label: (seriesIdx: number) => string;
|
||||
fill: (seriesIdx: number, valueIdx: number, value: any) => CanvasRenderingContext2D['fillStyle'];
|
||||
stroke: (seriesIdx: number, valueIdx: number, value: any) => CanvasRenderingContext2D['strokeStyle'];
|
||||
fill: (seriesIdx: number, value: any) => CanvasRenderingContext2D['fillStyle'];
|
||||
stroke: (seriesIdx: number, value: any) => CanvasRenderingContext2D['strokeStyle'];
|
||||
getTimeRange: () => TimeRange;
|
||||
formatValue?: (seriesIdx: number, value: any) => string;
|
||||
onHover?: (seriesIdx: number, valueIdx: number) => void;
|
||||
@ -56,11 +55,13 @@ export function getConfig(opts: TimelineCoreOptions) {
|
||||
rowHeight = 0,
|
||||
colWidth = 0,
|
||||
showValue,
|
||||
theme,
|
||||
label,
|
||||
fill,
|
||||
stroke,
|
||||
formatValue,
|
||||
getTimeRange,
|
||||
colorLookup,
|
||||
// onHover,
|
||||
// onLeave,
|
||||
} = opts;
|
||||
@ -73,10 +74,11 @@ export function getConfig(opts: TimelineCoreOptions) {
|
||||
let mark = document.createElement('div');
|
||||
mark.classList.add('bar-mark');
|
||||
mark.style.position = 'absolute';
|
||||
mark.style.background = 'rgba(255,255,255,0.4)';
|
||||
mark.style.background = 'rgba(255,255,255,0.2)';
|
||||
return mark;
|
||||
});
|
||||
|
||||
const font = `500 ${Math.round(12 * devicePixelRatio)}px ${theme.typography.fontFamily}`;
|
||||
const hovered: Array<Rect | null> = Array(numSeries).fill(null);
|
||||
|
||||
const size = [colWidth, Infinity];
|
||||
@ -117,7 +119,7 @@ export function getConfig(opts: TimelineCoreOptions) {
|
||||
discrete: boolean
|
||||
) {
|
||||
if (discrete) {
|
||||
let fillStyle = fill(seriesIdx + 1, valueIdx, value);
|
||||
let fillStyle = fill(seriesIdx + 1, value);
|
||||
let fillPath = fillPaths.get(fillStyle);
|
||||
|
||||
if (fillPath == null) {
|
||||
@ -127,7 +129,7 @@ export function getConfig(opts: TimelineCoreOptions) {
|
||||
rect(fillPath, lft, top, wid, hgt);
|
||||
|
||||
if (strokeWidth) {
|
||||
let strokeStyle = stroke(seriesIdx + 1, valueIdx, value);
|
||||
let strokeStyle = stroke(seriesIdx + 1, value);
|
||||
let strokePath = strokePaths.get(strokeStyle);
|
||||
|
||||
if (strokePath == null) {
|
||||
@ -139,13 +141,13 @@ export function getConfig(opts: TimelineCoreOptions) {
|
||||
} else {
|
||||
ctx.beginPath();
|
||||
rect(ctx, lft, top, wid, hgt);
|
||||
ctx.fillStyle = fill(seriesIdx, valueIdx, value);
|
||||
ctx.fillStyle = fill(seriesIdx, value);
|
||||
ctx.fill();
|
||||
|
||||
if (strokeWidth) {
|
||||
ctx.beginPath();
|
||||
rect(ctx, lft + strokeWidth / 2, top + strokeWidth / 2, wid - strokeWidth, hgt - strokeWidth);
|
||||
ctx.strokeStyle = stroke(seriesIdx, valueIdx, value);
|
||||
ctx.strokeStyle = stroke(seriesIdx, value);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
@ -195,7 +197,7 @@ export function getConfig(opts: TimelineCoreOptions) {
|
||||
yOff,
|
||||
lft,
|
||||
round(yOff + y0),
|
||||
rgt - lft,
|
||||
rgt - lft - 2,
|
||||
round(hgt),
|
||||
strokeWidth,
|
||||
iy,
|
||||
@ -257,7 +259,6 @@ export function getConfig(opts: TimelineCoreOptions) {
|
||||
u.ctx.clip();
|
||||
|
||||
u.ctx.font = font;
|
||||
u.ctx.fillStyle = 'black';
|
||||
u.ctx.textAlign = mode === TimelineMode.Changes ? 'left' : 'center';
|
||||
u.ctx.textBaseline = 'middle';
|
||||
|
||||
@ -285,6 +286,15 @@ export function getConfig(opts: TimelineCoreOptions) {
|
||||
for (let ix = 0; ix < dataY.length; ix++) {
|
||||
if (dataY[ix] != null) {
|
||||
let x = valToPosX(dataX[ix], scaleX, xDim, xOff);
|
||||
|
||||
// For the left aligned values shift them 2 pixels of edge
|
||||
if (mode === TimelineMode.Changes) {
|
||||
x += 2;
|
||||
}
|
||||
|
||||
const valueColor = colorLookup(sidx, dataY[ix]);
|
||||
|
||||
u.ctx.fillStyle = theme.colors.getContrastText(valueColor, 3);
|
||||
u.ctx.fillText(formatValue(sidx, dataY[ix]), x, y);
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ import {
|
||||
formattedValueToString,
|
||||
getFieldDisplayName,
|
||||
outerJoinDataFrames,
|
||||
classicColors,
|
||||
Field,
|
||||
FALLBACK_COLOR,
|
||||
} from '@grafana/data';
|
||||
import {
|
||||
UPlotConfigBuilder,
|
||||
@ -72,15 +72,17 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{
|
||||
return !(mode && field.display && mode.startsWith('continuous-'));
|
||||
};
|
||||
|
||||
const colorLookup = (seriesIdx: number, valueIdx: number, value: any) => {
|
||||
const colorLookup = (seriesIdx: number, value: any) => {
|
||||
const field = frame.fields[seriesIdx];
|
||||
|
||||
if (field.display) {
|
||||
const disp = field.display(value); // will apply color modes
|
||||
if (disp.color) {
|
||||
return disp.color;
|
||||
}
|
||||
}
|
||||
return classicColors[Math.floor(value % classicColors.length)];
|
||||
|
||||
return FALLBACK_COLOR;
|
||||
};
|
||||
|
||||
const yAxisWidth =
|
||||
@ -99,9 +101,11 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{
|
||||
rowHeight: rowHeight!,
|
||||
colWidth: colWidth,
|
||||
showValue: showValue!,
|
||||
theme,
|
||||
label: (seriesIdx) => getFieldDisplayName(frame.fields[seriesIdx], frame),
|
||||
fill: colorLookup,
|
||||
stroke: colorLookup,
|
||||
colorLookup,
|
||||
getTimeRange,
|
||||
// hardcoded formatter for state values
|
||||
formatValue: (seriesIdx, value) => formattedValueToString(frame.fields[seriesIdx].display!(value)),
|
||||
|
Loading…
Reference in New Issue
Block a user