mirror of
https://github.com/grafana/grafana.git
synced 2026-07-29 15:59:50 -05:00
GraphNG: support fill below to (bands) (#30268)
This commit is contained in:
@@ -1175,8 +1175,8 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"gridPos": {
|
"gridPos": {
|
||||||
"h": 5,
|
"h": 7,
|
||||||
"w": 24,
|
"w": 12,
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 13
|
"y": 13
|
||||||
},
|
},
|
||||||
@@ -1359,6 +1359,154 @@
|
|||||||
"title": "Dashed lines",
|
"title": "Dashed lines",
|
||||||
"type": "timeseries"
|
"type": "timeseries"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"datasource": null,
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillGradient": "hue",
|
||||||
|
"fillOpacity": 25,
|
||||||
|
"hideFrom": {
|
||||||
|
"graph": false,
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "smooth",
|
||||||
|
"lineWidth": 2,
|
||||||
|
"pointSize": 6,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "never",
|
||||||
|
"spanNulls": true
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"nullValueMode": "null",
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Max"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "custom.fillBelowTo",
|
||||||
|
"value": "Min"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "custom.lineWidth",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "color",
|
||||||
|
"value": {
|
||||||
|
"fixedColor": "red",
|
||||||
|
"mode": "fixed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Min"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "custom.lineWidth",
|
||||||
|
"value": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Value"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "color",
|
||||||
|
"value": {
|
||||||
|
"fixedColor": "blue",
|
||||||
|
"mode": "fixed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 7,
|
||||||
|
"w": 12,
|
||||||
|
"x": 12,
|
||||||
|
"y": 13
|
||||||
|
},
|
||||||
|
"id": 70,
|
||||||
|
"interval": null,
|
||||||
|
"maxDataPoints": 100,
|
||||||
|
"options": {
|
||||||
|
"graph": {},
|
||||||
|
"legend": {
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "right"
|
||||||
|
},
|
||||||
|
"tooltipOptions": {
|
||||||
|
"mode": "single"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "7.4.0-pre",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"alias": "",
|
||||||
|
"csvWave": {
|
||||||
|
"timeStep": 60,
|
||||||
|
"valuesCSV": "0,0,2,2,1,1"
|
||||||
|
},
|
||||||
|
"lines": 10,
|
||||||
|
"points": [],
|
||||||
|
"pulseWave": {
|
||||||
|
"offCount": 3,
|
||||||
|
"offValue": 1,
|
||||||
|
"onCount": 3,
|
||||||
|
"onValue": 2,
|
||||||
|
"timeStep": 60
|
||||||
|
},
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "random_walk_table",
|
||||||
|
"stream": {
|
||||||
|
"bands": 1,
|
||||||
|
"noise": 2.2,
|
||||||
|
"speed": 250,
|
||||||
|
"spread": 3.5,
|
||||||
|
"type": "signal"
|
||||||
|
},
|
||||||
|
"stringInput": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Fill below to",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"collapsed": false,
|
"collapsed": false,
|
||||||
"datasource": null,
|
"datasource": null,
|
||||||
@@ -1366,7 +1514,7 @@
|
|||||||
"h": 1,
|
"h": 1,
|
||||||
"w": 24,
|
"w": 24,
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 18
|
"y": 20
|
||||||
},
|
},
|
||||||
"id": 62,
|
"id": 62,
|
||||||
"panels": [],
|
"panels": [],
|
||||||
@@ -1444,7 +1592,7 @@
|
|||||||
"h": 6,
|
"h": 6,
|
||||||
"w": 6,
|
"w": 6,
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 19
|
"y": 21
|
||||||
},
|
},
|
||||||
"id": 63,
|
"id": 63,
|
||||||
"maxDataPoints": 10,
|
"maxDataPoints": 10,
|
||||||
@@ -1582,7 +1730,7 @@
|
|||||||
"h": 6,
|
"h": 6,
|
||||||
"w": 6,
|
"w": 6,
|
||||||
"x": 6,
|
"x": 6,
|
||||||
"y": 19
|
"y": 21
|
||||||
},
|
},
|
||||||
"id": 64,
|
"id": 64,
|
||||||
"maxDataPoints": 10,
|
"maxDataPoints": 10,
|
||||||
@@ -1720,7 +1868,7 @@
|
|||||||
"h": 6,
|
"h": 6,
|
||||||
"w": 6,
|
"w": 6,
|
||||||
"x": 12,
|
"x": 12,
|
||||||
"y": 19
|
"y": 21
|
||||||
},
|
},
|
||||||
"id": 65,
|
"id": 65,
|
||||||
"maxDataPoints": 10,
|
"maxDataPoints": 10,
|
||||||
@@ -1858,7 +2006,7 @@
|
|||||||
"h": 6,
|
"h": 6,
|
||||||
"w": 6,
|
"w": 6,
|
||||||
"x": 18,
|
"x": 18,
|
||||||
"y": 19
|
"y": 21
|
||||||
},
|
},
|
||||||
"id": 66,
|
"id": 66,
|
||||||
"maxDataPoints": 100,
|
"maxDataPoints": 100,
|
||||||
@@ -1918,7 +2066,7 @@
|
|||||||
"h": 1,
|
"h": 1,
|
||||||
"w": 24,
|
"w": 24,
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 25
|
"y": 27
|
||||||
},
|
},
|
||||||
"id": 34,
|
"id": 34,
|
||||||
"panels": [],
|
"panels": [],
|
||||||
@@ -2024,7 +2172,7 @@
|
|||||||
"h": 8,
|
"h": 8,
|
||||||
"w": 6,
|
"w": 6,
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 26
|
"y": 28
|
||||||
},
|
},
|
||||||
"id": 32,
|
"id": 32,
|
||||||
"maxDataPoints": 100,
|
"maxDataPoints": 100,
|
||||||
@@ -2164,7 +2312,7 @@
|
|||||||
"h": 8,
|
"h": 8,
|
||||||
"w": 6,
|
"w": 6,
|
||||||
"x": 6,
|
"x": 6,
|
||||||
"y": 26
|
"y": 28
|
||||||
},
|
},
|
||||||
"id": 35,
|
"id": 35,
|
||||||
"maxDataPoints": 100,
|
"maxDataPoints": 100,
|
||||||
@@ -2318,7 +2466,7 @@
|
|||||||
"h": 8,
|
"h": 8,
|
||||||
"w": 6,
|
"w": 6,
|
||||||
"x": 12,
|
"x": 12,
|
||||||
"y": 26
|
"y": 28
|
||||||
},
|
},
|
||||||
"id": 31,
|
"id": 31,
|
||||||
"maxDataPoints": 200,
|
"maxDataPoints": 200,
|
||||||
@@ -2471,7 +2619,7 @@
|
|||||||
"h": 8,
|
"h": 8,
|
||||||
"w": 6,
|
"w": 6,
|
||||||
"x": 18,
|
"x": 18,
|
||||||
"y": 26
|
"y": 28
|
||||||
},
|
},
|
||||||
"id": 51,
|
"id": 51,
|
||||||
"maxDataPoints": 200,
|
"maxDataPoints": 200,
|
||||||
@@ -2532,7 +2680,7 @@
|
|||||||
"h": 1,
|
"h": 1,
|
||||||
"w": 24,
|
"w": 24,
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 34
|
"y": 36
|
||||||
},
|
},
|
||||||
"id": 17,
|
"id": 17,
|
||||||
"panels": [],
|
"panels": [],
|
||||||
@@ -2614,7 +2762,7 @@
|
|||||||
"h": 7,
|
"h": 7,
|
||||||
"w": 6,
|
"w": 6,
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 35
|
"y": 37
|
||||||
},
|
},
|
||||||
"id": 19,
|
"id": 19,
|
||||||
"options": {
|
"options": {
|
||||||
@@ -2722,7 +2870,7 @@
|
|||||||
"h": 7,
|
"h": 7,
|
||||||
"w": 6,
|
"w": 6,
|
||||||
"x": 6,
|
"x": 6,
|
||||||
"y": 35
|
"y": 37
|
||||||
},
|
},
|
||||||
"id": 20,
|
"id": 20,
|
||||||
"options": {
|
"options": {
|
||||||
@@ -2829,7 +2977,7 @@
|
|||||||
"h": 7,
|
"h": 7,
|
||||||
"w": 6,
|
"w": 6,
|
||||||
"x": 12,
|
"x": 12,
|
||||||
"y": 35
|
"y": 37
|
||||||
},
|
},
|
||||||
"id": 21,
|
"id": 21,
|
||||||
"options": {
|
"options": {
|
||||||
@@ -2937,7 +3085,7 @@
|
|||||||
"h": 7,
|
"h": 7,
|
||||||
"w": 6,
|
"w": 6,
|
||||||
"x": 18,
|
"x": 18,
|
||||||
"y": 35
|
"y": 37
|
||||||
},
|
},
|
||||||
"id": 9,
|
"id": 9,
|
||||||
"options": {
|
"options": {
|
||||||
@@ -2980,7 +3128,7 @@
|
|||||||
"h": 1,
|
"h": 1,
|
||||||
"w": 24,
|
"w": 24,
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 42
|
"y": 44
|
||||||
},
|
},
|
||||||
"id": 45,
|
"id": 45,
|
||||||
"panels": [],
|
"panels": [],
|
||||||
@@ -3061,7 +3209,7 @@
|
|||||||
"h": 10,
|
"h": 10,
|
||||||
"w": 12,
|
"w": 12,
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 43
|
"y": 45
|
||||||
},
|
},
|
||||||
"id": 46,
|
"id": 46,
|
||||||
"options": {
|
"options": {
|
||||||
@@ -3204,7 +3352,7 @@
|
|||||||
"h": 10,
|
"h": 10,
|
||||||
"w": 12,
|
"w": 12,
|
||||||
"x": 12,
|
"x": 12,
|
||||||
"y": 43
|
"y": 45
|
||||||
},
|
},
|
||||||
"id": 68,
|
"id": 68,
|
||||||
"options": {
|
"options": {
|
||||||
@@ -3269,5 +3417,5 @@
|
|||||||
"timezone": "",
|
"timezone": "",
|
||||||
"title": "Panel Tests - Graph NG",
|
"title": "Panel Tests - Graph NG",
|
||||||
"uid": "TkZXxlNG3",
|
"uid": "TkZXxlNG3",
|
||||||
"version": 27
|
"version": 34
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import { VizLegend } from '../VizLegend/VizLegend';
|
|||||||
import { UPlotConfigBuilder } from '../uPlot/config/UPlotConfigBuilder';
|
import { UPlotConfigBuilder } from '../uPlot/config/UPlotConfigBuilder';
|
||||||
import { useRevision } from '../uPlot/hooks';
|
import { useRevision } from '../uPlot/hooks';
|
||||||
import { GraphNGLegendEvent, GraphNGLegendEventMode } from './types';
|
import { GraphNGLegendEvent, GraphNGLegendEventMode } from './types';
|
||||||
|
import { isNumber } from 'lodash';
|
||||||
|
|
||||||
const defaultFormatter = (v: any) => (v == null ? '-' : v.toFixed(1));
|
const defaultFormatter = (v: any) => (v == null ? '-' : v.toFixed(1));
|
||||||
|
|
||||||
@@ -135,6 +136,7 @@ export const GraphNG: React.FC<GraphNGProps> = ({
|
|||||||
theme,
|
theme,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
let indexByName: Map<string, number> | undefined = undefined;
|
||||||
|
|
||||||
for (let i = 0; i < alignedFrame.fields.length; i++) {
|
for (let i = 0; i < alignedFrame.fields.length; i++) {
|
||||||
const field = alignedFrame.fields[i];
|
const field = alignedFrame.fields[i];
|
||||||
@@ -176,6 +178,24 @@ export const GraphNG: React.FC<GraphNGProps> = ({
|
|||||||
const showPoints = customConfig.drawStyle === DrawStyle.Points ? PointVisibility.Always : customConfig.showPoints;
|
const showPoints = customConfig.drawStyle === DrawStyle.Points ? PointVisibility.Always : customConfig.showPoints;
|
||||||
const dataFrameFieldIndex = getDataFrameFieldIndex ? getDataFrameFieldIndex(i) : undefined;
|
const dataFrameFieldIndex = getDataFrameFieldIndex ? getDataFrameFieldIndex(i) : undefined;
|
||||||
|
|
||||||
|
let { fillOpacity } = customConfig;
|
||||||
|
if (customConfig.fillBelowTo) {
|
||||||
|
if (!indexByName) {
|
||||||
|
indexByName = getNamesToFieldIndex(alignedFrame);
|
||||||
|
}
|
||||||
|
const t = indexByName.get(getFieldDisplayName(field, alignedFrame));
|
||||||
|
const b = indexByName.get(customConfig.fillBelowTo);
|
||||||
|
if (isNumber(b) && isNumber(t)) {
|
||||||
|
builder.addBand({
|
||||||
|
series: [t, b],
|
||||||
|
fill: null as any, // using null will have the band use fill options from `t`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!fillOpacity) {
|
||||||
|
fillOpacity = 35; // default from flot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
builder.addSeries({
|
builder.addSeries({
|
||||||
scaleKey,
|
scaleKey,
|
||||||
drawStyle: customConfig.drawStyle!,
|
drawStyle: customConfig.drawStyle!,
|
||||||
@@ -186,7 +206,7 @@ export const GraphNG: React.FC<GraphNGProps> = ({
|
|||||||
showPoints,
|
showPoints,
|
||||||
pointSize: customConfig.pointSize,
|
pointSize: customConfig.pointSize,
|
||||||
pointColor: customConfig.pointColor ?? seriesColor,
|
pointColor: customConfig.pointColor ?? seriesColor,
|
||||||
fillOpacity: customConfig.fillOpacity,
|
fillOpacity,
|
||||||
spanNulls: customConfig.spanNulls || false,
|
spanNulls: customConfig.spanNulls || false,
|
||||||
show: !customConfig.hideFrom?.graph,
|
show: !customConfig.hideFrom?.graph,
|
||||||
fillGradient: customConfig.fillGradient,
|
fillGradient: customConfig.fillGradient,
|
||||||
@@ -291,3 +311,11 @@ const mapMouseEventToMode = (event: React.MouseEvent): GraphNGLegendEventMode =>
|
|||||||
}
|
}
|
||||||
return GraphNGLegendEventMode.ToggleSelection;
|
return GraphNGLegendEventMode.ToggleSelection;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getNamesToFieldIndex(frame: DataFrame): Map<string, number> {
|
||||||
|
const names = new Map<string, number>();
|
||||||
|
for (let i = 0; i < frame.fields.length; i++) {
|
||||||
|
names.set(getFieldDisplayName(frame.fields[i], frame), i);
|
||||||
|
}
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ export interface FillConfig {
|
|||||||
fillColor?: string;
|
fillColor?: string;
|
||||||
fillOpacity?: number;
|
fillOpacity?: number;
|
||||||
fillGradient?: FillGradientMode;
|
fillGradient?: FillGradientMode;
|
||||||
|
fillBelowTo?: string; // name of the field
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,13 +3,14 @@ import { ScaleProps, UPlotScaleBuilder } from './UPlotScaleBuilder';
|
|||||||
import { SeriesProps, UPlotSeriesBuilder } from './UPlotSeriesBuilder';
|
import { SeriesProps, UPlotSeriesBuilder } from './UPlotSeriesBuilder';
|
||||||
import { AxisProps, UPlotAxisBuilder } from './UPlotAxisBuilder';
|
import { AxisProps, UPlotAxisBuilder } from './UPlotAxisBuilder';
|
||||||
import { AxisPlacement } from '../config';
|
import { AxisPlacement } from '../config';
|
||||||
import { Cursor } from 'uplot';
|
import { Cursor, Band } from 'uplot';
|
||||||
import { defaultsDeep } from 'lodash';
|
import { defaultsDeep } from 'lodash';
|
||||||
|
|
||||||
export class UPlotConfigBuilder {
|
export class UPlotConfigBuilder {
|
||||||
private series: UPlotSeriesBuilder[] = [];
|
private series: UPlotSeriesBuilder[] = [];
|
||||||
private axes: Record<string, UPlotAxisBuilder> = {};
|
private axes: Record<string, UPlotAxisBuilder> = {};
|
||||||
private scales: UPlotScaleBuilder[] = [];
|
private scales: UPlotScaleBuilder[] = [];
|
||||||
|
private bands: Band[] = [];
|
||||||
private cursor: Cursor | undefined;
|
private cursor: Cursor | undefined;
|
||||||
private hasLeftAxis = false;
|
private hasLeftAxis = false;
|
||||||
private hasBottomAxis = false;
|
private hasBottomAxis = false;
|
||||||
@@ -71,6 +72,10 @@ export class UPlotConfigBuilder {
|
|||||||
this.scales.push(new UPlotScaleBuilder(props));
|
this.scales.push(new UPlotScaleBuilder(props));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addBand(band: Band) {
|
||||||
|
this.bands.push(band);
|
||||||
|
}
|
||||||
|
|
||||||
getConfig() {
|
getConfig() {
|
||||||
const config: PlotSeriesConfig = { series: [{}] };
|
const config: PlotSeriesConfig = { series: [{}] };
|
||||||
config.axes = this.ensureNonOverlappingAxes(Object.values(this.axes)).map(a => a.getConfig());
|
config.axes = this.ensureNonOverlappingAxes(Object.values(this.axes)).map(a => a.getConfig());
|
||||||
@@ -81,6 +86,20 @@ export class UPlotConfigBuilder {
|
|||||||
|
|
||||||
config.cursor = this.cursor || {};
|
config.cursor = this.cursor || {};
|
||||||
|
|
||||||
|
// When bands exist, only keep fill when defined
|
||||||
|
if (config.bands?.length) {
|
||||||
|
config.bands = this.bands;
|
||||||
|
const keepFill = new Set<number>();
|
||||||
|
for (const b of config.bands) {
|
||||||
|
keepFill.add(b.series[0]);
|
||||||
|
}
|
||||||
|
for (let i = 1; i < config.series.length; i++) {
|
||||||
|
if (!keepFill.has(i)) {
|
||||||
|
config.series[i].fill = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const cursorDefaults: Cursor = {
|
const cursorDefaults: Cursor = {
|
||||||
// prevent client-side zoom from triggering at the end of a selection
|
// prevent client-side zoom from triggering at the end of a selection
|
||||||
drag: { setScale: false },
|
drag: { setScale: false },
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import uPlot, { Options, Series, Hooks } from 'uplot';
|
|||||||
import { DataFrame, DataFrameFieldIndex, TimeRange, TimeZone } from '@grafana/data';
|
import { DataFrame, DataFrameFieldIndex, TimeRange, TimeZone } from '@grafana/data';
|
||||||
import { UPlotConfigBuilder } from './config/UPlotConfigBuilder';
|
import { UPlotConfigBuilder } from './config/UPlotConfigBuilder';
|
||||||
|
|
||||||
export type PlotSeriesConfig = Pick<Options, 'series' | 'scales' | 'axes' | 'cursor'>;
|
export type PlotSeriesConfig = Pick<Options, 'series' | 'scales' | 'axes' | 'cursor' | 'bands'>;
|
||||||
export type PlotPlugin = {
|
export type PlotPlugin = {
|
||||||
id: string;
|
id: string;
|
||||||
/** can mutate provided opts as necessary */
|
/** can mutate provided opts as necessary */
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import { FieldOverrideEditorProps, FieldType, getFieldDisplayName, SelectableValue } from '@grafana/data';
|
||||||
|
import { Select } from '@grafana/ui';
|
||||||
|
|
||||||
|
export const FillBellowToEditor: React.FC<FieldOverrideEditorProps<string, any>> = ({ value, context, onChange }) => {
|
||||||
|
const names = useMemo(() => {
|
||||||
|
const names: Array<SelectableValue<string>> = [];
|
||||||
|
if (context.data.length) {
|
||||||
|
for (const frame of context.data) {
|
||||||
|
for (const field of frame.fields) {
|
||||||
|
if (field.type === FieldType.number) {
|
||||||
|
const label = getFieldDisplayName(field, frame, context.data);
|
||||||
|
names.push({
|
||||||
|
label,
|
||||||
|
value: label,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return names;
|
||||||
|
}, [context]);
|
||||||
|
|
||||||
|
const current = useMemo(() => {
|
||||||
|
const found = names.find(v => v.value === value);
|
||||||
|
if (found) {
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
if (value) {
|
||||||
|
return {
|
||||||
|
label: value,
|
||||||
|
value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}, names);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
options={names}
|
||||||
|
value={current}
|
||||||
|
onChange={v => {
|
||||||
|
onChange(v.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
import { FieldColorModeId, FieldConfigProperty, FieldType, identityOverrideProcessor } from '@grafana/data';
|
import {
|
||||||
|
FieldColorModeId,
|
||||||
|
FieldConfigProperty,
|
||||||
|
FieldType,
|
||||||
|
identityOverrideProcessor,
|
||||||
|
stringOverrideProcessor,
|
||||||
|
} from '@grafana/data';
|
||||||
import {
|
import {
|
||||||
AxisPlacement,
|
AxisPlacement,
|
||||||
DrawStyle,
|
DrawStyle,
|
||||||
@@ -15,6 +21,7 @@ import { ScaleDistributionEditor } from './ScaleDistributionEditor';
|
|||||||
import { LineStyleEditor } from './LineStyleEditor';
|
import { LineStyleEditor } from './LineStyleEditor';
|
||||||
import { SetFieldConfigOptionsArgs } from '@grafana/data/src/panel/PanelPlugin';
|
import { SetFieldConfigOptionsArgs } from '@grafana/data/src/panel/PanelPlugin';
|
||||||
import { FillGradientMode } from '@grafana/ui/src/components/uPlot/config';
|
import { FillGradientMode } from '@grafana/ui/src/components/uPlot/config';
|
||||||
|
import { FillBellowToEditor } from './FillBelowToEditor';
|
||||||
|
|
||||||
export const defaultGraphConfig: GraphFieldConfig = {
|
export const defaultGraphConfig: GraphFieldConfig = {
|
||||||
drawStyle: DrawStyle.Line,
|
drawStyle: DrawStyle.Line,
|
||||||
@@ -86,6 +93,16 @@ export function getGraphFieldConfig(cfg: GraphFieldConfig): SetFieldConfigOption
|
|||||||
},
|
},
|
||||||
showIf: c => !!(c.drawStyle !== DrawStyle.Points && c.fillOpacity && c.fillOpacity > 0),
|
showIf: c => !!(c.drawStyle !== DrawStyle.Points && c.fillOpacity && c.fillOpacity > 0),
|
||||||
})
|
})
|
||||||
|
.addCustomEditor({
|
||||||
|
id: 'fillBelowTo',
|
||||||
|
path: 'fillBelowTo',
|
||||||
|
name: 'Fill below to',
|
||||||
|
editor: FillBellowToEditor,
|
||||||
|
override: FillBellowToEditor,
|
||||||
|
process: stringOverrideProcessor,
|
||||||
|
hideFromDefaults: true,
|
||||||
|
shouldApply: f => true,
|
||||||
|
})
|
||||||
.addCustomEditor<void, LineStyle>({
|
.addCustomEditor<void, LineStyle>({
|
||||||
id: 'lineStyle',
|
id: 'lineStyle',
|
||||||
path: 'lineStyle',
|
path: 'lineStyle',
|
||||||
|
|||||||
@@ -93,6 +93,8 @@ export function flotToGraphOptions(angular: any): { fieldConfig: FieldConfigSour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let hasFillBelowTo = false;
|
||||||
|
|
||||||
if (angular.seriesOverrides?.length) {
|
if (angular.seriesOverrides?.length) {
|
||||||
for (const seriesOverride of angular.seriesOverrides) {
|
for (const seriesOverride of angular.seriesOverrides) {
|
||||||
if (!seriesOverride.alias) {
|
if (!seriesOverride.alias) {
|
||||||
@@ -127,6 +129,13 @@ export function flotToGraphOptions(angular: any): { fieldConfig: FieldConfigSour
|
|||||||
value: v * 10, // was 0-10, new graph is 0 - 100
|
value: v * 10, // was 0-10, new graph is 0 - 100
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case 'fillBelowTo':
|
||||||
|
hasFillBelowTo = true;
|
||||||
|
rule.properties.push({
|
||||||
|
id: 'custom.fillBelowTo',
|
||||||
|
value: v,
|
||||||
|
});
|
||||||
|
break;
|
||||||
case 'fillGradient':
|
case 'fillGradient':
|
||||||
if (v) {
|
if (v) {
|
||||||
rule.properties.push({
|
rule.properties.push({
|
||||||
@@ -162,6 +171,12 @@ export function flotToGraphOptions(angular: any): { fieldConfig: FieldConfigSour
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'lines':
|
||||||
|
rule.properties.push({
|
||||||
|
id: 'custom.lineWidth',
|
||||||
|
value: 0, // don't show lines
|
||||||
|
});
|
||||||
|
break;
|
||||||
case 'linewidth':
|
case 'linewidth':
|
||||||
rule.properties.push({
|
rule.properties.push({
|
||||||
id: 'custom.lineWidth',
|
id: 'custom.lineWidth',
|
||||||
@@ -229,7 +244,9 @@ export function flotToGraphOptions(angular: any): { fieldConfig: FieldConfigSour
|
|||||||
graph.pointSize = 2 + angular.pointradius * 2;
|
graph.pointSize = 2 + angular.pointradius * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNumber(angular.fill)) {
|
if (hasFillBelowTo) {
|
||||||
|
graph.fillOpacity = 35; // bands are hardcoded in flot
|
||||||
|
} else if (isNumber(angular.fill)) {
|
||||||
graph.fillOpacity = angular.fill * 10; // fill was 0 - 10, new is 0 to 100
|
graph.fillOpacity = angular.fill * 10; // fill was 0 - 10, new is 0 to 100
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user