Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
8aba480a
Unverified
Commit
8aba480a
authored
Jan 15, 2021
by
Ryan McKinley
Committed by
GitHub
Jan 15, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
GraphNG: support fill below to (bands) (#30268)
parent
62485898
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
303 additions
and
26 deletions
+303
-26
devenv/dev-dashboards/panel-graph/graph-ng.json
+169
-21
packages/grafana-ui/src/components/GraphNG/GraphNG.tsx
+29
-1
packages/grafana-ui/src/components/uPlot/config.ts
+1
-0
packages/grafana-ui/src/components/uPlot/config/UPlotConfigBuilder.ts
+20
-1
packages/grafana-ui/src/components/uPlot/types.ts
+1
-1
public/app/plugins/panel/timeseries/FillBelowToEditor.tsx
+47
-0
public/app/plugins/panel/timeseries/config.ts
+18
-1
public/app/plugins/panel/timeseries/migrations.ts
+18
-1
No files found.
devenv/dev-dashboards/panel-graph/graph-ng.json
View file @
8aba480a
...
...
@@ -1175,8 +1175,8 @@
]
},
"gridPos"
:
{
"h"
:
5
,
"w"
:
24
,
"h"
:
7
,
"w"
:
12
,
"x"
:
0
,
"y"
:
13
},
...
...
@@ -1360,13 +1360,161 @@
"type"
:
"timeseries"
},
{
"datasource"
:
null
,
"fieldConfig"
:
{
"defaults"
:
{
"color"
:
{
"mode"
:
"palette-classic"
},
"custom"
:
{
"axisLabel"
:
""
,
"axisPlacement"
:
"auto"
,
"drawStyle"
:
"line"
,
"fillGradient"
:
"hue"
,
"fillOpacity"
:
25
,
"hideFrom"
:
{
"graph"
:
false
,
"legend"
:
false
,
"tooltip"
:
false
},
"lineInterpolation"
:
"smooth"
,
"lineWidth"
:
2
,
"pointSize"
:
6
,
"scaleDistribution"
:
{
"type"
:
"linear"
},
"showPoints"
:
"never"
,
"spanNulls"
:
true
},
"mappings"
:
[],
"nullValueMode"
:
"null"
,
"thresholds"
:
{
"mode"
:
"absolute"
,
"steps"
:
[
{
"color"
:
"green"
,
"value"
:
null
},
{
"color"
:
"red"
,
"value"
:
80
}
]
},
"unit"
:
"short"
},
"overrides"
:
[
{
"matcher"
:
{
"id"
:
"byName"
,
"options"
:
"Max"
},
"properties"
:
[
{
"id"
:
"custom.fillBelowTo"
,
"value"
:
"Min"
},
{
"id"
:
"custom.lineWidth"
,
"value"
:
0
},
{
"id"
:
"color"
,
"value"
:
{
"fixedColor"
:
"red"
,
"mode"
:
"fixed"
}
}
]
},
{
"matcher"
:
{
"id"
:
"byName"
,
"options"
:
"Min"
},
"properties"
:
[
{
"id"
:
"custom.lineWidth"
,
"value"
:
0
}
]
},
{
"matcher"
:
{
"id"
:
"byName"
,
"options"
:
"Value"
},
"properties"
:
[
{
"id"
:
"color"
,
"value"
:
{
"fixedColor"
:
"blue"
,
"mode"
:
"fixed"
}
}
]
}
]
},
"gridPos"
:
{
"h"
:
7
,
"w"
:
12
,
"x"
:
12
,
"y"
:
13
},
"id"
:
70
,
"interval"
:
null
,
"maxDataPoints"
:
100
,
"options"
:
{
"graph"
:
{},
"legend"
:
{
"displayMode"
:
"list"
,
"placement"
:
"right"
},
"tooltipOptions"
:
{
"mode"
:
"single"
}
},
"pluginVersion"
:
"7.4.0-pre"
,
"targets"
:
[
{
"alias"
:
""
,
"csvWave"
:
{
"timeStep"
:
60
,
"valuesCSV"
:
"0,0,2,2,1,1"
},
"lines"
:
10
,
"points"
:
[],
"pulseWave"
:
{
"offCount"
:
3
,
"offValue"
:
1
,
"onCount"
:
3
,
"onValue"
:
2
,
"timeStep"
:
60
},
"refId"
:
"A"
,
"scenarioId"
:
"random_walk_table"
,
"stream"
:
{
"bands"
:
1
,
"noise"
:
2.2
,
"speed"
:
250
,
"spread"
:
3.5
,
"type"
:
"signal"
},
"stringInput"
:
""
}
],
"title"
:
"Fill below to"
,
"type"
:
"timeseries"
},
{
"collapsed"
:
false
,
"datasource"
:
null
,
"gridPos"
:
{
"h"
:
1
,
"w"
:
24
,
"x"
:
0
,
"y"
:
18
"y"
:
20
},
"id"
:
62
,
"panels"
:
[],
...
...
@@ -1444,7 +1592,7 @@
"h"
:
6
,
"w"
:
6
,
"x"
:
0
,
"y"
:
19
"y"
:
21
},
"id"
:
63
,
"maxDataPoints"
:
10
,
...
...
@@ -1582,7 +1730,7 @@
"h"
:
6
,
"w"
:
6
,
"x"
:
6
,
"y"
:
19
"y"
:
21
},
"id"
:
64
,
"maxDataPoints"
:
10
,
...
...
@@ -1720,7 +1868,7 @@
"h"
:
6
,
"w"
:
6
,
"x"
:
12
,
"y"
:
19
"y"
:
21
},
"id"
:
65
,
"maxDataPoints"
:
10
,
...
...
@@ -1858,7 +2006,7 @@
"h"
:
6
,
"w"
:
6
,
"x"
:
18
,
"y"
:
19
"y"
:
21
},
"id"
:
66
,
"maxDataPoints"
:
100
,
...
...
@@ -1918,7 +2066,7 @@
"h"
:
1
,
"w"
:
24
,
"x"
:
0
,
"y"
:
2
5
"y"
:
2
7
},
"id"
:
34
,
"panels"
:
[],
...
...
@@ -2024,7 +2172,7 @@
"h"
:
8
,
"w"
:
6
,
"x"
:
0
,
"y"
:
2
6
"y"
:
2
8
},
"id"
:
32
,
"maxDataPoints"
:
100
,
...
...
@@ -2164,7 +2312,7 @@
"h"
:
8
,
"w"
:
6
,
"x"
:
6
,
"y"
:
2
6
"y"
:
2
8
},
"id"
:
35
,
"maxDataPoints"
:
100
,
...
...
@@ -2318,7 +2466,7 @@
"h"
:
8
,
"w"
:
6
,
"x"
:
12
,
"y"
:
2
6
"y"
:
2
8
},
"id"
:
31
,
"maxDataPoints"
:
200
,
...
...
@@ -2471,7 +2619,7 @@
"h"
:
8
,
"w"
:
6
,
"x"
:
18
,
"y"
:
2
6
"y"
:
2
8
},
"id"
:
51
,
"maxDataPoints"
:
200
,
...
...
@@ -2532,7 +2680,7 @@
"h"
:
1
,
"w"
:
24
,
"x"
:
0
,
"y"
:
3
4
"y"
:
3
6
},
"id"
:
17
,
"panels"
:
[],
...
...
@@ -2614,7 +2762,7 @@
"h"
:
7
,
"w"
:
6
,
"x"
:
0
,
"y"
:
3
5
"y"
:
3
7
},
"id"
:
19
,
"options"
:
{
...
...
@@ -2722,7 +2870,7 @@
"h"
:
7
,
"w"
:
6
,
"x"
:
6
,
"y"
:
3
5
"y"
:
3
7
},
"id"
:
20
,
"options"
:
{
...
...
@@ -2829,7 +2977,7 @@
"h"
:
7
,
"w"
:
6
,
"x"
:
12
,
"y"
:
3
5
"y"
:
3
7
},
"id"
:
21
,
"options"
:
{
...
...
@@ -2937,7 +3085,7 @@
"h"
:
7
,
"w"
:
6
,
"x"
:
18
,
"y"
:
3
5
"y"
:
3
7
},
"id"
:
9
,
"options"
:
{
...
...
@@ -2980,7 +3128,7 @@
"h"
:
1
,
"w"
:
24
,
"x"
:
0
,
"y"
:
4
2
"y"
:
4
4
},
"id"
:
45
,
"panels"
:
[],
...
...
@@ -3061,7 +3209,7 @@
"h"
:
10
,
"w"
:
12
,
"x"
:
0
,
"y"
:
4
3
"y"
:
4
5
},
"id"
:
46
,
"options"
:
{
...
...
@@ -3204,7 +3352,7 @@
"h"
:
10
,
"w"
:
12
,
"x"
:
12
,
"y"
:
4
3
"y"
:
4
5
},
"id"
:
68
,
"options"
:
{
...
...
@@ -3269,5 +3417,5 @@
"timezone"
:
""
,
"title"
:
"Panel Tests - Graph NG"
,
"uid"
:
"TkZXxlNG3"
,
"version"
:
27
"version"
:
34
}
packages/grafana-ui/src/components/GraphNG/GraphNG.tsx
View file @
8aba480a
...
...
@@ -24,6 +24,7 @@ import { VizLegend } from '../VizLegend/VizLegend';
import
{
UPlotConfigBuilder
}
from
'../uPlot/config/UPlotConfigBuilder'
;
import
{
useRevision
}
from
'../uPlot/hooks'
;
import
{
GraphNGLegendEvent
,
GraphNGLegendEventMode
}
from
'./types'
;
import
{
isNumber
}
from
'lodash'
;
const
defaultFormatter
=
(
v
:
any
)
=>
(
v
==
null
?
'-'
:
v
.
toFixed
(
1
));
...
...
@@ -135,6 +136,7 @@ export const GraphNG: React.FC<GraphNGProps> = ({
theme
,
});
}
let
indexByName
:
Map
<
string
,
number
>
|
undefined
=
undefined
;
for
(
let
i
=
0
;
i
<
alignedFrame
.
fields
.
length
;
i
++
)
{
const
field
=
alignedFrame
.
fields
[
i
];
...
...
@@ -176,6 +178,24 @@ export const GraphNG: React.FC<GraphNGProps> = ({
const
showPoints
=
customConfig
.
drawStyle
===
DrawStyle
.
Points
?
PointVisibility
.
Always
:
customConfig
.
showPoints
;
const
dataFrameFieldIndex
=
getDataFrameFieldIndex
?
getDataFrameFieldIndex
(
i
)
:
undefined
;
let
{
fillOpacity
}
=
customConfig
;
if
(
customConfig
.
fillBelowTo
)
{
if
(
!
indexByName
)
{
indexByName
=
getNamesToFieldIndex
(
alignedFrame
);
}
const
t
=
indexByName
.
get
(
getFieldDisplayName
(
field
,
alignedFrame
));
const
b
=
indexByName
.
get
(
customConfig
.
fillBelowTo
);
if
(
isNumber
(
b
)
&&
isNumber
(
t
))
{
builder
.
addBand
({
series
:
[
t
,
b
],
fill
:
null
as
any
,
// using null will have the band use fill options from `t`
});
}
if
(
!
fillOpacity
)
{
fillOpacity
=
35
;
// default from flot
}
}
builder
.
addSeries
({
scaleKey
,
drawStyle
:
customConfig
.
drawStyle
!
,
...
...
@@ -186,7 +206,7 @@ export const GraphNG: React.FC<GraphNGProps> = ({
showPoints
,
pointSize
:
customConfig
.
pointSize
,
pointColor
:
customConfig
.
pointColor
??
seriesColor
,
fillOpacity
:
customConfig
.
fillOpacity
,
fillOpacity
,
spanNulls
:
customConfig
.
spanNulls
||
false
,
show
:
!
customConfig
.
hideFrom
?.
graph
,
fillGradient
:
customConfig
.
fillGradient
,
...
...
@@ -291,3 +311,11 @@ const mapMouseEventToMode = (event: React.MouseEvent): GraphNGLegendEventMode =>
}
return
GraphNGLegendEventMode
.
ToggleSelection
;
};
function
getNamesToFieldIndex
(
frame
:
DataFrame
):
Map
<
string
,
number
>
{
const
names
=
new
Map
<
string
,
number
>
();
for
(
let
i
=
0
;
i
<
frame
.
fields
.
length
;
i
++
)
{
names
.
set
(
getFieldDisplayName
(
frame
.
fields
[
i
],
frame
),
i
);
}
return
names
;
}
packages/grafana-ui/src/components/uPlot/config.ts
View file @
8aba480a
...
...
@@ -74,6 +74,7 @@ export interface FillConfig {
fillColor
?:
string
;
fillOpacity
?:
number
;
fillGradient
?:
FillGradientMode
;
fillBelowTo
?:
string
;
// name of the field
}
/**
...
...
packages/grafana-ui/src/components/uPlot/config/UPlotConfigBuilder.ts
View file @
8aba480a
...
...
@@ -3,13 +3,14 @@ import { ScaleProps, UPlotScaleBuilder } from './UPlotScaleBuilder';
import
{
SeriesProps
,
UPlotSeriesBuilder
}
from
'./UPlotSeriesBuilder'
;
import
{
AxisProps
,
UPlotAxisBuilder
}
from
'./UPlotAxisBuilder'
;
import
{
AxisPlacement
}
from
'../config'
;
import
{
Cursor
}
from
'uplot'
;
import
{
Cursor
,
Band
}
from
'uplot'
;
import
{
defaultsDeep
}
from
'lodash'
;
export
class
UPlotConfigBuilder
{
private
series
:
UPlotSeriesBuilder
[]
=
[];
private
axes
:
Record
<
string
,
UPlotAxisBuilder
>
=
{};
private
scales
:
UPlotScaleBuilder
[]
=
[];
private
bands
:
Band
[]
=
[];
private
cursor
:
Cursor
|
undefined
;
private
hasLeftAxis
=
false
;
private
hasBottomAxis
=
false
;
...
...
@@ -71,6 +72,10 @@ export class UPlotConfigBuilder {
this
.
scales
.
push
(
new
UPlotScaleBuilder
(
props
));
}
addBand
(
band
:
Band
)
{
this
.
bands
.
push
(
band
);
}
getConfig
()
{
const
config
:
PlotSeriesConfig
=
{
series
:
[{}]
};
config
.
axes
=
this
.
ensureNonOverlappingAxes
(
Object
.
values
(
this
.
axes
)).
map
(
a
=>
a
.
getConfig
());
...
...
@@ -81,6 +86,20 @@ export class UPlotConfigBuilder {
config
.
cursor
=
this
.
cursor
||
{};
// When bands exist, only keep fill when defined
if
(
config
.
bands
?.
length
)
{
config
.
bands
=
this
.
bands
;
const
keepFill
=
new
Set
<
number
>
();
for
(
const
b
of
config
.
bands
)
{
keepFill
.
add
(
b
.
series
[
0
]);
}
for
(
let
i
=
1
;
i
<
config
.
series
.
length
;
i
++
)
{
if
(
!
keepFill
.
has
(
i
))
{
config
.
series
[
i
].
fill
=
undefined
;
}
}
}
const
cursorDefaults
:
Cursor
=
{
// prevent client-side zoom from triggering at the end of a selection
drag
:
{
setScale
:
false
},
...
...
packages/grafana-ui/src/components/uPlot/types.ts
View file @
8aba480a
...
...
@@ -3,7 +3,7 @@ import uPlot, { Options, Series, Hooks } from 'uplot';
import
{
DataFrame
,
DataFrameFieldIndex
,
TimeRange
,
TimeZone
}
from
'@grafana/data'
;
import
{
UPlotConfigBuilder
}
from
'./config/UPlotConfigBuilder'
;
export
type
PlotSeriesConfig
=
Pick
<
Options
,
'series'
|
'scales'
|
'axes'
|
'cursor'
>
;
export
type
PlotSeriesConfig
=
Pick
<
Options
,
'series'
|
'scales'
|
'axes'
|
'cursor'
|
'bands'
>
;
export
type
PlotPlugin
=
{
id
:
string
;
/** can mutate provided opts as necessary */
...
...
public/app/plugins/panel/timeseries/FillBelowToEditor.tsx
0 → 100644
View file @
8aba480a
import
React
,
{
useMemo
}
from
'react'
;
import
{
FieldOverrideEditorProps
,
FieldType
,
getFieldDisplayName
,
SelectableValue
}
from
'@grafana/data'
;
import
{
Select
}
from
'@grafana/ui'
;
export
const
FillBellowToEditor
:
React
.
FC
<
FieldOverrideEditorProps
<
string
,
any
>>
=
({
value
,
context
,
onChange
})
=>
{
const
names
=
useMemo
(()
=>
{
const
names
:
Array
<
SelectableValue
<
string
>>
=
[];
if
(
context
.
data
.
length
)
{
for
(
const
frame
of
context
.
data
)
{
for
(
const
field
of
frame
.
fields
)
{
if
(
field
.
type
===
FieldType
.
number
)
{
const
label
=
getFieldDisplayName
(
field
,
frame
,
context
.
data
);
names
.
push
({
label
,
value
:
label
,
});
}
}
}
}
return
names
;
},
[
context
]);
const
current
=
useMemo
(()
=>
{
const
found
=
names
.
find
(
v
=>
v
.
value
===
value
);
if
(
found
)
{
return
found
;
}
if
(
value
)
{
return
{
label
:
value
,
value
,
};
}
return
undefined
;
},
names
);
return
(
<
Select
options=
{
names
}
value=
{
current
}
onChange=
{
v
=>
{
onChange
(
v
.
value
);
}
}
/>
);
};
public/app/plugins/panel/timeseries/config.ts
View file @
8aba480a
import
{
FieldColorModeId
,
FieldConfigProperty
,
FieldType
,
identityOverrideProcessor
}
from
'@grafana/data'
;
import
{
FieldColorModeId
,
FieldConfigProperty
,
FieldType
,
identityOverrideProcessor
,
stringOverrideProcessor
,
}
from
'@grafana/data'
;
import
{
AxisPlacement
,
DrawStyle
,
...
...
@@ -15,6 +21,7 @@ import { ScaleDistributionEditor } from './ScaleDistributionEditor';
import
{
LineStyleEditor
}
from
'./LineStyleEditor'
;
import
{
SetFieldConfigOptionsArgs
}
from
'@grafana/data/src/panel/PanelPlugin'
;
import
{
FillGradientMode
}
from
'@grafana/ui/src/components/uPlot/config'
;
import
{
FillBellowToEditor
}
from
'./FillBelowToEditor'
;
export
const
defaultGraphConfig
:
GraphFieldConfig
=
{
drawStyle
:
DrawStyle
.
Line
,
...
...
@@ -86,6 +93,16 @@ export function getGraphFieldConfig(cfg: GraphFieldConfig): SetFieldConfigOption
},
showIf
:
c
=>
!!
(
c
.
drawStyle
!==
DrawStyle
.
Points
&&
c
.
fillOpacity
&&
c
.
fillOpacity
>
0
),
})
.
addCustomEditor
({
id
:
'fillBelowTo'
,
path
:
'fillBelowTo'
,
name
:
'Fill below to'
,
editor
:
FillBellowToEditor
,
override
:
FillBellowToEditor
,
process
:
stringOverrideProcessor
,
hideFromDefaults
:
true
,
shouldApply
:
f
=>
true
,
})
.
addCustomEditor
<
void
,
LineStyle
>
({
id
:
'lineStyle'
,
path
:
'lineStyle'
,
...
...
public/app/plugins/panel/timeseries/migrations.ts
View file @
8aba480a
...
...
@@ -93,6 +93,8 @@ export function flotToGraphOptions(angular: any): { fieldConfig: FieldConfigSour
}
}
let
hasFillBelowTo
=
false
;
if
(
angular
.
seriesOverrides
?.
length
)
{
for
(
const
seriesOverride
of
angular
.
seriesOverrides
)
{
if
(
!
seriesOverride
.
alias
)
{
...
...
@@ -127,6 +129,13 @@ export function flotToGraphOptions(angular: any): { fieldConfig: FieldConfigSour
value
:
v
*
10
,
// was 0-10, new graph is 0 - 100
});
break
;
case
'fillBelowTo'
:
hasFillBelowTo
=
true
;
rule
.
properties
.
push
({
id
:
'custom.fillBelowTo'
,
value
:
v
,
});
break
;
case
'fillGradient'
:
if
(
v
)
{
rule
.
properties
.
push
({
...
...
@@ -162,6 +171,12 @@ export function flotToGraphOptions(angular: any): { fieldConfig: FieldConfigSour
});
}
break
;
case
'lines'
:
rule
.
properties
.
push
({
id
:
'custom.lineWidth'
,
value
:
0
,
// don't show lines
});
break
;
case
'linewidth'
:
rule
.
properties
.
push
({
id
:
'custom.lineWidth'
,
...
...
@@ -229,7 +244,9 @@ export function flotToGraphOptions(angular: any): { fieldConfig: FieldConfigSour
graph
.
pointSize
=
2
+
angular
.
pointradius
*
2
;
}
if
(
isNumber
(
angular
.
fill
))
{
if
(
hasFillBelowTo
)
{
graph
.
fillOpacity
=
35
;
// bands are hardcoded in flot
}
else
if
(
isNumber
(
angular
.
fill
))
{
graph
.
fillOpacity
=
angular
.
fill
*
10
;
// fill was 0 - 10, new is 0 to 100
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment