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