mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
GraphNG: support fill gradient (#29765)
This commit is contained in:
parent
0c8498401e
commit
8250b59dfe
571
devenv/dev-dashboards/panel-graph/graph-ng-gradient-area.json
Normal file
571
devenv/dev-dashboards/panel-graph/graph-ng-gradient-area.json
Normal file
@ -0,0 +1,571 @@
|
||||
{
|
||||
"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": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "line",
|
||||
"fillGradient": 0.5,
|
||||
"fillOpacity": 40,
|
||||
"lineInterpolation": "linear",
|
||||
"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": "A-series"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "rgb(48, 139, 237)",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 10,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"interval": "1m",
|
||||
"links": [],
|
||||
"options": {
|
||||
"graph": {},
|
||||
"legend": {
|
||||
"displayMode": "hidden",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltipOptions": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Req/s",
|
||||
"type": "graph3"
|
||||
},
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "bars",
|
||||
"fillGradient": 0.4,
|
||||
"fillOpacity": 53,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"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": "A-series"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "blue",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 7,
|
||||
"x": 10,
|
||||
"y": 0
|
||||
},
|
||||
"id": 11,
|
||||
"interval": "1m",
|
||||
"links": [],
|
||||
"maxDataPoints": 10,
|
||||
"options": {
|
||||
"graph": {},
|
||||
"legend": {
|
||||
"displayMode": "hidden",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltipOptions": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Req/s",
|
||||
"type": "graph3"
|
||||
},
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "bars",
|
||||
"fillGradient": "opacity",
|
||||
"fillOpacity": 100,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 0,
|
||||
"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": "A-series"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "red",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 7,
|
||||
"x": 17,
|
||||
"y": 0
|
||||
},
|
||||
"id": 12,
|
||||
"interval": "1m",
|
||||
"links": [],
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"graph": {},
|
||||
"legend": {
|
||||
"displayMode": "hidden",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltipOptions": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Req/s",
|
||||
"type": "graph3"
|
||||
},
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "line",
|
||||
"fillGradient": 0.5,
|
||||
"fillOpacity": 20,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"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": "decgbytes"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "A-series"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "red",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 10,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 7,
|
||||
"interval": "1m",
|
||||
"links": [],
|
||||
"options": {
|
||||
"graph": {},
|
||||
"legend": {
|
||||
"displayMode": "hidden",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltipOptions": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Memory",
|
||||
"type": "graph3"
|
||||
},
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "line",
|
||||
"fillGradient": "hue",
|
||||
"fillOpacity": 62,
|
||||
"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": "A-series"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "semi-dark-blue",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 14,
|
||||
"x": 10,
|
||||
"y": 8
|
||||
},
|
||||
"id": 13,
|
||||
"interval": "1m",
|
||||
"links": [],
|
||||
"maxDataPoints": 80,
|
||||
"options": {
|
||||
"graph": {},
|
||||
"legend": {
|
||||
"displayMode": "hidden",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltipOptions": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Hue gradient mode",
|
||||
"type": "graph3"
|
||||
},
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "bars",
|
||||
"fillGradient": "hue",
|
||||
"fillOpacity": 100,
|
||||
"lineInterpolation": "smooth",
|
||||
"lineWidth": 0,
|
||||
"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": "A-series"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "red",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 11,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 16
|
||||
},
|
||||
"id": 16,
|
||||
"interval": "1m",
|
||||
"links": [],
|
||||
"maxDataPoints": 50,
|
||||
"options": {
|
||||
"graph": {},
|
||||
"legend": {
|
||||
"displayMode": "hidden",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltipOptions": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Hue gradient mode",
|
||||
"type": "graph3"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 27,
|
||||
"style": "dark",
|
||||
"tags": ["gdev", "panel-tests"],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
|
||||
"time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"]
|
||||
},
|
||||
"timezone": "",
|
||||
"title": "Panel Tests - Graph NG - Gradient Area Fills",
|
||||
"uid": "_gWgX2JGk",
|
||||
"version": 1
|
||||
}
|
@ -165,6 +165,7 @@ export const GraphNG: React.FC<GraphNGProps> = ({
|
||||
pointColor: customConfig.pointColor ?? seriesColor,
|
||||
fillOpacity: customConfig.fillOpacity,
|
||||
spanNulls: customConfig.spanNulls || false,
|
||||
fillGradient: customConfig.fillGradient,
|
||||
});
|
||||
|
||||
if (hasLegend.current) {
|
||||
|
@ -133,6 +133,7 @@ export class Sparkline extends PureComponent<Props, State> {
|
||||
const colorMode = getFieldColorModeForField(field);
|
||||
const seriesColor = colorMode.getCalculator(field, theme)(0, 0);
|
||||
const pointsMode = customConfig.drawStyle === DrawStyle.Points ? PointVisibility.Always : customConfig.showPoints;
|
||||
|
||||
builder.addSeries({
|
||||
scaleKey,
|
||||
drawStyle: customConfig.drawStyle!,
|
||||
|
@ -8,9 +8,12 @@ import { DataFrame } from '@grafana/data';
|
||||
import { UPlotConfigBuilder } from './config/UPlotConfigBuilder';
|
||||
import usePrevious from 'react-use/lib/usePrevious';
|
||||
|
||||
// uPlot abstraction responsible for plot initialisation, setup and refresh
|
||||
// Receives a data frame that is x-axis aligned, as of https://github.com/leeoniya/uPlot/tree/master/docs#data-format
|
||||
// Exposes contexts for plugins registration and uPlot instance access
|
||||
/**
|
||||
* @internal
|
||||
* uPlot abstraction responsible for plot initialisation, setup and refresh
|
||||
* Receives a data frame that is x-axis aligned, as of https://github.com/leeoniya/uPlot/tree/master/docs#data-format
|
||||
* Exposes contexts for plugins registration and uPlot instance access
|
||||
*/
|
||||
export const UPlotChart: React.FC<PlotProps> = props => {
|
||||
const canvasRef = useRef<HTMLDivElement>(null);
|
||||
const plotInstance = useRef<uPlot>();
|
||||
|
@ -1,5 +1,8 @@
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export enum AxisPlacement {
|
||||
Auto = 'auto', // First axis on the left, the rest on the right
|
||||
Top = 'top',
|
||||
@ -9,18 +12,27 @@ export enum AxisPlacement {
|
||||
Hidden = 'hidden',
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export enum PointVisibility {
|
||||
Auto = 'auto', // will show points when the density is low or line is hidden
|
||||
Never = 'never',
|
||||
Always = 'always',
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export enum DrawStyle {
|
||||
Line = 'line', // default
|
||||
Bars = 'bars', // will also have a gap percent
|
||||
Points = 'points', // Only show points
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export enum LineInterpolation {
|
||||
Linear = 'linear',
|
||||
Smooth = 'smooth',
|
||||
@ -28,6 +40,9 @@ export enum LineInterpolation {
|
||||
StepAfter = 'stepAfter',
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export enum ScaleDistribution {
|
||||
Linear = 'linear',
|
||||
Logarithmic = 'log',
|
||||
@ -40,6 +55,7 @@ export interface LineConfig {
|
||||
lineColor?: string;
|
||||
lineWidth?: number;
|
||||
lineInterpolation?: LineInterpolation;
|
||||
lineDash?: number[];
|
||||
spanNulls?: boolean;
|
||||
}
|
||||
|
||||
@ -49,6 +65,16 @@ export interface LineConfig {
|
||||
export interface AreaConfig {
|
||||
fillColor?: string;
|
||||
fillOpacity?: number;
|
||||
fillGradient?: AreaGradientMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export enum AreaGradientMode {
|
||||
None = 'none',
|
||||
Opacity = 'opacity',
|
||||
Hue = 'hue',
|
||||
}
|
||||
|
||||
/**
|
||||
@ -61,11 +87,18 @@ export interface PointsConfig {
|
||||
pointSymbol?: string; // eventually dot,star, etc
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export interface ScaleDistributionConfig {
|
||||
type: ScaleDistribution;
|
||||
log?: number;
|
||||
}
|
||||
// Axis is actually unique based on the unit... not each field!
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
* Axis is actually unique based on the unit... not each field!
|
||||
*/
|
||||
export interface AxisConfig {
|
||||
axisPlacement?: AxisPlacement;
|
||||
axisLabel?: string;
|
||||
@ -80,6 +113,9 @@ export interface GraphFieldConfig extends LineConfig, AreaConfig, PointsConfig,
|
||||
drawStyle?: DrawStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export const graphFieldOptions = {
|
||||
drawStyle: [
|
||||
{ label: 'Lines', value: DrawStyle.Line },
|
||||
@ -106,4 +142,10 @@ export const graphFieldOptions = {
|
||||
{ label: 'Right', value: AxisPlacement.Right },
|
||||
{ label: 'Hidden', value: AxisPlacement.Hidden },
|
||||
] as Array<SelectableValue<AxisPlacement>>,
|
||||
|
||||
fillGradient: [
|
||||
{ label: 'None', value: undefined },
|
||||
{ label: 'Opacity', value: AreaGradientMode.Opacity },
|
||||
{ label: 'Hue', value: AreaGradientMode.Hue },
|
||||
] as Array<SelectableValue<AreaGradientMode>>,
|
||||
};
|
||||
|
@ -3,7 +3,7 @@
|
||||
import { UPlotConfigBuilder } from './UPlotConfigBuilder';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { expect } from '../../../../../../public/test/lib/common';
|
||||
import { AxisPlacement, DrawStyle, PointVisibility, ScaleDistribution } from '../config';
|
||||
import { AreaGradientMode, AxisPlacement, DrawStyle, PointVisibility, ScaleDistribution } from '../config';
|
||||
|
||||
describe('UPlotConfigBuilder', () => {
|
||||
describe('scales config', () => {
|
||||
@ -266,13 +266,62 @@ describe('UPlotConfigBuilder', () => {
|
||||
expect(builder.getAxisPlacement('y2')).toBe(AxisPlacement.Right);
|
||||
});
|
||||
|
||||
it('When fillColor is not set fill', () => {
|
||||
const builder = new UPlotConfigBuilder();
|
||||
builder.addSeries({
|
||||
drawStyle: DrawStyle.Line,
|
||||
scaleKey: 'scale-x',
|
||||
lineColor: '#0000ff',
|
||||
});
|
||||
|
||||
expect(builder.getConfig().series[1].fill).toBe(undefined);
|
||||
});
|
||||
|
||||
it('When fillOpacity is set', () => {
|
||||
const builder = new UPlotConfigBuilder();
|
||||
builder.addSeries({
|
||||
drawStyle: DrawStyle.Line,
|
||||
scaleKey: 'scale-x',
|
||||
lineColor: '#FFAABB',
|
||||
fillOpacity: 50,
|
||||
});
|
||||
|
||||
expect(builder.getConfig().series[1].fill).toBe('rgba(255, 170, 187, 0.5)');
|
||||
});
|
||||
|
||||
it('When fillColor is set ignore fillOpacity', () => {
|
||||
const builder = new UPlotConfigBuilder();
|
||||
builder.addSeries({
|
||||
drawStyle: DrawStyle.Line,
|
||||
scaleKey: 'scale-x',
|
||||
lineColor: '#FFAABB',
|
||||
fillOpacity: 50,
|
||||
fillColor: '#FF0000',
|
||||
});
|
||||
|
||||
expect(builder.getConfig().series[1].fill).toBe('#FF0000');
|
||||
});
|
||||
|
||||
it('When fillGradient mode is opacity', () => {
|
||||
const builder = new UPlotConfigBuilder();
|
||||
builder.addSeries({
|
||||
drawStyle: DrawStyle.Line,
|
||||
scaleKey: 'scale-x',
|
||||
lineColor: '#FFAABB',
|
||||
fillOpacity: 50,
|
||||
fillGradient: AreaGradientMode.Opacity,
|
||||
});
|
||||
|
||||
expect(builder.getConfig().series[1].fill).toBeInstanceOf(Function);
|
||||
});
|
||||
|
||||
it('allows series configuration', () => {
|
||||
const builder = new UPlotConfigBuilder();
|
||||
builder.addSeries({
|
||||
drawStyle: DrawStyle.Line,
|
||||
scaleKey: 'scale-x',
|
||||
fillColor: '#ff0000',
|
||||
fillOpacity: 50,
|
||||
fillGradient: AreaGradientMode.Opacity,
|
||||
showPoints: PointVisibility.Auto,
|
||||
pointSize: 5,
|
||||
pointColor: '#00ff00',
|
||||
@ -299,7 +348,7 @@ describe('UPlotConfigBuilder', () => {
|
||||
"series": Array [
|
||||
Object {},
|
||||
Object {
|
||||
"fill": "rgba(255, 0, 0, 0.5)",
|
||||
"fill": [Function],
|
||||
"paths": [Function],
|
||||
"points": Object {
|
||||
"fill": "#00ff00",
|
||||
|
@ -1,6 +1,15 @@
|
||||
import tinycolor from 'tinycolor2';
|
||||
import uPlot, { Series } from 'uplot';
|
||||
import { DrawStyle, LineConfig, AreaConfig, PointsConfig, PointVisibility, LineInterpolation } from '../config';
|
||||
import { getCanvasContext } from '../../../utils/measureText';
|
||||
import {
|
||||
DrawStyle,
|
||||
LineConfig,
|
||||
AreaConfig,
|
||||
PointsConfig,
|
||||
PointVisibility,
|
||||
LineInterpolation,
|
||||
AreaGradientMode,
|
||||
} from '../config';
|
||||
import { PlotConfigBuilder } from '../types';
|
||||
|
||||
export interface SeriesProps extends LineConfig, AreaConfig, PointsConfig {
|
||||
@ -18,8 +27,6 @@ export class UPlotSeriesBuilder extends PlotConfigBuilder<SeriesProps, Series> {
|
||||
showPoints,
|
||||
pointColor,
|
||||
pointSize,
|
||||
fillColor,
|
||||
fillOpacity,
|
||||
scaleKey,
|
||||
spanNulls,
|
||||
} = this.props;
|
||||
@ -56,31 +63,41 @@ export class UPlotSeriesBuilder extends PlotConfigBuilder<SeriesProps, Series> {
|
||||
pointsConfig.points!.show = true;
|
||||
}
|
||||
|
||||
let fillConfig: any | undefined;
|
||||
let fillOpacityNumber = fillOpacity ?? 0;
|
||||
|
||||
if (fillColor) {
|
||||
fillConfig = {
|
||||
fill: fillColor,
|
||||
};
|
||||
}
|
||||
|
||||
if (fillOpacityNumber !== 0) {
|
||||
fillConfig = {
|
||||
fill: tinycolor(fillColor ?? lineColor)
|
||||
.setAlpha(fillOpacityNumber / 100)
|
||||
.toRgbString(),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
scale: scaleKey,
|
||||
spanGaps: spanNulls,
|
||||
fill: this.getFill(),
|
||||
...lineConfig,
|
||||
...pointsConfig,
|
||||
...fillConfig,
|
||||
};
|
||||
}
|
||||
|
||||
getFill(): Series.Fill | undefined {
|
||||
const { lineColor, fillColor, fillGradient, fillOpacity } = this.props;
|
||||
|
||||
if (fillColor) {
|
||||
return fillColor;
|
||||
}
|
||||
|
||||
const mode = fillGradient ?? AreaGradientMode.None;
|
||||
let fillOpacityNumber = fillOpacity ?? 0;
|
||||
|
||||
if (mode !== AreaGradientMode.None) {
|
||||
return getCanvasGradient({
|
||||
color: (fillColor ?? lineColor)!,
|
||||
opacity: fillOpacityNumber / 100,
|
||||
mode,
|
||||
});
|
||||
}
|
||||
|
||||
if (fillOpacityNumber > 0) {
|
||||
return tinycolor(lineColor)
|
||||
.setAlpha(fillOpacityNumber / 100)
|
||||
.toString();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
interface PathBuilders {
|
||||
@ -130,3 +147,50 @@ function mapDrawStyleToPathBuilder(
|
||||
|
||||
return builders.linear; // the default
|
||||
}
|
||||
|
||||
interface AreaGradientOptions {
|
||||
color: string;
|
||||
mode: AreaGradientMode;
|
||||
opacity: number;
|
||||
}
|
||||
|
||||
function getCanvasGradient(opts: AreaGradientOptions): (self: uPlot, seriesIdx: number) => CanvasGradient {
|
||||
return (plot: uPlot, seriesIdx: number) => {
|
||||
const { color, mode, opacity } = opts;
|
||||
|
||||
const ctx = getCanvasContext();
|
||||
const gradient = ctx.createLinearGradient(0, plot.bbox.top, 0, plot.bbox.top + plot.bbox.height);
|
||||
|
||||
switch (mode) {
|
||||
case AreaGradientMode.Hue:
|
||||
const color1 = tinycolor(color)
|
||||
.spin(-25)
|
||||
.darken(30)
|
||||
.setAlpha(opacity)
|
||||
.toRgbString();
|
||||
const color2 = tinycolor(color)
|
||||
.spin(25)
|
||||
.lighten(35)
|
||||
.setAlpha(opacity)
|
||||
.toRgbString();
|
||||
gradient.addColorStop(0, color2);
|
||||
gradient.addColorStop(1, color1);
|
||||
|
||||
case AreaGradientMode.Opacity:
|
||||
default:
|
||||
gradient.addColorStop(
|
||||
0,
|
||||
tinycolor(color)
|
||||
.setAlpha(opacity)
|
||||
.toRgbString()
|
||||
);
|
||||
gradient.addColorStop(
|
||||
1,
|
||||
tinycolor(color)
|
||||
.setAlpha(0)
|
||||
.toRgbString()
|
||||
);
|
||||
return gradient;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,22 @@
|
||||
let canvas: HTMLCanvasElement | null = null;
|
||||
const cache: Record<string, TextMetrics> = {};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function getCanvasContext() {
|
||||
if (canvas === null) {
|
||||
canvas = document.createElement('canvas');
|
||||
}
|
||||
|
||||
const context = canvas.getContext('2d');
|
||||
if (!context) {
|
||||
throw new Error('Could not create context');
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @beta
|
||||
*/
|
||||
@ -13,14 +29,7 @@ export function measureText(text: string, fontSize: number): TextMetrics {
|
||||
return fromCache;
|
||||
}
|
||||
|
||||
if (canvas === null) {
|
||||
canvas = document.createElement('canvas');
|
||||
}
|
||||
|
||||
const context = canvas.getContext('2d');
|
||||
if (!context) {
|
||||
throw new Error('Could not create context');
|
||||
}
|
||||
const context = getCanvasContext();
|
||||
|
||||
context.font = fontStyle;
|
||||
const metrics = context.measureText(text);
|
||||
|
@ -33,7 +33,8 @@ Object {
|
||||
"custom": Object {
|
||||
"axisPlacement": "hidden",
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 50,
|
||||
"fillGradient": "opacity",
|
||||
"fillOpacity": 60,
|
||||
"lineInterpolation": "stepAfter",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 6,
|
||||
|
@ -11,7 +11,13 @@ import {
|
||||
FieldColorModeId,
|
||||
} from '@grafana/data';
|
||||
import { GraphFieldConfig, LegendDisplayMode } from '@grafana/ui';
|
||||
import { AxisPlacement, DrawStyle, LineInterpolation, PointVisibility } from '@grafana/ui/src/components/uPlot/config';
|
||||
import {
|
||||
AreaGradientMode,
|
||||
AxisPlacement,
|
||||
DrawStyle,
|
||||
LineInterpolation,
|
||||
PointVisibility,
|
||||
} from '@grafana/ui/src/components/uPlot/config';
|
||||
import { Options } from './types';
|
||||
import omitBy from 'lodash/omitBy';
|
||||
import isNil from 'lodash/isNil';
|
||||
@ -112,6 +118,18 @@ export function flotToGraphOptions(angular: any): { fieldConfig: FieldConfigSour
|
||||
value: v * 10, // was 0-10, new graph is 0 - 100
|
||||
});
|
||||
break;
|
||||
case 'fillGradient':
|
||||
if (v) {
|
||||
rule.properties.push({
|
||||
id: 'custom.fillGradient',
|
||||
value: 'opacity', // was 0-10
|
||||
});
|
||||
rule.properties.push({
|
||||
id: 'custom.fillOpacity',
|
||||
value: v * 10, // was 0-10, new graph is 0 - 100
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'points':
|
||||
rule.properties.push({
|
||||
id: 'custom.showPoints',
|
||||
@ -159,6 +177,7 @@ export function flotToGraphOptions(angular: any): { fieldConfig: FieldConfigSour
|
||||
|
||||
const graph = y1.custom ?? ({} as GraphFieldConfig);
|
||||
graph.drawStyle = angular.bars ? DrawStyle.Bars : angular.lines ? DrawStyle.Line : DrawStyle.Points;
|
||||
|
||||
if (angular.points) {
|
||||
graph.showPoints = PointVisibility.Always;
|
||||
} else if (graph.drawStyle !== DrawStyle.Points) {
|
||||
@ -166,19 +185,30 @@ export function flotToGraphOptions(angular: any): { fieldConfig: FieldConfigSour
|
||||
}
|
||||
|
||||
graph.lineWidth = angular.linewidth;
|
||||
|
||||
if (isNumber(angular.pointradius)) {
|
||||
graph.pointSize = 2 + angular.pointradius * 2;
|
||||
}
|
||||
|
||||
if (isNumber(angular.fill)) {
|
||||
graph.fillOpacity = angular.fill * 10; // fill was 0 - 10, new is 0 to 100
|
||||
}
|
||||
|
||||
if (isNumber(angular.fillGradient) && angular.fillGradient > 0) {
|
||||
graph.fillGradient = AreaGradientMode.Opacity;
|
||||
graph.fillOpacity = angular.fillGradient * 10; // fill is 0-10
|
||||
}
|
||||
|
||||
graph.spanNulls = angular.nullPointMode === NullValueMode.Null;
|
||||
|
||||
if (angular.steppedLine) {
|
||||
graph.lineInterpolation = LineInterpolation.StepAfter;
|
||||
}
|
||||
|
||||
if (graph.drawStyle === DrawStyle.Bars) {
|
||||
graph.fillOpacity = 1.0; // bars were always
|
||||
}
|
||||
|
||||
y1.custom = omitBy(graph, isNil);
|
||||
y1.nullValueMode = angular.nullPointMode as NullValueMode;
|
||||
|
||||
|
@ -74,6 +74,15 @@ export const plugin = new PanelPlugin<Options, GraphFieldConfig>(GraphPanel)
|
||||
},
|
||||
showIf: c => c.drawStyle !== DrawStyle.Points,
|
||||
})
|
||||
.addRadio({
|
||||
path: 'fillGradient',
|
||||
name: 'Fill gradient',
|
||||
defaultValue: graphFieldOptions.fillGradient[0],
|
||||
settings: {
|
||||
options: graphFieldOptions.fillGradient,
|
||||
},
|
||||
showIf: c => !!(c.drawStyle !== DrawStyle.Points && c.fillOpacity && c.fillOpacity > 0),
|
||||
})
|
||||
.addRadio({
|
||||
path: 'spanNulls',
|
||||
name: 'Null values',
|
||||
|
Loading…
Reference in New Issue
Block a user