From 953aadd6e478bf9fbdf7a592c29d9acc27aa755c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 14 May 2021 17:24:40 +0200 Subject: [PATCH] Timeline: Adds opacity & line width option (#34118) * Timeline: Adds opacity & line width option * Updated devenv dashboards, added back original timeline modes --- .../panel-timeline/timeline-demo.json | 414 ++++++++++++++++++ .../panel-timeline/timeline-modes.json | 2 +- .../grafana-data/src/themes/createColors.ts | 2 +- .../src/utils/OptionsUIBuilders.ts | 7 +- .../uPlot/config/UPlotConfigBuilder.ts | 1 + public/app/plugins/panel/timeline/module.tsx | 21 +- public/app/plugins/panel/timeline/timeline.ts | 93 ++-- public/app/plugins/panel/timeline/types.ts | 6 +- public/app/plugins/panel/timeline/utils.ts | 25 +- 9 files changed, 487 insertions(+), 84 deletions(-) create mode 100644 devenv/dev-dashboards/panel-timeline/timeline-demo.json diff --git a/devenv/dev-dashboards/panel-timeline/timeline-demo.json b/devenv/dev-dashboards/panel-timeline/timeline-demo.json new file mode 100644 index 00000000000..81372febb15 --- /dev/null +++ b/devenv/dev-dashboards/panel-timeline/timeline-demo.json @@ -0,0 +1,414 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "fillOpacity": 80, + "lineWidth": 1 + }, + "mappings": [ + { + "options": { + "CRITICAL": { + "color": "red", + "index": 3 + }, + "HIGH": { + "color": "orange", + "index": 2 + }, + "LOW": { + "color": "blue", + "index": 0 + }, + "NORMAL": { + "color": "green", + "index": 1 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 9, + "options": { + "alignValue": "center", + "colWidth": 0.9, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "mode": "changes", + "rowHeight": 0.98, + "showValue": "always" + }, + "pluginVersion": "7.5.0-pre", + "targets": [ + { + "alias": "SensorA", + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "LOW,HIGH,NORMAL,NORMAL,NORMAL,LOW,LOW,NORMAL,HIGH,CRITICAL" + }, + { + "alias": "SensorB", + "hide": false, + "refId": "B", + "scenarioId": "csv_metric_values", + "stringInput": "NORMAL,LOW,LOW,CRITICAL,CRITICAL,LOW,LOW,NORMAL,HIGH,CRITICAL" + }, + { + "alias": "SensorA", + "hide": false, + "refId": "C", + "scenarioId": "csv_metric_values", + "stringInput": "NORMAL,NORMAL,NORMAL,NORMAL,CRITICAL,LOW,NORMAL,NORMAL,NORMAL,LOW" + } + ], + "title": "State changes strings", + "type": "timeline" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 1 + }, + "mappings": [ + { + "options": { + "match": "true", + "result": { + "color": "semi-dark-green", + "index": 0, + "text": "ON" + } + }, + "type": "special" + }, + { + "options": { + "match": "false", + "result": { + "color": "red", + "index": 1, + "text": "OFF" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 13, + "x": 0, + "y": 8 + }, + "id": 13, + "options": { + "alignValue": "center", + "colWidth": 1, + "mode": "changes", + "rowHeight": 0.98, + "showValue": "always" + }, + "targets": [ + { + "alias": "", + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "true,false,true,true,true,true,false,false" + }, + { + "hide": false, + "refId": "B", + "scenarioId": "csv_metric_values", + "stringInput": "false,true,false,true,true,false,false,false,true,true" + }, + { + "hide": false, + "refId": "C", + "scenarioId": "csv_metric_values", + "stringInput": "true,false,true,true" + }, + { + "hide": false, + "refId": "D", + "scenarioId": "csv_metric_values", + "stringInput": "false,true,false,true,true" + } + ], + "title": "State changes with boolean values", + "type": "timeline" + }, + { + "datasource": null, + "description": "Should show gaps", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 80, + "lineWidth": 1 + }, + "mappings": [ + { + "options": { + "match": "true", + "result": { + "color": "semi-dark-green", + "index": 0, + "text": "ON" + } + }, + "type": "special" + }, + { + "options": { + "match": "false", + "result": { + "color": "red", + "index": 1, + "text": "OFF" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 11, + "x": 13, + "y": 8 + }, + "id": 12, + "options": { + "alignValue": "center", + "colWidth": 1, + "mode": "changes", + "rowHeight": 0.98, + "showValue": "always" + }, + "targets": [ + { + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "true,false,true,true,true,true,false,false" + }, + { + "hide": false, + "refId": "B", + "scenarioId": "csv_metric_values", + "stringInput": "false,true,false,true,true,false,false,false,true,true" + }, + { + "hide": false, + "refId": "C", + "scenarioId": "csv_metric_values", + "stringInput": "true,false,null,true,true" + }, + { + "hide": false, + "refId": "D", + "scenarioId": "csv_metric_values", + "stringInput": "false,null,null,false,true,true" + } + ], + "title": "State changes with nulls", + "type": "timeline" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "fillOpacity": 96, + "lineWidth": 0 + }, + "decimals": 0, + "mappings": [], + "max": 30, + "min": -10, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 4, + "interval": null, + "maxDataPoints": 20, + "options": { + "alignValue": "center", + "colWidth": 0.96, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "mode": "samples", + "rowHeight": 0.98, + "showValue": "always" + }, + "pluginVersion": "7.5.0-pre", + "targets": [ + { + "alias": "", + "csvWave": { + "timeStep": 60, + "valuesCSV": "0,0,2,2,1,1" + }, + "lines": 10, + "max": 30, + "min": -10, + "noise": 2, + "points": [], + "pulseWave": { + "offCount": 3, + "offValue": 1, + "onCount": 3, + "onValue": 2, + "timeStep": 60 + }, + "refId": "A", + "scenarioId": "random_walk", + "seriesCount": 4, + "spread": 15, + "startValue": 5, + "stream": { + "bands": 1, + "noise": 2.2, + "speed": 250, + "spread": 3.5, + "type": "signal" + }, + "stringInput": "" + } + ], + "title": "\"Periodic samples\" Mode", + "type": "timeline" + } + ], + "refresh": false, + "schemaVersion": 30, + "style": "dark", + "tags": [ + "gdev", + "demo" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": {}, + "timezone": "utc", + "title": "Timeline Demo", + "uid": "mIJjFy8Kz", + "version": 13 +} \ No newline at end of file diff --git a/devenv/dev-dashboards/panel-timeline/timeline-modes.json b/devenv/dev-dashboards/panel-timeline/timeline-modes.json index 07d71ceac91..28c0f186671 100644 --- a/devenv/dev-dashboards/panel-timeline/timeline-modes.json +++ b/devenv/dev-dashboards/panel-timeline/timeline-modes.json @@ -338,7 +338,7 @@ "refresh": false, "schemaVersion": 29, "style": "dark", - "tags": [], + "tags": ["gdev", "panel-tests"], "templating": { "list": [] }, diff --git a/packages/grafana-data/src/themes/createColors.ts b/packages/grafana-data/src/themes/createColors.ts index d0e6187f76a..17b1dafd403 100644 --- a/packages/grafana-data/src/themes/createColors.ts +++ b/packages/grafana-data/src/themes/createColors.ts @@ -257,7 +257,7 @@ export function createColors(colors: ThemeColorsInput): ThemeColors { function getContrastText(background: string, threshold: number = contrastThreshold) { const contrastText = - getContrastRatio(background, dark.text.maxContrast) >= threshold ? dark.text.maxContrast : light.text.maxContrast; + getContrastRatio(dark.text.maxContrast, background) >= threshold ? dark.text.maxContrast : light.text.maxContrast; // todo, need color framework return contrastText; } diff --git a/packages/grafana-data/src/utils/OptionsUIBuilders.ts b/packages/grafana-data/src/utils/OptionsUIBuilders.ts index 0c63d9f9292..32b09db0ae6 100644 --- a/packages/grafana-data/src/utils/OptionsUIBuilders.ts +++ b/packages/grafana-data/src/utils/OptionsUIBuilders.ts @@ -1,6 +1,5 @@ import { FieldConfigEditorProps, FieldConfigPropertyItem, FieldConfigEditorConfig } from '../types/fieldOverrides'; import { OptionsUIRegistryBuilder } from '../types/OptionsUIRegistryBuilder'; -import { FieldType } from '../types/dataFrame'; import { PanelOptionsEditorConfig, PanelOptionsEditorItem } from '../types/panel'; import { numberOverrideProcessor, @@ -33,7 +32,7 @@ export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder override: standardEditorsRegistry.get('number').editor as any, editor: standardEditorsRegistry.get('number').editor as any, process: numberOverrideProcessor, - shouldApply: config.shouldApply ? config.shouldApply : (field) => field.type === FieldType.number, + shouldApply: config.shouldApply ?? (() => true), settings: config.settings || {}, }); } @@ -45,7 +44,7 @@ export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder override: standardEditorsRegistry.get('slider').editor as any, editor: standardEditorsRegistry.get('slider').editor as any, process: numberOverrideProcessor, - shouldApply: config.shouldApply ? config.shouldApply : (field) => field.type === FieldType.number, + shouldApply: config.shouldApply ?? (() => true), settings: config.settings || {}, }); } @@ -57,7 +56,7 @@ export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder override: standardEditorsRegistry.get('text').editor as any, editor: standardEditorsRegistry.get('text').editor as any, process: stringOverrideProcessor, - shouldApply: config.shouldApply ? config.shouldApply : (field) => field.type === FieldType.string, + shouldApply: config.shouldApply ?? (() => true), settings: config.settings || {}, }); } diff --git a/packages/grafana-ui/src/components/uPlot/config/UPlotConfigBuilder.ts b/packages/grafana-ui/src/components/uPlot/config/UPlotConfigBuilder.ts index b864a2b30b1..aecb58eac10 100644 --- a/packages/grafana-ui/src/components/uPlot/config/UPlotConfigBuilder.ts +++ b/packages/grafana-ui/src/components/uPlot/config/UPlotConfigBuilder.ts @@ -107,6 +107,7 @@ export class UPlotConfigBuilder { setStacking(enabled = true) { this.isStacking = enabled; } + addSeries(props: SeriesProps) { this.series.push(new UPlotSeriesBuilder(props)); } diff --git a/public/app/plugins/panel/timeline/module.tsx b/public/app/plugins/panel/timeline/module.tsx index c9394a2f97c..23d8fccc398 100755 --- a/public/app/plugins/panel/timeline/module.tsx +++ b/public/app/plugins/panel/timeline/module.tsx @@ -1,6 +1,6 @@ import { FieldColorModeId, FieldConfigProperty, PanelPlugin } from '@grafana/data'; import { TimelinePanel } from './TimelinePanel'; -import { TimelineOptions, TimelineFieldConfig, TimelineMode } from './types'; +import { TimelineOptions, TimelineFieldConfig, TimelineMode, defaultTimelineFieldConfig } from './types'; import { BarValueVisibility } from '@grafana/ui'; export const plugin = new PanelPlugin(TimelinePanel) @@ -15,15 +15,12 @@ export const plugin = new PanelPlugin(Time }, }, }, - /* useCustomConfig: (builder) => { - const cfg = defaultBarChartFieldConfig; - builder .addSliderInput({ path: 'lineWidth', name: 'Line width', - defaultValue: cfg.lineWidth, + defaultValue: defaultTimelineFieldConfig.lineWidth, settings: { min: 0, max: 10, @@ -33,26 +30,14 @@ export const plugin = new PanelPlugin(Time .addSliderInput({ path: 'fillOpacity', name: 'Fill opacity', - defaultValue: cfg.fillOpacity, + defaultValue: defaultTimelineFieldConfig.fillOpacity, settings: { min: 0, max: 100, step: 1, }, - }) - .addRadio({ - path: 'gradientMode', - name: 'Gradient mode', - defaultValue: graphFieldOptions.fillGradient[0].value, - settings: { - options: graphFieldOptions.fillGradient, - }, }); - - // addAxisConfig(builder, cfg, true); - addHideFrom(builder); }, - */ }) .setPanelOptions((builder) => { builder diff --git a/public/app/plugins/panel/timeline/timeline.ts b/public/app/plugins/panel/timeline/timeline.ts index da9f8c763cd..ea88e0e6320 100644 --- a/public/app/plugins/panel/timeline/timeline.ts +++ b/public/app/plugins/panel/timeline/timeline.ts @@ -2,9 +2,10 @@ import uPlot, { Series, Cursor } from 'uplot'; 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, TimelineValueAlignment } from './types'; +import { TimelineFieldConfig, TimelineMode, TimelineValueAlignment } from './types'; import { GrafanaTheme2, TimeRange } from '@grafana/data'; import { BarValueVisibility } from '@grafana/ui'; +import tinycolor from 'tinycolor2'; const { round, min, ceil } = Math; @@ -26,6 +27,7 @@ function walk(rowHeight: number, yIdx: number | null, count: number, dim: number interface TimelineBoxRect extends Rect { left: number; strokeWidth: number; + fillColor: string; } /** @@ -40,12 +42,11 @@ export interface TimelineCoreOptions { showValue: BarValueVisibility; alignValue: TimelineValueAlignment; isDiscrete: (seriesIdx: number) => boolean; - colorLookup: (seriesIdx: number, value: any) => string; + getValueColor: (seriesIdx: number, value: any) => string; label: (seriesIdx: number) => string; - fill: (seriesIdx: number, value: any) => CanvasRenderingContext2D['fillStyle']; - stroke: (seriesIdx: number, value: any) => CanvasRenderingContext2D['strokeStyle']; getTimeRange: () => TimeRange; formatValue?: (seriesIdx: number, value: any) => string; + getFieldConfig: (seriesIdx: number) => TimelineFieldConfig; onHover?: (seriesIdx: number, valueIdx: number) => void; onLeave?: (seriesIdx: number, valueIdx: number) => void; } @@ -64,11 +65,10 @@ export function getConfig(opts: TimelineCoreOptions) { alignValue, theme, label, - fill, - stroke, formatValue, getTimeRange, - colorLookup, + getValueColor, + getFieldConfig, // onHover, // onLeave, } = opts; @@ -85,7 +85,7 @@ export function getConfig(opts: TimelineCoreOptions) { return mark; }); - // alignement-aware text position cache filled by drawPaths->putBox for use in drawPoints + // Needed for to calculate text positions let boxRectsBySeries: TimelineBoxRect[][]; const resetBoxRectsBySeries = (count: number) => { @@ -134,8 +134,32 @@ export function getConfig(opts: TimelineCoreOptions) { value: any, discrete: boolean ) { + // do not render super small boxes + if (boxWidth < 1) { + return; + } + + const valueColor = getValueColor(seriesIdx + 1, value); + const fieldConfig = getFieldConfig(seriesIdx); + const fillColor = getFillColor(fieldConfig, valueColor); + + const boxRect = (boxRectsBySeries[seriesIdx][valueIdx] = { + x: round(left - xOff), + y: round(top - yOff), + w: boxWidth, + h: boxHeight, + sidx: seriesIdx + 1, + didx: valueIdx, + // These two are needed for later text positioning + left: left, + strokeWidth, + fillColor, + }); + + qt.add(boxRect); + if (discrete) { - let fillStyle = fill(seriesIdx + 1, value); + let fillStyle = fillColor; let fillPath = fillPaths.get(fillStyle); if (fillPath == null) { @@ -145,7 +169,7 @@ export function getConfig(opts: TimelineCoreOptions) { rect(fillPath, left, top, boxWidth, boxHeight); if (strokeWidth) { - let strokeStyle = stroke(seriesIdx + 1, value); + let strokeStyle = valueColor; let strokePath = strokePaths.get(strokeStyle); if (strokePath == null) { @@ -163,30 +187,17 @@ export function getConfig(opts: TimelineCoreOptions) { } else { ctx.beginPath(); rect(ctx, left, top, boxWidth, boxHeight); - ctx.fillStyle = fill(seriesIdx, value); + ctx.fillStyle = fillColor; ctx.fill(); if (strokeWidth) { ctx.beginPath(); rect(ctx, left + strokeWidth / 2, top + strokeWidth / 2, boxWidth - strokeWidth, boxHeight - strokeWidth); - ctx.strokeStyle = stroke(seriesIdx, value); + ctx.strokeStyle = valueColor; + ctx.lineWidth = strokeWidth; ctx.stroke(); } } - - const boxRect = (boxRectsBySeries[seriesIdx][valueIdx] = { - x: round(left - xOff), - y: round(top - yOff), - w: boxWidth, - h: boxHeight, - sidx: seriesIdx + 1, - didx: valueIdx, - // These two are needed for later text positioning - left: left, - strokeWidth, - }); - - qt.add(boxRect); } const drawPaths: Series.PathBuilder = (u, sidx, idx0, idx1) => { @@ -202,17 +213,17 @@ export function getConfig(opts: TimelineCoreOptions) { rect(u.ctx, u.bbox.left, u.bbox.top, u.bbox.width, u.bbox.height); u.ctx.clip(); - walk(rowHeight, sidx - 1, numSeries, yDim, (iy, y0, hgt) => { + walk(rowHeight, sidx - 1, numSeries, yDim, (iy, y0, height) => { if (mode === TimelineMode.Changes) { for (let ix = 0; ix < dataY.length; ix++) { if (dataY[ix] != null) { - let lft = Math.round(valToPosX(dataX[ix], scaleX, xDim, xOff)); + let left = Math.round(valToPosX(dataX[ix], scaleX, xDim, xOff)); let nextIx = ix; while (dataY[++nextIx] === undefined && nextIx < dataY.length) {} // to now (not to end of chart) - let rgt = + let right = nextIx === dataY.length ? xOff + xDim + strokeWidth : Math.round(valToPosX(dataX[nextIx], scaleX, xDim, xOff)); @@ -222,10 +233,10 @@ export function getConfig(opts: TimelineCoreOptions) { rect, xOff, yOff, - lft, + left, round(yOff + y0), - rgt - lft - 2, - round(hgt), + right - left - 2, + round(height), strokeWidth, iy, ix, @@ -246,17 +257,17 @@ export function getConfig(opts: TimelineCoreOptions) { for (let ix = idx0; ix <= idx1; ix++) { if (dataY[ix] != null) { // TODO: all xPos can be pre-computed once for all series in aligned set - let lft = valToPosX(dataX[ix], scaleX, xDim, xOff); + let left = valToPosX(dataX[ix], scaleX, xDim, xOff); putBox( u.ctx, rect, xOff, yOff, - round(lft - xShift), + round(left - xShift), round(yOff + y0), barWid, - round(hgt), + round(height), strokeWidth, iy, ix, @@ -315,14 +326,13 @@ export function getConfig(opts: TimelineCoreOptions) { const boxRect = boxRectsBySeries[sidx - 1][ix]; // Todo refine this to better know when to not render text (when values do not fit) - if (boxRect.w < 20) { + if (!boxRect || boxRect.w < 20) { continue; } const x = getTextPositionOffet(boxRect, alignValue); - const valueColor = colorLookup(sidx, dataY[ix]); - u.ctx.fillStyle = theme.colors.getContrastText(valueColor, 3); + u.ctx.fillStyle = theme.colors.getContrastText(boxRect.fillColor, 3); u.ctx.fillText(formatValue(sidx, dataY[ix]), x, y); } } @@ -455,8 +465,8 @@ export function getConfig(opts: TimelineCoreOptions) { return ySplits; }, - yValues: (u: uPlot, splits: number[]) => splits.map((v, i) => label(i + 1)), + yValues: (u: uPlot, splits: number[]) => splits.map((v, i) => label(i + 1)), yRange: [0, 1] as uPlot.Range.MinMax, // pathbuilders @@ -482,3 +492,8 @@ function getTextPositionOffet(rect: TimelineBoxRect, alignValue: TimelineValueAl textPadding ); } + +function getFillColor(fieldConfig: TimelineFieldConfig, color: string) { + const opacityPercent = (fieldConfig.fillOpacity ?? 100) / 100; + return tinycolor(color).setAlpha(opacityPercent).toString(); +} diff --git a/public/app/plugins/panel/timeline/types.ts b/public/app/plugins/panel/timeline/types.ts index 1bdad8abd7a..f4dcf1b7fe5 100644 --- a/public/app/plugins/panel/timeline/types.ts +++ b/public/app/plugins/panel/timeline/types.ts @@ -1,4 +1,4 @@ -import { VizLegendOptions, GraphGradientMode, HideableFieldConfig, BarValueVisibility } from '@grafana/ui'; +import { VizLegendOptions, HideableFieldConfig, BarValueVisibility } from '@grafana/ui'; /** * @alpha @@ -20,7 +20,6 @@ export type TimelineValueAlignment = 'center' | 'left' | 'right'; export interface TimelineFieldConfig extends HideableFieldConfig { lineWidth?: number; // 0 fillOpacity?: number; // 100 - gradientMode?: GraphGradientMode; } /** @@ -28,8 +27,7 @@ export interface TimelineFieldConfig extends HideableFieldConfig { */ export const defaultTimelineFieldConfig: TimelineFieldConfig = { lineWidth: 1, - fillOpacity: 80, - gradientMode: GraphGradientMode.None, + fillOpacity: 70, }; /** diff --git a/public/app/plugins/panel/timeline/utils.ts b/public/app/plugins/panel/timeline/utils.ts index 16017cae165..d7ed865dd9b 100644 --- a/public/app/plugins/panel/timeline/utils.ts +++ b/public/app/plugins/panel/timeline/utils.ts @@ -11,20 +11,13 @@ import { } from '@grafana/data'; import { UPlotConfigBuilder, FIXED_UNIT, SeriesVisibilityChangeMode, UPlotConfigPrepFn } from '@grafana/ui'; import { TimelineCoreOptions, getConfig } from './timeline'; -import { - AxisPlacement, - GraphGradientMode, - ScaleDirection, - ScaleOrientation, -} from '@grafana/ui/src/components/uPlot/config'; +import { AxisPlacement, ScaleDirection, ScaleOrientation } from '@grafana/ui/src/components/uPlot/config'; import { measureText } from '@grafana/ui/src/utils/measureText'; - import { TimelineFieldConfig, TimelineOptions } from './types'; const defaultConfig: TimelineFieldConfig = { lineWidth: 0, fillOpacity: 80, - gradientMode: GraphGradientMode.None, }; export function mapMouseEventToMode(event: React.MouseEvent): SeriesVisibilityChangeMode { @@ -61,7 +54,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn = ({ return !(mode && field.display && mode.startsWith('continuous-')); }; - const colorLookup = (seriesIdx: number, value: any) => { + const getValueColor = (seriesIdx: number, value: any) => { const field = frame.fields[seriesIdx]; if (field.display) { @@ -93,9 +86,8 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn = ({ alignValue, theme, label: (seriesIdx) => getFieldDisplayName(frame.fields[seriesIdx], frame), - fill: colorLookup, - stroke: colorLookup, - colorLookup, + getFieldConfig: (seriesIdx) => frame.fields[seriesIdx].config.custom, + getValueColor, getTimeRange, // hardcoded formatter for state values formatValue: (seriesIdx, value) => formattedValueToString(frame.fields[seriesIdx].display!(value)), @@ -170,17 +162,16 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn = ({ field.state!.seriesIndex = seriesIndex++; - //const scaleKey = config.unit || FIXED_UNIT; - //const colorMode = getFieldColorModeForField(field); - - let { fillOpacity } = customConfig; + // const scaleKey = config.unit || FIXED_UNIT; + // const colorMode = getFieldColorModeForField(field); builder.addSeries({ scaleKey: FIXED_UNIT, pathBuilder: coreConfig.drawPaths, pointsBuilder: coreConfig.drawPoints, //colorMode, - fillOpacity, + lineWidth: customConfig.lineWidth, + fillOpacity: customConfig.fillOpacity, theme, show: !customConfig.hideFrom?.viz, thresholds: config.thresholds,