mirror of
https://github.com/grafana/grafana.git
synced 2026-07-29 15:59:50 -05:00
GraphNG: stacking (#30749)
* First iteration * Dev dash * Re-use StackingMode type * Fix ts and api issues * Stacking work resurected * Fix overrides * Correct values in tooltip and updated test dashboard * Update dev dashboard * Apply correct bands for stacking * Merge fix * Update snapshot * Revert go.sum * Handle null values correctyl and make filleBelowTo and stacking mutual exclusive * Snapshots update * Graph->Time series stacking migration * Review comments * Indicate overrides in StandardEditorContext * Change stacking UI editor, migrate stacking to object option * Small refactor, fix for hiding series and dev dashboard
This commit is contained in:
@@ -0,0 +1,896 @@
|
|||||||
|
{
|
||||||
|
"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",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 10,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"graph": false,
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "never",
|
||||||
|
"spanNulls": true,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 16,
|
||||||
|
"w": 8,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"id": 14,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"tooltipOptions": {
|
||||||
|
"mode": "single"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "7.5.0-pre",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 15, 14, 30, 30, 30, 30, 30, 30, 30, -15, 30, 30, 30, 15, 0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "B",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 20, 10, 10, 10, 10, 10"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "C",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 20, 10, 10, 10, 10, 10"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "D",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "E",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "Data not stacked",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": null,
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 10,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"graph": false,
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "never",
|
||||||
|
"spanNulls": true,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "normal"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 16,
|
||||||
|
"x": 8,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"id": 3,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"tooltipOptions": {
|
||||||
|
"mode": "single"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "7.5.0-pre",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 15, 14, 30, 30, 30, 30, 30, 30, 30, -15, 30, 30, 30, 15, 0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "B",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 20, 10, 10, 10, 10, 10"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "C",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 20, 10, 10, 10, 10, 10"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "D",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "E",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "Normal stacking (series order 1)",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": null,
|
||||||
|
"description": "",
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 10,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"graph": false,
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "never",
|
||||||
|
"spanNulls": true,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "normal"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 16,
|
||||||
|
"x": 8,
|
||||||
|
"y": 8
|
||||||
|
},
|
||||||
|
"id": 5,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"tooltipOptions": {
|
||||||
|
"mode": "single"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "7.5.0-pre",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "D",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "E",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "B",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 20, 10, 10, 10, 10, 10"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "C",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 20, 10, 10, 10, 10, 10"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 15, 14, 30, 30, 30, 30, 30, 30, 30, -15, 30, 30, 30, 15, 0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "Normal stacking (series order 2)",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": null,
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "bars",
|
||||||
|
"fillOpacity": 100,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"graph": false,
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "never",
|
||||||
|
"spanNulls": true,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 16,
|
||||||
|
"w": 8,
|
||||||
|
"x": 0,
|
||||||
|
"y": 16
|
||||||
|
},
|
||||||
|
"id": 9,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"tooltipOptions": {
|
||||||
|
"mode": "single"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "7.5.0-pre",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "109,117,122,104,105,117,119,121,117,121,122,129,119,113,113,121,108,108,100,103,113,110,null,null,null,null,87,83,91,85,81,69,76,61,63,74,76,68,55,61,48,39,54,44,37,30,22,33,29,21,22,43,47,33,47,28,29,31,32,35,37,25,-5,-14,-7,-14,-7,-18,-18,-18,-16,-41,-22,-30,-27,-30,-47,-49,-47,-42,-55,-34,-27,-22,-23,-34,-23,-32,-36,-47,-33,-32,-18,-23,-21,-33,-39,-21,-18,-27,-5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "B",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "253,248,247,282,212,275,306,276,253,243,276,261,313,233,231,315,302,288,251,300,263,227,232,271,258,212,225,234,244,200,249,205,231,173,263,246,190,184,198,233,246,232,228,201,212,163,194,155,177,179,130,160,245,184,225,221,217,229,165,172,227,212,181,133,140,128,111,177,177,159,92,100,92,154,161,124,83,99,104,76,117,87,151,154,77,71,164,68,94,105,107,74,130,156,91,103,97,98,96,76,117"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "C",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "408,436,368,422,383,454,459,380,360,400,378,419,468,394,343,457,411,422,448,419,431,389,414,381,415,357,419,398,352,398,379,400,337,299,369,416,329,303,333,362,438,383,350,337,348,289,362,298,355,285,294,319,445,308,375,387,337,406,323,372,342,389,311,254,270,248,271,309,374,323,255,289,223,280,331,237,247,229,293,230,239,242,271,343,255,185,296,217,236,268,257,273,323,346,205,285,277,265,277,253,219"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "D",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "556,581,482,552,550,589,575,565,471,575,565,605,663,544,471,641,567,535,630,535,623,579,582,559,611,509,521,563,513,544,523,558,450,486,478,584,440,432,473,480,555,510,451,476,490,470,555,418,463,402,403,476,591,431,560,581,532,579,427,501,452,551,479,405,397,376,458,439,490,508,389,488,360,413,509,351,434,392,430,426,375,414,401,459,435,327,491,406,397,406,384,423,439,538,338,467,421,406,477,428,371"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Bars, data not stacked",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": null,
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "bars",
|
||||||
|
"fillOpacity": 100,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"graph": false,
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "never",
|
||||||
|
"spanNulls": true,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "normal"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 16,
|
||||||
|
"x": 8,
|
||||||
|
"y": 16
|
||||||
|
},
|
||||||
|
"id": 11,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"stacking": "none",
|
||||||
|
"tooltipOptions": {
|
||||||
|
"mode": "single"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "7.5.0-pre",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "109,117,122,104,105,117,119,121,117,121,122,129,119,113,113,121,108,108,100,103,113,110,null,null,null,null,87,83,91,85,81,69,76,61,63,74,76,68,55,61,48,39,54,44,37,30,22,33,29,21,22,43,47,33,47,28,29,31,32,35,37,25,-5,-14,-7,-14,-7,-18,-18,-18,-16,-41,-22,-30,-27,-30,-47,-49,-47,-42,-55,-34,-27,-22,-23,-34,-23,-32,-36,-47,-33,-32,-18,-23,-21,-33,-39,-21,-18,-27,-5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "B",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "253,248,247,282,212,275,306,276,253,243,276,261,313,233,231,315,302,288,251,300,263,227,232,271,258,212,225,234,244,200,249,205,231,173,263,246,190,184,198,233,246,232,228,201,212,163,194,155,177,179,130,160,245,184,225,221,217,229,165,172,227,212,181,133,140,128,111,177,177,159,92,100,92,154,161,124,83,99,104,76,117,87,151,154,77,71,164,68,94,105,107,74,130,156,91,103,97,98,96,76,117"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "C",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "408,436,368,422,383,454,459,380,360,400,378,419,468,394,343,457,411,422,448,419,431,389,414,381,415,357,419,398,352,398,379,400,337,299,369,416,329,303,333,362,438,383,350,337,348,289,362,298,355,285,294,319,445,308,375,387,337,406,323,372,342,389,311,254,270,248,271,309,374,323,255,289,223,280,331,237,247,229,293,230,239,242,271,343,255,185,296,217,236,268,257,273,323,346,205,285,277,265,277,253,219"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "D",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "556,581,482,552,550,589,575,565,471,575,565,605,663,544,471,641,567,535,630,535,623,579,582,559,611,509,521,563,513,544,523,558,450,486,478,584,440,432,473,480,555,510,451,476,490,470,555,418,463,402,403,476,591,431,560,581,532,579,427,501,452,551,479,405,397,376,458,439,490,508,389,488,360,413,509,351,434,392,430,426,375,414,401,459,435,327,491,406,397,406,384,423,439,538,338,467,421,406,477,428,371"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Bars, normal stacking (series order 1)",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": null,
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "bars",
|
||||||
|
"fillOpacity": 100,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"graph": false,
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "never",
|
||||||
|
"spanNulls": true,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "normal"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 16,
|
||||||
|
"x": 8,
|
||||||
|
"y": 24
|
||||||
|
},
|
||||||
|
"id": 15,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"stacking": "none",
|
||||||
|
"tooltipOptions": {
|
||||||
|
"mode": "single"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "7.5.0-pre",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "D",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "556,581,482,552,550,589,575,565,471,575,565,605,663,544,471,641,567,535,630,535,623,579,582,559,611,509,521,563,513,544,523,558,450,486,478,584,440,432,473,480,555,510,451,476,490,470,555,418,463,402,403,476,591,431,560,581,532,579,427,501,452,551,479,405,397,376,458,439,490,508,389,488,360,413,509,351,434,392,430,426,375,414,401,459,435,327,491,406,397,406,384,423,439,538,338,467,421,406,477,428,371"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "C",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "408,436,368,422,383,454,459,380,360,400,378,419,468,394,343,457,411,422,448,419,431,389,414,381,415,357,419,398,352,398,379,400,337,299,369,416,329,303,333,362,438,383,350,337,348,289,362,298,355,285,294,319,445,308,375,387,337,406,323,372,342,389,311,254,270,248,271,309,374,323,255,289,223,280,331,237,247,229,293,230,239,242,271,343,255,185,296,217,236,268,257,273,323,346,205,285,277,265,277,253,219"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "B",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "253,248,247,282,212,275,306,276,253,243,276,261,313,233,231,315,302,288,251,300,263,227,232,271,258,212,225,234,244,200,249,205,231,173,263,246,190,184,198,233,246,232,228,201,212,163,194,155,177,179,130,160,245,184,225,221,217,229,165,172,227,212,181,133,140,128,111,177,177,159,92,100,92,154,161,124,83,99,104,76,117,87,151,154,77,71,164,68,94,105,107,74,130,156,91,103,97,98,96,76,117"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "109,117,122,104,105,117,119,121,117,121,122,129,119,113,113,121,108,108,100,103,113,110,null,null,null,null,87,83,91,85,81,69,76,61,63,74,76,68,55,61,48,39,54,44,37,30,22,33,29,21,22,43,47,33,47,28,29,31,32,35,37,25,-5,-14,-7,-14,-7,-18,-18,-18,-16,-41,-22,-30,-27,-30,-47,-49,-47,-42,-55,-34,-27,-22,-23,-34,-23,-32,-36,-47,-33,-32,-18,-23,-21,-33,-39,-21,-18,-27,-5"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Bars, normal stacking (series order 2)",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": null,
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 10,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"graph": false,
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "never",
|
||||||
|
"spanNulls": true,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 8,
|
||||||
|
"x": 0,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"id": 13,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"stacking": "none",
|
||||||
|
"tooltipOptions": {
|
||||||
|
"mode": "single"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "7.5.0-pre",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "5,6,7,8,7,6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "B",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "5,5,5,5,5,5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "C",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "5,5,5,5,5,5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "D",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "5,5,5,5,5,5"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "Stacking groups, data not stacked",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": null,
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 10,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"graph": false,
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "never",
|
||||||
|
"spanNulls": true,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "A-series"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "custom.stacking",
|
||||||
|
"value": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "normal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "B-series"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "custom.stacking",
|
||||||
|
"value": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "normal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "C-series"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "custom.stacking",
|
||||||
|
"value": {
|
||||||
|
"group": "B",
|
||||||
|
"mode": "normal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "D-series"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "custom.stacking",
|
||||||
|
"value": {
|
||||||
|
"group": "B",
|
||||||
|
"mode": "normal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 16,
|
||||||
|
"x": 8,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"id": 16,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom"
|
||||||
|
},
|
||||||
|
"stacking": "none",
|
||||||
|
"tooltipOptions": {
|
||||||
|
"mode": "single"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "7.5.0-pre",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "5,6,7,8,7,6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "B",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "5,5,5,5,5,5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "C",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "5,5,5,5,5,5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hide": false,
|
||||||
|
"refId": "D",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "5,5,5,5,5,5"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "Stacking groups, data stacked, two stacking groups",
|
||||||
|
"type": "timeseries"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"schemaVersion": 27,
|
||||||
|
"style": "dark",
|
||||||
|
"tags": [],
|
||||||
|
"templating": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"from": "now-6h",
|
||||||
|
"to": "now"
|
||||||
|
},
|
||||||
|
"timepicker": {},
|
||||||
|
"timezone": "",
|
||||||
|
"title": "Panel Tests - TimeSeries - stacking",
|
||||||
|
"uid": "Ei86FP_Mx",
|
||||||
|
"version": 6
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ export interface StandardEditorContext<TOptions> {
|
|||||||
eventBus?: EventBus;
|
eventBus?: EventBus;
|
||||||
getSuggestions?: (scope?: VariableSuggestionsScope) => VariableSuggestion[];
|
getSuggestions?: (scope?: VariableSuggestionsScope) => VariableSuggestion[];
|
||||||
options?: TOptions;
|
options?: TOptions;
|
||||||
|
isOverride?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StandardEditorProps<TValue = any, TSettings = any, TOptions = any> {
|
export interface StandardEditorProps<TValue = any, TSettings = any, TOptions = any> {
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import { LegendDisplayMode } from '../VizLegend/models.gen';
|
|||||||
import { prepDataForStorybook } from '../../utils/storybook/data';
|
import { prepDataForStorybook } from '../../utils/storybook/data';
|
||||||
import { useTheme } from '../../themes';
|
import { useTheme } from '../../themes';
|
||||||
import { select } from '@storybook/addon-knobs';
|
import { select } from '@storybook/addon-knobs';
|
||||||
import { BarChartOptions, BarStackingMode, BarValueVisibility } from './types';
|
import { BarChartOptions, BarValueVisibility } from './types';
|
||||||
|
import { StackingMode } from '../uPlot/config';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'Visualizations/BarChart',
|
title: 'Visualizations/BarChart',
|
||||||
@@ -55,7 +56,7 @@ export const Basic: React.FC = () => {
|
|||||||
const options: BarChartOptions = {
|
const options: BarChartOptions = {
|
||||||
orientation: orientation,
|
orientation: orientation,
|
||||||
legend: { displayMode: LegendDisplayMode.List, placement: legendPlacement, calcs: [] },
|
legend: { displayMode: LegendDisplayMode.List, placement: legendPlacement, calcs: [] },
|
||||||
stacking: BarStackingMode.None,
|
stacking: StackingMode.None,
|
||||||
showValue: BarValueVisibility.Always,
|
showValue: BarValueVisibility.Always,
|
||||||
barWidth: 0.97,
|
barWidth: 0.97,
|
||||||
groupWidth: 0.7,
|
groupWidth: 0.7,
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ UPlotConfigBuilder {
|
|||||||
[Function],
|
[Function],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
"isStacking": false,
|
||||||
"scales": Array [
|
"scales": Array [
|
||||||
UPlotScaleBuilder {
|
UPlotScaleBuilder {
|
||||||
"props": Object {
|
"props": Object {
|
||||||
@@ -176,6 +177,7 @@ UPlotConfigBuilder {
|
|||||||
[Function],
|
[Function],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
"isStacking": false,
|
||||||
"scales": Array [
|
"scales": Array [
|
||||||
UPlotScaleBuilder {
|
UPlotScaleBuilder {
|
||||||
"props": Object {
|
"props": Object {
|
||||||
@@ -296,6 +298,7 @@ UPlotConfigBuilder {
|
|||||||
[Function],
|
[Function],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
"isStacking": false,
|
||||||
"scales": Array [
|
"scales": Array [
|
||||||
UPlotScaleBuilder {
|
UPlotScaleBuilder {
|
||||||
"props": Object {
|
"props": Object {
|
||||||
@@ -416,6 +419,7 @@ UPlotConfigBuilder {
|
|||||||
[Function],
|
[Function],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
"isStacking": false,
|
||||||
"scales": Array [
|
"scales": Array [
|
||||||
UPlotScaleBuilder {
|
UPlotScaleBuilder {
|
||||||
"props": Object {
|
"props": Object {
|
||||||
@@ -536,6 +540,7 @@ UPlotConfigBuilder {
|
|||||||
[Function],
|
[Function],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
"isStacking": false,
|
||||||
"scales": Array [
|
"scales": Array [
|
||||||
UPlotScaleBuilder {
|
UPlotScaleBuilder {
|
||||||
"props": Object {
|
"props": Object {
|
||||||
@@ -656,6 +661,7 @@ UPlotConfigBuilder {
|
|||||||
[Function],
|
[Function],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
"isStacking": false,
|
||||||
"scales": Array [
|
"scales": Array [
|
||||||
UPlotScaleBuilder {
|
UPlotScaleBuilder {
|
||||||
"props": Object {
|
"props": Object {
|
||||||
@@ -776,6 +782,7 @@ UPlotConfigBuilder {
|
|||||||
[Function],
|
[Function],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
"isStacking": false,
|
||||||
"scales": Array [
|
"scales": Array [
|
||||||
UPlotScaleBuilder {
|
UPlotScaleBuilder {
|
||||||
"props": Object {
|
"props": Object {
|
||||||
@@ -896,6 +903,7 @@ UPlotConfigBuilder {
|
|||||||
[Function],
|
[Function],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
"isStacking": false,
|
||||||
"scales": Array [
|
"scales": Array [
|
||||||
UPlotScaleBuilder {
|
UPlotScaleBuilder {
|
||||||
"props": Object {
|
"props": Object {
|
||||||
|
|||||||
@@ -1,16 +1,7 @@
|
|||||||
import { VizOrientation } from '@grafana/data';
|
import { VizOrientation } from '@grafana/data';
|
||||||
import { AxisConfig, GraphGradientMode, HideableFieldConfig } from '../uPlot/config';
|
import { AxisConfig, GraphGradientMode, HideableFieldConfig, StackingMode } from '../uPlot/config';
|
||||||
import { VizLegendOptions } from '../VizLegend/models.gen';
|
import { VizLegendOptions } from '../VizLegend/models.gen';
|
||||||
|
|
||||||
/**
|
|
||||||
* @alpha
|
|
||||||
*/
|
|
||||||
export enum BarStackingMode {
|
|
||||||
None = 'none',
|
|
||||||
Standard = 'standard',
|
|
||||||
Percent = 'percent',
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @alpha
|
* @alpha
|
||||||
*/
|
*/
|
||||||
@@ -26,7 +17,7 @@ export enum BarValueVisibility {
|
|||||||
export interface BarChartOptions {
|
export interface BarChartOptions {
|
||||||
orientation: VizOrientation;
|
orientation: VizOrientation;
|
||||||
legend: VizLegendOptions;
|
legend: VizLegendOptions;
|
||||||
stacking: BarStackingMode;
|
stacking: StackingMode;
|
||||||
showValue: BarValueVisibility;
|
showValue: BarValueVisibility;
|
||||||
barWidth: number;
|
barWidth: number;
|
||||||
groupWidth: number;
|
groupWidth: number;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { preparePlotConfigBuilder, preparePlotFrame } from './utils';
|
import { preparePlotConfigBuilder, preparePlotFrame } from './utils';
|
||||||
import { FieldConfig, FieldType, GrafanaTheme, MutableDataFrame, VizOrientation } from '@grafana/data';
|
import { FieldConfig, FieldType, GrafanaTheme, MutableDataFrame, VizOrientation } from '@grafana/data';
|
||||||
import { BarChartFieldConfig, BarChartOptions, BarStackingMode, BarValueVisibility } from './types';
|
import { BarChartFieldConfig, BarChartOptions, BarValueVisibility } from './types';
|
||||||
import { GraphGradientMode } from '../uPlot/config';
|
import { GraphGradientMode, StackingMode } from '../uPlot/config';
|
||||||
import { LegendDisplayMode } from '../VizLegend/models.gen';
|
import { LegendDisplayMode } from '../VizLegend/models.gen';
|
||||||
|
|
||||||
function mockDataFrame() {
|
function mockDataFrame() {
|
||||||
@@ -73,7 +73,7 @@ describe('GraphNG utils', () => {
|
|||||||
placement: 'bottom',
|
placement: 'bottom',
|
||||||
calcs: [],
|
calcs: [],
|
||||||
},
|
},
|
||||||
stacking: BarStackingMode.None,
|
stacking: StackingMode.None,
|
||||||
};
|
};
|
||||||
|
|
||||||
it.each([VizOrientation.Auto, VizOrientation.Horizontal, VizOrientation.Vertical])('orientation', (v) => {
|
it.each([VizOrientation.Auto, VizOrientation.Horizontal, VizOrientation.Vertical])('orientation', (v) => {
|
||||||
@@ -94,7 +94,7 @@ describe('GraphNG utils', () => {
|
|||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each([BarStackingMode.None, BarStackingMode.Percent, BarStackingMode.Standard])('stacking', (v) => {
|
it.each([StackingMode.None, StackingMode.Percent, StackingMode.Normal])('stacking', (v) => {
|
||||||
expect(
|
expect(
|
||||||
preparePlotConfigBuilder(frame!, { colors: { panelBg: '#000000' } } as GrafanaTheme, {
|
preparePlotConfigBuilder(frame!, { colors: { panelBg: '#000000' } } as GrafanaTheme, {
|
||||||
...config,
|
...config,
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ export const Lines: Story<StoryProps> = ({ placement, unit, legendDisplayMode, .
|
|||||||
placement: placement,
|
placement: placement,
|
||||||
calcs: [],
|
calcs: [],
|
||||||
}}
|
}}
|
||||||
|
timeZone="browser"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,10 +31,24 @@ UPlotConfigBuilder {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"bands": Array [],
|
"bands": Array [
|
||||||
|
Object {
|
||||||
|
"series": Array [
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"series": Array [
|
||||||
|
4,
|
||||||
|
3,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
"hasBottomAxis": true,
|
"hasBottomAxis": true,
|
||||||
"hasLeftAxis": true,
|
"hasLeftAxis": true,
|
||||||
"hooks": Object {},
|
"hooks": Object {},
|
||||||
|
"isStacking": true,
|
||||||
"scales": Array [
|
"scales": Array [
|
||||||
UPlotScaleBuilder {
|
UPlotScaleBuilder {
|
||||||
"props": Object {
|
"props": Object {
|
||||||
@@ -146,6 +160,135 @@ UPlotConfigBuilder {
|
|||||||
"thresholds": undefined,
|
"thresholds": undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
UPlotSeriesBuilder {
|
||||||
|
"props": Object {
|
||||||
|
"barAlignment": undefined,
|
||||||
|
"colorMode": Object {
|
||||||
|
"description": "Derive colors from thresholds",
|
||||||
|
"getCalculator": [Function],
|
||||||
|
"id": "thresholds",
|
||||||
|
"isByValue": true,
|
||||||
|
"name": "From thresholds",
|
||||||
|
},
|
||||||
|
"dataFrameFieldIndex": Object {
|
||||||
|
"fieldIndex": 2,
|
||||||
|
"frameIndex": 1,
|
||||||
|
},
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fieldName": "Metric 3",
|
||||||
|
"fillOpacity": 0.1,
|
||||||
|
"gradientMode": "opacity",
|
||||||
|
"hideInLegend": undefined,
|
||||||
|
"lineColor": "#ff0000",
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineStyle": Object {
|
||||||
|
"dash": Array [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
],
|
||||||
|
"fill": "dash",
|
||||||
|
},
|
||||||
|
"lineWidth": 2,
|
||||||
|
"pointColor": "#808080",
|
||||||
|
"pointSize": undefined,
|
||||||
|
"scaleKey": "__fixed",
|
||||||
|
"show": true,
|
||||||
|
"showPoints": "always",
|
||||||
|
"spanNulls": false,
|
||||||
|
"theme": Object {
|
||||||
|
"colors": Object {
|
||||||
|
"panelBg": "#000000",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"thresholds": undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UPlotSeriesBuilder {
|
||||||
|
"props": Object {
|
||||||
|
"barAlignment": -1,
|
||||||
|
"colorMode": Object {
|
||||||
|
"description": "Derive colors from thresholds",
|
||||||
|
"getCalculator": [Function],
|
||||||
|
"id": "thresholds",
|
||||||
|
"isByValue": true,
|
||||||
|
"name": "From thresholds",
|
||||||
|
},
|
||||||
|
"dataFrameFieldIndex": Object {
|
||||||
|
"fieldIndex": 3,
|
||||||
|
"frameIndex": 1,
|
||||||
|
},
|
||||||
|
"drawStyle": "bars",
|
||||||
|
"fieldName": "Metric 4",
|
||||||
|
"fillOpacity": 0.1,
|
||||||
|
"gradientMode": "hue",
|
||||||
|
"hideInLegend": undefined,
|
||||||
|
"lineColor": "#ff0000",
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineStyle": Object {
|
||||||
|
"dash": Array [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
],
|
||||||
|
"fill": "dash",
|
||||||
|
},
|
||||||
|
"lineWidth": 2,
|
||||||
|
"pointColor": "#808080",
|
||||||
|
"pointSize": undefined,
|
||||||
|
"scaleKey": "__fixed",
|
||||||
|
"show": true,
|
||||||
|
"showPoints": "always",
|
||||||
|
"spanNulls": false,
|
||||||
|
"theme": Object {
|
||||||
|
"colors": Object {
|
||||||
|
"panelBg": "#000000",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"thresholds": undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UPlotSeriesBuilder {
|
||||||
|
"props": Object {
|
||||||
|
"barAlignment": -1,
|
||||||
|
"colorMode": Object {
|
||||||
|
"description": "Derive colors from thresholds",
|
||||||
|
"getCalculator": [Function],
|
||||||
|
"id": "thresholds",
|
||||||
|
"isByValue": true,
|
||||||
|
"name": "From thresholds",
|
||||||
|
},
|
||||||
|
"dataFrameFieldIndex": Object {
|
||||||
|
"fieldIndex": 4,
|
||||||
|
"frameIndex": 1,
|
||||||
|
},
|
||||||
|
"drawStyle": "bars",
|
||||||
|
"fieldName": "Metric 4",
|
||||||
|
"fillOpacity": 0.1,
|
||||||
|
"gradientMode": "hue",
|
||||||
|
"hideInLegend": undefined,
|
||||||
|
"lineColor": "#ff0000",
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineStyle": Object {
|
||||||
|
"dash": Array [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
],
|
||||||
|
"fill": "dash",
|
||||||
|
},
|
||||||
|
"lineWidth": 2,
|
||||||
|
"pointColor": "#808080",
|
||||||
|
"pointSize": undefined,
|
||||||
|
"scaleKey": "__fixed",
|
||||||
|
"show": true,
|
||||||
|
"showPoints": "always",
|
||||||
|
"spanNulls": false,
|
||||||
|
"theme": Object {
|
||||||
|
"colors": Object {
|
||||||
|
"panelBg": "#000000",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"thresholds": undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
"tz": "UTC",
|
"tz": "UTC",
|
||||||
"tzDate": [Function],
|
"tzDate": [Function],
|
||||||
|
|||||||
@@ -37,5 +37,6 @@ export const useGraphNGContext = () => {
|
|||||||
dimFields,
|
dimFields,
|
||||||
mapSeriesIndexToDataFrameFieldIndex,
|
mapSeriesIndexToDataFrameFieldIndex,
|
||||||
getXAxisField,
|
getXAxisField,
|
||||||
|
alignedData: data,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,15 @@ import {
|
|||||||
GrafanaTheme,
|
GrafanaTheme,
|
||||||
MutableDataFrame,
|
MutableDataFrame,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { BarAlignment, DrawStyle, GraphFieldConfig, GraphGradientMode, LineInterpolation, PointVisibility } from '..';
|
import {
|
||||||
|
BarAlignment,
|
||||||
|
DrawStyle,
|
||||||
|
GraphFieldConfig,
|
||||||
|
GraphGradientMode,
|
||||||
|
LineInterpolation,
|
||||||
|
PointVisibility,
|
||||||
|
StackingMode,
|
||||||
|
} from '..';
|
||||||
|
|
||||||
function mockDataFrame() {
|
function mockDataFrame() {
|
||||||
const df1 = new MutableDataFrame({
|
const df1 = new MutableDataFrame({
|
||||||
@@ -38,6 +46,10 @@ function mockDataFrame() {
|
|||||||
fillColor: '#ff0000',
|
fillColor: '#ff0000',
|
||||||
fillOpacity: 0.1,
|
fillOpacity: 0.1,
|
||||||
showPoints: PointVisibility.Always,
|
showPoints: PointVisibility.Always,
|
||||||
|
stacking: {
|
||||||
|
group: 'A',
|
||||||
|
mode: StackingMode.Normal,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -58,6 +70,80 @@ function mockDataFrame() {
|
|||||||
fillColor: '#ff0000',
|
fillColor: '#ff0000',
|
||||||
fillOpacity: 0.1,
|
fillOpacity: 0.1,
|
||||||
showPoints: PointVisibility.Always,
|
showPoints: PointVisibility.Always,
|
||||||
|
stacking: {
|
||||||
|
group: 'A',
|
||||||
|
mode: StackingMode.Normal,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const f3Config: FieldConfig<GraphFieldConfig> = {
|
||||||
|
displayName: 'Metric 3',
|
||||||
|
decimals: 2,
|
||||||
|
custom: {
|
||||||
|
drawStyle: DrawStyle.Line,
|
||||||
|
gradientMode: GraphGradientMode.Opacity,
|
||||||
|
lineColor: '#ff0000',
|
||||||
|
lineWidth: 2,
|
||||||
|
lineInterpolation: LineInterpolation.Linear,
|
||||||
|
lineStyle: {
|
||||||
|
fill: 'dash',
|
||||||
|
dash: [1, 2],
|
||||||
|
},
|
||||||
|
spanNulls: false,
|
||||||
|
fillColor: '#ff0000',
|
||||||
|
fillOpacity: 0.1,
|
||||||
|
showPoints: PointVisibility.Always,
|
||||||
|
stacking: {
|
||||||
|
group: 'B',
|
||||||
|
mode: StackingMode.Normal,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const f4Config: FieldConfig<GraphFieldConfig> = {
|
||||||
|
displayName: 'Metric 4',
|
||||||
|
decimals: 2,
|
||||||
|
custom: {
|
||||||
|
drawStyle: DrawStyle.Bars,
|
||||||
|
gradientMode: GraphGradientMode.Hue,
|
||||||
|
lineColor: '#ff0000',
|
||||||
|
lineWidth: 2,
|
||||||
|
lineInterpolation: LineInterpolation.Linear,
|
||||||
|
lineStyle: {
|
||||||
|
fill: 'dash',
|
||||||
|
dash: [1, 2],
|
||||||
|
},
|
||||||
|
barAlignment: BarAlignment.Before,
|
||||||
|
fillColor: '#ff0000',
|
||||||
|
fillOpacity: 0.1,
|
||||||
|
showPoints: PointVisibility.Always,
|
||||||
|
stacking: {
|
||||||
|
group: 'B',
|
||||||
|
mode: StackingMode.Normal,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const f5Config: FieldConfig<GraphFieldConfig> = {
|
||||||
|
displayName: 'Metric 4',
|
||||||
|
decimals: 2,
|
||||||
|
custom: {
|
||||||
|
drawStyle: DrawStyle.Bars,
|
||||||
|
gradientMode: GraphGradientMode.Hue,
|
||||||
|
lineColor: '#ff0000',
|
||||||
|
lineWidth: 2,
|
||||||
|
lineInterpolation: LineInterpolation.Linear,
|
||||||
|
lineStyle: {
|
||||||
|
fill: 'dash',
|
||||||
|
dash: [1, 2],
|
||||||
|
},
|
||||||
|
barAlignment: BarAlignment.Before,
|
||||||
|
fillColor: '#ff0000',
|
||||||
|
fillOpacity: 0.1,
|
||||||
|
showPoints: PointVisibility.Always,
|
||||||
|
stacking: {
|
||||||
|
group: 'B',
|
||||||
|
mode: StackingMode.None,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -72,6 +158,21 @@ function mockDataFrame() {
|
|||||||
type: FieldType.number,
|
type: FieldType.number,
|
||||||
config: f2Config,
|
config: f2Config,
|
||||||
});
|
});
|
||||||
|
df2.addField({
|
||||||
|
name: 'metric3',
|
||||||
|
type: FieldType.number,
|
||||||
|
config: f3Config,
|
||||||
|
});
|
||||||
|
df2.addField({
|
||||||
|
name: 'metric4',
|
||||||
|
type: FieldType.number,
|
||||||
|
config: f4Config,
|
||||||
|
});
|
||||||
|
df2.addField({
|
||||||
|
name: 'metric5',
|
||||||
|
type: FieldType.number,
|
||||||
|
config: f5Config,
|
||||||
|
});
|
||||||
|
|
||||||
return preparePlotFrame([df1, df2], {
|
return preparePlotFrame([df1, df2], {
|
||||||
x: fieldMatchers.get(FieldMatcherID.firstTimeField).get({}),
|
x: fieldMatchers.get(FieldMatcherID.firstTimeField).get({}),
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
ScaleDirection,
|
ScaleDirection,
|
||||||
ScaleOrientation,
|
ScaleOrientation,
|
||||||
} from '../uPlot/config';
|
} from '../uPlot/config';
|
||||||
|
import { collectStackingGroups } from '../uPlot/utils';
|
||||||
|
|
||||||
const defaultFormatter = (v: any) => (v == null ? '-' : v.toFixed(1));
|
const defaultFormatter = (v: any) => (v == null ? '-' : v.toFixed(1));
|
||||||
|
|
||||||
@@ -130,6 +131,8 @@ export function preparePlotConfigBuilder(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stackingGroups: Map<string, number[]> = new Map();
|
||||||
|
|
||||||
let indexByName: Map<string, number> | undefined = undefined;
|
let indexByName: Map<string, number> | undefined = undefined;
|
||||||
|
|
||||||
for (let i = 0; i < frame.fields.length; i++) {
|
for (let i = 0; i < frame.fields.length; i++) {
|
||||||
@@ -178,6 +181,7 @@ export function preparePlotConfigBuilder(
|
|||||||
const showPoints = customConfig.drawStyle === DrawStyle.Points ? PointVisibility.Always : customConfig.showPoints;
|
const showPoints = customConfig.drawStyle === DrawStyle.Points ? PointVisibility.Always : customConfig.showPoints;
|
||||||
|
|
||||||
let { fillOpacity } = customConfig;
|
let { fillOpacity } = customConfig;
|
||||||
|
|
||||||
if (customConfig.fillBelowTo) {
|
if (customConfig.fillBelowTo) {
|
||||||
if (!indexByName) {
|
if (!indexByName) {
|
||||||
indexByName = getNamesToFieldIndex(frame);
|
indexByName = getNamesToFieldIndex(frame);
|
||||||
@@ -219,8 +223,20 @@ export function preparePlotConfigBuilder(
|
|||||||
fieldName: getFieldDisplayName(field, frame),
|
fieldName: getFieldDisplayName(field, frame),
|
||||||
hideInLegend: customConfig.hideFrom?.legend,
|
hideInLegend: customConfig.hideFrom?.legend,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
collectStackingGroups(field, stackingGroups, seriesIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stackingGroups.size !== 0) {
|
||||||
|
builder.setStacking(true);
|
||||||
|
for (const [_, seriesIdxs] of stackingGroups.entries()) {
|
||||||
|
for (let j = seriesIdxs.length - 1; j > 0; j--) {
|
||||||
|
builder.addBand({
|
||||||
|
series: [seriesIdxs[j], seriesIdxs[j - 1]],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -176,7 +176,6 @@ export class Sparkline extends PureComponent<SparklineProps, State> {
|
|||||||
render() {
|
render() {
|
||||||
const { data, configBuilder } = this.state;
|
const { data, configBuilder } = this.state;
|
||||||
const { width, height, sparkline } = this.props;
|
const { width, height, sparkline } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UPlotChart data={data} config={configBuilder} width={width} height={height} timeRange={sparkline.timeRange!} />
|
<UPlotChart data={data} config={configBuilder} width={width} height={height} timeRange={sparkline.timeRange!} />
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ export { GraphNG, FIXED_UNIT } from './GraphNG/GraphNG';
|
|||||||
export { useGraphNGContext } from './GraphNG/hooks';
|
export { useGraphNGContext } from './GraphNG/hooks';
|
||||||
export { BarChart } from './BarChart/BarChart';
|
export { BarChart } from './BarChart/BarChart';
|
||||||
export { TimelineChart } from './Timeline/TimelineChart';
|
export { TimelineChart } from './Timeline/TimelineChart';
|
||||||
export { BarChartOptions, BarStackingMode, BarValueVisibility, BarChartFieldConfig } from './BarChart/types';
|
export { BarChartOptions, BarValueVisibility, BarChartFieldConfig } from './BarChart/types';
|
||||||
export { TimelineOptions, TimelineFieldConfig } from './Timeline/types';
|
export { TimelineOptions, TimelineFieldConfig } from './Timeline/types';
|
||||||
export { GraphNGLegendEvent, GraphNGLegendEventMode } from './GraphNG/types';
|
export { GraphNGLegendEvent, GraphNGLegendEventMode } from './GraphNG/types';
|
||||||
export * from './NodeGraph';
|
export * from './NodeGraph';
|
||||||
|
|||||||
@@ -133,7 +133,6 @@ describe('UPlotChart', () => {
|
|||||||
describe('config update', () => {
|
describe('config update', () => {
|
||||||
it('skips uPlot intialization for width and height equal 0', async () => {
|
it('skips uPlot intialization for width and height equal 0', async () => {
|
||||||
const { data, timeRange, config } = mockData();
|
const { data, timeRange, config } = mockData();
|
||||||
|
|
||||||
const { queryAllByTestId } = render(
|
const { queryAllByTestId } = render(
|
||||||
<UPlotChart data={preparePlotData(data)} config={config} timeRange={timeRange} width={0} height={0} />
|
<UPlotChart data={preparePlotData(data)} config={config} timeRange={timeRange} width={0} height={0} />
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -175,6 +175,23 @@ export interface HideableFieldConfig {
|
|||||||
hideFrom?: HideSeriesConfig;
|
hideFrom?: HideSeriesConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @alpha
|
||||||
|
*/
|
||||||
|
export enum StackingMode {
|
||||||
|
None = 'none',
|
||||||
|
Normal = 'normal',
|
||||||
|
Percent = 'percent',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @alpha
|
||||||
|
*/
|
||||||
|
export interface StackingConfig {
|
||||||
|
mode?: StackingMode;
|
||||||
|
group?: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @alpha
|
* @alpha
|
||||||
*/
|
*/
|
||||||
@@ -187,6 +204,7 @@ export interface GraphFieldConfig
|
|||||||
HideableFieldConfig {
|
HideableFieldConfig {
|
||||||
drawStyle?: DrawStyle;
|
drawStyle?: DrawStyle;
|
||||||
gradientMode?: GraphGradientMode;
|
gradientMode?: GraphGradientMode;
|
||||||
|
stacking?: StackingConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -231,4 +249,9 @@ export const graphFieldOptions = {
|
|||||||
{ label: 'Hue', value: GraphGradientMode.Hue },
|
{ label: 'Hue', value: GraphGradientMode.Hue },
|
||||||
// { label: 'Color scheme', value: GraphGradientMode.Scheme },
|
// { label: 'Color scheme', value: GraphGradientMode.Scheme },
|
||||||
] as Array<SelectableValue<GraphGradientMode>>,
|
] as Array<SelectableValue<GraphGradientMode>>,
|
||||||
|
|
||||||
|
stacking: [
|
||||||
|
{ label: 'Off', value: StackingMode.None },
|
||||||
|
{ label: 'Normal', value: StackingMode.Normal },
|
||||||
|
] as Array<SelectableValue<StackingMode>>,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -350,7 +350,7 @@ describe('UPlotConfigBuilder', () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Handles auto axis placement', () => {
|
it('handles auto axis placement', () => {
|
||||||
const builder = new UPlotConfigBuilder();
|
const builder = new UPlotConfigBuilder();
|
||||||
|
|
||||||
builder.addAxis({
|
builder.addAxis({
|
||||||
@@ -370,7 +370,7 @@ describe('UPlotConfigBuilder', () => {
|
|||||||
expect(builder.getConfig().axes![1].grid!.show).toBe(false);
|
expect(builder.getConfig().axes![1].grid!.show).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('When fillColor is not set fill', () => {
|
it('when fillColor is not set fill', () => {
|
||||||
const builder = new UPlotConfigBuilder();
|
const builder = new UPlotConfigBuilder();
|
||||||
builder.addSeries({
|
builder.addSeries({
|
||||||
drawStyle: DrawStyle.Line,
|
drawStyle: DrawStyle.Line,
|
||||||
@@ -383,7 +383,7 @@ describe('UPlotConfigBuilder', () => {
|
|||||||
expect(builder.getConfig().series[1].fill).toBe(undefined);
|
expect(builder.getConfig().series[1].fill).toBe(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('When fillOpacity is set', () => {
|
it('when fillOpacity is set', () => {
|
||||||
const builder = new UPlotConfigBuilder();
|
const builder = new UPlotConfigBuilder();
|
||||||
builder.addSeries({
|
builder.addSeries({
|
||||||
drawStyle: DrawStyle.Line,
|
drawStyle: DrawStyle.Line,
|
||||||
@@ -397,7 +397,7 @@ describe('UPlotConfigBuilder', () => {
|
|||||||
expect(builder.getConfig().series[1].fill).toBe('rgba(255, 170, 187, 0.5)');
|
expect(builder.getConfig().series[1].fill).toBe('rgba(255, 170, 187, 0.5)');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('When fillColor is set ignore fillOpacity', () => {
|
it('when fillColor is set ignore fillOpacity', () => {
|
||||||
const builder = new UPlotConfigBuilder();
|
const builder = new UPlotConfigBuilder();
|
||||||
builder.addSeries({
|
builder.addSeries({
|
||||||
drawStyle: DrawStyle.Line,
|
drawStyle: DrawStyle.Line,
|
||||||
@@ -412,7 +412,7 @@ describe('UPlotConfigBuilder', () => {
|
|||||||
expect(builder.getConfig().series[1].fill).toBe('#FF0000');
|
expect(builder.getConfig().series[1].fill).toBe('#FF0000');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('When fillGradient mode is opacity', () => {
|
it('when fillGradient mode is opacity', () => {
|
||||||
const builder = new UPlotConfigBuilder();
|
const builder = new UPlotConfigBuilder();
|
||||||
builder.addSeries({
|
builder.addSeries({
|
||||||
drawStyle: DrawStyle.Line,
|
drawStyle: DrawStyle.Line,
|
||||||
@@ -486,4 +486,147 @@ describe('UPlotConfigBuilder', () => {
|
|||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Stacking', () => {
|
||||||
|
it('allows stacking config', () => {
|
||||||
|
const builder = new UPlotConfigBuilder();
|
||||||
|
builder.setStacking();
|
||||||
|
builder.addSeries({
|
||||||
|
drawStyle: DrawStyle.Line,
|
||||||
|
scaleKey: 'scale-x',
|
||||||
|
fieldName: 'A-series',
|
||||||
|
fillOpacity: 50,
|
||||||
|
gradientMode: GraphGradientMode.Opacity,
|
||||||
|
showPoints: PointVisibility.Auto,
|
||||||
|
lineColor: '#0000ff',
|
||||||
|
lineWidth: 1,
|
||||||
|
spanNulls: false,
|
||||||
|
theme: darkTheme,
|
||||||
|
});
|
||||||
|
builder.addSeries({
|
||||||
|
drawStyle: DrawStyle.Line,
|
||||||
|
scaleKey: 'scale-x',
|
||||||
|
fieldName: 'B-series',
|
||||||
|
fillOpacity: 50,
|
||||||
|
gradientMode: GraphGradientMode.Opacity,
|
||||||
|
showPoints: PointVisibility.Auto,
|
||||||
|
pointSize: 5,
|
||||||
|
lineColor: '#00ff00',
|
||||||
|
lineWidth: 1,
|
||||||
|
spanNulls: false,
|
||||||
|
theme: darkTheme,
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.addSeries({
|
||||||
|
drawStyle: DrawStyle.Line,
|
||||||
|
scaleKey: 'scale-x',
|
||||||
|
fieldName: 'C-series',
|
||||||
|
fillOpacity: 50,
|
||||||
|
gradientMode: GraphGradientMode.Opacity,
|
||||||
|
showPoints: PointVisibility.Auto,
|
||||||
|
pointSize: 5,
|
||||||
|
lineColor: '#ff0000',
|
||||||
|
lineWidth: 1,
|
||||||
|
spanNulls: false,
|
||||||
|
theme: darkTheme,
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.addBand({
|
||||||
|
series: [3, 2],
|
||||||
|
fill: 'red',
|
||||||
|
});
|
||||||
|
builder.addBand({
|
||||||
|
series: [2, 1],
|
||||||
|
fill: 'blue',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(builder.getConfig()).toMatchInlineSnapshot(`
|
||||||
|
Object {
|
||||||
|
"axes": Array [],
|
||||||
|
"bands": Array [
|
||||||
|
Object {
|
||||||
|
"fill": "red",
|
||||||
|
"series": Array [
|
||||||
|
3,
|
||||||
|
2,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"fill": "blue",
|
||||||
|
"series": Array [
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"cursor": Object {
|
||||||
|
"drag": Object {
|
||||||
|
"setScale": false,
|
||||||
|
},
|
||||||
|
"focus": Object {
|
||||||
|
"prox": 30,
|
||||||
|
},
|
||||||
|
"points": Object {
|
||||||
|
"fill": [Function],
|
||||||
|
"size": [Function],
|
||||||
|
"stroke": [Function],
|
||||||
|
"width": [Function],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"hooks": Object {},
|
||||||
|
"scales": Object {},
|
||||||
|
"select": undefined,
|
||||||
|
"series": Array [
|
||||||
|
Object {},
|
||||||
|
Object {
|
||||||
|
"fill": [Function],
|
||||||
|
"paths": [Function],
|
||||||
|
"points": Object {
|
||||||
|
"fill": undefined,
|
||||||
|
"size": undefined,
|
||||||
|
"stroke": undefined,
|
||||||
|
},
|
||||||
|
"pxAlign": undefined,
|
||||||
|
"scale": "scale-x",
|
||||||
|
"show": true,
|
||||||
|
"spanGaps": false,
|
||||||
|
"stroke": "#0000ff",
|
||||||
|
"width": 1,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"fill": [Function],
|
||||||
|
"paths": [Function],
|
||||||
|
"points": Object {
|
||||||
|
"fill": undefined,
|
||||||
|
"size": 5,
|
||||||
|
"stroke": undefined,
|
||||||
|
},
|
||||||
|
"pxAlign": undefined,
|
||||||
|
"scale": "scale-x",
|
||||||
|
"show": true,
|
||||||
|
"spanGaps": false,
|
||||||
|
"stroke": "#00ff00",
|
||||||
|
"width": 1,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"fill": [Function],
|
||||||
|
"paths": [Function],
|
||||||
|
"points": Object {
|
||||||
|
"fill": undefined,
|
||||||
|
"size": 5,
|
||||||
|
"stroke": undefined,
|
||||||
|
},
|
||||||
|
"pxAlign": undefined,
|
||||||
|
"scale": "scale-x",
|
||||||
|
"show": true,
|
||||||
|
"spanGaps": false,
|
||||||
|
"stroke": "#ff0000",
|
||||||
|
"width": 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"tzDate": [Function],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export class UPlotConfigBuilder {
|
|||||||
private scales: UPlotScaleBuilder[] = [];
|
private scales: UPlotScaleBuilder[] = [];
|
||||||
private bands: Band[] = [];
|
private bands: Band[] = [];
|
||||||
private cursor: Cursor | undefined;
|
private cursor: Cursor | undefined;
|
||||||
|
private isStacking = false;
|
||||||
// uPlot types don't export the Select interface prior to 1.6.4
|
// uPlot types don't export the Select interface prior to 1.6.4
|
||||||
private select: Partial<BBox> | undefined;
|
private select: Partial<BBox> | undefined;
|
||||||
private hasLeftAxis = false;
|
private hasLeftAxis = false;
|
||||||
@@ -78,6 +79,9 @@ export class UPlotConfigBuilder {
|
|||||||
this.select = select;
|
this.select = select;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setStacking(enabled = true) {
|
||||||
|
this.isStacking = enabled;
|
||||||
|
}
|
||||||
addSeries(props: SeriesProps) {
|
addSeries(props: SeriesProps) {
|
||||||
this.series.push(new UPlotSeriesBuilder(props));
|
this.series.push(new UPlotSeriesBuilder(props));
|
||||||
}
|
}
|
||||||
@@ -118,16 +122,22 @@ export class UPlotConfigBuilder {
|
|||||||
|
|
||||||
config.tzDate = this.tzDate;
|
config.tzDate = this.tzDate;
|
||||||
|
|
||||||
// When bands exist, only keep fill when defined
|
if (this.isStacking) {
|
||||||
if (this.bands?.length) {
|
// Let uPlot handle bands and fills
|
||||||
config.bands = this.bands;
|
config.bands = this.bands;
|
||||||
const keepFill = new Set<number>();
|
} else {
|
||||||
for (const b of config.bands) {
|
// When fillBelowTo option enabled, handle series bands fill manually
|
||||||
keepFill.add(b.series[0]);
|
if (this.bands?.length) {
|
||||||
}
|
config.bands = this.bands;
|
||||||
for (let i = 1; i < config.series.length; i++) {
|
const keepFill = new Set<number>();
|
||||||
if (!keepFill.has(i)) {
|
for (const b of config.bands) {
|
||||||
config.series[i].fill = undefined;
|
keepFill.add(b.series[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 1; i < config.series.length; i++) {
|
||||||
|
if (!keepFill.has(i)) {
|
||||||
|
config.series[i].fill = undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,10 +58,11 @@ export const TooltipPlugin: React.FC<TooltipPluginProps> = ({ mode = 'single', t
|
|||||||
|
|
||||||
// when interacting with a point in single mode
|
// when interacting with a point in single mode
|
||||||
if (mode === 'single' && originFieldIndex !== null) {
|
if (mode === 'single' && originFieldIndex !== null) {
|
||||||
const field = otherProps.data[originFieldIndex.frameIndex].fields[originFieldIndex.fieldIndex];
|
const field = graphContext.alignedData.fields[focusedSeriesIdx!];
|
||||||
const plotSeries = plotContext.getSeries();
|
const plotSeries = plotContext.getSeries();
|
||||||
const fieldFmt = field.display || getDisplayProcessor({ field, timeZone });
|
const fieldFmt = field.display || getDisplayProcessor({ field, timeZone });
|
||||||
const value = fieldFmt(plotContext.data[focusedSeriesIdx!][focusedPointIdx]);
|
|
||||||
|
const value = fieldFmt(field.values.get(focusedPointIdx));
|
||||||
|
|
||||||
tooltip = (
|
tooltip = (
|
||||||
<SeriesTable
|
<SeriesTable
|
||||||
@@ -95,7 +96,9 @@ export const TooltipPlugin: React.FC<TooltipPluginProps> = ({ mode = 'single', t
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const value = field.display!(plotContext.data[i][focusedPointIdx]);
|
// using aligned data value field here as it's indexes are in line with Plot data
|
||||||
|
const valueField = graphContext.alignedData.fields[i];
|
||||||
|
const value = valueField.display!(valueField.values.get(focusedPointIdx));
|
||||||
|
|
||||||
series.push({
|
series.push({
|
||||||
// TODO: align with uPlot typings
|
// TODO: align with uPlot typings
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { timeFormatToTemplate } from './utils';
|
import { preparePlotData, timeFormatToTemplate } from './utils';
|
||||||
|
import { FieldType, MutableDataFrame } from '@grafana/data';
|
||||||
|
import { StackingMode } from './config';
|
||||||
|
|
||||||
describe('timeFormatToTemplate', () => {
|
describe('timeFormatToTemplate', () => {
|
||||||
it.each`
|
it.each`
|
||||||
@@ -13,3 +15,285 @@ describe('timeFormatToTemplate', () => {
|
|||||||
expect(timeFormatToTemplate(format)).toEqual(expected);
|
expect(timeFormatToTemplate(format)).toEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('preparePlotData', () => {
|
||||||
|
const df = new MutableDataFrame({
|
||||||
|
fields: [
|
||||||
|
{ name: 'time', type: FieldType.time, values: [9997, 9998, 9999] },
|
||||||
|
{ name: 'a', values: [-10, 20, 10] },
|
||||||
|
{ name: 'b', values: [10, 10, 10] },
|
||||||
|
{ name: 'c', values: [20, 20, 20] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates array from DataFrame', () => {
|
||||||
|
expect(preparePlotData(df)).toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
Array [
|
||||||
|
9997,
|
||||||
|
9998,
|
||||||
|
9999,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
-10,
|
||||||
|
20,
|
||||||
|
10,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
20,
|
||||||
|
20,
|
||||||
|
20,
|
||||||
|
],
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('stacking', () => {
|
||||||
|
it('none', () => {
|
||||||
|
const df = new MutableDataFrame({
|
||||||
|
fields: [
|
||||||
|
{ name: 'time', type: FieldType.time, values: [9997, 9998, 9999] },
|
||||||
|
{
|
||||||
|
name: 'a',
|
||||||
|
values: [-10, 20, 10],
|
||||||
|
config: { custom: { stacking: { mode: StackingMode.None } } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'b',
|
||||||
|
values: [10, 10, 10],
|
||||||
|
config: { custom: { stacking: { mode: StackingMode.None } } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'c',
|
||||||
|
values: [20, 20, 20],
|
||||||
|
config: { custom: { stacking: { mode: StackingMode.None } } },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
expect(preparePlotData(df)).toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
Array [
|
||||||
|
9997,
|
||||||
|
9998,
|
||||||
|
9999,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
-10,
|
||||||
|
20,
|
||||||
|
10,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
20,
|
||||||
|
20,
|
||||||
|
20,
|
||||||
|
],
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('standard', () => {
|
||||||
|
const df = new MutableDataFrame({
|
||||||
|
fields: [
|
||||||
|
{ name: 'time', type: FieldType.time, values: [9997, 9998, 9999] },
|
||||||
|
{
|
||||||
|
name: 'a',
|
||||||
|
values: [-10, 20, 10],
|
||||||
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'b',
|
||||||
|
values: [10, 10, 10],
|
||||||
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'c',
|
||||||
|
values: [20, 20, 20],
|
||||||
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
expect(preparePlotData(df)).toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
Array [
|
||||||
|
9997,
|
||||||
|
9998,
|
||||||
|
9999,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
-10,
|
||||||
|
20,
|
||||||
|
10,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
0,
|
||||||
|
30,
|
||||||
|
20,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
20,
|
||||||
|
50,
|
||||||
|
40,
|
||||||
|
],
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('standard with multiple groups', () => {
|
||||||
|
const df = new MutableDataFrame({
|
||||||
|
fields: [
|
||||||
|
{ name: 'time', type: FieldType.time, values: [9997, 9998, 9999] },
|
||||||
|
{
|
||||||
|
name: 'a',
|
||||||
|
values: [-10, 20, 10],
|
||||||
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'b',
|
||||||
|
values: [10, 10, 10],
|
||||||
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'c',
|
||||||
|
values: [20, 20, 20],
|
||||||
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'd',
|
||||||
|
values: [1, 2, 3],
|
||||||
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackB' } } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'e',
|
||||||
|
values: [1, 2, 3],
|
||||||
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackB' } } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'f',
|
||||||
|
values: [1, 2, 3],
|
||||||
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackB' } } },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(preparePlotData(df)).toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
Array [
|
||||||
|
9997,
|
||||||
|
9998,
|
||||||
|
9999,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
-10,
|
||||||
|
20,
|
||||||
|
10,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
0,
|
||||||
|
30,
|
||||||
|
20,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
20,
|
||||||
|
50,
|
||||||
|
40,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
6,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
3,
|
||||||
|
6,
|
||||||
|
9,
|
||||||
|
],
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('standard with multiple groups and hidden fields', () => {
|
||||||
|
const df = new MutableDataFrame({
|
||||||
|
fields: [
|
||||||
|
{ name: 'time', type: FieldType.time, values: [9997, 9998, 9999] },
|
||||||
|
{
|
||||||
|
name: 'a',
|
||||||
|
values: [-10, 20, 10],
|
||||||
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' }, hideFrom: { graph: true } } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Will ignore a series as stacking base as it's hidden from graph
|
||||||
|
name: 'b',
|
||||||
|
values: [10, 10, 10],
|
||||||
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'd',
|
||||||
|
values: [1, 2, 3],
|
||||||
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackB' } } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'e',
|
||||||
|
values: [1, 2, 3],
|
||||||
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackB' }, hideFrom: { graph: true } } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Will ignore e series as stacking base as it's hidden from graph
|
||||||
|
name: 'f',
|
||||||
|
values: [1, 2, 3],
|
||||||
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackB' } } },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(preparePlotData(df)).toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
Array [
|
||||||
|
9997,
|
||||||
|
9998,
|
||||||
|
9999,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
-10,
|
||||||
|
20,
|
||||||
|
10,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
],
|
||||||
|
Array [
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
6,
|
||||||
|
],
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { DataFrame, dateTime, FieldType } from '@grafana/data';
|
import { DataFrame, dateTime, Field, FieldType } from '@grafana/data';
|
||||||
import { AlignedData, Options } from 'uplot';
|
import { AlignedData, Options } from 'uplot';
|
||||||
import { PlotPlugin, PlotProps } from './types';
|
import { PlotPlugin, PlotProps } from './types';
|
||||||
|
import { StackingMode } from './config';
|
||||||
import { createLogger } from '../../utils/logger';
|
import { createLogger } from '../../utils/logger';
|
||||||
import { attachDebugger } from '../../utils';
|
import { attachDebugger } from '../../utils';
|
||||||
|
|
||||||
@@ -33,8 +34,11 @@ export function buildPlotConfig(props: PlotProps, plugins: Record<string, PlotPl
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
|
|
||||||
export function preparePlotData(frame: DataFrame, ignoreFieldTypes?: FieldType[]): AlignedData {
|
export function preparePlotData(frame: DataFrame, ignoreFieldTypes?: FieldType[]): AlignedData {
|
||||||
const result: any[] = [];
|
const result: any[] = [];
|
||||||
|
const stackingGroups: Map<string, number[]> = new Map();
|
||||||
|
let seriesIndex = 0;
|
||||||
|
|
||||||
for (let i = 0; i < frame.fields.length; i++) {
|
for (let i = 0; i < frame.fields.length; i++) {
|
||||||
const f = frame.fields[i];
|
const f = frame.fields[i];
|
||||||
@@ -46,20 +50,59 @@ export function preparePlotData(frame: DataFrame, ignoreFieldTypes?: FieldType[]
|
|||||||
timestamps.push(dateTime(f.values.get(i)).valueOf());
|
timestamps.push(dateTime(f.values.get(i)).valueOf());
|
||||||
}
|
}
|
||||||
result.push(timestamps);
|
result.push(timestamps);
|
||||||
|
seriesIndex++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
result.push(f.values.toArray());
|
result.push(f.values.toArray());
|
||||||
|
seriesIndex++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ignoreFieldTypes && ignoreFieldTypes.indexOf(f.type) > -1) {
|
if (ignoreFieldTypes && ignoreFieldTypes.indexOf(f.type) > -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
collectStackingGroups(f, stackingGroups, seriesIndex);
|
||||||
result.push(f.values.toArray());
|
result.push(f.values.toArray());
|
||||||
|
seriesIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stacking
|
||||||
|
if (stackingGroups.size !== 0) {
|
||||||
|
// array or stacking groups
|
||||||
|
for (const [_, seriesIdxs] of stackingGroups.entries()) {
|
||||||
|
const acc = Array(result[0].length).fill(0);
|
||||||
|
for (let j = 0; j < seriesIdxs.length; j++) {
|
||||||
|
const currentlyStacking = result[seriesIdxs[j]];
|
||||||
|
for (let k = 0; k < result[0].length; k++) {
|
||||||
|
const v = currentlyStacking[k];
|
||||||
|
acc[k] += v === null || v === undefined ? 0 : +v;
|
||||||
|
}
|
||||||
|
result[seriesIdxs[j]] = acc.slice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result as AlignedData;
|
||||||
}
|
}
|
||||||
return result as AlignedData;
|
return result as AlignedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function collectStackingGroups(f: Field, groups: Map<string, number[]>, seriesIdx: number) {
|
||||||
|
const customConfig = f.config.custom;
|
||||||
|
if (!customConfig) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
customConfig.stacking?.mode !== StackingMode.None &&
|
||||||
|
customConfig.stacking?.group &&
|
||||||
|
!customConfig.hideFrom?.graph
|
||||||
|
) {
|
||||||
|
if (!groups.has(customConfig.stacking.group)) {
|
||||||
|
groups.set(customConfig.stacking.group, [seriesIdx]);
|
||||||
|
} else {
|
||||||
|
groups.set(customConfig.stacking.group, groups.get(customConfig.stacking.group)!.concat(seriesIdx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Dev helpers
|
// Dev helpers
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
isSystemOverride as isSystemOverrideGuard,
|
isSystemOverride as isSystemOverrideGuard,
|
||||||
VariableSuggestionsScope,
|
VariableSuggestionsScope,
|
||||||
DynamicConfigValue,
|
DynamicConfigValue,
|
||||||
|
ConfigOverrideRule,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { Container, fieldMatchersUI, ValuePicker } from '@grafana/ui';
|
import { Container, fieldMatchersUI, ValuePicker } from '@grafana/ui';
|
||||||
import { OptionPaneRenderProps } from './types';
|
import { OptionPaneRenderProps } from './types';
|
||||||
@@ -51,6 +52,7 @@ export function getFieldOverrideCategories(props: OptionPaneRenderProps): Option
|
|||||||
const context = {
|
const context = {
|
||||||
data,
|
data,
|
||||||
getSuggestions: (scope?: VariableSuggestionsScope) => getDataLinksVariableSuggestions(data, scope),
|
getSuggestions: (scope?: VariableSuggestionsScope) => getDataLinksVariableSuggestions(data, scope),
|
||||||
|
isOverride: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,7 +90,7 @@ export function getFieldOverrideCategories(props: OptionPaneRenderProps): Option
|
|||||||
onOverrideChange(idx, override);
|
onOverrideChange(idx, override);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDynamicConfigValueAdd = (value: SelectableValue<string>) => {
|
const onDynamicConfigValueAdd = (o: ConfigOverrideRule, value: SelectableValue<string>) => {
|
||||||
const registryItem = registry.get(value.value!);
|
const registryItem = registry.get(value.value!);
|
||||||
const propertyConfig: DynamicConfigValue = {
|
const propertyConfig: DynamicConfigValue = {
|
||||||
id: registryItem.id,
|
id: registryItem.id,
|
||||||
@@ -96,12 +98,12 @@ export function getFieldOverrideCategories(props: OptionPaneRenderProps): Option
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (override.properties) {
|
if (override.properties) {
|
||||||
override.properties.push(propertyConfig);
|
o.properties.push(propertyConfig);
|
||||||
} else {
|
} else {
|
||||||
override.properties = [propertyConfig];
|
o.properties = [propertyConfig];
|
||||||
}
|
}
|
||||||
|
|
||||||
onOverrideChange(idx, override);
|
onOverrideChange(idx, o);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -185,7 +187,7 @@ export function getFieldOverrideCategories(props: OptionPaneRenderProps): Option
|
|||||||
icon="plus"
|
icon="plus"
|
||||||
menuPlacement="auto"
|
menuPlacement="auto"
|
||||||
options={configPropertiesOptions}
|
options={configPropertiesOptions}
|
||||||
onChange={onDynamicConfigValueAdd}
|
onChange={(v) => onDynamicConfigValueAdd(override, v)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -241,8 +243,8 @@ function getOverrideProperties(registry: FieldConfigOptionsRegistry) {
|
|||||||
.filter((o) => !o.hideFromOverrides)
|
.filter((o) => !o.hideFromOverrides)
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
let label = item.name;
|
let label = item.name;
|
||||||
if (item.category && item.category.length > 1) {
|
if (item.category) {
|
||||||
label = [...item.category!.slice(1), item.name].join(' > ');
|
label = [...item.category, item.name].join(' > ');
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
label,
|
label,
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export const TestStuffPage: FC = () => {
|
|||||||
timeRange={data.timeRange}
|
timeRange={data.timeRange}
|
||||||
timeZone="browser"
|
timeZone="browser"
|
||||||
/>
|
/>
|
||||||
<hr></hr>
|
<hr />
|
||||||
<Table data={data.series[0]} width={1200} height={300} />
|
<Table data={data.series[0]} width={1200} height={300} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -7,13 +7,7 @@ import {
|
|||||||
VizOrientation,
|
VizOrientation,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { BarChartPanel } from './BarChartPanel';
|
import { BarChartPanel } from './BarChartPanel';
|
||||||
import {
|
import { BarChartFieldConfig, BarChartOptions, StackingMode, BarValueVisibility, graphFieldOptions } from '@grafana/ui';
|
||||||
BarChartFieldConfig,
|
|
||||||
BarChartOptions,
|
|
||||||
BarStackingMode,
|
|
||||||
BarValueVisibility,
|
|
||||||
graphFieldOptions,
|
|
||||||
} from '@grafana/ui';
|
|
||||||
import { addAxisConfig, addHideFrom, addLegendOptions } from '../timeseries/config';
|
import { addAxisConfig, addHideFrom, addLegendOptions } from '../timeseries/config';
|
||||||
import { defaultBarChartFieldConfig } from '@grafana/ui/src/components/BarChart/types';
|
import { defaultBarChartFieldConfig } from '@grafana/ui/src/components/BarChart/types';
|
||||||
|
|
||||||
@@ -80,19 +74,6 @@ export const plugin = new PanelPlugin<BarChartOptions, BarChartFieldConfig>(BarC
|
|||||||
},
|
},
|
||||||
defaultValue: VizOrientation.Auto,
|
defaultValue: VizOrientation.Auto,
|
||||||
})
|
})
|
||||||
.addRadio({
|
|
||||||
path: 'stacking',
|
|
||||||
name: 'Stacking',
|
|
||||||
settings: {
|
|
||||||
options: [
|
|
||||||
{ value: BarStackingMode.None, label: 'None' },
|
|
||||||
{ value: BarStackingMode.Standard, label: 'Standard' },
|
|
||||||
{ value: BarStackingMode.Percent, label: 'Percent' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
defaultValue: BarStackingMode.None,
|
|
||||||
showIf: () => false, // <<< Hide from the UI for now
|
|
||||||
})
|
|
||||||
.addRadio({
|
.addRadio({
|
||||||
path: 'showValue',
|
path: 'showValue',
|
||||||
name: 'Show values',
|
name: 'Show values',
|
||||||
@@ -115,7 +96,7 @@ export const plugin = new PanelPlugin<BarChartOptions, BarChartFieldConfig>(BarC
|
|||||||
step: 0.01,
|
step: 0.01,
|
||||||
},
|
},
|
||||||
showIf: (c, data) => {
|
showIf: (c, data) => {
|
||||||
if (c.stacking && c.stacking !== BarStackingMode.None) {
|
if (c.stacking && c.stacking !== StackingMode.None) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return countNumberFields(data) !== 1;
|
return countNumberFields(data) !== 1;
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { FieldOverrideEditorProps } from '@grafana/data';
|
||||||
|
import {
|
||||||
|
HorizontalGroup,
|
||||||
|
IconButton,
|
||||||
|
Input,
|
||||||
|
RadioButtonGroup,
|
||||||
|
StackingConfig,
|
||||||
|
StackingMode,
|
||||||
|
Tooltip,
|
||||||
|
} from '@grafana/ui';
|
||||||
|
|
||||||
|
export const StackingEditor: React.FC<FieldOverrideEditorProps<StackingConfig, any>> = ({
|
||||||
|
value,
|
||||||
|
context,
|
||||||
|
onChange,
|
||||||
|
item,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<HorizontalGroup>
|
||||||
|
<RadioButtonGroup
|
||||||
|
value={value?.mode || StackingMode.None}
|
||||||
|
options={item.settings.options}
|
||||||
|
onChange={(v) => {
|
||||||
|
onChange({
|
||||||
|
...value,
|
||||||
|
mode: v,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{context.isOverride && value?.mode && value?.mode !== StackingMode.None && (
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
placeholder="Group"
|
||||||
|
suffix={
|
||||||
|
<Tooltip content="Name of the stacking group" placement="top">
|
||||||
|
<IconButton name="question-circle" />
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
defaultValue={value?.group}
|
||||||
|
onChange={(v) => {
|
||||||
|
onChange({
|
||||||
|
...value,
|
||||||
|
group: v.currentTarget.value.trim(),
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</HorizontalGroup>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -35,7 +35,6 @@ Object {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
"options": Object {
|
"options": Object {
|
||||||
"graph": Object {},
|
|
||||||
"legend": Object {
|
"legend": Object {
|
||||||
"calcs": Array [
|
"calcs": Array [
|
||||||
"mean",
|
"mean",
|
||||||
@@ -68,7 +67,6 @@ Object {
|
|||||||
"overrides": Array [],
|
"overrides": Array [],
|
||||||
},
|
},
|
||||||
"options": Object {
|
"options": Object {
|
||||||
"graph": Object {},
|
|
||||||
"legend": Object {
|
"legend": Object {
|
||||||
"calcs": Array [],
|
"calcs": Array [],
|
||||||
"displayMode": "list",
|
"displayMode": "list",
|
||||||
@@ -81,6 +79,150 @@ Object {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`Graph Migrations stacking groups 1`] = `
|
||||||
|
Object {
|
||||||
|
"fieldConfig": Object {
|
||||||
|
"defaults": Object {
|
||||||
|
"custom": Object {
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 50,
|
||||||
|
"lineInterpolation": "stepAfter",
|
||||||
|
"lineWidth": 5,
|
||||||
|
"showPoints": "never",
|
||||||
|
"spanNulls": true,
|
||||||
|
"stacking": Object {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "normal",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"nullValueMode": "null",
|
||||||
|
"unit": "short",
|
||||||
|
},
|
||||||
|
"overrides": Array [
|
||||||
|
Object {
|
||||||
|
"matcher": Object {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "A-series",
|
||||||
|
},
|
||||||
|
"properties": Array [
|
||||||
|
Object {
|
||||||
|
"id": "color",
|
||||||
|
"value": Object {
|
||||||
|
"fixedColor": "red",
|
||||||
|
"mode": "fixed",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"matcher": Object {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "A-series",
|
||||||
|
},
|
||||||
|
"properties": Array [
|
||||||
|
Object {
|
||||||
|
"id": "custom.stacking",
|
||||||
|
"value": Object {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "normal",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"matcher": Object {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "B-series",
|
||||||
|
},
|
||||||
|
"properties": Array [
|
||||||
|
Object {
|
||||||
|
"id": "custom.stacking",
|
||||||
|
"value": Object {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "normal",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"options": Object {
|
||||||
|
"legend": Object {
|
||||||
|
"calcs": Array [
|
||||||
|
"mean",
|
||||||
|
"lastNotNull",
|
||||||
|
"max",
|
||||||
|
"min",
|
||||||
|
"sum",
|
||||||
|
],
|
||||||
|
"displayMode": "table",
|
||||||
|
"placement": "bottom",
|
||||||
|
},
|
||||||
|
"tooltipOptions": Object {
|
||||||
|
"mode": "single",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Graph Migrations stacking simple 1`] = `
|
||||||
|
Object {
|
||||||
|
"fieldConfig": Object {
|
||||||
|
"defaults": Object {
|
||||||
|
"custom": Object {
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 50,
|
||||||
|
"lineInterpolation": "stepAfter",
|
||||||
|
"lineWidth": 5,
|
||||||
|
"showPoints": "never",
|
||||||
|
"spanNulls": true,
|
||||||
|
"stacking": Object {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "normal",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"nullValueMode": "null",
|
||||||
|
"unit": "short",
|
||||||
|
},
|
||||||
|
"overrides": Array [
|
||||||
|
Object {
|
||||||
|
"matcher": Object {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "A-series",
|
||||||
|
},
|
||||||
|
"properties": Array [
|
||||||
|
Object {
|
||||||
|
"id": "color",
|
||||||
|
"value": Object {
|
||||||
|
"fixedColor": "red",
|
||||||
|
"mode": "fixed",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"options": Object {
|
||||||
|
"legend": Object {
|
||||||
|
"calcs": Array [
|
||||||
|
"mean",
|
||||||
|
"lastNotNull",
|
||||||
|
"max",
|
||||||
|
"min",
|
||||||
|
"sum",
|
||||||
|
],
|
||||||
|
"displayMode": "table",
|
||||||
|
"placement": "bottom",
|
||||||
|
},
|
||||||
|
"tooltipOptions": Object {
|
||||||
|
"mode": "single",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`Graph Migrations stairscase 1`] = `
|
exports[`Graph Migrations stairscase 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"fieldConfig": Object {
|
"fieldConfig": Object {
|
||||||
@@ -102,7 +244,6 @@ Object {
|
|||||||
"overrides": Array [],
|
"overrides": Array [],
|
||||||
},
|
},
|
||||||
"options": Object {
|
"options": Object {
|
||||||
"graph": Object {},
|
|
||||||
"legend": Object {
|
"legend": Object {
|
||||||
"calcs": Array [
|
"calcs": Array [
|
||||||
"mean",
|
"mean",
|
||||||
@@ -156,7 +297,6 @@ Object {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
"options": Object {
|
"options": Object {
|
||||||
"graph": Object {},
|
|
||||||
"legend": Object {
|
"legend": Object {
|
||||||
"calcs": Array [],
|
"calcs": Array [],
|
||||||
"displayMode": "list",
|
"displayMode": "list",
|
||||||
@@ -237,7 +377,6 @@ Object {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
"options": Object {
|
"options": Object {
|
||||||
"graph": Object {},
|
|
||||||
"legend": Object {
|
"legend": Object {
|
||||||
"calcs": Array [],
|
"calcs": Array [],
|
||||||
"displayMode": "list",
|
"displayMode": "list",
|
||||||
|
|||||||
@@ -11,20 +11,22 @@ import {
|
|||||||
stringOverrideProcessor,
|
stringOverrideProcessor,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import {
|
import {
|
||||||
|
AxisConfig,
|
||||||
AxisPlacement,
|
AxisPlacement,
|
||||||
BarAlignment,
|
BarAlignment,
|
||||||
DrawStyle,
|
DrawStyle,
|
||||||
GraphFieldConfig,
|
GraphFieldConfig,
|
||||||
graphFieldOptions,
|
graphFieldOptions,
|
||||||
|
GraphGradientMode,
|
||||||
|
HideableFieldConfig,
|
||||||
|
LegendDisplayMode,
|
||||||
LineInterpolation,
|
LineInterpolation,
|
||||||
LineStyle,
|
LineStyle,
|
||||||
PointVisibility,
|
PointVisibility,
|
||||||
ScaleDistribution,
|
ScaleDistribution,
|
||||||
ScaleDistributionConfig,
|
ScaleDistributionConfig,
|
||||||
GraphGradientMode,
|
StackingConfig,
|
||||||
LegendDisplayMode,
|
StackingMode,
|
||||||
AxisConfig,
|
|
||||||
HideableFieldConfig,
|
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
import { SeriesConfigEditor } from './HideSeriesConfigEditor';
|
import { SeriesConfigEditor } from './HideSeriesConfigEditor';
|
||||||
import { ScaleDistributionEditor } from './ScaleDistributionEditor';
|
import { ScaleDistributionEditor } from './ScaleDistributionEditor';
|
||||||
@@ -32,6 +34,7 @@ import { LineStyleEditor } from './LineStyleEditor';
|
|||||||
import { FillBellowToEditor } from './FillBelowToEditor';
|
import { FillBellowToEditor } from './FillBelowToEditor';
|
||||||
import { OptionsWithLegend } from './types';
|
import { OptionsWithLegend } from './types';
|
||||||
import { SpanNullsEditor } from './SpanNullsEditor';
|
import { SpanNullsEditor } from './SpanNullsEditor';
|
||||||
|
import { StackingEditor } from './StackingEditor';
|
||||||
|
|
||||||
export const defaultGraphConfig: GraphFieldConfig = {
|
export const defaultGraphConfig: GraphFieldConfig = {
|
||||||
drawStyle: DrawStyle.Line,
|
drawStyle: DrawStyle.Line,
|
||||||
@@ -40,11 +43,15 @@ export const defaultGraphConfig: GraphFieldConfig = {
|
|||||||
fillOpacity: 0,
|
fillOpacity: 0,
|
||||||
gradientMode: GraphGradientMode.None,
|
gradientMode: GraphGradientMode.None,
|
||||||
barAlignment: BarAlignment.Center,
|
barAlignment: BarAlignment.Center,
|
||||||
|
stacking: {
|
||||||
|
mode: StackingMode.None,
|
||||||
|
group: 'A',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getGraphFieldConfig(cfg: GraphFieldConfig): SetFieldConfigOptionsArgs<GraphFieldConfig> {
|
const categoryStyles = ['Graph styles'];
|
||||||
const categoryStyles = ['Graph styles'];
|
|
||||||
|
|
||||||
|
export function getGraphFieldConfig(cfg: GraphFieldConfig): SetFieldConfigOptionsArgs<GraphFieldConfig> {
|
||||||
return {
|
return {
|
||||||
standardOptions: {
|
standardOptions: {
|
||||||
[FieldConfigProperty.Color]: {
|
[FieldConfigProperty.Color]: {
|
||||||
@@ -180,6 +187,7 @@ export function getGraphFieldConfig(cfg: GraphFieldConfig): SetFieldConfigOption
|
|||||||
showIf: (c) => c.showPoints !== PointVisibility.Never || c.drawStyle === DrawStyle.Points,
|
showIf: (c) => c.showPoints !== PointVisibility.Never || c.drawStyle === DrawStyle.Points,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addStackingConfig(builder, cfg.stacking);
|
||||||
addAxisConfig(builder, cfg);
|
addAxisConfig(builder, cfg);
|
||||||
addHideFrom(builder);
|
addHideFrom(builder);
|
||||||
},
|
},
|
||||||
@@ -319,3 +327,23 @@ export function addLegendOptions<T extends OptionsWithLegend>(builder: PanelOpti
|
|||||||
showIf: (currentConfig) => currentConfig.legend.displayMode !== LegendDisplayMode.Hidden,
|
showIf: (currentConfig) => currentConfig.legend.displayMode !== LegendDisplayMode.Hidden,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function addStackingConfig(
|
||||||
|
builder: FieldConfigEditorBuilder<{ stacking: StackingConfig }>,
|
||||||
|
defaultConfig?: StackingConfig
|
||||||
|
) {
|
||||||
|
builder.addCustomEditor({
|
||||||
|
id: 'stacking',
|
||||||
|
path: 'stacking',
|
||||||
|
name: 'Stack series',
|
||||||
|
category: categoryStyles,
|
||||||
|
defaultValue: defaultConfig,
|
||||||
|
editor: StackingEditor,
|
||||||
|
override: StackingEditor,
|
||||||
|
settings: {
|
||||||
|
options: graphFieldOptions.stacking,
|
||||||
|
},
|
||||||
|
process: identityOverrideProcessor,
|
||||||
|
shouldApply: (f) => f.type === FieldType.number,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -48,6 +48,25 @@ describe('Graph Migrations', () => {
|
|||||||
panel.options = graphPanelChangedHandler(panel, 'graph', old);
|
panel.options = graphPanelChangedHandler(panel, 'graph', old);
|
||||||
expect(panel).toMatchSnapshot();
|
expect(panel).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('stacking', () => {
|
||||||
|
test('simple', () => {
|
||||||
|
const old: any = {
|
||||||
|
angular: stacking,
|
||||||
|
};
|
||||||
|
const panel = {} as PanelModel;
|
||||||
|
panel.options = graphPanelChangedHandler(panel, 'graph', old);
|
||||||
|
expect(panel).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
test('groups', () => {
|
||||||
|
const old: any = {
|
||||||
|
angular: stackingGroups,
|
||||||
|
};
|
||||||
|
const panel = {} as PanelModel;
|
||||||
|
panel.options = graphPanelChangedHandler(panel, 'graph', old);
|
||||||
|
expect(panel).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const stairscase = {
|
const stairscase = {
|
||||||
@@ -409,3 +428,200 @@ const legend = {
|
|||||||
timeShift: null,
|
timeShift: null,
|
||||||
datasource: null,
|
datasource: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const stacking = {
|
||||||
|
aliasColors: {
|
||||||
|
'A-series': 'red',
|
||||||
|
},
|
||||||
|
dashLength: 10,
|
||||||
|
fieldConfig: {
|
||||||
|
defaults: {
|
||||||
|
custom: {},
|
||||||
|
},
|
||||||
|
overrides: [],
|
||||||
|
},
|
||||||
|
fill: 5,
|
||||||
|
gridPos: {
|
||||||
|
h: 9,
|
||||||
|
w: 12,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
},
|
||||||
|
id: 2,
|
||||||
|
legend: {
|
||||||
|
avg: true,
|
||||||
|
current: true,
|
||||||
|
max: false,
|
||||||
|
min: false,
|
||||||
|
show: true,
|
||||||
|
total: true,
|
||||||
|
values: true,
|
||||||
|
alignAsTable: true,
|
||||||
|
},
|
||||||
|
lines: true,
|
||||||
|
linewidth: 5,
|
||||||
|
maxDataPoints: 20,
|
||||||
|
nullPointMode: 'null',
|
||||||
|
options: {
|
||||||
|
alertThreshold: true,
|
||||||
|
},
|
||||||
|
pluginVersion: '7.4.0-pre',
|
||||||
|
pointradius: 2,
|
||||||
|
renderer: 'flot',
|
||||||
|
seriesOverrides: [],
|
||||||
|
spaceLength: 10,
|
||||||
|
steppedLine: true,
|
||||||
|
thresholds: [],
|
||||||
|
timeRegions: [],
|
||||||
|
title: 'Panel Title',
|
||||||
|
tooltip: {
|
||||||
|
shared: true,
|
||||||
|
sort: 0,
|
||||||
|
value_type: 'individual',
|
||||||
|
},
|
||||||
|
type: 'graph',
|
||||||
|
xaxis: {
|
||||||
|
buckets: null,
|
||||||
|
mode: 'time',
|
||||||
|
name: null,
|
||||||
|
show: true,
|
||||||
|
values: [],
|
||||||
|
},
|
||||||
|
yaxes: [
|
||||||
|
{
|
||||||
|
$$hashKey: 'object:38',
|
||||||
|
format: 'short',
|
||||||
|
label: null,
|
||||||
|
logBase: 1,
|
||||||
|
max: null,
|
||||||
|
min: null,
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$$hashKey: 'object:39',
|
||||||
|
format: 'short',
|
||||||
|
label: null,
|
||||||
|
logBase: 1,
|
||||||
|
max: null,
|
||||||
|
min: null,
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
yaxis: {
|
||||||
|
align: false,
|
||||||
|
alignLevel: null,
|
||||||
|
},
|
||||||
|
bars: false,
|
||||||
|
dashes: false,
|
||||||
|
fillGradient: 0,
|
||||||
|
hiddenSeries: false,
|
||||||
|
percentage: false,
|
||||||
|
points: false,
|
||||||
|
stack: true,
|
||||||
|
timeFrom: null,
|
||||||
|
timeShift: null,
|
||||||
|
datasource: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const stackingGroups = {
|
||||||
|
aliasColors: {
|
||||||
|
'A-series': 'red',
|
||||||
|
},
|
||||||
|
dashLength: 10,
|
||||||
|
fieldConfig: {
|
||||||
|
defaults: {
|
||||||
|
custom: {},
|
||||||
|
},
|
||||||
|
overrides: [],
|
||||||
|
},
|
||||||
|
fill: 5,
|
||||||
|
gridPos: {
|
||||||
|
h: 9,
|
||||||
|
w: 12,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
},
|
||||||
|
id: 2,
|
||||||
|
legend: {
|
||||||
|
avg: true,
|
||||||
|
current: true,
|
||||||
|
max: false,
|
||||||
|
min: false,
|
||||||
|
show: true,
|
||||||
|
total: true,
|
||||||
|
values: true,
|
||||||
|
alignAsTable: true,
|
||||||
|
},
|
||||||
|
lines: true,
|
||||||
|
linewidth: 5,
|
||||||
|
maxDataPoints: 20,
|
||||||
|
nullPointMode: 'null',
|
||||||
|
options: {
|
||||||
|
alertThreshold: true,
|
||||||
|
},
|
||||||
|
pluginVersion: '7.4.0-pre',
|
||||||
|
pointradius: 2,
|
||||||
|
renderer: 'flot',
|
||||||
|
seriesOverrides: [
|
||||||
|
{
|
||||||
|
alias: 'A-series',
|
||||||
|
stack: 'A',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
alias: 'B-series',
|
||||||
|
stack: 'A',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
spaceLength: 10,
|
||||||
|
steppedLine: true,
|
||||||
|
thresholds: [],
|
||||||
|
timeRegions: [],
|
||||||
|
title: 'Panel Title',
|
||||||
|
tooltip: {
|
||||||
|
shared: true,
|
||||||
|
sort: 0,
|
||||||
|
value_type: 'individual',
|
||||||
|
},
|
||||||
|
type: 'graph',
|
||||||
|
xaxis: {
|
||||||
|
buckets: null,
|
||||||
|
mode: 'time',
|
||||||
|
name: null,
|
||||||
|
show: true,
|
||||||
|
values: [],
|
||||||
|
},
|
||||||
|
yaxes: [
|
||||||
|
{
|
||||||
|
$$hashKey: 'object:38',
|
||||||
|
format: 'short',
|
||||||
|
label: null,
|
||||||
|
logBase: 1,
|
||||||
|
max: null,
|
||||||
|
min: null,
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$$hashKey: 'object:39',
|
||||||
|
format: 'short',
|
||||||
|
label: null,
|
||||||
|
logBase: 1,
|
||||||
|
max: null,
|
||||||
|
min: null,
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
yaxis: {
|
||||||
|
align: false,
|
||||||
|
alignLevel: null,
|
||||||
|
},
|
||||||
|
bars: false,
|
||||||
|
dashes: false,
|
||||||
|
fillGradient: 0,
|
||||||
|
hiddenSeries: false,
|
||||||
|
percentage: false,
|
||||||
|
points: false,
|
||||||
|
stack: true,
|
||||||
|
timeFrom: null,
|
||||||
|
timeShift: null,
|
||||||
|
datasource: null,
|
||||||
|
};
|
||||||
|
|||||||
@@ -10,19 +10,22 @@ import {
|
|||||||
NullValueMode,
|
NullValueMode,
|
||||||
PanelModel,
|
PanelModel,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { GraphFieldConfig, LegendDisplayMode } from '@grafana/ui';
|
|
||||||
import {
|
import {
|
||||||
GraphGradientMode,
|
|
||||||
AxisPlacement,
|
AxisPlacement,
|
||||||
DrawStyle,
|
DrawStyle,
|
||||||
|
GraphFieldConfig,
|
||||||
|
GraphGradientMode,
|
||||||
|
LegendDisplayMode,
|
||||||
LineInterpolation,
|
LineInterpolation,
|
||||||
LineStyle,
|
LineStyle,
|
||||||
PointVisibility,
|
PointVisibility,
|
||||||
} from '@grafana/ui/src/components/uPlot/config';
|
StackingMode,
|
||||||
|
} from '@grafana/ui';
|
||||||
import { Options } from './types';
|
import { Options } from './types';
|
||||||
import omitBy from 'lodash/omitBy';
|
import omitBy from 'lodash/omitBy';
|
||||||
import isNil from 'lodash/isNil';
|
import isNil from 'lodash/isNil';
|
||||||
import { isNumber, isString } from 'lodash';
|
import { isNumber, isString } from 'lodash';
|
||||||
|
import { defaultGraphConfig } from './config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is called when the panel changes from another panel
|
* This is called when the panel changes from another panel
|
||||||
@@ -210,6 +213,12 @@ export function flotToGraphOptions(angular: any): { fieldConfig: FieldConfigSour
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'stack':
|
||||||
|
rule.properties.push({
|
||||||
|
id: 'custom.stacking',
|
||||||
|
value: { mode: StackingMode.Normal, group: v },
|
||||||
|
});
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.log('Ignore override migration:', seriesOverride.alias, p, v);
|
console.log('Ignore override migration:', seriesOverride.alias, p, v);
|
||||||
}
|
}
|
||||||
@@ -265,11 +274,17 @@ export function flotToGraphOptions(angular: any): { fieldConfig: FieldConfigSour
|
|||||||
graph.fillOpacity = 100; // bars were always
|
graph.fillOpacity = 100; // bars were always
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (angular.stack) {
|
||||||
|
graph.stacking = {
|
||||||
|
mode: StackingMode.Normal,
|
||||||
|
group: defaultGraphConfig.stacking!.group,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
y1.custom = omitBy(graph, isNil);
|
y1.custom = omitBy(graph, isNil);
|
||||||
y1.nullValueMode = angular.nullPointMode as NullValueMode;
|
y1.nullValueMode = angular.nullPointMode as NullValueMode;
|
||||||
|
|
||||||
const options: Options = {
|
const options: Options = {
|
||||||
graph: {},
|
|
||||||
legend: {
|
legend: {
|
||||||
displayMode: LegendDisplayMode.List,
|
displayMode: LegendDisplayMode.List,
|
||||||
placement: 'bottom',
|
placement: 'bottom',
|
||||||
|
|||||||
@@ -23,5 +23,6 @@ export const plugin = new PanelPlugin<Options, GraphFieldConfig>(TimeSeriesPanel
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
addLegendOptions(builder);
|
addLegendOptions(builder);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,14 +1,9 @@
|
|||||||
import { VizLegendOptions, GraphTooltipOptions } from '@grafana/ui';
|
import { VizLegendOptions, GraphTooltipOptions } from '@grafana/ui';
|
||||||
|
|
||||||
export interface GraphOptions {
|
|
||||||
// nothing for now
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OptionsWithLegend {
|
export interface OptionsWithLegend {
|
||||||
legend: VizLegendOptions;
|
legend: VizLegendOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Options extends OptionsWithLegend {
|
export interface Options extends OptionsWithLegend {
|
||||||
graph: GraphOptions;
|
|
||||||
tooltipOptions: GraphTooltipOptions;
|
tooltipOptions: GraphTooltipOptions;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
import { Button, TooltipPlugin, GraphNG, GraphNGLegendEvent } from '@grafana/ui';
|
import { Button, GraphNG, GraphNGLegendEvent, TooltipPlugin } from '@grafana/ui';
|
||||||
import { PanelProps } from '@grafana/data';
|
import { PanelProps } from '@grafana/data';
|
||||||
import { Options } from './types';
|
import { Options } from './types';
|
||||||
import { hideSeriesConfigFactory } from '../timeseries/overrides/hideSeriesConfigFactory';
|
import { hideSeriesConfigFactory } from '../timeseries/overrides/hideSeriesConfigFactory';
|
||||||
|
|||||||
Reference in New Issue
Block a user