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
9f87d8d3
Commit
9f87d8d3
authored
Dec 08, 2017
by
Torkel Ödegaard
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop-graph-legend' into develop
parents
f78f86d0
35a7109a
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
323 additions
and
235 deletions
+323
-235
public/app/core/core.ts
+6
-2
public/app/core/time_series2.ts
+43
-0
public/app/core/utils/ticks.ts
+91
-0
public/app/features/panel/panel_directive.ts
+1
-1
public/app/plugins/panel/graph/graph.ts
+92
-141
public/app/plugins/panel/graph/legend.ts
+54
-36
public/app/plugins/panel/graph/specs/graph_specs.ts
+2
-0
public/app/plugins/panel/graph/template.ts
+4
-16
public/sass/components/_panel_graph.scss
+30
-39
No files found.
public/app/core/core.ts
View file @
9f87d8d3
...
...
@@ -52,6 +52,8 @@ import {gfPageDirective} from './components/gf_page';
import
{
orgSwitcher
}
from
'./components/org_switcher'
;
import
{
profiler
}
from
'./profiler'
;
import
{
registerAngularDirectives
}
from
'./angular_wrappers'
;
import
{
updateLegendValues
}
from
'./time_series2'
;
import
TimeSeries
from
'./time_series2'
;
import
{
searchResultsDirective
}
from
'./components/search/search_results'
;
import
{
manageDashboardsDirective
}
from
'./components/manage_dashboards/manage_dashboards'
;
...
...
@@ -86,6 +88,8 @@ export {
geminiScrollbar
,
gfPageDirective
,
orgSwitcher
,
searchResultsDirective
,
manageDashboardsDirective
manageDashboardsDirective
,
TimeSeries
,
updateLegendValues
,
searchResultsDirective
};
public/app/core/time_series2.ts
View file @
9f87d8d3
import
kbn
from
'app/core/utils/kbn'
;
import
{
getFlotTickDecimals
}
from
'app/core/utils/ticks'
;
import
_
from
'lodash'
;
function
matchSeriesOverride
(
aliasOrRegex
,
seriesAlias
)
{
...
...
@@ -16,6 +17,48 @@ function translateFillOption(fill) {
return
fill
===
0
?
0.001
:
fill
/
10
;
}
/**
* Calculate decimals for legend and update values for each series.
* @param data series data
* @param panel
*/
export
function
updateLegendValues
(
data
:
TimeSeries
[],
panel
)
{
for
(
let
i
=
0
;
i
<
data
.
length
;
i
++
)
{
let
series
=
data
[
i
];
let
yaxes
=
panel
.
yaxes
;
let
axis
=
yaxes
[
series
.
yaxis
-
1
];
let
{
tickDecimals
,
scaledDecimals
}
=
getFlotTickDecimals
(
data
,
axis
);
let
formater
=
kbn
.
valueFormats
[
panel
.
yaxes
[
series
.
yaxis
-
1
].
format
];
// decimal override
if
(
_
.
isNumber
(
panel
.
decimals
))
{
series
.
updateLegendValues
(
formater
,
panel
.
decimals
,
null
);
}
else
{
// auto decimals
// legend and tooltip gets one more decimal precision
// than graph legend ticks
tickDecimals
=
(
tickDecimals
||
-
1
)
+
1
;
series
.
updateLegendValues
(
formater
,
tickDecimals
,
scaledDecimals
+
2
);
}
}
}
export
function
getDataMinMax
(
data
:
TimeSeries
[])
{
let
datamin
=
null
;
let
datamax
=
null
;
for
(
let
series
of
data
)
{
if
(
datamax
===
null
||
datamax
<
series
.
stats
.
max
)
{
datamax
=
series
.
stats
.
max
;
}
if
(
datamin
===
null
||
datamin
>
series
.
stats
.
min
)
{
datamin
=
series
.
stats
.
min
;
}
}
return
{
datamin
,
datamax
};
}
export
default
class
TimeSeries
{
datapoints
:
any
;
id
:
string
;
...
...
public/app/core/utils/ticks.ts
View file @
9f87d8d3
import
{
getDataMinMax
}
from
'app/core/time_series2'
;
/**
* Calculate tick step.
* Implementation from d3-array (ticks.js)
...
...
@@ -32,6 +34,7 @@ export function getScaledDecimals(decimals, tick_size) {
/**
* Calculate tick size based on min and max values, number of ticks and precision.
* Implementation from Flot.
* @param min Axis minimum
* @param max Axis maximum
* @param noTicks Number of ticks
...
...
@@ -65,3 +68,91 @@ export function getFlotTickSize(min: number, max: number, noTicks: number, tickD
return
size
;
}
/**
* Calculate axis range (min and max).
* Implementation from Flot.
*/
export
function
getFlotRange
(
panelMin
,
panelMax
,
datamin
,
datamax
)
{
const
autoscaleMargin
=
0.02
;
let
min
=
+
(
panelMin
!=
null
?
panelMin
:
datamin
);
let
max
=
+
(
panelMax
!=
null
?
panelMax
:
datamax
);
let
delta
=
max
-
min
;
if
(
delta
===
0.0
)
{
// Grafana fix: wide Y min and max using increased wideFactor
// when all series values are the same
var
wideFactor
=
0.25
;
var
widen
=
Math
.
abs
(
max
===
0
?
1
:
max
*
wideFactor
);
if
(
panelMin
===
null
)
{
min
-=
widen
;
}
// always widen max if we couldn't widen min to ensure we
// don't fall into min == max which doesn't work
if
(
panelMax
==
null
||
panelMin
!=
null
)
{
max
+=
widen
;
}
}
else
{
// consider autoscaling
var
margin
=
autoscaleMargin
;
if
(
margin
!=
null
)
{
if
(
panelMin
==
null
)
{
min
-=
delta
*
margin
;
// make sure we don't go below zero if all values
// are positive
if
(
min
<
0
&&
datamin
!=
null
&&
datamin
>=
0
)
{
min
=
0
;
}
}
if
(
panelMax
==
null
)
{
max
+=
delta
*
margin
;
if
(
max
>
0
&&
datamax
!=
null
&&
datamax
<=
0
)
{
max
=
0
;
}
}
}
}
return
{
min
,
max
};
}
/**
* Calculate tick decimals.
* Implementation from Flot.
*/
export
function
getFlotTickDecimals
(
data
,
axis
)
{
let
{
datamin
,
datamax
}
=
getDataMinMax
(
data
);
let
{
min
,
max
}
=
getFlotRange
(
axis
.
min
,
axis
.
max
,
datamin
,
datamax
);
let
noTicks
=
3
;
let
tickDecimals
,
maxDec
;
let
delta
=
(
max
-
min
)
/
noTicks
;
let
dec
=
-
Math
.
floor
(
Math
.
log
(
delta
)
/
Math
.
LN10
);
let
magn
=
Math
.
pow
(
10
,
-
dec
);
// norm is between 1.0 and 10.0
let
norm
=
delta
/
magn
;
let
size
;
if
(
norm
<
1.5
)
{
size
=
1
;
}
else
if
(
norm
<
3
)
{
size
=
2
;
// special case for 2.5, requires an extra decimal
if
(
norm
>
2.25
&&
(
maxDec
==
null
||
dec
+
1
<=
maxDec
))
{
size
=
2.5
;
++
dec
;
}
}
else
if
(
norm
<
7.5
)
{
size
=
5
;
}
else
{
size
=
10
;
}
size
*=
magn
;
tickDecimals
=
Math
.
max
(
0
,
maxDec
!=
null
?
maxDec
:
dec
);
// grafana addition
const
scaledDecimals
=
tickDecimals
-
Math
.
floor
(
Math
.
log
(
size
)
/
Math
.
LN10
);
return
{
tickDecimals
,
scaledDecimals
};
}
public/app/features/panel/panel_directive.ts
View file @
9f87d8d3
...
...
@@ -20,7 +20,7 @@ var panelTemplate = `
</div>
<div class="panel-content">
<ng-transclude></ng-transclude>
<ng-transclude
class="panel-height-helper"
></ng-transclude>
</div>
</div>
...
...
public/app/plugins/panel/graph/graph.ts
View file @
9f87d8d3
This diff is collapsed.
Click to expand it.
public/app/plugins/panel/graph/legend.
j
s
→
public/app/plugins/panel/graph/legend.
t
s
View file @
9f87d8d3
define
([
'angular'
,
'lodash'
,
'jquery'
,
],
function
(
angular
,
_
,
$
)
{
'use strict'
;
import
angular
from
'angular'
;
import
_
from
'lodash'
;
import
$
from
'jquery'
;
import
PerfectScrollbar
from
'perfect-scrollbar'
;
import
{
updateLegendValues
}
from
'app/core/core'
;
var
module
=
angular
.
module
(
'grafana.directives'
);
var
module
=
angular
.
module
(
'grafana.directives'
);
module
.
directive
(
'graphLegend'
,
function
(
popoverSrv
,
$timeout
)
{
module
.
directive
(
'graphLegend'
,
function
(
popoverSrv
,
$timeout
)
{
return
{
link
:
function
(
scope
,
elem
)
{
var
$container
=
$
(
'<section class="graph-legend"></section>'
);
var
firstRender
=
true
;
var
ctrl
=
scope
.
ctrl
;
var
panel
=
ctrl
.
panel
;
var
data
;
var
seriesList
;
var
i
;
var
legendScrollbar
;
ctrl
.
events
.
on
(
'render'
,
function
()
{
scope
.
$on
(
"$destroy"
,
function
()
{
if
(
!
legendScrollbar
)
{
legendScrollbar
.
destroy
();
}
});
ctrl
.
events
.
on
(
'render-legend'
,
()
=>
{
data
=
ctrl
.
seriesList
;
if
(
data
)
{
render
();
}
ctrl
.
events
.
emit
(
'legend-rendering-complete'
);
});
function
updateLegendDecimals
()
{
updateLegendValues
(
data
,
panel
);
}
function
getSeriesIndexForElement
(
el
)
{
return
el
.
parents
(
'[data-series-index]'
).
data
(
'series-index'
);
}
...
...
@@ -65,9 +74,9 @@ function (angular, _, $) {
var
el
=
$
(
e
.
currentTarget
);
var
index
=
getSeriesIndexForElement
(
el
);
var
seriesInfo
=
seriesList
[
index
];
var
scrollPosition
=
$
(
$container
.
children
(
'tbody'
)).
scrollTop
();
var
scrollPosition
=
$
(
elem
.
children
(
'tbody'
)).
scrollTop
();
ctrl
.
toggleSeries
(
seriesInfo
,
e
);
$
(
$container
.
children
(
'tbody'
)).
scrollTop
(
scrollPosition
);
$
(
elem
.
children
(
'tbody'
)).
scrollTop
(
scrollPosition
);
}
function
sortLegend
(
e
)
{
...
...
@@ -109,22 +118,21 @@ function (angular, _, $) {
}
if
(
firstRender
)
{
elem
.
append
(
$container
);
$container
.
on
(
'click'
,
'.graph-legend-icon'
,
openColorSelector
);
$container
.
on
(
'click'
,
'.graph-legend-alias'
,
toggleSeries
);
$container
.
on
(
'click'
,
'th'
,
sortLegend
);
elem
.
on
(
'click'
,
'.graph-legend-icon'
,
openColorSelector
);
elem
.
on
(
'click'
,
'.graph-legend-alias'
,
toggleSeries
);
elem
.
on
(
'click'
,
'th'
,
sortLegend
);
firstRender
=
false
;
}
seriesList
=
data
;
$container
.
empty
();
elem
.
empty
();
// Set min-width if side style and there is a value, otherwise remove the CSS propery
var
width
=
panel
.
legend
.
rightSide
&&
panel
.
legend
.
sideWidth
?
panel
.
legend
.
sideWidth
+
"px"
:
""
;
$container
.
css
(
"min-width"
,
width
);
elem
.
css
(
"min-width"
,
width
);
$container
.
toggleClass
(
'graph-legend-table'
,
panel
.
legend
.
alignAsTable
===
true
);
elem
.
toggleClass
(
'graph-legend-table'
,
panel
.
legend
.
alignAsTable
===
true
);
var
tableHeaderElem
;
if
(
panel
.
legend
.
alignAsTable
)
{
...
...
@@ -150,9 +158,20 @@ function (angular, _, $) {
}
}
var
seriesShown
=
0
;
var
seriesElements
=
[];
// render first time for getting proper legend height
if
(
!
panel
.
legend
.
rightSide
)
{
renderLegendElement
(
tableHeaderElem
);
updateLegendDecimals
();
elem
.
empty
();
}
else
{
updateLegendDecimals
();
}
renderLegendElement
(
tableHeaderElem
);
}
function
renderSeriesLegendElements
()
{
let
seriesElements
=
[];
for
(
i
=
0
;
i
<
seriesList
.
length
;
i
++
)
{
var
series
=
seriesList
[
i
];
...
...
@@ -187,29 +206,28 @@ function (angular, _, $) {
html
+=
'</div>'
;
seriesElements
.
push
(
$
(
html
));
seriesShown
++
;
}
if
(
panel
.
legend
.
alignAsTable
)
{
var
maxHeight
=
ctrl
.
height
;
if
(
!
panel
.
legend
.
rightSide
)
{
maxHeight
=
maxHeight
/
2
;
return
seriesElements
;
}
var
topPadding
=
6
;
function
renderLegendElement
(
tableHeaderElem
)
{
var
seriesElements
=
renderSeriesLegendElements
();
if
(
panel
.
legend
.
alignAsTable
)
{
var
tbodyElem
=
$
(
'<tbody></tbody>'
);
tbodyElem
.
css
(
"max-height"
,
maxHeight
-
topPadding
);
tbodyElem
.
append
(
tableHeaderElem
);
tbodyElem
.
append
(
seriesElements
);
$container
.
append
(
tbodyElem
);
elem
.
append
(
tbodyElem
);
}
else
{
elem
.
append
(
seriesElements
);
if
(
!
legendScrollbar
)
{
legendScrollbar
=
new
PerfectScrollbar
(
elem
[
0
]);
}
else
{
$container
.
append
(
seriesElements
);
legendScrollbar
.
update
();
}
}
}
}
};
});
});
public/app/plugins/panel/graph/specs/graph_specs.ts
View file @
9f87d8d3
...
...
@@ -87,6 +87,8 @@ describe('grafanaGraph', function() {
$
.
plot
=
ctx
.
plotSpy
=
sinon
.
spy
();
ctrl
.
events
.
emit
(
'render'
,
ctx
.
data
);
ctrl
.
events
.
emit
(
'render-legend'
);
ctrl
.
events
.
emit
(
'legend-rendering-complete'
);
ctx
.
plotData
=
ctx
.
plotSpy
.
getCall
(
0
).
args
[
1
];
ctx
.
plotOptions
=
ctx
.
plotSpy
.
getCall
(
0
).
args
[
2
];
}));
...
...
public/app/plugins/panel/graph/template.ts
View file @
9f87d8d3
var
template
=
`
<div class="graph-wrapper" ng-class="{'graph-legend-rightside': ctrl.panel.legend.rightSide}">
<div class="graph-canvas-wrapper">
<div class="datapoints-warning" ng-if="ctrl.dataWarning">
<span class="small" bs-tooltip="ctrl.dataWarning.tip">{{ctrl.dataWarning.title}}</span>
</div>
<div grafana-graph class="histogram-chart" ng-dblclick="ctrl.zoomOut()">
</div>
<div class="graph-panel" ng-class="{'graph-panel--legend-right': ctrl.panel.legend.rightSide}">
<div class="graph-panel__chart" grafana-graph ng-dblclick="ctrl.zoomOut()">
</div>
<div class="graph-legend-wrapper" graph-legend></div>
</div>
<div class="clearfix"></div>
<div class="graph-legend" graph-legend></div>
</div>
`
;
export
default
template
;
public/sass/components/_panel_graph.scss
View file @
9f87d8d3
.graph-canvas-wrapper
{
position
:
relative
;
cursor
:
crosshair
;
.graph-panel
{
display
:
flex
;
flex-direction
:
column
;
height
:
100%
;
&
--legend-right
{
flex-direction
:
row
;
.graph-legend
{
flex
:
0
1
10px
;
max-height
:
100%
;
}
.graph-legend-series
{
display
:
block
;
padding-left
:
0px
;
}
.graph-legend-table
.graph-legend-series
{
display
:
table-row
;
}
}
}
.
histogram-
chart
{
.
graph-panel__
chart
{
position
:
relative
;
cursor
:
crosshair
;
flex-grow
:
1
;
}
.datapoints-warning
{
...
...
@@ -22,11 +43,12 @@
}
.graph-legend
{
@include
clearfix
();
flex
:
0
1
auto
;
max-height
:
30%
;
margin
:
0
$spacer
;
text-align
:
center
;
width
:
calc
(
100%
-
$spacer
);
padding-top
:
6px
;
position
:
relative
;
.popover-content
{
padding
:
0
;
...
...
@@ -89,7 +111,9 @@
display
:
block
;
overflow-y
:
auto
;
overflow-x
:
hidden
;
height
:
100%
;
padding-bottom
:
1px
;
padding-right
:
5px
;
}
.graph-legend-series
{
...
...
@@ -160,39 +184,6 @@
}
}
.graph-legend-rightside
{
&
.graph-wrapper
{
display
:
table
;
width
:
100%
;
}
.graph-canvas-wrapper
{
display
:
table-cell
;
width
:
100%
;
position
:
relative
;
}
.graph-legend-wrapper
{
display
:
table-cell
;
vertical-align
:
top
;
position
:
relative
;
left
:
4px
;
}
.graph-legend
{
margin
:
0
0
0
1rem
;
}
.graph-legend-series
{
display
:
block
;
padding-left
:
0px
;
}
.graph-legend-table
.graph-legend-series
{
display
:
table-row
;
}
}
.graph-legend-series-hidden
{
.graph-legend-value
,
...
...
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