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
18a90667
Commit
18a90667
authored
Mar 07, 2018
by
Alexander Zobnin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
heatmap: refactor
parent
a791a92d
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
109 additions
and
88 deletions
+109
-88
public/app/core/utils/ticks.ts
+58
-0
public/app/plugins/panel/heatmap/heatmap_ctrl.ts
+17
-2
public/app/plugins/panel/heatmap/heatmap_data_converter.ts
+7
-3
public/app/plugins/panel/heatmap/heatmap_tooltip.ts
+7
-25
public/app/plugins/panel/heatmap/rendering.ts
+20
-58
No files found.
public/app/core/utils/ticks.ts
View file @
18a90667
...
...
@@ -156,3 +156,61 @@ export function getFlotTickDecimals(data, axis) {
const
scaledDecimals
=
tickDecimals
-
Math
.
floor
(
Math
.
log
(
size
)
/
Math
.
LN10
);
return
{
tickDecimals
,
scaledDecimals
};
}
/**
* Format timestamp similar to Grafana graph panel.
* @param ticks Number of ticks
* @param min Time from (in milliseconds)
* @param max Time to (in milliseconds)
*/
export
function
grafanaTimeFormat
(
ticks
,
min
,
max
)
{
if
(
min
&&
max
&&
ticks
)
{
let
range
=
max
-
min
;
let
secPerTick
=
range
/
ticks
/
1000
;
let
oneDay
=
86400000
;
let
oneYear
=
31536000000
;
if
(
secPerTick
<=
45
)
{
return
'%H:%M:%S'
;
}
if
(
secPerTick
<=
7200
||
range
<=
oneDay
)
{
return
'%H:%M'
;
}
if
(
secPerTick
<=
80000
)
{
return
'%m/%d %H:%M'
;
}
if
(
secPerTick
<=
2419200
||
range
<=
oneYear
)
{
return
'%m/%d'
;
}
return
'%Y-%m'
;
}
return
'%H:%M'
;
}
/**
* Logarithm of value for arbitrary base.
*/
export
function
logp
(
value
,
base
)
{
return
Math
.
log
(
value
)
/
Math
.
log
(
base
);
}
/**
* Get decimal precision of number (3.14 => 2)
*/
export
function
getPrecision
(
num
:
number
):
number
{
let
str
=
num
.
toString
();
return
getStringPrecision
(
str
);
}
/**
* Get decimal precision of number stored as a string ("3.14" => 2)
*/
export
function
getStringPrecision
(
num
:
string
):
number
{
let
dot_index
=
num
.
indexOf
(
'.'
);
if
(
dot_index
===
-
1
)
{
return
0
;
}
else
{
return
num
.
length
-
dot_index
-
1
;
}
}
public/app/plugins/panel/heatmap/heatmap_ctrl.ts
View file @
18a90667
...
...
@@ -89,6 +89,8 @@ let colorSchemes = [
{
name
:
'YlOrRd'
,
value
:
'interpolateYlOrRd'
,
invert
:
'darm'
},
];
const
ds_support_histogram_sort
=
[
'prometheus'
,
'elasticsearch'
];
export
class
HeatmapCtrl
extends
MetricsPanelCtrl
{
static
templateUrl
=
'module.html'
;
...
...
@@ -207,15 +209,20 @@ export class HeatmapCtrl extends MetricsPanelCtrl {
}
convertHistogramToHeatmapData
()
{
const
panelDatasource
=
this
.
getPanelDataSourceType
();
let
xBucketSize
,
yBucketSize
,
bucketsData
,
tsBuckets
;
// Try to sort series by bucket bound, if datasource doesn't do it.
if
(
!
_
.
includes
(
ds_support_histogram_sort
,
panelDatasource
))
{
this
.
series
.
sort
(
sortSeriesByLabel
);
}
// Convert histogram to heatmap. Each histogram bucket represented by the series which name is
// a top (or bottom, depends of datasource) bucket bound. Further, these values will be used as X axis labels.
this
.
series
.
sort
(
sortSeriesByLabel
);
bucketsData
=
histogramToHeatmap
(
this
.
series
);
tsBuckets
=
_
.
map
(
this
.
series
,
'label'
);
if
(
this
.
datasource
&&
this
.
datasource
.
typ
e
===
'prometheus'
)
{
if
(
panelDatasourc
e
===
'prometheus'
)
{
// Prometheus labels are upper inclusive bounds, so add empty bottom bucket label.
tsBuckets
=
[
''
].
concat
(
tsBuckets
);
}
else
{
...
...
@@ -241,6 +248,14 @@ export class HeatmapCtrl extends MetricsPanelCtrl {
};
}
getPanelDataSourceType
()
{
if
(
this
.
datasource
.
meta
&&
this
.
datasource
.
meta
.
id
)
{
return
this
.
datasource
.
meta
.
id
;
}
else
{
return
'unknown'
;
}
}
onDataReceived
(
dataList
)
{
this
.
series
=
dataList
.
map
(
this
.
seriesHandler
.
bind
(
this
));
...
...
public/app/plugins/panel/heatmap/heatmap_data_converter.ts
View file @
18a90667
...
...
@@ -67,7 +67,7 @@ function sortSeriesByLabel(s1, s2) {
label1
=
parseHistogramLabel
(
s1
.
label
);
label2
=
parseHistogramLabel
(
s2
.
label
);
}
catch
(
err
)
{
console
.
log
(
err
);
console
.
log
(
err
.
message
||
err
);
return
0
;
}
...
...
@@ -83,10 +83,14 @@ function sortSeriesByLabel(s1, s2) {
}
function
parseHistogramLabel
(
label
:
string
):
number
{
if
(
label
===
'+Inf'
)
{
if
(
label
===
'+Inf'
||
label
===
'inf'
)
{
return
+
Infinity
;
}
return
Number
(
label
);
const
value
=
Number
(
label
);
if
(
isNaN
(
value
))
{
throw
new
Error
(
`Error parsing histogram label:
${
label
}
is not a number`
);
}
return
value
;
}
/**
...
...
public/app/plugins/panel/heatmap/heatmap_tooltip.ts
View file @
18a90667
...
...
@@ -100,14 +100,14 @@ export class HeatmapTooltip {
let
countValueFormatter
,
bucketBoundFormatter
;
if
(
_
.
isNumber
(
this
.
panel
.
tooltipDecimals
))
{
countValueFormatter
=
this
.
countValueFormatter
(
this
.
panel
.
tooltipDecimals
,
null
);
bucketBoundFormatter
=
this
.
bucketBoundFormatter
(
this
.
panel
.
tooltipD
ecimals
,
null
);
bucketBoundFormatter
=
this
.
panelCtrl
.
tickValueFormatter
(
this
.
panelCtrl
.
d
ecimals
,
null
);
}
else
{
// auto decimals
// legend and tooltip gets one more decimal precision
// than graph legend ticks
let
decimals
=
(
this
.
panelCtrl
.
decimals
||
-
1
)
+
1
;
countValueFormatter
=
this
.
countValueFormatter
(
decimals
,
this
.
panelCtrl
.
scaledDecimals
+
2
);
bucketBoundFormatter
=
this
.
bucketBound
Formatter
(
decimals
,
this
.
panelCtrl
.
scaledDecimals
+
2
);
bucketBoundFormatter
=
this
.
panelCtrl
.
tickValue
Formatter
(
decimals
,
this
.
panelCtrl
.
scaledDecimals
+
2
);
}
let
tooltipHtml
=
`<div class="graph-tooltip-time">
${
time
}
</div>
...
...
@@ -116,19 +116,13 @@ export class HeatmapTooltip {
if
(
yData
)
{
if
(
yData
.
bounds
)
{
if
(
data
.
tsBuckets
)
{
const
decimals
=
this
.
panelCtrl
.
decimals
||
0
;
// Use Y-axis labels
const
tickFormatter
=
valIndex
=>
{
let
valueFormatted
=
data
.
tsBuckets
[
valIndex
];
if
(
!
_
.
isNaN
(
_
.
toNumber
(
valueFormatted
))
&&
valueFormatted
!==
''
)
{
// Try to format numeric tick labels
valueFormatted
=
this
.
bucketBoundFormatter
(
decimals
)(
_
.
toNumber
(
valueFormatted
));
}
return
valueFormatted
;
return
data
.
tsBucketsFormatted
?
data
.
tsBucketsFormatted
[
valIndex
]
:
data
.
tsBuckets
[
valIndex
];
};
const
tsBucketsTickFormatter
=
tickFormatter
.
bind
(
this
);
boundBottom
=
t
sBucketsT
ickFormatter
(
yBucketIndex
);
boundTop
=
yBucketIndex
<
data
.
tsBuckets
.
length
-
1
?
t
sBucketsT
ickFormatter
(
yBucketIndex
+
1
)
:
''
;
boundBottom
=
tickFormatter
(
yBucketIndex
);
boundTop
=
yBucketIndex
<
data
.
tsBuckets
.
length
-
1
?
tickFormatter
(
yBucketIndex
+
1
)
:
''
;
}
else
{
// Display 0 if bucket is a special 'zero' bucket
let
bottom
=
yData
.
y
?
yData
.
bounds
.
bottom
:
0
;
...
...
@@ -282,21 +276,9 @@ export class HeatmapTooltip {
}
countValueFormatter
(
decimals
,
scaledDecimals
=
null
)
{
let
format
=
'
none
'
;
let
format
=
'
short
'
;
return
function
(
value
)
{
return
kbn
.
valueFormats
[
format
](
value
,
decimals
,
scaledDecimals
);
};
}
bucketBoundFormatter
(
decimals
,
scaledDecimals
=
null
)
{
let
format
=
this
.
panel
.
yAxis
.
format
;
return
function
(
value
)
{
try
{
return
format
!==
'none'
?
kbn
.
valueFormats
[
format
](
value
,
decimals
,
scaledDecimals
)
:
value
;
}
catch
(
err
)
{
console
.
error
(
err
.
message
||
err
);
return
value
;
}
};
}
}
public/app/plugins/panel/heatmap/rendering.ts
View file @
18a90667
...
...
@@ -4,7 +4,7 @@ import moment from 'moment';
import
*
as
d3
from
'd3'
;
import
kbn
from
'app/core/utils/kbn'
;
import
{
appEvents
,
contextSrv
}
from
'app/core/core'
;
import
{
tickStep
,
getScaledDecimals
,
getFlotTickSize
}
from
'app/core/utils/ticks'
;
import
*
as
ticksUtils
from
'app/core/utils/ticks'
;
import
{
HeatmapTooltip
}
from
'./heatmap_tooltip'
;
import
{
mergeZeroBuckets
}
from
'./heatmap_data_converter'
;
import
{
getColorScale
,
getOpacityScale
}
from
'./color_scale'
;
...
...
@@ -108,7 +108,7 @@ export default function link(scope, elem, attrs, ctrl) {
.
range
([
0
,
chartWidth
]);
let
ticks
=
chartWidth
/
DEFAULT_X_TICK_SIZE_PX
;
let
grafanaTimeFormatter
=
grafanaTimeFormat
(
ticks
,
timeRange
.
from
,
timeRange
.
to
);
let
grafanaTimeFormatter
=
ticksUtils
.
grafanaTimeFormat
(
ticks
,
timeRange
.
from
,
timeRange
.
to
);
let
timeFormat
;
let
dashboardTimeZone
=
ctrl
.
dashboard
.
getTimezone
();
if
(
dashboardTimeZone
===
'utc'
)
{
...
...
@@ -141,7 +141,7 @@ export default function link(scope, elem, attrs, ctrl) {
function
addYAxis
()
{
let
ticks
=
Math
.
ceil
(
chartHeight
/
DEFAULT_Y_TICK_SIZE_PX
);
let
tick_interval
=
tickStep
(
data
.
heatmapStats
.
min
,
data
.
heatmapStats
.
max
,
ticks
);
let
tick_interval
=
tick
sUtils
.
tick
Step
(
data
.
heatmapStats
.
min
,
data
.
heatmapStats
.
max
,
ticks
);
let
{
y_min
,
y_max
}
=
wideYAxisRange
(
data
.
heatmapStats
.
min
,
data
.
heatmapStats
.
max
,
tick_interval
);
// Rewrite min and max if it have been set explicitly
...
...
@@ -149,14 +149,14 @@ export default function link(scope, elem, attrs, ctrl) {
y_max
=
panel
.
yAxis
.
max
!==
null
?
panel
.
yAxis
.
max
:
y_max
;
// Adjust ticks after Y range widening
tick_interval
=
tickStep
(
y_min
,
y_max
,
ticks
);
tick_interval
=
tick
sUtils
.
tick
Step
(
y_min
,
y_max
,
ticks
);
ticks
=
Math
.
ceil
((
y_max
-
y_min
)
/
tick_interval
);
let
decimalsAuto
=
getPrecision
(
tick_interval
);
let
decimalsAuto
=
ticksUtils
.
getPrecision
(
tick_interval
);
let
decimals
=
panel
.
yAxis
.
decimals
===
null
?
decimalsAuto
:
panel
.
yAxis
.
decimals
;
// Calculate scaledDecimals for log scales using tick size (as in jquery.flot.js)
let
flot_tick_size
=
getFlotTickSize
(
y_min
,
y_max
,
ticks
,
decimalsAuto
);
let
scaledDecimals
=
getScaledDecimals
(
decimals
,
flot_tick_size
);
let
flot_tick_size
=
ticksUtils
.
getFlotTickSize
(
y_min
,
y_max
,
ticks
,
decimalsAuto
);
let
scaledDecimals
=
ticksUtils
.
getScaledDecimals
(
decimals
,
flot_tick_size
);
ctrl
.
decimals
=
decimals
;
ctrl
.
scaledDecimals
=
scaledDecimals
;
...
...
@@ -248,12 +248,12 @@ export default function link(scope, elem, attrs, ctrl) {
let
domain
=
yScale
.
domain
();
let
tick_values
=
logScaleTickValues
(
domain
,
log_base
);
let
decimalsAuto
=
getPrecision
(
y_min
);
let
decimalsAuto
=
ticksUtils
.
getPrecision
(
y_min
);
let
decimals
=
panel
.
yAxis
.
decimals
||
decimalsAuto
;
// Calculate scaledDecimals for log scales using tick size (as in jquery.flot.js)
let
flot_tick_size
=
getFlotTickSize
(
y_min
,
y_max
,
tick_values
.
length
,
decimalsAuto
);
let
scaledDecimals
=
getScaledDecimals
(
decimals
,
flot_tick_size
);
let
flot_tick_size
=
ticksUtils
.
getFlotTickSize
(
y_min
,
y_max
,
tick_values
.
length
,
decimalsAuto
);
let
scaledDecimals
=
ticksUtils
.
getScaledDecimals
(
decimals
,
flot_tick_size
);
ctrl
.
decimals
=
decimals
;
ctrl
.
scaledDecimals
=
scaledDecimals
;
...
...
@@ -305,7 +305,7 @@ export default function link(scope, elem, attrs, ctrl) {
.
range
([
chartHeight
,
0
]);
const
tick_values
=
_
.
map
(
tsBuckets
,
(
b
,
i
)
=>
i
);
const
decimalsAuto
=
_
.
max
(
_
.
map
(
tsBuckets
,
getStringPrecision
));
const
decimalsAuto
=
_
.
max
(
_
.
map
(
tsBuckets
,
ticksUtils
.
getStringPrecision
));
const
decimals
=
panel
.
yAxis
.
decimals
===
null
?
decimalsAuto
:
panel
.
yAxis
.
decimals
;
ctrl
.
decimals
=
decimals
;
...
...
@@ -318,6 +318,9 @@ export default function link(scope, elem, attrs, ctrl) {
return
valueFormatted
;
}
const
tsBucketsFormatted
=
_
.
map
(
tsBuckets
,
(
v
,
i
)
=>
tickFormatter
(
i
));
data
.
tsBucketsFormatted
=
tsBucketsFormatted
;
let
yAxis
=
d3
.
axisLeft
(
yScale
)
.
tickValues
(
tick_values
)
...
...
@@ -361,11 +364,11 @@ export default function link(scope, elem, attrs, ctrl) {
}
function
adjustLogMax
(
max
,
base
)
{
return
Math
.
pow
(
base
,
Math
.
ceil
(
logp
(
max
,
base
)));
return
Math
.
pow
(
base
,
Math
.
ceil
(
ticksUtils
.
logp
(
max
,
base
)));
}
function
adjustLogMin
(
min
,
base
)
{
return
Math
.
pow
(
base
,
Math
.
floor
(
logp
(
min
,
base
)));
return
Math
.
pow
(
base
,
Math
.
floor
(
ticksUtils
.
logp
(
min
,
base
)));
}
function
logScaleTickValues
(
domain
,
base
)
{
...
...
@@ -374,14 +377,14 @@ export default function link(scope, elem, attrs, ctrl) {
let
tickValues
=
[];
if
(
domainMin
<
1
)
{
let
under_one_ticks
=
Math
.
floor
(
logp
(
domainMin
,
base
));
let
under_one_ticks
=
Math
.
floor
(
ticksUtils
.
logp
(
domainMin
,
base
));
for
(
let
i
=
under_one_ticks
;
i
<
0
;
i
++
)
{
let
tick_value
=
Math
.
pow
(
base
,
i
);
tickValues
.
push
(
tick_value
);
}
}
let
ticks
=
Math
.
ceil
(
logp
(
domainMax
,
base
));
let
ticks
=
Math
.
ceil
(
ticksUtils
.
logp
(
domainMax
,
base
));
for
(
let
i
=
0
;
i
<=
ticks
;
i
++
)
{
let
tick_value
=
Math
.
pow
(
base
,
i
);
tickValues
.
push
(
tick_value
);
...
...
@@ -402,6 +405,8 @@ export default function link(scope, elem, attrs, ctrl) {
};
}
ctrl
.
tickValueFormatter
=
tickValueFormatter
;
function
fixYAxisTickSize
()
{
heatmap
.
select
(
'.axis-y'
)
...
...
@@ -827,46 +832,3 @@ export default function link(scope, elem, attrs, ctrl) {
$heatmap
.
on
(
'mousemove'
,
onMouseMove
);
$heatmap
.
on
(
'mouseleave'
,
onMouseLeave
);
}
function
grafanaTimeFormat
(
ticks
,
min
,
max
)
{
if
(
min
&&
max
&&
ticks
)
{
let
range
=
max
-
min
;
let
secPerTick
=
range
/
ticks
/
1000
;
let
oneDay
=
86400000
;
let
oneYear
=
31536000000
;
if
(
secPerTick
<=
45
)
{
return
'%H:%M:%S'
;
}
if
(
secPerTick
<=
7200
||
range
<=
oneDay
)
{
return
'%H:%M'
;
}
if
(
secPerTick
<=
80000
)
{
return
'%m/%d %H:%M'
;
}
if
(
secPerTick
<=
2419200
||
range
<=
oneYear
)
{
return
'%m/%d'
;
}
return
'%Y-%m'
;
}
return
'%H:%M'
;
}
function
logp
(
value
,
base
)
{
return
Math
.
log
(
value
)
/
Math
.
log
(
base
);
}
function
getPrecision
(
num
:
number
):
number
{
let
str
=
num
.
toString
();
return
getStringPrecision
(
str
);
}
function
getStringPrecision
(
num
:
string
):
number
{
let
dot_index
=
num
.
indexOf
(
'.'
);
if
(
dot_index
===
-
1
)
{
return
0
;
}
else
{
return
num
.
length
-
dot_index
-
1
;
}
}
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