mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
GraphNG: Color series from by value scheme & change to fillGradient to gradientMode (#29893)
This commit is contained in:
parent
f004655b7d
commit
93a59561ba
@ -34,7 +34,7 @@
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "line",
|
||||
"fillGradient": 0.5,
|
||||
"gradientMode": "opacity",
|
||||
"fillOpacity": 40,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 2,
|
||||
@ -122,7 +122,7 @@
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "bars",
|
||||
"fillGradient": 0.4,
|
||||
"gradientNode": "opacity",
|
||||
"fillOpacity": 53,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
@ -211,7 +211,7 @@
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "bars",
|
||||
"fillGradient": "opacity",
|
||||
"gradientMode": "opacity",
|
||||
"fillOpacity": 100,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 0,
|
||||
@ -300,7 +300,7 @@
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "line",
|
||||
"fillGradient": 0.5,
|
||||
"gradientMode": "opacity",
|
||||
"fillOpacity": 20,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
@ -388,7 +388,7 @@
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "line",
|
||||
"fillGradient": "hue",
|
||||
"gradientMode": "hue",
|
||||
"fillOpacity": 62,
|
||||
"lineInterpolation": "smooth",
|
||||
"lineWidth": 2,
|
||||
@ -477,7 +477,7 @@
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "bars",
|
||||
"fillGradient": "hue",
|
||||
"gradientMode": "hue",
|
||||
"fillOpacity": 100,
|
||||
"lineInterpolation": "smooth",
|
||||
"lineWidth": 0,
|
||||
|
892
devenv/dev-dashboards/panel-graph/graph-ng-hue-gradients.json
Normal file
892
devenv/dev-dashboards/panel-graph/graph-ng-hue-gradients.json
Normal file
@ -0,0 +1,892 @@
|
||||
{
|
||||
"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,
|
||||
"id": 391,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "bars",
|
||||
"fillOpacity": 100,
|
||||
"gradientMode": "hue",
|
||||
"hideFrom": {
|
||||
"graph": false,
|
||||
"legend": false,
|
||||
"tooltip": false
|
||||
},
|
||||
"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": 9,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"interval": "1m",
|
||||
"links": [],
|
||||
"maxDataPoints": 9,
|
||||
"options": {
|
||||
"graph": {},
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"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": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "bars",
|
||||
"fillOpacity": 72,
|
||||
"gradientMode": "hue",
|
||||
"hideFrom": {
|
||||
"graph": false,
|
||||
"legend": false,
|
||||
"tooltip": false
|
||||
},
|
||||
"lineInterpolation": "smooth",
|
||||
"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": "green",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 0
|
||||
},
|
||||
"id": 3,
|
||||
"interval": "1m",
|
||||
"links": [],
|
||||
"maxDataPoints": 9,
|
||||
"options": {
|
||||
"graph": {},
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"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 (line + opacity)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "bars",
|
||||
"fillOpacity": 78,
|
||||
"gradientMode": "hue",
|
||||
"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": "A-series"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "color",
|
||||
"value": {
|
||||
"fixedColor": "orange",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 8,
|
||||
"x": 16,
|
||||
"y": 0
|
||||
},
|
||||
"id": 5,
|
||||
"interval": "1m",
|
||||
"links": [],
|
||||
"maxDataPoints": 9,
|
||||
"options": {
|
||||
"graph": {},
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"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 (line + opacity)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "bars",
|
||||
"fillOpacity": 100,
|
||||
"gradientMode": "hue",
|
||||
"hideFrom": {
|
||||
"graph": false,
|
||||
"legend": false,
|
||||
"tooltip": false
|
||||
},
|
||||
"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": "purple",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 9
|
||||
},
|
||||
"id": 4,
|
||||
"interval": "1m",
|
||||
"links": [],
|
||||
"maxDataPoints": 9,
|
||||
"options": {
|
||||
"graph": {},
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"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": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "bars",
|
||||
"fillOpacity": 100,
|
||||
"gradientMode": "hue",
|
||||
"hideFrom": {
|
||||
"graph": false,
|
||||
"legend": false,
|
||||
"tooltip": false
|
||||
},
|
||||
"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": "yellow",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 9
|
||||
},
|
||||
"id": 6,
|
||||
"interval": "1m",
|
||||
"links": [],
|
||||
"maxDataPoints": 9,
|
||||
"options": {
|
||||
"graph": {},
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"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": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "bars",
|
||||
"fillOpacity": 100,
|
||||
"gradientMode": "hue",
|
||||
"hideFrom": {
|
||||
"graph": false,
|
||||
"legend": false,
|
||||
"tooltip": false
|
||||
},
|
||||
"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": "rgb(12, 187, 242)",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 8,
|
||||
"x": 16,
|
||||
"y": 9
|
||||
},
|
||||
"id": 7,
|
||||
"interval": "1m",
|
||||
"links": [],
|
||||
"maxDataPoints": 9,
|
||||
"options": {
|
||||
"graph": {},
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"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": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 78,
|
||||
"gradientMode": "hue",
|
||||
"hideFrom": {
|
||||
"graph": false,
|
||||
"legend": false,
|
||||
"tooltip": false
|
||||
},
|
||||
"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": "orange",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 18
|
||||
},
|
||||
"id": 8,
|
||||
"interval": "1m",
|
||||
"links": [],
|
||||
"maxDataPoints": 100,
|
||||
"options": {
|
||||
"graph": {},
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"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 (line + opacity)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 78,
|
||||
"gradientMode": "hue",
|
||||
"hideFrom": {
|
||||
"graph": false,
|
||||
"legend": false,
|
||||
"tooltip": false
|
||||
},
|
||||
"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": "blue",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 18
|
||||
},
|
||||
"id": 9,
|
||||
"interval": "1m",
|
||||
"links": [],
|
||||
"maxDataPoints": 100,
|
||||
"options": {
|
||||
"graph": {},
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"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 (line + opacity)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 78,
|
||||
"gradientMode": "hue",
|
||||
"hideFrom": {
|
||||
"graph": false,
|
||||
"legend": false,
|
||||
"tooltip": false
|
||||
},
|
||||
"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": "green",
|
||||
"mode": "fixed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 8,
|
||||
"x": 16,
|
||||
"y": 18
|
||||
},
|
||||
"id": 10,
|
||||
"interval": "1m",
|
||||
"links": [],
|
||||
"maxDataPoints": 100,
|
||||
"options": {
|
||||
"graph": {},
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"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 (line + opacity)",
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 27,
|
||||
"style": "dark",
|
||||
"tags": ["gdev", "panel-tests", "graph-ng"],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Panel Tests - GraphNG - Hue Gradients",
|
||||
"uid": "k3XQFOBMk",
|
||||
"version": 3
|
||||
}
|
@ -34,7 +34,7 @@
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "line",
|
||||
"fillGradient": 0,
|
||||
"fillGradient": "none",
|
||||
"fillOpacity": 0,
|
||||
"hideFrom": {
|
||||
"graph": false,
|
||||
@ -135,7 +135,7 @@
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "line",
|
||||
"fillGradient": 0,
|
||||
"fillGradient": "none",
|
||||
"fillOpacity": 0,
|
||||
"hideFrom": {
|
||||
"graph": false,
|
||||
@ -245,7 +245,7 @@
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "line",
|
||||
"fillGradient": 0,
|
||||
"fillGradient": "none",
|
||||
"fillOpacity": 0,
|
||||
"hideFrom": {
|
||||
"graph": false,
|
||||
@ -374,7 +374,7 @@
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "line",
|
||||
"fillGradient": 0,
|
||||
"fillGradient": "none",
|
||||
"fillOpacity": 0,
|
||||
"hideFrom": {
|
||||
"graph": false,
|
||||
@ -475,7 +475,7 @@
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "line",
|
||||
"fillGradient": 0,
|
||||
"fillGradient": "none",
|
||||
"fillOpacity": 0,
|
||||
"hideFrom": {
|
||||
"graph": false,
|
||||
@ -585,7 +585,7 @@
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "line",
|
||||
"fillGradient": 0,
|
||||
"fillGradient": "none",
|
||||
"fillOpacity": 0,
|
||||
"hideFrom": {
|
||||
"graph": false,
|
||||
@ -726,9 +726,7 @@
|
||||
"fill": {
|
||||
"alpha": 0
|
||||
},
|
||||
"fillGradient": {
|
||||
"label": "None"
|
||||
},
|
||||
"fillGradient": "none",
|
||||
"fillOpacity": 10,
|
||||
"hideFrom": {
|
||||
"graph": false,
|
||||
@ -889,9 +887,7 @@
|
||||
"fill": {
|
||||
"alpha": 0
|
||||
},
|
||||
"fillGradient": {
|
||||
"label": "None"
|
||||
},
|
||||
"fillGradient": "none",
|
||||
"fillOpacity": 10,
|
||||
"hideFrom": {
|
||||
"graph": false,
|
||||
|
@ -1,18 +1,35 @@
|
||||
import { Field, FieldColorModeId } from '../types';
|
||||
import { Field, FieldColorModeId, FieldType } from '../types';
|
||||
import { getTestTheme } from '../utils/testdata/testTheme';
|
||||
import { fieldColorModeRegistry, FieldValueColorCalculator } from './fieldColor';
|
||||
import { ArrayVector } from '../vector/ArrayVector';
|
||||
import { fieldColorModeRegistry, FieldValueColorCalculator, getFieldSeriesColor } from './fieldColor';
|
||||
|
||||
function getTestField(mode: string): Field {
|
||||
return {
|
||||
name: 'name',
|
||||
type: FieldType.number,
|
||||
values: new ArrayVector(),
|
||||
config: {
|
||||
color: {
|
||||
mode: mode,
|
||||
} as any,
|
||||
},
|
||||
state: {},
|
||||
};
|
||||
}
|
||||
|
||||
interface GetCalcOptions {
|
||||
mode: string;
|
||||
seriesIndex?: number;
|
||||
}
|
||||
|
||||
function getCalculator(options: GetCalcOptions): FieldValueColorCalculator {
|
||||
const field = getTestField(options.mode);
|
||||
const mode = fieldColorModeRegistry.get(options.mode);
|
||||
field.state!.seriesIndex = options.seriesIndex;
|
||||
return mode.getCalculator(field, getTestTheme());
|
||||
}
|
||||
|
||||
describe('fieldColorModeRegistry', () => {
|
||||
interface GetCalcOptions {
|
||||
mode: string;
|
||||
seriesIndex?: number;
|
||||
}
|
||||
|
||||
function getCalculator(options: GetCalcOptions): FieldValueColorCalculator {
|
||||
const mode = fieldColorModeRegistry.get(options.mode);
|
||||
return mode.getCalculator({ state: { seriesIndex: options.seriesIndex } } as Field, getTestTheme());
|
||||
}
|
||||
|
||||
it('Schemes should interpolate', () => {
|
||||
const calcFn = getCalculator({ mode: 'continuous-GrYlRd' });
|
||||
expect(calcFn(70, 0.5, undefined)).toEqual('rgb(226, 192, 61)');
|
||||
@ -27,4 +44,48 @@ describe('fieldColorModeRegistry', () => {
|
||||
const calcFn = getCalculator({ mode: FieldColorModeId.PaletteClassic, seriesIndex: 1 });
|
||||
expect(calcFn(70, 0, undefined)).toEqual('#EAB839');
|
||||
});
|
||||
|
||||
it('When color.seriesBy is set to last use that instead of v', () => {
|
||||
const field = getTestField('continuous-GrYlRd');
|
||||
|
||||
field.config.color!.seriesBy = 'last';
|
||||
// min = -10, max = 10, last = 5
|
||||
// last percent 75%
|
||||
field.values = new ArrayVector([0, -10, 5, 10, 2, 5]);
|
||||
|
||||
const color = getFieldSeriesColor(field, getTestTheme());
|
||||
const calcFn = getCalculator({ mode: 'continuous-GrYlRd' });
|
||||
|
||||
expect(color.color).toEqual(calcFn(4, 0.75));
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFieldSeriesColor', () => {
|
||||
const field = getTestField('continuous-GrYlRd');
|
||||
field.values = new ArrayVector([0, -10, 5, 10, 2, 5]);
|
||||
|
||||
it('When color.seriesBy is last use that to calc series color', () => {
|
||||
field.config.color!.seriesBy = 'last';
|
||||
const color = getFieldSeriesColor(field, getTestTheme());
|
||||
const calcFn = getCalculator({ mode: 'continuous-GrYlRd' });
|
||||
|
||||
// the 4 can be anything, 0.75 comes from 5 being 75% in the range -10 to 10 (see data above)
|
||||
expect(color.color).toEqual(calcFn(4, 0.75));
|
||||
});
|
||||
|
||||
it('When color.seriesBy is max use that to calc series color', () => {
|
||||
field.config.color!.seriesBy = 'max';
|
||||
const color = getFieldSeriesColor(field, getTestTheme());
|
||||
const calcFn = getCalculator({ mode: 'continuous-GrYlRd' });
|
||||
|
||||
expect(color.color).toEqual(calcFn(10, 1));
|
||||
});
|
||||
|
||||
it('When color.seriesBy is min use that to calc series color', () => {
|
||||
field.config.color!.seriesBy = 'min';
|
||||
const color = getFieldSeriesColor(field, getTestTheme());
|
||||
const calcFn = getCalculator({ mode: 'continuous-GrYlRd' });
|
||||
|
||||
expect(color.color).toEqual(calcFn(-10, 0));
|
||||
});
|
||||
});
|
||||
|
@ -3,6 +3,8 @@ import { classicColors, getColorForTheme, RegistryItem } from '../utils';
|
||||
import { Registry } from '../utils/Registry';
|
||||
import { interpolateRgbBasis } from 'd3-interpolate';
|
||||
import { fallBackTreshold } from './thresholds';
|
||||
import { getScaleCalculator, ColorScaleValue } from './scale';
|
||||
import { reduceField } from '../transformations/fieldReducer';
|
||||
|
||||
export type FieldValueColorCalculator = (value: number, percent: number, Threshold?: Threshold) => string;
|
||||
|
||||
@ -209,6 +211,30 @@ export function getFieldColorMode(mode?: FieldColorModeId): FieldColorMode {
|
||||
return fieldColorModeRegistry.get(mode ?? FieldColorModeId.Thresholds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
* Function that will return a series color for any given color mode. If the color mode is a by value color
|
||||
* mode it will use the field.config.color.seriesBy property to figure out which value to use
|
||||
*/
|
||||
export function getFieldSeriesColor(field: Field, theme: GrafanaTheme): ColorScaleValue {
|
||||
const mode = getFieldColorModeForField(field);
|
||||
|
||||
if (!mode.isByValue) {
|
||||
return {
|
||||
color: mode.getCalculator(field, theme)(0, 0),
|
||||
threshold: fallBackTreshold,
|
||||
percent: 1,
|
||||
};
|
||||
}
|
||||
|
||||
const scale = getScaleCalculator(field, theme);
|
||||
const stat = field.config.color?.seriesBy ?? 'last';
|
||||
const calcs = reduceField({ field, reducers: [stat] });
|
||||
const value = calcs[stat] ?? 0;
|
||||
|
||||
return scale(value);
|
||||
}
|
||||
|
||||
function getFixedColor(field: Field, theme: GrafanaTheme) {
|
||||
return () => {
|
||||
return getColorForTheme(field.config.color?.fixedColor ?? FALLBACK_COLOR, theme);
|
||||
|
@ -3,7 +3,13 @@ export * from './displayProcessor';
|
||||
export * from './standardFieldConfigEditorRegistry';
|
||||
export * from './overrides/processors';
|
||||
|
||||
export { getFieldColorModeForField, getFieldColorMode, fieldColorModeRegistry, FieldColorMode } from './fieldColor';
|
||||
export {
|
||||
getFieldColorModeForField,
|
||||
getFieldColorMode,
|
||||
fieldColorModeRegistry,
|
||||
FieldColorMode,
|
||||
getFieldSeriesColor,
|
||||
} from './fieldColor';
|
||||
export { FieldConfigOptionsRegistry } from './FieldConfigOptionsRegistry';
|
||||
export { sortThresholds, getActiveThreshold } from './thresholds';
|
||||
export { applyFieldOverrides, validateFieldConfig, applyRawFieldOverrides } from './fieldOverrides';
|
||||
|
@ -131,6 +131,11 @@ export interface FieldColorConfigSettings {
|
||||
* to from thresholds if it was set to a by series palette
|
||||
*/
|
||||
preferThresholdsMode?: boolean;
|
||||
/**
|
||||
* Set to true if the visualization supports both by value and by series
|
||||
* This will enable the Color by series UI option that sets the `color.seriesBy` option.
|
||||
*/
|
||||
bySeriesSupport?: boolean;
|
||||
}
|
||||
|
||||
export interface StatsPickerConfigSettings {
|
||||
|
@ -4,13 +4,13 @@ import { Field, FieldConfig, FieldType, GrafanaTheme, NumericRange, Threshold }
|
||||
import { getFieldColorModeForField } from './fieldColor';
|
||||
import { getActiveThresholdForValue } from './thresholds';
|
||||
|
||||
export interface ScaledValue {
|
||||
export interface ColorScaleValue {
|
||||
percent: number; // 0-1
|
||||
threshold: Threshold;
|
||||
color: string;
|
||||
}
|
||||
|
||||
export type ScaleCalculator = (value: number) => ScaledValue;
|
||||
export type ScaleCalculator = (value: number) => ColorScaleValue;
|
||||
|
||||
export function getScaleCalculator(field: Field, theme: GrafanaTheme): ScaleCalculator {
|
||||
const mode = getFieldColorModeForField(field);
|
||||
|
@ -18,5 +18,5 @@ export {
|
||||
BasicValueMatcherOptions,
|
||||
RangeValueMatcherOptions,
|
||||
} from './transformations/matchers/valueMatchers/types';
|
||||
export { PanelPlugin } from './panel/PanelPlugin';
|
||||
export { PanelPlugin, SetFieldConfigOptionsArgs } from './panel/PanelPlugin';
|
||||
export { createFieldConfigRegistry } from './panel/registryFactories';
|
||||
|
@ -21,6 +21,7 @@ type StandardOptionConfig = {
|
||||
settings?: any;
|
||||
};
|
||||
|
||||
/** @beta */
|
||||
export interface SetFieldConfigOptionsArgs<TFieldConfigOptions = any> {
|
||||
/**
|
||||
* Configuration object of the standard field config properites
|
||||
|
@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export enum FieldColorModeId {
|
||||
Thresholds = 'thresholds',
|
||||
PaletteClassic = 'palette-classic',
|
||||
@ -5,9 +8,21 @@ export enum FieldColorModeId {
|
||||
Fixed = 'fixed',
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface FieldColor {
|
||||
/** The main color scheme mode */
|
||||
mode: FieldColorModeId;
|
||||
/** Stores the fixed color value if mode is fixed */
|
||||
fixedColor?: string;
|
||||
/** Some visualizations need to know how to assign a series color from by value color schemes */
|
||||
seriesBy?: FieldColorSeriesByMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @beta
|
||||
*/
|
||||
export type FieldColorSeriesByMode = 'min' | 'max' | 'last';
|
||||
|
||||
export const FALLBACK_COLOR = 'gray';
|
||||
|
@ -8,7 +8,6 @@ import {
|
||||
fieldReducers,
|
||||
FieldType,
|
||||
formattedValueToString,
|
||||
getFieldColorModeForField,
|
||||
getFieldDisplayName,
|
||||
reduceField,
|
||||
TimeRange,
|
||||
@ -23,6 +22,7 @@ import { LegendDisplayMode, VizLegendItem, VizLegendOptions } from '../VizLegend
|
||||
import { VizLegend } from '../VizLegend/VizLegend';
|
||||
import { UPlotConfigBuilder } from '../uPlot/config/UPlotConfigBuilder';
|
||||
import { useRevision } from '../uPlot/hooks';
|
||||
import { getFieldColorModeForField, getFieldSeriesColor } from '@grafana/data';
|
||||
import { GraphNGLegendEvent, GraphNGLegendEventMode } from './types';
|
||||
import { isNumber } from 'lodash';
|
||||
|
||||
@ -109,6 +109,7 @@ export const GraphNG: React.FC<GraphNGProps> = ({
|
||||
|
||||
// X is the first field in the aligned frame
|
||||
const xField = alignedFrame.fields[0];
|
||||
|
||||
if (xField.type === FieldType.time) {
|
||||
builder.addScale({
|
||||
scaleKey: 'x',
|
||||
@ -118,6 +119,7 @@ export const GraphNG: React.FC<GraphNGProps> = ({
|
||||
return [r.from.valueOf(), r.to.valueOf()];
|
||||
},
|
||||
});
|
||||
|
||||
builder.addAxis({
|
||||
scaleKey: 'x',
|
||||
isTime: true,
|
||||
@ -130,6 +132,7 @@ export const GraphNG: React.FC<GraphNGProps> = ({
|
||||
builder.addScale({
|
||||
scaleKey: 'x',
|
||||
});
|
||||
|
||||
builder.addAxis({
|
||||
scaleKey: 'x',
|
||||
placement: AxisPlacement.Bottom,
|
||||
@ -153,7 +156,8 @@ export const GraphNG: React.FC<GraphNGProps> = ({
|
||||
const fmt = field.display ?? defaultFormatter;
|
||||
const scaleKey = config.unit || FIXED_UNIT;
|
||||
const colorMode = getFieldColorModeForField(field);
|
||||
const seriesColor = colorMode.getCalculator(field, theme)(0, 0);
|
||||
const scaleColor = getFieldSeriesColor(field, theme);
|
||||
const seriesColor = scaleColor.color;
|
||||
|
||||
if (customConfig.axisPlacement !== AxisPlacement.Hidden) {
|
||||
// The builder will manage unique scaleKeys and combine where appropriate
|
||||
@ -200,18 +204,21 @@ export const GraphNG: React.FC<GraphNGProps> = ({
|
||||
|
||||
builder.addSeries({
|
||||
scaleKey,
|
||||
showPoints,
|
||||
colorMode,
|
||||
fillOpacity,
|
||||
theme,
|
||||
drawStyle: customConfig.drawStyle!,
|
||||
lineColor: customConfig.lineColor ?? seriesColor,
|
||||
lineWidth: customConfig.lineWidth,
|
||||
lineInterpolation: customConfig.lineInterpolation,
|
||||
lineStyle: customConfig.lineStyle,
|
||||
showPoints,
|
||||
pointSize: customConfig.pointSize,
|
||||
pointColor: customConfig.pointColor ?? seriesColor,
|
||||
fillOpacity,
|
||||
spanNulls: customConfig.spanNulls || false,
|
||||
show: !customConfig.hideFrom?.graph,
|
||||
fillGradient: customConfig.fillGradient,
|
||||
gradientMode: customConfig.gradientMode,
|
||||
thresholds: config.thresholds,
|
||||
|
||||
// The following properties are not used in the uPlot config, but are utilized as transport for legend config
|
||||
dataFrameFieldIndex,
|
||||
|
@ -9,11 +9,15 @@ import {
|
||||
GrafanaTheme,
|
||||
getColorForTheme,
|
||||
FieldColorConfigSettings,
|
||||
FieldColorSeriesByMode,
|
||||
getFieldColorMode,
|
||||
} from '@grafana/data';
|
||||
import { Select } from '../Select/Select';
|
||||
import { ColorValueEditor } from './color';
|
||||
import { useStyles, useTheme } from '../../themes/ThemeContext';
|
||||
import { css } from 'emotion';
|
||||
import { Field } from '../Forms/Field';
|
||||
import { RadioButtonGroup } from '../Forms/RadioButtonGroup/RadioButtonGroup';
|
||||
|
||||
export const FieldColorEditor: React.FC<FieldConfigEditorProps<FieldColor | undefined, FieldColorConfigSettings>> = ({
|
||||
value,
|
||||
@ -23,6 +27,7 @@ export const FieldColorEditor: React.FC<FieldConfigEditorProps<FieldColor | unde
|
||||
const theme = useTheme();
|
||||
const styles = useStyles(getStyles);
|
||||
|
||||
const colorMode = getFieldColorMode(value?.mode);
|
||||
const availableOptions = item.settings?.byValueSupport
|
||||
? fieldColorModeRegistry.list()
|
||||
: fieldColorModeRegistry.list().filter(m => !m.isByValue);
|
||||
@ -44,17 +49,27 @@ export const FieldColorEditor: React.FC<FieldConfigEditorProps<FieldColor | unde
|
||||
|
||||
const onModeChange = (newMode: SelectableValue<string>) => {
|
||||
onChange({
|
||||
...value,
|
||||
mode: newMode.value! as FieldColorModeId,
|
||||
});
|
||||
};
|
||||
|
||||
const onColorChange = (color?: string) => {
|
||||
onChange({
|
||||
...value,
|
||||
mode,
|
||||
fixedColor: color,
|
||||
});
|
||||
};
|
||||
|
||||
const onSeriesModeChange = (seriesBy?: FieldColorSeriesByMode) => {
|
||||
onChange({
|
||||
...value,
|
||||
mode,
|
||||
seriesBy,
|
||||
});
|
||||
};
|
||||
|
||||
const mode = value?.mode ?? FieldColorModeId.Thresholds;
|
||||
|
||||
if (mode === FieldColorModeId.Fixed) {
|
||||
@ -66,6 +81,25 @@ export const FieldColorEditor: React.FC<FieldConfigEditorProps<FieldColor | unde
|
||||
);
|
||||
}
|
||||
|
||||
if (item.settings?.bySeriesSupport && colorMode.isByValue) {
|
||||
const seriesModes: Array<SelectableValue<FieldColorSeriesByMode>> = [
|
||||
{ label: 'Last', value: 'last' },
|
||||
{ label: 'Min', value: 'min' },
|
||||
{ label: 'Max', value: 'max' },
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ marginBottom: theme.spacing.formInputMargin }}>
|
||||
<Select minMenuHeight={200} options={options} value={mode} onChange={onModeChange} />
|
||||
</div>
|
||||
<Field label="Color series by">
|
||||
<RadioButtonGroup value={value?.seriesBy ?? 'last'} options={seriesModes} onChange={onSeriesModeChange} />
|
||||
</Field>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return <Select minMenuHeight={200} options={options} value={mode} onChange={onModeChange} />;
|
||||
};
|
||||
|
||||
|
@ -137,6 +137,7 @@ export class Sparkline extends PureComponent<Props, State> {
|
||||
|
||||
builder.addSeries({
|
||||
scaleKey,
|
||||
theme,
|
||||
fieldName: getFieldDisplayName(field, data),
|
||||
drawStyle: customConfig.drawStyle!,
|
||||
lineColor: customConfig.lineColor ?? seriesColor,
|
||||
|
@ -73,17 +73,17 @@ export interface LineConfig {
|
||||
export interface FillConfig {
|
||||
fillColor?: string;
|
||||
fillOpacity?: number;
|
||||
fillGradient?: FillGradientMode;
|
||||
fillBelowTo?: string; // name of the field
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export enum FillGradientMode {
|
||||
export enum GraphGradientMode {
|
||||
None = 'none',
|
||||
Opacity = 'opacity',
|
||||
Hue = 'hue',
|
||||
Scheme = 'scheme',
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,6 +131,7 @@ export interface HideSeriesConfig {
|
||||
*/
|
||||
export interface GraphFieldConfig extends LineConfig, FillConfig, PointsConfig, AxisConfig {
|
||||
drawStyle?: DrawStyle;
|
||||
gradientMode?: GraphGradientMode;
|
||||
hideFrom?: HideSeriesConfig;
|
||||
}
|
||||
|
||||
@ -165,8 +166,9 @@ export const graphFieldOptions = {
|
||||
] as Array<SelectableValue<AxisPlacement>>,
|
||||
|
||||
fillGradient: [
|
||||
{ label: 'None', value: FillGradientMode.None },
|
||||
{ label: 'Opacity', value: FillGradientMode.Opacity },
|
||||
{ label: 'Hue', value: FillGradientMode.Hue },
|
||||
] as Array<SelectableValue<FillGradientMode>>,
|
||||
{ label: 'None', value: GraphGradientMode.None },
|
||||
{ label: 'Opacity', value: GraphGradientMode.Opacity },
|
||||
{ label: 'Hue', value: GraphGradientMode.Hue },
|
||||
// { label: 'Color scheme', value: GraphGradientMode.Scheme },
|
||||
] as Array<SelectableValue<GraphGradientMode>>,
|
||||
};
|
||||
|
@ -2,8 +2,7 @@
|
||||
|
||||
import { UPlotConfigBuilder } from './UPlotConfigBuilder';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { expect } from '../../../../../../public/test/lib/common';
|
||||
import { FillGradientMode, AxisPlacement, DrawStyle, PointVisibility, ScaleDistribution } from '../config';
|
||||
import { GraphGradientMode, AxisPlacement, DrawStyle, PointVisibility, ScaleDistribution } from '../config';
|
||||
import darkTheme from '../../../themes/dark';
|
||||
|
||||
describe('UPlotConfigBuilder', () => {
|
||||
@ -327,6 +326,7 @@ describe('UPlotConfigBuilder', () => {
|
||||
scaleKey: 'scale-x',
|
||||
fieldName: 'A-series',
|
||||
lineColor: '#0000ff',
|
||||
theme: darkTheme,
|
||||
});
|
||||
|
||||
expect(builder.getConfig().series[1].fill).toBe(undefined);
|
||||
@ -340,6 +340,7 @@ describe('UPlotConfigBuilder', () => {
|
||||
fieldName: 'A-series',
|
||||
lineColor: '#FFAABB',
|
||||
fillOpacity: 50,
|
||||
theme: darkTheme,
|
||||
});
|
||||
|
||||
expect(builder.getConfig().series[1].fill).toBe('rgba(255, 170, 187, 0.5)');
|
||||
@ -354,6 +355,7 @@ describe('UPlotConfigBuilder', () => {
|
||||
lineColor: '#FFAABB',
|
||||
fillOpacity: 50,
|
||||
fillColor: '#FF0000',
|
||||
theme: darkTheme,
|
||||
});
|
||||
|
||||
expect(builder.getConfig().series[1].fill).toBe('#FF0000');
|
||||
@ -367,7 +369,8 @@ describe('UPlotConfigBuilder', () => {
|
||||
fieldName: 'A-series',
|
||||
lineColor: '#FFAABB',
|
||||
fillOpacity: 50,
|
||||
fillGradient: FillGradientMode.Opacity,
|
||||
gradientMode: GraphGradientMode.Opacity,
|
||||
theme: darkTheme,
|
||||
});
|
||||
|
||||
expect(builder.getConfig().series[1].fill).toBeInstanceOf(Function);
|
||||
@ -380,13 +383,14 @@ describe('UPlotConfigBuilder', () => {
|
||||
scaleKey: 'scale-x',
|
||||
fieldName: 'A-series',
|
||||
fillOpacity: 50,
|
||||
fillGradient: FillGradientMode.Opacity,
|
||||
gradientMode: GraphGradientMode.Opacity,
|
||||
showPoints: PointVisibility.Auto,
|
||||
pointSize: 5,
|
||||
pointColor: '#00ff00',
|
||||
lineColor: '#0000ff',
|
||||
lineWidth: 1,
|
||||
spanNulls: false,
|
||||
theme: darkTheme,
|
||||
});
|
||||
|
||||
expect(builder.getConfig()).toMatchInlineSnapshot(`
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { FALLBACK_COLOR, FieldColorMode, GrafanaTheme, ThresholdsConfig } from '@grafana/data';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import uPlot, { Series } from 'uplot';
|
||||
import { getCanvasContext } from '../../../utils/measureText';
|
||||
import {
|
||||
DrawStyle,
|
||||
LineConfig,
|
||||
@ -8,18 +8,25 @@ import {
|
||||
PointsConfig,
|
||||
PointVisibility,
|
||||
LineInterpolation,
|
||||
FillGradientMode,
|
||||
GraphGradientMode,
|
||||
} from '../config';
|
||||
import { PlotConfigBuilder } from '../types';
|
||||
import { DataFrameFieldIndex } from '@grafana/data';
|
||||
import { getScaleGradientFn, getOpacityGradientFn, getHueGradientFn } from './gradientFills';
|
||||
|
||||
export interface SeriesProps extends LineConfig, FillConfig, PointsConfig {
|
||||
scaleKey: string;
|
||||
gradientMode?: GraphGradientMode;
|
||||
/** Used when gradientMode is set to Scheme */
|
||||
thresholds?: ThresholdsConfig;
|
||||
/** Used when gradientMode is set to Scheme */
|
||||
colorMode?: FieldColorMode;
|
||||
fieldName: string;
|
||||
drawStyle: DrawStyle;
|
||||
show?: boolean;
|
||||
dataFrameFieldIndex?: DataFrameFieldIndex;
|
||||
hideInLegend?: boolean;
|
||||
theme: GrafanaTheme;
|
||||
}
|
||||
|
||||
export class UPlotSeriesBuilder extends PlotConfigBuilder<SeriesProps, Series> {
|
||||
@ -27,7 +34,6 @@ export class UPlotSeriesBuilder extends PlotConfigBuilder<SeriesProps, Series> {
|
||||
const {
|
||||
drawStyle,
|
||||
lineInterpolation,
|
||||
lineColor,
|
||||
lineWidth,
|
||||
lineStyle,
|
||||
showPoints,
|
||||
@ -43,7 +49,7 @@ export class UPlotSeriesBuilder extends PlotConfigBuilder<SeriesProps, Series> {
|
||||
if (drawStyle === DrawStyle.Points) {
|
||||
lineConfig.paths = () => null;
|
||||
} else {
|
||||
lineConfig.stroke = lineColor;
|
||||
lineConfig.stroke = this.getLineColor();
|
||||
lineConfig.width = lineWidth;
|
||||
if (lineStyle && lineStyle.fill !== 'solid') {
|
||||
if (lineStyle.fill === 'dot') {
|
||||
@ -90,28 +96,39 @@ export class UPlotSeriesBuilder extends PlotConfigBuilder<SeriesProps, Series> {
|
||||
};
|
||||
}
|
||||
|
||||
getFill(): Series.Fill | undefined {
|
||||
const { lineColor, fillColor, fillGradient, fillOpacity } = this.props;
|
||||
private getLineColor(): Series.Stroke {
|
||||
const { lineColor, gradientMode, colorMode, thresholds } = this.props;
|
||||
|
||||
if (gradientMode === GraphGradientMode.Scheme) {
|
||||
return getScaleGradientFn(1, colorMode, thresholds);
|
||||
}
|
||||
|
||||
return lineColor ?? FALLBACK_COLOR;
|
||||
}
|
||||
|
||||
private getFill(): Series.Fill | undefined {
|
||||
const { lineColor, fillColor, gradientMode, fillOpacity, colorMode, thresholds, theme } = this.props;
|
||||
|
||||
if (fillColor) {
|
||||
return fillColor;
|
||||
}
|
||||
|
||||
const mode = fillGradient ?? FillGradientMode.None;
|
||||
let fillOpacityNumber = fillOpacity ?? 0;
|
||||
const mode = gradientMode ?? GraphGradientMode.None;
|
||||
const opacityPercent = (fillOpacity ?? 0) / 100;
|
||||
|
||||
if (mode !== FillGradientMode.None) {
|
||||
return getCanvasGradient({
|
||||
color: (fillColor ?? lineColor)!,
|
||||
opacity: fillOpacityNumber / 100,
|
||||
mode,
|
||||
});
|
||||
}
|
||||
|
||||
if (fillOpacityNumber > 0) {
|
||||
return tinycolor(lineColor)
|
||||
.setAlpha(fillOpacityNumber / 100)
|
||||
.toString();
|
||||
switch (mode) {
|
||||
case GraphGradientMode.Opacity:
|
||||
return getOpacityGradientFn((fillColor ?? lineColor)!, opacityPercent);
|
||||
case GraphGradientMode.Hue:
|
||||
return getHueGradientFn((fillColor ?? lineColor)!, opacityPercent, theme);
|
||||
case GraphGradientMode.Scheme:
|
||||
return getScaleGradientFn(opacityPercent, colorMode, thresholds);
|
||||
default:
|
||||
if (opacityPercent > 0) {
|
||||
return tinycolor(lineColor)
|
||||
.setAlpha(opacityPercent)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
@ -165,50 +182,3 @@ function mapDrawStyleToPathBuilder(
|
||||
|
||||
return builders.linear; // the default
|
||||
}
|
||||
|
||||
interface AreaGradientOptions {
|
||||
color: string;
|
||||
mode: FillGradientMode;
|
||||
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 FillGradientMode.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 FillGradientMode.Opacity:
|
||||
default:
|
||||
gradient.addColorStop(
|
||||
0,
|
||||
tinycolor(color)
|
||||
.setAlpha(opacity)
|
||||
.toRgbString()
|
||||
);
|
||||
gradient.addColorStop(
|
||||
1,
|
||||
tinycolor(color)
|
||||
.setAlpha(0)
|
||||
.toRgbString()
|
||||
);
|
||||
return gradient;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
125
packages/grafana-ui/src/components/uPlot/config/gradientFills.ts
Normal file
125
packages/grafana-ui/src/components/uPlot/config/gradientFills.ts
Normal file
@ -0,0 +1,125 @@
|
||||
import { FieldColorMode, getColorForTheme, GrafanaTheme, ThresholdsConfig } from '@grafana/data';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import uPlot from 'uplot';
|
||||
import darkTheme from '../../../themes/dark';
|
||||
import { getCanvasContext } from '../../../utils/measureText';
|
||||
|
||||
export function getOpacityGradientFn(
|
||||
color: string,
|
||||
opacity: number
|
||||
): (self: uPlot, seriesIdx: number) => CanvasGradient {
|
||||
return (plot: uPlot, seriesIdx: number) => {
|
||||
const ctx = getCanvasContext();
|
||||
const gradient = ctx.createLinearGradient(0, plot.bbox.top, 0, plot.bbox.top + plot.bbox.height);
|
||||
|
||||
gradient.addColorStop(
|
||||
0,
|
||||
tinycolor(color)
|
||||
.setAlpha(opacity)
|
||||
.toRgbString()
|
||||
);
|
||||
gradient.addColorStop(
|
||||
1,
|
||||
tinycolor(color)
|
||||
.setAlpha(0)
|
||||
.toRgbString()
|
||||
);
|
||||
|
||||
return gradient;
|
||||
};
|
||||
}
|
||||
export function getHueGradientFn(
|
||||
color: string,
|
||||
opacity: number,
|
||||
theme: GrafanaTheme
|
||||
): (self: uPlot, seriesIdx: number) => CanvasGradient {
|
||||
return (plot: uPlot, seriesIdx: number) => {
|
||||
const ctx = getCanvasContext();
|
||||
const gradient = ctx.createLinearGradient(0, plot.bbox.top, 0, plot.bbox.top + plot.bbox.height);
|
||||
const color1 = tinycolor(color).spin(-15);
|
||||
const color2 = tinycolor(color).spin(15);
|
||||
|
||||
if (theme.isDark) {
|
||||
gradient.addColorStop(
|
||||
0,
|
||||
color2
|
||||
.lighten(10)
|
||||
.setAlpha(opacity)
|
||||
.toString()
|
||||
);
|
||||
gradient.addColorStop(
|
||||
1,
|
||||
color1
|
||||
.darken(10)
|
||||
.setAlpha(opacity)
|
||||
.toString()
|
||||
);
|
||||
} else {
|
||||
gradient.addColorStop(
|
||||
0,
|
||||
color2
|
||||
.lighten(10)
|
||||
.setAlpha(opacity)
|
||||
.toString()
|
||||
);
|
||||
gradient.addColorStop(1, color1.setAlpha(opacity).toString());
|
||||
}
|
||||
|
||||
return gradient;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Experimental & quick and dirty test
|
||||
* Not being used
|
||||
*/
|
||||
export function getScaleGradientFn(
|
||||
opacity: number,
|
||||
colorMode?: FieldColorMode,
|
||||
thresholds?: ThresholdsConfig
|
||||
): (self: uPlot, seriesIdx: number) => CanvasGradient {
|
||||
if (!colorMode) {
|
||||
throw Error('Missing colorMode required for color scheme gradients');
|
||||
}
|
||||
|
||||
if (!thresholds) {
|
||||
throw Error('Missing thresholds required for color scheme gradients');
|
||||
}
|
||||
|
||||
return (plot: uPlot, seriesIdx: number) => {
|
||||
const ctx = getCanvasContext();
|
||||
const gradient = ctx.createLinearGradient(0, plot.bbox.top, 0, plot.bbox.top + plot.bbox.height);
|
||||
const series = plot.series[seriesIdx];
|
||||
const scale = plot.scales[series.scale!];
|
||||
const range = plot.bbox.height;
|
||||
|
||||
console.log('scale', scale);
|
||||
console.log('series.min', series.min);
|
||||
console.log('series.max', series.max);
|
||||
|
||||
const getColorWithAlpha = (color: string) => {
|
||||
return tinycolor(getColorForTheme(color, darkTheme))
|
||||
.setAlpha(opacity)
|
||||
.toString();
|
||||
};
|
||||
|
||||
const addColorStop = (value: number, color: string) => {
|
||||
const pos = plot.valToPos(value, series.scale!);
|
||||
const percent = pos / range;
|
||||
console.log(`addColorStop(value = ${value}, xPos=${pos})`);
|
||||
gradient.addColorStop(Math.min(percent, 1), getColorWithAlpha(color));
|
||||
};
|
||||
|
||||
for (let idx = 0; idx < thresholds.steps.length; idx++) {
|
||||
const step = thresholds.steps[idx];
|
||||
const value = step.value === -Infinity ? 0 : step.value;
|
||||
addColorStop(value, step.color);
|
||||
|
||||
// to make the gradient discrete
|
||||
if (thresholds.steps.length > idx + 1) {
|
||||
addColorStop(thresholds.steps[idx + 1].value - 0.0000001, step.color);
|
||||
}
|
||||
}
|
||||
|
||||
return gradient;
|
||||
};
|
||||
}
|
@ -89,8 +89,8 @@ Object {
|
||||
"custom": Object {
|
||||
"axisPlacement": "hidden",
|
||||
"drawStyle": "line",
|
||||
"fillGradient": "opacity",
|
||||
"fillOpacity": 60,
|
||||
"gradientMode": "opacity",
|
||||
"lineInterpolation": "stepAfter",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 6,
|
||||
|
@ -3,6 +3,7 @@ import {
|
||||
FieldConfigProperty,
|
||||
FieldType,
|
||||
identityOverrideProcessor,
|
||||
SetFieldConfigOptionsArgs,
|
||||
stringOverrideProcessor,
|
||||
} from '@grafana/data';
|
||||
import {
|
||||
@ -15,12 +16,11 @@ import {
|
||||
PointVisibility,
|
||||
ScaleDistribution,
|
||||
ScaleDistributionConfig,
|
||||
GraphGradientMode,
|
||||
} from '@grafana/ui';
|
||||
import { SeriesConfigEditor } from './HideSeriesConfigEditor';
|
||||
import { ScaleDistributionEditor } from './ScaleDistributionEditor';
|
||||
import { LineStyleEditor } from './LineStyleEditor';
|
||||
import { SetFieldConfigOptionsArgs } from '@grafana/data/src/panel/PanelPlugin';
|
||||
import { FillGradientMode } from '@grafana/ui/src/components/uPlot/config';
|
||||
import { FillBellowToEditor } from './FillBelowToEditor';
|
||||
|
||||
export const defaultGraphConfig: GraphFieldConfig = {
|
||||
@ -28,7 +28,7 @@ export const defaultGraphConfig: GraphFieldConfig = {
|
||||
lineInterpolation: LineInterpolation.Linear,
|
||||
lineWidth: 1,
|
||||
fillOpacity: 0,
|
||||
fillGradient: FillGradientMode.None,
|
||||
gradientMode: GraphGradientMode.None,
|
||||
};
|
||||
|
||||
export function getGraphFieldConfig(cfg: GraphFieldConfig): SetFieldConfigOptionsArgs<GraphFieldConfig> {
|
||||
@ -37,6 +37,8 @@ export function getGraphFieldConfig(cfg: GraphFieldConfig): SetFieldConfigOption
|
||||
[FieldConfigProperty.Color]: {
|
||||
settings: {
|
||||
byValueSupport: false,
|
||||
bySeriesSupport: true,
|
||||
preferThresholdsMode: false,
|
||||
},
|
||||
defaultValue: {
|
||||
mode: FieldColorModeId.PaletteClassic,
|
||||
@ -85,13 +87,13 @@ export function getGraphFieldConfig(cfg: GraphFieldConfig): SetFieldConfigOption
|
||||
showIf: c => c.drawStyle !== DrawStyle.Points,
|
||||
})
|
||||
.addRadio({
|
||||
path: 'fillGradient',
|
||||
name: 'Fill gradient',
|
||||
defaultValue: graphFieldOptions.fillGradient[0].value,
|
||||
path: 'gradientMode',
|
||||
name: 'Gradient mode',
|
||||
defaultValue: graphFieldOptions.fillGradient[0],
|
||||
settings: {
|
||||
options: graphFieldOptions.fillGradient,
|
||||
},
|
||||
showIf: c => !!(c.drawStyle !== DrawStyle.Points && c.fillOpacity && c.fillOpacity > 0),
|
||||
showIf: c => c.drawStyle !== DrawStyle.Points,
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'fillBelowTo',
|
||||
|
@ -12,9 +12,9 @@ import {
|
||||
} from '@grafana/data';
|
||||
import { GraphFieldConfig, LegendDisplayMode } from '@grafana/ui';
|
||||
import {
|
||||
GraphGradientMode,
|
||||
AxisPlacement,
|
||||
DrawStyle,
|
||||
FillGradientMode,
|
||||
LineInterpolation,
|
||||
LineStyle,
|
||||
PointVisibility,
|
||||
@ -251,7 +251,7 @@ export function flotToGraphOptions(angular: any): { fieldConfig: FieldConfigSour
|
||||
}
|
||||
|
||||
if (isNumber(angular.fillGradient) && angular.fillGradient > 0) {
|
||||
graph.fillGradient = FillGradientMode.Opacity;
|
||||
graph.gradientMode = GraphGradientMode.Opacity;
|
||||
graph.fillOpacity = angular.fillGradient * 10; // fill is 0-10
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user