mirror of
https://github.com/timberjoegithub/grafana-statusmap.git
synced 2026-07-21 23:42:03 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bccc3320a8 | ||
|
|
5d7cf54348 | ||
|
|
1f43ffe158 | ||
|
|
c7882402ce | ||
|
|
09cdd2f224 | ||
|
|
0a8463e2ed | ||
|
|
4d952a841b | ||
|
|
36e907f8b6 | ||
|
|
af55883905 | ||
|
|
afec01cb93 |
@@ -1,2 +1,4 @@
|
|||||||
node_modules
|
node_modules
|
||||||
.jshintrc
|
.jshintrc
|
||||||
|
.idea
|
||||||
|
.sass-cache
|
||||||
|
|||||||
+2
-1
@@ -53,7 +53,8 @@ module.exports = (grunt) => {
|
|||||||
sass: {
|
sass: {
|
||||||
dist: {
|
dist: {
|
||||||
files: {
|
files: {
|
||||||
'dist/css/status-heatmap.css': 'src/css/status-heatmap.scss'
|
'dist/css/statusmap.dark.css': 'src/css/statusmap.dark.scss',
|
||||||
|
'dist/css/statusmap.light.css': 'src/css/statusmap.light.scss'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,14 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* Grouping values into rows and buckets using legend from query
|
* Grouping values into rows and buckets using legend from query
|
||||||
* User defined color mapping
|
* User defined color mapping
|
||||||
* Multiple values in bucket can be displayed via tooltip
|
* Multiple values in bucket are displayed via tooltip
|
||||||
* Increasing rows/buckets' interval for better visual representation
|
* Increasing rows/buckets' interval for better visual representation
|
||||||
* Representing null values as empty bucket or zero value
|
* Representing null values as empty bucket or zero value
|
||||||
|
|
||||||
@@ -17,7 +20,7 @@
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Plugin can be installed via Git:
|
Plugin can be installed with GF_INSTALL_PLUGINS="flant-statusmap-panel" or you can use Git and clone this repo:
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone git@github.com:flant/grafana-statusmap.git /var/lib/grafana/plugins/flant-statusmap-panel
|
git clone git@github.com:flant/grafana-statusmap.git /var/lib/grafana/plugins/flant-statusmap-panel
|
||||||
@@ -26,15 +29,19 @@ git clone git@github.com:flant/grafana-statusmap.git /var/lib/grafana/plugins/fl
|
|||||||
Alternatively, you can download [ZIP archive](https://github.com/flant/grafana-statusmap/archive/master.zip)
|
Alternatively, you can download [ZIP archive](https://github.com/flant/grafana-statusmap/archive/master.zip)
|
||||||
of this repo and unpack it into /var/lib/grafana/plugins directory.
|
of this repo and unpack it into /var/lib/grafana/plugins directory.
|
||||||
|
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
We had a desperate need to show a set of timeseries statuses over time period, so we can see
|
We had a desperate need to visualize a set of timeseries statuses over time period, so we can
|
||||||
a history of changes for objects' statuses. Since we maintain a lot of Kubernetes clusters
|
see a history of changes for objects' status. Since we maintain a lot of Kubernetes clusters
|
||||||
(and related infrastructure), our main cases for that are visualization of servers & Kubernetes
|
(and related infrastructure), our main cases for that are visualization of servers & Kubernetes
|
||||||
pods health states as well as HTTP services health checks. We've tried a variety of Grafana
|
pods health states as well as HTTP services health checks. We've tried a variety of Grafana
|
||||||
plugins available (they are listed in *Acknowledgements* below) but none of them could provide
|
plugins available (they are listed in *Acknowledgements* below) but none of them could provide
|
||||||
the features and visualization really close to what we've been looking for.
|
the features and visualization really close to what we've been looking for.
|
||||||
|
|
||||||
|
_NB: You can find more details about our journey of creating the plugin in
|
||||||
|
[this post](https://medium.com/flant-com/statusmap-grafana-plugin-to-visualize-status-over-time-fe6ced391853)._
|
||||||
|
|
||||||
_Objects_ being visualized with this plugin may be different: not only IT components (e.g. server
|
_Objects_ being visualized with this plugin may be different: not only IT components (e.g. server
|
||||||
hosts and Kubernetes pods) but just anything you can imagine like coffee makers on the picture
|
hosts and Kubernetes pods) but just anything you can imagine like coffee makers on the picture
|
||||||
above. These objects should have _discrete statuses_ which are sets of predefined values, e.g.
|
above. These objects should have _discrete statuses_ which are sets of predefined values, e.g.
|
||||||
@@ -44,7 +51,7 @@ above. These objects should have _discrete statuses_ which are sets of predefine
|
|||||||
|
|
||||||
### Prometheus
|
### Prometheus
|
||||||
|
|
||||||
To work with data from Prometheus you will need to setup discrete statuses of your objects.
|
To work with data from Prometheus you will need to setup discrete statuses for your objects.
|
||||||
Requirements to store these statuses in metrics are as follows:
|
Requirements to store these statuses in metrics are as follows:
|
||||||
* metrics should have two values: `0` and `1`;
|
* metrics should have two values: `0` and `1`;
|
||||||
* there should be a label with status' value.
|
* there should be a label with status' value.
|
||||||
@@ -58,8 +65,8 @@ When it's done, you can collect all the data via query, e.g.:
|
|||||||
If there was no such status (`<STATUS_VALUE>`) during query's interval, Prometheus would
|
If there was no such status (`<STATUS_VALUE>`) during query's interval, Prometheus would
|
||||||
return nothing. Otherwise, status' value will be returned.
|
return nothing. Otherwise, status' value will be returned.
|
||||||
|
|
||||||
For example, if you have 5 statuses and a metric (`coffee_maker_status`) with 5 allowed
|
For example, if you have 5 types of statuses and a metric (`coffee_maker_status`) with 5
|
||||||
values (`0`, `1`, `2`, `3`, `4`), you should transform this metric using the following rule:
|
allowed values (`0`, `1`, `2`, `3`, `4`), you should transform this metric using following rule:
|
||||||
|
|
||||||
```
|
```
|
||||||
- record: coffee_maker_status:discrete
|
- record: coffee_maker_status:discrete
|
||||||
@@ -137,7 +144,13 @@ This plugin is based on "Heatmap" panel by Grafana and partly inspired by ideas
|
|||||||
|
|
||||||
#### Changelog
|
#### Changelog
|
||||||
|
|
||||||
|
##### v0.0.2
|
||||||
|
|
||||||
|
- Install with GF_INSTALL_PLUGINS
|
||||||
|
- Fix legend overlap
|
||||||
|
|
||||||
##### v0.0.1
|
##### v0.0.1
|
||||||
|
|
||||||
- First public release
|
- First public release
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Vendored
+83
-25
@@ -2,13 +2,16 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* Group values into rows and buckets by query's legend
|
* Grouping values into rows and buckets using legend from query
|
||||||
* User defined color mapping
|
* User defined color mapping
|
||||||
* Multiple values in bucket display in tooltip
|
* Multiple values in bucket are displayed via tooltip
|
||||||
* Interval shaping to better visual representation
|
* Increasing rows/buckets' interval for better visual representation
|
||||||
* Represent null values as empty bucket or as zero value
|
* Representing null values as empty bucket or zero value
|
||||||
|
|
||||||
### Supported environment
|
### Supported environment
|
||||||
|
|
||||||
@@ -17,59 +20,107 @@
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Plugin can be installed with git:
|
Plugin can be installed with GF_INSTALL_PLUGINS="flant-statusmap-panel" or you can use Git and clone this repo:
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone git@github.com:flant/grafana-statusmap.git /var/lib/grafana/plugins/flant-statusmap-panel
|
git clone git@github.com:flant/grafana-statusmap.git /var/lib/grafana/plugins/flant-statusmap-panel
|
||||||
```
|
```
|
||||||
|
|
||||||
Or you can download ZIP archive of this repo and unpack it into /var/lib/grafana/plugins directory.
|
Alternatively, you can download [ZIP archive](https://github.com/flant/grafana-statusmap/archive/master.zip)
|
||||||
|
of this repo and unpack it into /var/lib/grafana/plugins directory.
|
||||||
|
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
This plugin emerges from our needs to visually represent history of changes for a set of objects
|
We had a desperate need to visualize a set of timeseries statuses over time period, so we can
|
||||||
with discrete statuses.
|
see a history of changes for objects' status. Since we maintain a lot of Kubernetes clusters
|
||||||
_Objects_ can be hosts, Kubernetes pods or coffee makers and _discrete statuses_ are a set
|
(and related infrastructure), our main cases for that are visualization of servers & Kubernetes
|
||||||
of predefined values: something like `ok` = 0, `off` = 1, `fail` = 2.
|
pods health states as well as HTTP services health checks. We've tried a variety of Grafana
|
||||||
|
plugins available (they are listed in *Acknowledgements* below) but none of them could provide
|
||||||
|
the features and visualization really close to what we've been looking for.
|
||||||
|
|
||||||
|
_NB: You can find more details about our journey of creating the plugin in
|
||||||
|
[this post](https://medium.com/flant-com/statusmap-grafana-plugin-to-visualize-status-over-time-fe6ced391853)._
|
||||||
|
|
||||||
|
_Objects_ being visualized with this plugin may be different: not only IT components (e.g. server
|
||||||
|
hosts and Kubernetes pods) but just anything you can imagine like coffee makers on the picture
|
||||||
|
above. These objects should have _discrete statuses_ which are sets of predefined values, e.g.
|
||||||
|
`ok` = 0, `off` = 1, `fail` = 2, etc.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
Recommended setup is to create query for each possible status value with similar legend:
|
### Prometheus
|
||||||
|
|
||||||
|
To work with data from Prometheus you will need to setup discrete statuses for your objects.
|
||||||
|
Requirements to store these statuses in metrics are as follows:
|
||||||
|
* metrics should have two values: `0` and `1`;
|
||||||
|
* there should be a label with status' value.
|
||||||
|
|
||||||
|
When it's done, you can collect all the data via query, e.g.:
|
||||||
|
|
||||||
|
```
|
||||||
|
(max_over_time(coffee_maker_status{status="<STATUS_VALUE>"}[$__interval]) == 1) * <STATUS_VALUE>
|
||||||
|
```
|
||||||
|
|
||||||
|
If there was no such status (`<STATUS_VALUE>`) during query's interval, Prometheus would
|
||||||
|
return nothing. Otherwise, status' value will be returned.
|
||||||
|
|
||||||
|
For example, if you have 5 types of statuses and a metric (`coffee_maker_status`) with 5
|
||||||
|
allowed values (`0`, `1`, `2`, `3`, `4`), you should transform this metric using following rule:
|
||||||
|
|
||||||
|
```
|
||||||
|
- record: coffee_maker_status:discrete
|
||||||
|
expr: |
|
||||||
|
count_values("status", coffee_maker_status)
|
||||||
|
```
|
||||||
|
|
||||||
|
That's how `coffee_maker_status` metric with value `3` will be transformed into new metric:
|
||||||
|
|
||||||
|
```
|
||||||
|
coffee_maker_status:discrete{status="3"} 1
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, when Prometheus has `0` and `1` values for each status, all these metrics can be
|
||||||
|
aggregated, so you will get all available statuses of your objects over time.
|
||||||
|
|
||||||
|
### Panel
|
||||||
|
|
||||||
|
First of all, an individual query for each possible status' value should be created.
|
||||||
|
Each query should also have similar legend for grouping:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Next define color mapping for status values in __Discrete__ color mode.
|
Then, color mapping for status' values should be defined in __Discrete__ color mode:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
_Note: __Spectrum__ and __Opacity__ color modes function the same way they do in [Heatmap](https://grafana.com/plugins/heatmap) plugin._
|
||||||
__Spectrum__ and __Opacity__ color modes works as in a [Heatmap](https://grafana.com/plugins/heatmap) plugin.
|
|
||||||
|
|
||||||
|
|
||||||
### More options
|
### More options
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
__Multiple values__ check determine multiple values display mode. If check is unset then multiple values
|
__Multiple values__ checkbox specifies how they should be displayed:
|
||||||
for one bucket treated as error. If check is on then color for bucket determined
|
* If it's off, multiple values for one bucket are treated as error;
|
||||||
by value with least index in color mapping.
|
* If it's on, color for such bucket would be determined by the value having least index in color mapping.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
__Null values__ can be treated as empty buckets or displayed as color of 0 value.
|
__Null values__ can be treated as empty buckets or displayed with the color of `0` value.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
__Min width__ and __spacing__ are determine minimal bucket width and spacing between buckets.
|
__Min width__ and __spacing__ are used to specify minimal bucket width and spacing between buckets.
|
||||||
__Rounding__ is for round edges.
|
__Rounding__ may be used to round edges.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
The easy way to test and develop plugin is to run Grafana instance in docker with following command in the directory containing the plugin.
|
To test and improve the plugin you can run Grafana instance in Docker using following command (in
|
||||||
This will expose the local plugin on your machine to the Grafana container.
|
the directory containing Statusmap plugin):
|
||||||
|
|
||||||
```
|
```
|
||||||
docker run --rm -it -v $PWD:/var/lib/grafana/plugins/flant-statusmap-panel \
|
docker run --rm -it -v $PWD:/var/lib/grafana/plugins/flant-statusmap-panel \
|
||||||
@@ -78,7 +129,8 @@ docker run --rm -it -v $PWD:/var/lib/grafana/plugins/flant-statusmap-panel \
|
|||||||
grafana/grafana:5.1.3
|
grafana/grafana:5.1.3
|
||||||
```
|
```
|
||||||
|
|
||||||
Now run `grunt` to compile dist directory and start changes watcher:
|
This will expose local plugin from your machine to Grafana container. Now run `grunt` to compile
|
||||||
|
dist directory and start changes watcher:
|
||||||
|
|
||||||
```
|
```
|
||||||
grunt watch
|
grunt watch
|
||||||
@@ -86,13 +138,19 @@ grunt watch
|
|||||||
|
|
||||||
## Acknowledgements
|
## Acknowledgements
|
||||||
|
|
||||||
Idea of a plugin comes from Dmitry Stolyarov @distol, initial version written by Sergey Gnuskov @gsmetal and final changes made by Ivan Mikheykin @diafour.
|
The first public release of this plugin has been fully made by [Flant](https://flant.com/) engineers. The whole idea has come from Dmitry Stolyarov ([@distol](https://github.com/distol)), initial version has been written by Sergey Gnuskov ([@gsmetal](https://github.com/gsmetal)) and final changes has been made by Ivan Mikheykin ([@diafour](https://github.com/diafour)).
|
||||||
|
|
||||||
This plugin is based on a "Heatmap" panel by Grafana and inspired by ideas from Carpet plot, Discrete panel, Status Panel, Status Dot, Status By Group.
|
This plugin is based on "Heatmap" panel by Grafana and partly inspired by ideas from Carpet plot, Discrete panel, Status Panel, Status Dot, Status By Group.
|
||||||
|
|
||||||
#### Changelog
|
#### Changelog
|
||||||
|
|
||||||
|
##### v0.0.2
|
||||||
|
|
||||||
|
- Install with GF_INSTALL_PLUGINS
|
||||||
|
- Fix legend overlap
|
||||||
|
|
||||||
##### v0.0.1
|
##### v0.0.1
|
||||||
|
|
||||||
- First public release
|
- First public release
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Vendored
+8
-6
@@ -10,7 +10,7 @@ System.register(['angular', 'lodash', 'jquery', 'd3', './libs/d3-scale-chromatic
|
|||||||
var legend = d3.select(legendElem.get(0));
|
var legend = d3.select(legendElem.get(0));
|
||||||
clearLegend(elem);
|
clearLegend(elem);
|
||||||
|
|
||||||
var legendWidth = Math.floor(legendElem.outerWidth()) - 30;
|
var legendWidth = Math.floor(legendElem.outerWidth()) - 30; // narrow legendWidth by 30px to get space for first and last tick values
|
||||||
var legendHeight = legendElem.attr("height");
|
var legendHeight = legendElem.attr("height");
|
||||||
|
|
||||||
var rangeStep = 1;
|
var rangeStep = 1;
|
||||||
@@ -27,8 +27,9 @@ System.register(['angular', 'lodash', 'jquery', 'd3', './libs/d3-scale-chromatic
|
|||||||
|
|
||||||
var colorScale = getColorScale(colorScheme, maxValue, minValue);
|
var colorScale = getColorScale(colorScheme, maxValue, minValue);
|
||||||
legend.selectAll(".status-heatmap-color-legend-rect").data(valuesRange).enter().append("rect").attr("x", function (d) {
|
legend.selectAll(".status-heatmap-color-legend-rect").data(valuesRange).enter().append("rect").attr("x", function (d) {
|
||||||
return d * widthFactor;
|
return d * widthFactor + 10;
|
||||||
}).attr("y", 0).attr("width", rangeStep * widthFactor + 1) // Overlap rectangles to prevent gaps
|
}) // shift all color rectangles to the right
|
||||||
|
.attr("y", 0).attr("width", rangeStep * widthFactor + 1) // Overlap rectangles to prevent gaps
|
||||||
.attr("height", legendHeight).attr("stroke-width", 0).attr("fill", function (d) {
|
.attr("height", legendHeight).attr("stroke-width", 0).attr("fill", function (d) {
|
||||||
return colorScale(d);
|
return colorScale(d);
|
||||||
});
|
});
|
||||||
@@ -41,7 +42,7 @@ System.register(['angular', 'lodash', 'jquery', 'd3', './libs/d3-scale-chromatic
|
|||||||
var legend = d3.select(legendElem.get(0));
|
var legend = d3.select(legendElem.get(0));
|
||||||
clearLegend(elem);
|
clearLegend(elem);
|
||||||
|
|
||||||
var legendWidth = Math.floor(legendElem.outerWidth()) - 30;
|
var legendWidth = Math.floor(legendElem.outerWidth()) - 30; // narrow legendWidth by 30px to get space for first and last tick values
|
||||||
var legendHeight = legendElem.attr("height");
|
var legendHeight = legendElem.attr("height");
|
||||||
|
|
||||||
var rangeStep = 10;
|
var rangeStep = 10;
|
||||||
@@ -55,8 +56,9 @@ System.register(['angular', 'lodash', 'jquery', 'd3', './libs/d3-scale-chromatic
|
|||||||
|
|
||||||
var opacityScale = getOpacityScale(options, maxValue, minValue);
|
var opacityScale = getOpacityScale(options, maxValue, minValue);
|
||||||
legend.selectAll(".status-heatmap-opacity-legend-rect").data(valuesRange).enter().append("rect").attr("x", function (d) {
|
legend.selectAll(".status-heatmap-opacity-legend-rect").data(valuesRange).enter().append("rect").attr("x", function (d) {
|
||||||
return d * widthFactor;
|
return d * widthFactor + 10;
|
||||||
}).attr("y", 0).attr("width", rangeStep * widthFactor).attr("height", legendHeight).attr("stroke-width", 0).attr("fill", options.cardColor).style("opacity", function (d) {
|
}) // shift all opacity rectangles to the right
|
||||||
|
.attr("y", 0).attr("width", rangeStep * widthFactor).attr("height", legendHeight).attr("stroke-width", 0).attr("fill", options.cardColor).style("opacity", function (d) {
|
||||||
return opacityScale(d);
|
return opacityScale(d);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
-7
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 3,
|
|
||||||
"mappings": "AAGA,8BAA+B;EAE7B,MAAM,EAAE,SAAS;EAEjB,uDAAyB;IACzB,gBAAgB,EAAE,KAAK;IACvB,OAAO,EAAE,GAAG;;AAId,qBAAsB;EACpB,QAAQ,EAAE,QAAQ;EAGhB,sCAAK;IACH,IAAI,EAAE,OAAO;IACb,KAAK,EAAE,OAAO;IACd,SAAS,EAAE,IAAI;EAGjB,sCAAK;IACH,OAAO,EAAE,GAAG;IACZ,MAAM,EAAE,OAAO;EAKnB,yBAAI;IACF,cAAc,EAAE,IAAI;IAEpB,8BAAK;MACH,cAAc,EAAE,cAAc;;AAKpC,uBAAwB;EACtB,WAAW,EAAE,MAAM;EACnB,SAAS,EAzCI,IAAI;EA0CjB,gBAAgB,EAAE,OAAO;EACzB,KAAK,EAAE,OAAO;;AAGhB,8BAA+B;EAC7B,IAAI,EAAE,OAAO;;AAIb,8BAAK;EACH,MAAM,EAAE,OAAe;EACvB,YAAY,EAAE,CAAC;;AAInB,yBAA0B;EACxB,YAAY,EAAE,CAAC;EACf,IAAI,EAAE,wBAAwB;EAC9B,MAAM,EAAE,wBAAwB;;AAGlC,8BAA+B;EAE7B,MAAM,EAAE,MAAM;EAGd,kCAAI;IAGF,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,IAAI;IACX,WAAW,EAAE,MAAM;EAIrB,2DAA6B;IAC3B,UAAU,EAAE,GAAG;EAGjB,4DAA8B;IAC5B,OAAO,EAAE,YAAY;EAIrB,+CAAK;IACH,IAAI,EAAE,OAAO;IACb,KAAK,EAAE,OAAO;IACd,SAAS,EAAE,IAAI;EAGjB,+CAAK;IACH,OAAO,EAAE,GAAG;IACZ,MAAM,EAAE,OAAO;EAGjB,kDAAQ;IACN,OAAO,EAAE,GAAG;IACZ,MAAM,EAAE,OAAO",
|
|
||||||
"sources": ["../../src/css/status-heatmap.scss"],
|
|
||||||
"names": [],
|
|
||||||
"file": "status-heatmap.css"
|
|
||||||
}
|
|
||||||
Vendored
+66
@@ -0,0 +1,66 @@
|
|||||||
|
.status-heatmap-canvas-wrapper {
|
||||||
|
cursor: crosshair; }
|
||||||
|
.status-heatmap-canvas-wrapper .datapoints-warning span {
|
||||||
|
background-color: #333333;
|
||||||
|
color: #d8d9da;
|
||||||
|
padding: 1px; }
|
||||||
|
|
||||||
|
.status-heatmap-panel {
|
||||||
|
position: relative; }
|
||||||
|
.status-heatmap-panel .axis .tick text {
|
||||||
|
fill: #d8d9da;
|
||||||
|
color: #d8d9da;
|
||||||
|
font-size: 11px; }
|
||||||
|
.status-heatmap-panel .axis .tick line {
|
||||||
|
opacity: 0.4;
|
||||||
|
stroke: #8e8e8e; }
|
||||||
|
.status-heatmap-panel svg {
|
||||||
|
pointer-events: none; }
|
||||||
|
.status-heatmap-panel svg rect {
|
||||||
|
pointer-events: visiblePainted; }
|
||||||
|
|
||||||
|
.statusmap-tooltip {
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 12px;
|
||||||
|
background-color: #141414;
|
||||||
|
color: #d8d9da; }
|
||||||
|
.statusmap-tooltip .discrete-item {
|
||||||
|
color: #52545c;
|
||||||
|
padding: 1px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-shadow: 0 0 0.2em #FFF, 0 0 0.2em #FFF, 0 0 0.2em #FFF; }
|
||||||
|
|
||||||
|
.statusmap-histogram rect {
|
||||||
|
fill: #8e8e8e; }
|
||||||
|
|
||||||
|
.status-heatmap-crosshair line {
|
||||||
|
stroke: #9f3023;
|
||||||
|
stroke-width: 1; }
|
||||||
|
|
||||||
|
.status-heatmap-selection {
|
||||||
|
stroke-width: 1;
|
||||||
|
fill: rgba(102, 102, 102, 0.4);
|
||||||
|
stroke: rgba(102, 102, 102, 0.8); }
|
||||||
|
|
||||||
|
.status-heatmap-legend-wrapper {
|
||||||
|
margin: 0 10px; }
|
||||||
|
.status-heatmap-legend-wrapper svg {
|
||||||
|
height: 24px;
|
||||||
|
float: left;
|
||||||
|
white-space: nowrap; }
|
||||||
|
.status-heatmap-legend-wrapper .status-heatmap-color-legend {
|
||||||
|
margin-top: 4px; }
|
||||||
|
.status-heatmap-legend-wrapper .status-heatmap-legend-values {
|
||||||
|
display: inline-block; }
|
||||||
|
.status-heatmap-legend-wrapper .axis .tick text {
|
||||||
|
fill: #d8d9da;
|
||||||
|
color: #d8d9da;
|
||||||
|
font-size: 11px; }
|
||||||
|
.status-heatmap-legend-wrapper .axis .tick line {
|
||||||
|
opacity: 0.4;
|
||||||
|
stroke: #8e8e8e; }
|
||||||
|
.status-heatmap-legend-wrapper .axis .tick .domain {
|
||||||
|
opacity: 0.4;
|
||||||
|
stroke: #8e8e8e; }
|
||||||
|
|
||||||
|
/*# sourceMappingURL=statusmap.dark.css.map */
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"mappings": "AAAA,8BAA+B;EAE7B,MAAM,EAAE,SAAS;EAEjB,uDAAyB;IACzB,gBAAgB,ECDL,OAAO;IDElB,KAAK,ECLM,OAAO;IDMlB,OAAO,EAAE,GAAG;;AAId,qBAAsB;EACpB,QAAQ,EAAE,QAAQ;EAGhB,sCAAK;IACH,IAAI,ECfG,OAAO;IDgBd,KAAK,EChBE,OAAO;IDiBd,SAAS,EEjBE,IAAI;EFoBjB,sCAAK;IACH,OAAO,EAAE,GAAG;IACZ,MAAM,ECrBM,OAAO;ED0BvB,yBAAI;IACF,cAAc,EAAE,IAAI;IAEpB,8BAAK;MACH,cAAc,EAAE,cAAc;;AAKpC,kBAAmB;EACjB,WAAW,EAAE,MAAM;EACnB,SAAS,EEvCI,IAAI;EFwCjB,gBAAgB,ECrCC,OAAO;EDsCxB,KAAK,ECxCM,OAAO;ED0ClB,iCAAe;IACb,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,GAAG;IACZ,WAAW,EAAE,IAAI;IACjB,WAAW,EAAE,8CAA8C;;AAI/D,yBAA0B;EACxB,IAAI,EClDY,OAAO;;ADsDvB,8BAAK;EACH,MAAM,EAAE,OAAgB;EACxB,YAAY,EAAE,CAAC;;AAInB,yBAA0B;EACxB,YAAY,EAAE,CAAC;EACf,IAAI,EAAE,wBAAwB;EAC9B,MAAM,EAAE,wBAAwB;;AAIlC,8BAA+B;EAC7B,MAAM,EAAE,MAAM;EAEd,kCAAI;IACF,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,IAAI;IACX,WAAW,EAAE,MAAM;EAIrB,2DAA6B;IAC3B,UAAU,EAAE,GAAG;EAGjB,4DAA8B;IAC5B,OAAO,EAAE,YAAY;EAIrB,+CAAK;IACH,IAAI,ECxFG,OAAO;IDyFd,KAAK,ECzFE,OAAO;ID0Fd,SAAS,EE1FE,IAAI;EF6FjB,+CAAK;IACH,OAAO,EAAE,GAAG;IACZ,MAAM,EC9FM,OAAO;EDiGrB,kDAAQ;IACN,OAAO,EAAE,GAAG;IACZ,MAAM,ECnGM,OAAO",
|
||||||
|
"sources": ["../../src/css/_statusmap.scss","../../src/css/_variables.dark.scss","../../src/css/_variables.scss"],
|
||||||
|
"names": [],
|
||||||
|
"file": "statusmap.dark.css"
|
||||||
|
}
|
||||||
+11
-5
@@ -1,7 +1,8 @@
|
|||||||
.status-heatmap-canvas-wrapper {
|
.status-heatmap-canvas-wrapper {
|
||||||
cursor: crosshair; }
|
cursor: crosshair; }
|
||||||
.status-heatmap-canvas-wrapper .datapoints-warning span {
|
.status-heatmap-canvas-wrapper .datapoints-warning span {
|
||||||
background-color: white;
|
background-color: #e9edf2;
|
||||||
|
color: #52545c;
|
||||||
padding: 1px; }
|
padding: 1px; }
|
||||||
|
|
||||||
.status-heatmap-panel {
|
.status-heatmap-panel {
|
||||||
@@ -18,17 +19,22 @@
|
|||||||
.status-heatmap-panel svg rect {
|
.status-heatmap-panel svg rect {
|
||||||
pointer-events: visiblePainted; }
|
pointer-events: visiblePainted; }
|
||||||
|
|
||||||
.status-heatmap-tooltip {
|
.statusmap-tooltip {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
background-color: #dde4ed;
|
background-color: #dde4ed;
|
||||||
color: #52545c; }
|
color: #52545c; }
|
||||||
|
.statusmap-tooltip .discrete-item {
|
||||||
|
color: #52545c;
|
||||||
|
padding: 1px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-shadow: 0 0 0.2em #FFF, 0 0 0.2em #FFF, 0 0 0.2em #FFF; }
|
||||||
|
|
||||||
.status-heatmap-histogram rect {
|
.statusmap-histogram rect {
|
||||||
fill: #767980; }
|
fill: #767980; }
|
||||||
|
|
||||||
.status-heatmap-crosshair line {
|
.status-heatmap-crosshair line {
|
||||||
stroke: #b30000;
|
stroke: #9e2f22;
|
||||||
stroke-width: 1; }
|
stroke-width: 1; }
|
||||||
|
|
||||||
.status-heatmap-selection {
|
.status-heatmap-selection {
|
||||||
@@ -57,4 +63,4 @@
|
|||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
stroke: #767980; }
|
stroke: #767980; }
|
||||||
|
|
||||||
/*# sourceMappingURL=status-heatmap.css.map */
|
/*# sourceMappingURL=statusmap.light.css.map */
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"mappings": "AAAA,8BAA+B;EAE7B,MAAM,EAAE,SAAS;EAEjB,uDAAyB;IACzB,gBAAgB,ECDL,OAAO;IDElB,KAAK,ECLM,OAAO;IDMlB,OAAO,EAAE,GAAG;;AAId,qBAAsB;EACpB,QAAQ,EAAE,QAAQ;EAGhB,sCAAK;IACH,IAAI,ECfG,OAAO;IDgBd,KAAK,EChBE,OAAO;IDiBd,SAAS,EEjBE,IAAI;EFoBjB,sCAAK;IACH,OAAO,EAAE,GAAG;IACZ,MAAM,ECrBM,OAAO;ED0BvB,yBAAI;IACF,cAAc,EAAE,IAAI;IAEpB,8BAAK;MACH,cAAc,EAAE,cAAc;;AAKpC,kBAAmB;EACjB,WAAW,EAAE,MAAM;EACnB,SAAS,EEvCI,IAAI;EFwCjB,gBAAgB,ECrCC,OAAO;EDsCxB,KAAK,ECxCM,OAAO;ED0ClB,iCAAe;IACb,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,GAAG;IACZ,WAAW,EAAE,IAAI;IACjB,WAAW,EAAE,8CAA8C;;AAI/D,yBAA0B;EACxB,IAAI,EClDY,OAAO;;ADsDvB,8BAAK;EACH,MAAM,EAAE,OAAgB;EACxB,YAAY,EAAE,CAAC;;AAInB,yBAA0B;EACxB,YAAY,EAAE,CAAC;EACf,IAAI,EAAE,wBAAwB;EAC9B,MAAM,EAAE,wBAAwB;;AAIlC,8BAA+B;EAC7B,MAAM,EAAE,MAAM;EAEd,kCAAI;IACF,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,IAAI;IACX,WAAW,EAAE,MAAM;EAIrB,2DAA6B;IAC3B,UAAU,EAAE,GAAG;EAGjB,4DAA8B;IAC5B,OAAO,EAAE,YAAY;EAIrB,+CAAK;IACH,IAAI,ECxFG,OAAO;IDyFd,KAAK,ECzFE,OAAO;ID0Fd,SAAS,EE1FE,IAAI;EF6FjB,+CAAK;IACH,OAAO,EAAE,GAAG;IACZ,MAAM,EC9FM,OAAO;EDiGrB,kDAAQ;IACN,OAAO,EAAE,GAAG;IACZ,MAAM,ECnGM,OAAO",
|
||||||
|
"sources": ["../../src/css/_statusmap.scss","../../src/css/_variables.light.scss","../../src/css/_variables.scss"],
|
||||||
|
"names": [],
|
||||||
|
"file": "statusmap.light.css"
|
||||||
|
}
|
||||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
Vendored
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 64 KiB |
Vendored
+11
-3
@@ -1,14 +1,22 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
System.register(['./color_legend', './status_heatmap_ctrl'], function (_export, _context) {
|
System.register(['app/plugins/sdk', './status_heatmap_ctrl'], function (_export, _context) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var StatusHeatmapCtrl;
|
var loadPluginCss, StatusHeatmapCtrl;
|
||||||
return {
|
return {
|
||||||
setters: [function (_color_legend) {}, function (_status_heatmap_ctrl) {
|
setters: [function (_appPluginsSdk) {
|
||||||
|
loadPluginCss = _appPluginsSdk.loadPluginCss;
|
||||||
|
}, function (_status_heatmap_ctrl) {
|
||||||
StatusHeatmapCtrl = _status_heatmap_ctrl.StatusHeatmapCtrl;
|
StatusHeatmapCtrl = _status_heatmap_ctrl.StatusHeatmapCtrl;
|
||||||
}],
|
}],
|
||||||
execute: function () {
|
execute: function () {
|
||||||
|
|
||||||
|
loadPluginCss({
|
||||||
|
dark: 'plugins/flant-statusmap-panel/css/statusmap.dark.css',
|
||||||
|
light: 'plugins/flant-statusmap-panel/css/statusmap.light.css'
|
||||||
|
});
|
||||||
|
|
||||||
_export('PanelCtrl', StatusHeatmapCtrl);
|
_export('PanelCtrl', StatusHeatmapCtrl);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["../src/module.js"],"names":["loadPluginCss","StatusHeatmapCtrl","dark","light"],"mappings":";;;;;;;;AAAQA,mB,kBAAAA,a;;AACCC,uB,wBAAAA,iB;;;;AAETD,oBAAc;AACZE,cAAM,sDADM;AAEZC,eAAO;AAFK,OAAd;;2BAMEF,iB","file":"module.js","sourcesContent":["import {loadPluginCss} from 'app/plugins/sdk';\nimport { StatusHeatmapCtrl } from './status_heatmap_ctrl';\n\nloadPluginCss({\n dark: 'plugins/flant-statusmap-panel/css/statusmap.dark.css',\n light: 'plugins/flant-statusmap-panel/css/statusmap.light.css'\n});\n\nexport {\n StatusHeatmapCtrl as PanelCtrl\n};\n"]}
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["../src/options_editor.js"],"names":["statusHeatmapOptionsEditor","restrict","scope","templateUrl","controller","StatusHeatmapOptionsEditorCtrl","kbn","$scope","editor","panelCtrl","ctrl","panel","unitFormats","getUnitFormats","render","subItem","data","unitFormat","value"],"mappings":";;;;;;;;;;;;;AAkBO,WAASA,0BAAT,GAAsC;AAC3C;;AACA,WAAO;AACLC,gBAAU,GADL;AAELC,aAAO,IAFF;AAGLC,mBAAa,mEAHR;AAILC,kBAAYC;AAJP,KAAP;AAMD;;wCAReL,0B;;;;AAlBTM,S;;;;;;;;;;;;;;;;;;;;;gDAEMD,8B;AACX,gDAAYE,MAAZ,EAAoB;AAAA;;AAClBA,iBAAOC,MAAP,GAAgB,IAAhB;AACA,eAAKC,SAAL,GAAiBF,OAAOG,IAAxB;AACA,eAAKC,KAAL,GAAa,KAAKF,SAAL,CAAeE,KAA5B;AACA,eAAKC,WAAL,GAAmBN,IAAIO,cAAJ,EAAnB;;AAEA,eAAKJ,SAAL,CAAeK,MAAf;AACD;;;;wCAEaC,O,EAAS;AACrB,iBAAKJ,KAAL,CAAWK,IAAX,CAAgBC,UAAhB,GAA6BF,QAAQG,KAArC;AACA,iBAAKT,SAAL,CAAeK,MAAf;AACD","file":"options_editor.js","sourcesContent":["import kbn from 'app/core/utils/kbn';\n\nexport class StatusHeatmapOptionsEditorCtrl {\n constructor($scope) {\n $scope.editor = this;\n this.panelCtrl = $scope.ctrl;\n this.panel = this.panelCtrl.panel;\n this.unitFormats = kbn.getUnitFormats();\n\n this.panelCtrl.render();\n }\n\n setUnitFormat(subItem) {\n this.panel.data.unitFormat = subItem.value;\n this.panelCtrl.render();\n }\n}\n\nexport function statusHeatmapOptionsEditor() {\n 'use strict';\n return {\n restrict: 'E',\n scope: true,\n templateUrl: 'public/plugins/flant-statusmap-panel/partials/options_editor.html',\n controller: StatusHeatmapOptionsEditorCtrl,\n };\n}\n"]}
|
||||||
Vendored
+4
-3
@@ -20,12 +20,13 @@
|
|||||||
|
|
||||||
],
|
],
|
||||||
"screenshots": [
|
"screenshots": [
|
||||||
{"name": "Panel", "path": "img/flant-statusmap-panel.png"},
|
{"name": "Panel with light theme", "path": "img/flant-statusmap-panel.png"},
|
||||||
|
{"name": "Panel with dark theme", "path": "img/flant-statusmap-panel-dark.png"},
|
||||||
{"name": "Color mapping", "path": "img/color-mapping.png"},
|
{"name": "Color mapping", "path": "img/color-mapping.png"},
|
||||||
{"name": "Queries example", "path": "img/queries-example.png"}
|
{"name": "Queries example", "path": "img/queries-example.png"}
|
||||||
],
|
],
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"updated": "2018-09-17"
|
"updated": "2018-10-17"
|
||||||
},
|
},
|
||||||
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+6
-4
@@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
System.register(['app/plugins/sdk', 'lodash', 'app/core/core', 'app/core/utils/kbn', './rendering', './options_editor', './color_mode_discrete', './css/status-heatmap.css!'], function (_export, _context) {
|
System.register(['app/plugins/sdk', 'lodash', 'app/core/core', 'app/core/utils/kbn', './color_legend', './rendering', './options_editor', './color_mode_discrete'], function (_export, _context) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var MetricsPanelCtrl, _, contextSrv, kbn, rendering, statusHeatmapOptionsEditor, ColorModeDiscrete, CANVAS, SVG, VALUE_INDEX, TIME_INDEX, panelDefaults, renderer, colorSchemes, colorModes, opacityScales, StatusHeatmapCtrl;
|
var MetricsPanelCtrl, _, contextSrv, kbn, rendering, statusHeatmapOptionsEditor, ColorModeDiscrete, CANVAS, SVG, VALUE_INDEX, TIME_INDEX, panelDefaults, renderer, colorSchemes, colorModes, opacityScales, StatusHeatmapCtrl;
|
||||||
@@ -44,13 +44,13 @@ System.register(['app/plugins/sdk', 'lodash', 'app/core/core', 'app/core/utils/k
|
|||||||
contextSrv = _appCoreCore.contextSrv;
|
contextSrv = _appCoreCore.contextSrv;
|
||||||
}, function (_appCoreUtilsKbn) {
|
}, function (_appCoreUtilsKbn) {
|
||||||
kbn = _appCoreUtilsKbn.default;
|
kbn = _appCoreUtilsKbn.default;
|
||||||
}, function (_rendering) {
|
}, function (_color_legend) {}, function (_rendering) {
|
||||||
rendering = _rendering.default;
|
rendering = _rendering.default;
|
||||||
}, function (_options_editor) {
|
}, function (_options_editor) {
|
||||||
statusHeatmapOptionsEditor = _options_editor.statusHeatmapOptionsEditor;
|
statusHeatmapOptionsEditor = _options_editor.statusHeatmapOptionsEditor;
|
||||||
}, function (_color_mode_discrete) {
|
}, function (_color_mode_discrete) {
|
||||||
ColorModeDiscrete = _color_mode_discrete.ColorModeDiscrete;
|
ColorModeDiscrete = _color_mode_discrete.ColorModeDiscrete;
|
||||||
}, function (_cssStatusHeatmapCss) {}],
|
}],
|
||||||
execute: function () {
|
execute: function () {
|
||||||
CANVAS = 'CANVAS';
|
CANVAS = 'CANVAS';
|
||||||
SVG = 'SVG';
|
SVG = 'SVG';
|
||||||
@@ -109,7 +109,7 @@ System.register(['app/plugins/sdk', 'lodash', 'app/core/core', 'app/core/utils/k
|
|||||||
{ name: 'Blues', value: 'interpolateBlues', invert: 'dark' }, { name: 'Greens', value: 'interpolateGreens', invert: 'dark' }, { name: 'Greys', value: 'interpolateGreys', invert: 'dark' }, { name: 'Oranges', value: 'interpolateOranges', invert: 'dark' }, { name: 'Purples', value: 'interpolatePurples', invert: 'dark' }, { name: 'Reds', value: 'interpolateReds', invert: 'dark' },
|
{ name: 'Blues', value: 'interpolateBlues', invert: 'dark' }, { name: 'Greens', value: 'interpolateGreens', invert: 'dark' }, { name: 'Greys', value: 'interpolateGreys', invert: 'dark' }, { name: 'Oranges', value: 'interpolateOranges', invert: 'dark' }, { name: 'Purples', value: 'interpolatePurples', invert: 'dark' }, { name: 'Reds', value: 'interpolateReds', invert: 'dark' },
|
||||||
|
|
||||||
// Sequential (Multi-Hue)
|
// Sequential (Multi-Hue)
|
||||||
{ name: 'BuGn', value: 'interpolateBuGn', invert: 'dark' }, { name: 'BuPu', value: 'interpolateBuPu', invert: 'dark' }, { name: 'GnBu', value: 'interpolateGnBu', invert: 'dark' }, { name: 'OrRd', value: 'interpolateOrRd', invert: 'dark' }, { name: 'PuBuGn', value: 'interpolatePuBuGn', invert: 'dark' }, { name: 'PuBu', value: 'interpolatePuBu', invert: 'dark' }, { name: 'PuRd', value: 'interpolatePuRd', invert: 'dark' }, { name: 'RdPu', value: 'interpolateRdPu', invert: 'dark' }, { name: 'YlGnBu', value: 'interpolateYlGnBu', invert: 'dark' }, { name: 'YlGn', value: 'interpolateYlGn', invert: 'dark' }, { name: 'YlOrBr', value: 'interpolateYlOrBr', invert: 'dark' }, { name: 'YlOrRd', value: 'interpolateYlOrRd', invert: 'darm' }];
|
{ name: 'BuGn', value: 'interpolateBuGn', invert: 'dark' }, { name: 'BuPu', value: 'interpolateBuPu', invert: 'dark' }, { name: 'GnBu', value: 'interpolateGnBu', invert: 'dark' }, { name: 'OrRd', value: 'interpolateOrRd', invert: 'dark' }, { name: 'PuBuGn', value: 'interpolatePuBuGn', invert: 'dark' }, { name: 'PuBu', value: 'interpolatePuBu', invert: 'dark' }, { name: 'PuRd', value: 'interpolatePuRd', invert: 'dark' }, { name: 'RdPu', value: 'interpolateRdPu', invert: 'dark' }, { name: 'YlGnBu', value: 'interpolateYlGnBu', invert: 'dark' }, { name: 'YlGn', value: 'interpolateYlGn', invert: 'dark' }, { name: 'YlOrBr', value: 'interpolateYlOrBr', invert: 'dark' }, { name: 'YlOrRd', value: 'interpolateYlOrRd', invert: 'dark' }];
|
||||||
colorModes = ['opacity', 'spectrum', 'discrete'];
|
colorModes = ['opacity', 'spectrum', 'discrete'];
|
||||||
opacityScales = ['linear', 'sqrt'];
|
opacityScales = ['linear', 'sqrt'];
|
||||||
|
|
||||||
@@ -123,6 +123,7 @@ System.register(['app/plugins/sdk', 'lodash', 'app/core/core', 'app/core/utils/k
|
|||||||
|
|
||||||
_this.onRenderComplete = function (data) {
|
_this.onRenderComplete = function (data) {
|
||||||
_this.graph.chartWidth = data.chartWidth;
|
_this.graph.chartWidth = data.chartWidth;
|
||||||
|
_this.renderingCompleted();
|
||||||
};
|
};
|
||||||
|
|
||||||
_this.calculateInterval = function () {
|
_this.calculateInterval = function () {
|
||||||
@@ -344,6 +345,7 @@ System.register(['app/plugins/sdk', 'lodash', 'app/core/core', 'app/core/utils/k
|
|||||||
_this.events.on('init-edit-mode', _this.onInitEditMode);
|
_this.events.on('init-edit-mode', _this.onInitEditMode);
|
||||||
_this.events.on('render', _this.onRender);
|
_this.events.on('render', _this.onRender);
|
||||||
_this.events.on('refresh', _this.postRefresh);
|
_this.events.on('refresh', _this.postRefresh);
|
||||||
|
// custom event from rendering.js
|
||||||
_this.events.on('render-complete', _this.onRenderComplete);
|
_this.events.on('render-complete', _this.onRenderComplete);
|
||||||
return _this;
|
return _this;
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+3
-3
@@ -88,7 +88,7 @@ System.register(['d3', 'jquery', 'lodash', 'app/core/utils/kbn'], function (_exp
|
|||||||
}, {
|
}, {
|
||||||
key: 'add',
|
key: 'add',
|
||||||
value: function add() {
|
value: function add() {
|
||||||
this.tooltip = d3.select("body").append("div").attr("class", "heatmap-tooltip graph-tooltip grafana-tooltip");
|
this.tooltip = d3.select("body").append("div").attr("class", "statusmap-tooltip graph-tooltip grafana-tooltip");
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
key: 'destroy',
|
key: 'destroy',
|
||||||
@@ -128,7 +128,7 @@ System.register(['d3', 'jquery', 'lodash', 'app/core/utils/kbn'], function (_exp
|
|||||||
var tooltipTimeFormat = 'YYYY-MM-DD HH:mm:ss';
|
var tooltipTimeFormat = 'YYYY-MM-DD HH:mm:ss';
|
||||||
var time = this.dashboard.formatDate(+x, tooltipTimeFormat);
|
var time = this.dashboard.formatDate(+x, tooltipTimeFormat);
|
||||||
|
|
||||||
var tooltipHtml = '<div class="graph-tooltip-time">' + time + '</div>\n <div class="status-heatmap-histogram"></div>';
|
var tooltipHtml = '<div class="graph-tooltip-time">' + time + '</div>\n <div class="statusmap-histogram"></div>';
|
||||||
|
|
||||||
if (this.panel.color.mode === 'discrete') {
|
if (this.panel.color.mode === 'discrete') {
|
||||||
var statuses = this.panelCtrl.discreteHelper.convertValuesToTooltips(values);
|
var statuses = this.panelCtrl.discreteHelper.convertValuesToTooltips(values);
|
||||||
@@ -139,7 +139,7 @@ System.register(['d3', 'jquery', 'lodash', 'app/core/utils/kbn'], function (_exp
|
|||||||
statusesHtml = "statuses:";
|
statusesHtml = "statuses:";
|
||||||
}
|
}
|
||||||
tooltipHtml += '\n <div>\n name: <b>' + y + '</b> <br>\n ' + statusesHtml + '\n <ul>\n ' + _.join(_.map(statuses, function (v) {
|
tooltipHtml += '\n <div>\n name: <b>' + y + '</b> <br>\n ' + statusesHtml + '\n <ul>\n ' + _.join(_.map(statuses, function (v) {
|
||||||
return '<li style="background-color: ' + v.color + '; padding: 1px; font-weight: bold; text-shadow: 0 0 0.2em #FFF, 0 0 0.2em #FFF, 0 0 0.2em #FFF">' + v.tooltip + '</li>';
|
return '<li style="background-color: ' + v.color + '" class="discrete-item">' + v.tooltip + '</li>';
|
||||||
}), "") + '\n </ul>\n </div>';
|
}), "") + '\n </ul>\n </div>';
|
||||||
} else {
|
} else {
|
||||||
if (values.length === 1) {
|
if (values.length === 1) {
|
||||||
|
|||||||
Vendored
+1
File diff suppressed because one or more lines are too long
+4
-4
@@ -89,7 +89,7 @@ function drawColorLegend(elem, colorScheme, rangeFrom, rangeTo, maxValue, minVal
|
|||||||
let legend = d3.select(legendElem.get(0));
|
let legend = d3.select(legendElem.get(0));
|
||||||
clearLegend(elem);
|
clearLegend(elem);
|
||||||
|
|
||||||
let legendWidth = Math.floor(legendElem.outerWidth()) - 30;
|
let legendWidth = Math.floor(legendElem.outerWidth()) - 30; // narrow legendWidth by 30px to get space for first and last tick values
|
||||||
let legendHeight = legendElem.attr("height");
|
let legendHeight = legendElem.attr("height");
|
||||||
|
|
||||||
let rangeStep = 1;
|
let rangeStep = 1;
|
||||||
@@ -108,7 +108,7 @@ function drawColorLegend(elem, colorScheme, rangeFrom, rangeTo, maxValue, minVal
|
|||||||
legend.selectAll(".status-heatmap-color-legend-rect")
|
legend.selectAll(".status-heatmap-color-legend-rect")
|
||||||
.data(valuesRange)
|
.data(valuesRange)
|
||||||
.enter().append("rect")
|
.enter().append("rect")
|
||||||
.attr("x", d => d * widthFactor)
|
.attr("x", d => d * widthFactor + 10) // shift all color rectangles to the right
|
||||||
.attr("y", 0)
|
.attr("y", 0)
|
||||||
.attr("width", rangeStep * widthFactor + 1) // Overlap rectangles to prevent gaps
|
.attr("width", rangeStep * widthFactor + 1) // Overlap rectangles to prevent gaps
|
||||||
.attr("height", legendHeight)
|
.attr("height", legendHeight)
|
||||||
@@ -123,7 +123,7 @@ function drawOpacityLegend(elem, options, rangeFrom, rangeTo, maxValue, minValue
|
|||||||
let legend = d3.select(legendElem.get(0));
|
let legend = d3.select(legendElem.get(0));
|
||||||
clearLegend(elem);
|
clearLegend(elem);
|
||||||
|
|
||||||
let legendWidth = Math.floor(legendElem.outerWidth()) - 30;
|
let legendWidth = Math.floor(legendElem.outerWidth()) - 30; // narrow legendWidth by 30px to get space for first and last tick values
|
||||||
let legendHeight = legendElem.attr("height");
|
let legendHeight = legendElem.attr("height");
|
||||||
|
|
||||||
let rangeStep = 10;
|
let rangeStep = 10;
|
||||||
@@ -139,7 +139,7 @@ function drawOpacityLegend(elem, options, rangeFrom, rangeTo, maxValue, minValue
|
|||||||
legend.selectAll(".status-heatmap-opacity-legend-rect")
|
legend.selectAll(".status-heatmap-opacity-legend-rect")
|
||||||
.data(valuesRange)
|
.data(valuesRange)
|
||||||
.enter().append("rect")
|
.enter().append("rect")
|
||||||
.attr("x", d => d * widthFactor)
|
.attr("x", d => d * widthFactor + 10) // shift all opacity rectangles to the right
|
||||||
.attr("y", 0)
|
.attr("y", 0)
|
||||||
.attr("width", rangeStep * widthFactor)
|
.attr("width", rangeStep * widthFactor)
|
||||||
.attr("height", legendHeight)
|
.attr("height", legendHeight)
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
$font-size-sm: 12px !default;
|
|
||||||
|
|
||||||
|
|
||||||
.status-heatmap-canvas-wrapper {
|
.status-heatmap-canvas-wrapper {
|
||||||
// position: relative;
|
// position: relative;
|
||||||
cursor: crosshair;
|
cursor: crosshair;
|
||||||
|
|
||||||
.datapoints-warning span {
|
.datapoints-warning span {
|
||||||
background-color: white;
|
background-color: $warning-bg;
|
||||||
|
color: $text-color;
|
||||||
padding: 1px;
|
padding: 1px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,14 +14,14 @@ $font-size-sm: 12px !default;
|
|||||||
|
|
||||||
.axis .tick {
|
.axis .tick {
|
||||||
text {
|
text {
|
||||||
fill: #52545c;
|
fill: $text-color;
|
||||||
color: #52545c;
|
color: $text-color;
|
||||||
font-size: 11px;
|
font-size: $font-size-tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
line {
|
line {
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
stroke: #767980;
|
stroke: $text-color-weak;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,20 +35,27 @@ $font-size-sm: 12px !default;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-heatmap-tooltip {
|
.statusmap-tooltip {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
font-size: $font-size-sm;
|
font-size: $font-size-sm;
|
||||||
background-color: #dde4ed;
|
background-color: $graph-tooltip-bg;
|
||||||
color: #52545c;
|
color: $text-color;
|
||||||
|
|
||||||
|
.discrete-item {
|
||||||
|
color: #52545c;
|
||||||
|
padding: 1px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-shadow: 0 0 0.2em #FFF, 0 0 0.2em #FFF, 0 0 0.2em #FFF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-heatmap-histogram rect {
|
.statusmap-histogram rect {
|
||||||
fill: #767980;
|
fill: $text-color-weak;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-heatmap-crosshair {
|
.status-heatmap-crosshair {
|
||||||
line {
|
line {
|
||||||
stroke: darken(red,15%);
|
stroke: darken($red,15%);
|
||||||
stroke-width: 1;
|
stroke-width: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,14 +66,11 @@ $font-size-sm: 12px !default;
|
|||||||
stroke: rgba(102, 102, 102, 0.8);
|
stroke: rgba(102, 102, 102, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.status-heatmap-legend-wrapper {
|
.status-heatmap-legend-wrapper {
|
||||||
// @include clearfix();
|
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
//padding-top: 10px;
|
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
//width: 100%;
|
|
||||||
//max-width: 1300px;
|
|
||||||
height: 24px;
|
height: 24px;
|
||||||
float: left;
|
float: left;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@@ -85,19 +87,19 @@ $font-size-sm: 12px !default;
|
|||||||
|
|
||||||
.axis .tick {
|
.axis .tick {
|
||||||
text {
|
text {
|
||||||
fill: #52545c;
|
fill: $text-color;
|
||||||
color: #52545c;
|
color: $text-color;
|
||||||
font-size: 11px;
|
font-size: $font-size-tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
line {
|
line {
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
stroke: #767980;
|
stroke: $text-color-weak;
|
||||||
}
|
}
|
||||||
|
|
||||||
.domain {
|
.domain {
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
stroke: #767980;
|
stroke: $text-color-weak;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// Dark variables
|
||||||
|
$text-color: #d8d9da; // $gray-4
|
||||||
|
$text-color-weak: #8e8e8e; // $gray-2
|
||||||
|
$graph-tooltip-bg: #141414; // $dark-1
|
||||||
|
$warning-bg: #333333; // $dark-4
|
||||||
|
|
||||||
|
$theme-name: dark;
|
||||||
|
$white: #fff;
|
||||||
|
$red: #d44a3a;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// Light variables
|
||||||
|
$text-color: #52545c; // $gray-1
|
||||||
|
$text-color-weak: #767980; // $gray-2
|
||||||
|
$graph-tooltip-bg: #dde4ed; // $gray-5
|
||||||
|
$warning-bg: #e9edf2; // $gray-6
|
||||||
|
|
||||||
|
$theme-name: light;
|
||||||
|
$white: #fff;
|
||||||
|
$red: #d44939;
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
$font-size-sm: 12px !default;
|
||||||
|
$font-size-tick: 11px;
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
@import "variables";
|
||||||
|
@import "variables.dark";
|
||||||
|
@import "statusmap"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
@import "variables";
|
||||||
|
@import "variables.light";
|
||||||
|
@import "statusmap"
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
+6
-1
@@ -1,6 +1,11 @@
|
|||||||
import './color_legend';
|
import {loadPluginCss} from 'app/plugins/sdk';
|
||||||
import { StatusHeatmapCtrl } from './status_heatmap_ctrl';
|
import { StatusHeatmapCtrl } from './status_heatmap_ctrl';
|
||||||
|
|
||||||
|
loadPluginCss({
|
||||||
|
dark: 'plugins/flant-statusmap-panel/css/statusmap.dark.css',
|
||||||
|
light: 'plugins/flant-statusmap-panel/css/statusmap.light.css'
|
||||||
|
});
|
||||||
|
|
||||||
export {
|
export {
|
||||||
StatusHeatmapCtrl as PanelCtrl
|
StatusHeatmapCtrl as PanelCtrl
|
||||||
};
|
};
|
||||||
|
|||||||
+4
-3
@@ -20,12 +20,13 @@
|
|||||||
|
|
||||||
],
|
],
|
||||||
"screenshots": [
|
"screenshots": [
|
||||||
{"name": "Panel", "path": "img/flant-statusmap-panel.png"},
|
{"name": "Panel with light theme", "path": "img/flant-statusmap-panel.png"},
|
||||||
|
{"name": "Panel with dark theme", "path": "img/flant-statusmap-panel-dark.png"},
|
||||||
{"name": "Color mapping", "path": "img/color-mapping.png"},
|
{"name": "Color mapping", "path": "img/color-mapping.png"},
|
||||||
{"name": "Queries example", "path": "img/queries-example.png"}
|
{"name": "Queries example", "path": "img/queries-example.png"}
|
||||||
],
|
],
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"updated": "2018-09-17"
|
"updated": "2018-10-17"
|
||||||
},
|
},
|
||||||
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import _ from 'lodash';
|
|||||||
import { contextSrv } from 'app/core/core';
|
import { contextSrv } from 'app/core/core';
|
||||||
import kbn from 'app/core/utils/kbn';
|
import kbn from 'app/core/utils/kbn';
|
||||||
|
|
||||||
|
import './color_legend';
|
||||||
import rendering from './rendering';
|
import rendering from './rendering';
|
||||||
// import aggregates, { aggregatesMap } from './aggregates';
|
// import aggregates, { aggregatesMap } from './aggregates';
|
||||||
// import fragments, { fragmentsMap } from './fragments';
|
// import fragments, { fragmentsMap } from './fragments';
|
||||||
// import { labelFormats } from './xAxisLabelFormats';
|
// import { labelFormats } from './xAxisLabelFormats';
|
||||||
import {statusHeatmapOptionsEditor} from './options_editor';
|
import {statusHeatmapOptionsEditor} from './options_editor';
|
||||||
import {ColorModeDiscrete} from "./color_mode_discrete";
|
import {ColorModeDiscrete} from "./color_mode_discrete";
|
||||||
import './css/status-heatmap.css!';
|
|
||||||
|
|
||||||
const CANVAS = 'CANVAS';
|
const CANVAS = 'CANVAS';
|
||||||
const SVG = 'SVG';
|
const SVG = 'SVG';
|
||||||
@@ -89,7 +89,7 @@ const colorSchemes = [
|
|||||||
{ name: 'YlGnBu', value: 'interpolateYlGnBu', invert: 'dark' },
|
{ name: 'YlGnBu', value: 'interpolateYlGnBu', invert: 'dark' },
|
||||||
{ name: 'YlGn', value: 'interpolateYlGn', invert: 'dark' },
|
{ name: 'YlGn', value: 'interpolateYlGn', invert: 'dark' },
|
||||||
{ name: 'YlOrBr', value: 'interpolateYlOrBr', invert: 'dark' },
|
{ name: 'YlOrBr', value: 'interpolateYlOrBr', invert: 'dark' },
|
||||||
{ name: 'YlOrRd', value: 'interpolateYlOrRd', invert: 'darm' }
|
{ name: 'YlOrRd', value: 'interpolateYlOrRd', invert: 'dark' }
|
||||||
];
|
];
|
||||||
|
|
||||||
let colorModes = ['opacity', 'spectrum', 'discrete'];
|
let colorModes = ['opacity', 'spectrum', 'discrete'];
|
||||||
@@ -133,11 +133,13 @@ export class StatusHeatmapCtrl extends MetricsPanelCtrl {
|
|||||||
this.events.on('init-edit-mode', this.onInitEditMode);
|
this.events.on('init-edit-mode', this.onInitEditMode);
|
||||||
this.events.on('render', this.onRender);
|
this.events.on('render', this.onRender);
|
||||||
this.events.on('refresh', this.postRefresh);
|
this.events.on('refresh', this.postRefresh);
|
||||||
|
// custom event from rendering.js
|
||||||
this.events.on('render-complete', this.onRenderComplete);
|
this.events.on('render-complete', this.onRenderComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
onRenderComplete = (data) => {
|
onRenderComplete = (data) => {
|
||||||
this.graph.chartWidth = data.chartWidth;
|
this.graph.chartWidth = data.chartWidth;
|
||||||
|
this.renderingCompleted();
|
||||||
};
|
};
|
||||||
|
|
||||||
// override calculateInterval for discrete color mode
|
// override calculateInterval for discrete color mode
|
||||||
|
|||||||
+3
-3
@@ -42,7 +42,7 @@ export class StatusHeatmapTooltip {
|
|||||||
add() {
|
add() {
|
||||||
this.tooltip = d3.select("body")
|
this.tooltip = d3.select("body")
|
||||||
.append("div")
|
.append("div")
|
||||||
.attr("class", "heatmap-tooltip graph-tooltip grafana-tooltip");
|
.attr("class", "statusmap-tooltip graph-tooltip grafana-tooltip");
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
@@ -79,7 +79,7 @@ export class StatusHeatmapTooltip {
|
|||||||
let time = this.dashboard.formatDate(+x, tooltipTimeFormat);
|
let time = this.dashboard.formatDate(+x, tooltipTimeFormat);
|
||||||
|
|
||||||
let tooltipHtml = `<div class="graph-tooltip-time">${time}</div>
|
let tooltipHtml = `<div class="graph-tooltip-time">${time}</div>
|
||||||
<div class="status-heatmap-histogram"></div>`;
|
<div class="statusmap-histogram"></div>`;
|
||||||
|
|
||||||
if (this.panel.color.mode === 'discrete') {
|
if (this.panel.color.mode === 'discrete') {
|
||||||
let statuses = this.panelCtrl.discreteHelper.convertValuesToTooltips(values);
|
let statuses = this.panelCtrl.discreteHelper.convertValuesToTooltips(values);
|
||||||
@@ -94,7 +94,7 @@ export class StatusHeatmapTooltip {
|
|||||||
name: <b>${y}</b> <br>
|
name: <b>${y}</b> <br>
|
||||||
${statusesHtml}
|
${statusesHtml}
|
||||||
<ul>
|
<ul>
|
||||||
${_.join(_.map(statuses, v => `<li style="background-color: ${v.color}; padding: 1px; font-weight: bold; text-shadow: 0 0 0.2em #FFF, 0 0 0.2em #FFF, 0 0 0.2em #FFF">${v.tooltip}</li>`), "")}
|
${_.join(_.map(statuses, v => `<li style="background-color: ${v.color}" class="discrete-item">${v.tooltip}</li>`), "")}
|
||||||
</ul>
|
</ul>
|
||||||
</div>`;
|
</div>`;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user