From b536a9f760740d87b0225428d4b51908c9b7afa3 Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Thu, 8 Nov 2018 16:40:53 +0100 Subject: [PATCH 1/5] can render something --- .../app/features/plugins/built_in_plugins.ts | 2 + public/app/plugins/panel/gauge/module.tsx | 23 +++++ public/app/plugins/panel/gauge/plugin.json | 18 ++++ public/app/viz/Gauge.tsx | 99 +++++++++++++++++++ public/app/viz/GaugeOptions.tsx | 16 +++ 5 files changed, 158 insertions(+) create mode 100644 public/app/plugins/panel/gauge/module.tsx create mode 100644 public/app/plugins/panel/gauge/plugin.json create mode 100644 public/app/viz/Gauge.tsx create mode 100644 public/app/viz/GaugeOptions.tsx diff --git a/public/app/features/plugins/built_in_plugins.ts b/public/app/features/plugins/built_in_plugins.ts index b9779190a8b..a0cedb3ebfd 100644 --- a/public/app/features/plugins/built_in_plugins.ts +++ b/public/app/features/plugins/built_in_plugins.ts @@ -24,6 +24,7 @@ import * as heatmapPanel from 'app/plugins/panel/heatmap/module'; import * as tablePanel from 'app/plugins/panel/table/module'; import * as singlestatPanel from 'app/plugins/panel/singlestat/module'; import * as gettingStartedPanel from 'app/plugins/panel/gettingstarted/module'; +import * as gaugePanel from 'app/plugins/panel/gauge/module'; const builtInPlugins = { 'app/plugins/datasource/graphite/module': graphitePlugin, @@ -52,6 +53,7 @@ const builtInPlugins = { 'app/plugins/panel/table/module': tablePanel, 'app/plugins/panel/singlestat/module': singlestatPanel, 'app/plugins/panel/gettingstarted/module': gettingStartedPanel, + 'app/plugins/panel/gauge/module': gaugePanel, }; export default builtInPlugins; diff --git a/public/app/plugins/panel/gauge/module.tsx b/public/app/plugins/panel/gauge/module.tsx new file mode 100644 index 00000000000..526e7cca87a --- /dev/null +++ b/public/app/plugins/panel/gauge/module.tsx @@ -0,0 +1,23 @@ +import React, { PureComponent } from 'react'; +import { NullValueMode, PanelProps } from '../../../types'; +import { Gauge } from '../../../viz/Gauge'; +import { getTimeSeriesVMs } from '../../../viz/state/timeSeries'; + +export interface Options {} + +interface Props extends PanelProps {} + +export class GaugePanel extends PureComponent { + render() { + const { timeSeries } = this.props; + + const vmSeries = getTimeSeriesVMs({ + timeSeries: timeSeries, + nullValueMode: NullValueMode.Ignore, + }); + + return ; + } +} + +export { GaugePanel as PanelComponent }; diff --git a/public/app/plugins/panel/gauge/plugin.json b/public/app/plugins/panel/gauge/plugin.json new file mode 100644 index 00000000000..1fff76fdd3b --- /dev/null +++ b/public/app/plugins/panel/gauge/plugin.json @@ -0,0 +1,18 @@ +{ + "type": "panel", + "name": "Gauge", + "id": "gauge", + + "state": "alpha", + + "info": { + "author": { + "name": "Grafana Project", + "url": "https://grafana.com" + }, + "logos": { + + } + } +} + diff --git a/public/app/viz/Gauge.tsx b/public/app/viz/Gauge.tsx new file mode 100644 index 00000000000..f3f0c79d9a7 --- /dev/null +++ b/public/app/viz/Gauge.tsx @@ -0,0 +1,99 @@ +import React, { PureComponent } from 'react'; +import $ from 'jquery'; +import { TimeSeriesVMs } from 'app/types'; +import config from '../core/config'; + +interface Props { + timeSeries: TimeSeriesVMs; + minValue: number; + maxValue: number; + showThresholdMarkers?: boolean; + thresholds?: number[]; + showThresholdLables?: boolean; +} + +export class Gauge extends PureComponent { + element: any; + + static defaultProps = { + minValue: 0, + maxValue: 100, + showThresholdMarkers: true, + showThresholdLables: false, + thresholds: [], + }; + + componentDidMount() { + this.draw(); + } + + componentDidUpdate(prevProps: Props) { + if (prevProps.timeSeries !== this.props.timeSeries) { + this.draw(); + } + } + + draw() { + const { maxValue, minValue, showThresholdLables, showThresholdMarkers, timeSeries, thresholds } = this.props; + + console.log(timeSeries); + const backgroundColor = config.bootData.user.lightTheme ? 'rgb(230,230,230)' : 'rgb(38,38,38)'; + const fontColor = config.bootData.user.lightTheme ? 'rgb(38,38,38)' : 'rgb(230,230,230)'; + + const options = { + series: { + gauges: { + gauge: { + min: minValue, + max: maxValue, + background: { color: backgroundColor }, + border: { color: null }, + shadow: { show: false }, + width: '100%', + }, + frame: { show: false }, + label: { show: false }, + layout: { margin: 0, thresholdWidth: 0 }, + cell: { border: { width: 0 } }, + threshold: { + values: thresholds, + label: { + show: showThresholdLables, + margin: 2, + font: { size: 14 }, + }, + show: showThresholdMarkers, + width: 1, + }, + value: { + color: fontColor, + formatter: () => { + return Math.round(timeSeries[0].stats.avg); + }, + font: { + size: 78, + family: '"Helvetica Neue", Helvetica, Arial, sans-serif', + }, + }, + show: true, + }, + }, + }; + + try { + $.plot(this.element, timeSeries, options); + } catch (err) { + console.log('Gauge rendering error', err, options, timeSeries); + } + } + + getValueText() {} + + render() { + return ( +
+
(this.element = e)} /> +
+ ); + } +} diff --git a/public/app/viz/GaugeOptions.tsx b/public/app/viz/GaugeOptions.tsx new file mode 100644 index 00000000000..031855e1c78 --- /dev/null +++ b/public/app/viz/GaugeOptions.tsx @@ -0,0 +1,16 @@ +import React, { PureComponent } from 'react'; +import { PanelOptionsProps } from '../types'; + +interface Props {} + +export class GaugeOptions extends PureComponent> { + render() { + return ( +
+
+
Draw Modes
+
+
+ ); + } +} From 9163db02b420a53ceec8d927e26b6bf151d68e00 Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Fri, 9 Nov 2018 14:32:14 +0100 Subject: [PATCH 2/5] fix in to not render multiple labels --- public/vendor/flot/jquery.flot.gauge.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/vendor/flot/jquery.flot.gauge.js b/public/vendor/flot/jquery.flot.gauge.js index 14866dbef20..e0a3a33533d 100644 --- a/public/vendor/flot/jquery.flot.gauge.js +++ b/public/vendor/flot/jquery.flot.gauge.js @@ -583,7 +583,7 @@ * @param {Number} [a] the angle of the value drawn */ function drawText(x, y, id, text, textOptions, a) { - var span = $("." + id, placeholder); + var span = $(placeholder).find("#" + id); var exists = span.length; if (!exists) { span = $("") From 656900516b9d97ef2e7354ef1c8faf9a9f253f21 Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Fri, 9 Nov 2018 16:37:09 +0100 Subject: [PATCH 3/5] draw gauge --- public/app/plugins/panel/gauge/module.tsx | 6 +- public/app/viz/Gauge.tsx | 68 +++++++++++++++++------ 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/public/app/plugins/panel/gauge/module.tsx b/public/app/plugins/panel/gauge/module.tsx index 526e7cca87a..dc0b38f9a83 100644 --- a/public/app/plugins/panel/gauge/module.tsx +++ b/public/app/plugins/panel/gauge/module.tsx @@ -1,7 +1,7 @@ import React, { PureComponent } from 'react'; import { NullValueMode, PanelProps } from '../../../types'; -import { Gauge } from '../../../viz/Gauge'; -import { getTimeSeriesVMs } from '../../../viz/state/timeSeries'; +import Gauge from 'app/viz/Gauge'; +import { getTimeSeriesVMs } from 'app/viz/state/timeSeries'; export interface Options {} @@ -16,7 +16,7 @@ export class GaugePanel extends PureComponent { nullValueMode: NullValueMode.Ignore, }); - return ; + return ; } } diff --git a/public/app/viz/Gauge.tsx b/public/app/viz/Gauge.tsx index f3f0c79d9a7..5e90fd870db 100644 --- a/public/app/viz/Gauge.tsx +++ b/public/app/viz/Gauge.tsx @@ -1,5 +1,6 @@ import React, { PureComponent } from 'react'; import $ from 'jquery'; +import { withSize } from 'react-sizeme'; import { TimeSeriesVMs } from 'app/types'; import config from '../core/config'; @@ -10,10 +11,14 @@ interface Props { showThresholdMarkers?: boolean; thresholds?: number[]; showThresholdLables?: boolean; + size?: { width: number; height: number }; } +const colors = ['rgba(50, 172, 45, 0.97)', 'rgba(237, 129, 40, 0.89)', 'rgba(245, 54, 54, 0.9)']; + export class Gauge extends PureComponent { - element: any; + parentElement: any; + canvasElement: any; static defaultProps = { minValue: 0, @@ -28,17 +33,32 @@ export class Gauge extends PureComponent { } componentDidUpdate(prevProps: Props) { - if (prevProps.timeSeries !== this.props.timeSeries) { - this.draw(); - } + this.draw(); } draw() { - const { maxValue, minValue, showThresholdLables, showThresholdMarkers, timeSeries, thresholds } = this.props; + const { maxValue, minValue, showThresholdLables, size, showThresholdMarkers, timeSeries, thresholds } = this.props; + + const width = size.width; + const height = size.height; + const dimension = Math.min(width, height * 1.3); - console.log(timeSeries); const backgroundColor = config.bootData.user.lightTheme ? 'rgb(230,230,230)' : 'rgb(38,38,38)'; const fontColor = config.bootData.user.lightTheme ? 'rgb(38,38,38)' : 'rgb(230,230,230)'; + const fontScale = parseInt('80', 10) / 100; + const fontSize = Math.min(dimension / 5, 100) * fontScale; + const gaugeWidth = Math.min(dimension / 6, 60); + const thresholdMarkersWidth = gaugeWidth / 5; + const thresholdLabelFontSize = fontSize / 2.5; + + const formattedThresholds = []; + + thresholds.forEach((threshold, index) => { + formattedThresholds.push({ + value: threshold, + color: colors[index], + }); + }); const options = { series: { @@ -49,21 +69,21 @@ export class Gauge extends PureComponent { background: { color: backgroundColor }, border: { color: null }, shadow: { show: false }, - width: '100%', + width: gaugeWidth, }, frame: { show: false }, label: { show: false }, layout: { margin: 0, thresholdWidth: 0 }, cell: { border: { width: 0 } }, threshold: { - values: thresholds, + values: formattedThresholds, label: { show: showThresholdLables, - margin: 2, - font: { size: 14 }, + margin: thresholdMarkersWidth + 1, + font: { size: thresholdLabelFontSize }, }, show: showThresholdMarkers, - width: 1, + width: thresholdMarkersWidth, }, value: { color: fontColor, @@ -71,7 +91,7 @@ export class Gauge extends PureComponent { return Math.round(timeSeries[0].stats.avg); }, font: { - size: 78, + size: fontSize, family: '"Helvetica Neue", Helvetica, Arial, sans-serif', }, }, @@ -80,20 +100,34 @@ export class Gauge extends PureComponent { }, }; + const plotSeries = { + data: [[0, timeSeries[0].stats.avg]], + }; + try { - $.plot(this.element, timeSeries, options); + $.plot(this.canvasElement, [plotSeries], options); } catch (err) { console.log('Gauge rendering error', err, options, timeSeries); } } - getValueText() {} - render() { + const { height, width } = this.props.size; + return ( -
-
(this.element = e)} /> +
(this.parentElement = element)}> +
(this.canvasElement = element)} + />
); } } + +export default withSize({ monitorHeight: true })(Gauge); From 9f1784d0e5f5a6922f3b2cd1cc76f52437e28294 Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Mon, 12 Nov 2018 10:59:35 +0100 Subject: [PATCH 4/5] updated text styling when switching views --- public/vendor/flot/jquery.flot.gauge.js | 35 +++++++++++++------------ 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/public/vendor/flot/jquery.flot.gauge.js b/public/vendor/flot/jquery.flot.gauge.js index e0a3a33533d..db1cb1ffe24 100644 --- a/public/vendor/flot/jquery.flot.gauge.js +++ b/public/vendor/flot/jquery.flot.gauge.js @@ -588,25 +588,26 @@ if (!exists) { span = $("") span.attr("id", id); - span.css("position", "absolute"); - span.css("top", y + "px"); - if (textOptions.font.size) { - span.css("font-size", textOptions.font.size + "px"); - } - if (textOptions.font.family) { - span.css("font-family", textOptions.font.family); - } - if (textOptions.color) { - span.css("color", textOptions.color); - } - if (textOptions.background.color) { - span.css("background-color", textOptions.background.color); - } - if (textOptions.background.opacity) { - span.css("opacity", textOptions.background.opacity); - } placeholder.append(span); } + + span.css("position", "absolute"); + span.css("top", y + "px"); + if (textOptions.font.size) { + span.css("font-size", textOptions.font.size + "px"); + } + if (textOptions.font.family) { + span.css("font-family", textOptions.font.family); + } + if (textOptions.color) { + span.css("color", textOptions.color); + } + if (textOptions.background.color) { + span.css("background-color", textOptions.background.color); + } + if (textOptions.background.opacity) { + span.css("opacity", textOptions.background.opacity); + } span.text(text); // after append, readjust the left position span.css("left", x + "px"); // for redraw, resetting the left position is needed here From 490fb9e8e6e54931d1c1be3ba1f878330807cac2 Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Mon, 12 Nov 2018 11:25:47 +0100 Subject: [PATCH 5/5] import changes --- public/app/plugins/panel/gauge/module.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/plugins/panel/gauge/module.tsx b/public/app/plugins/panel/gauge/module.tsx index dc0b38f9a83..48dc4d809f3 100644 --- a/public/app/plugins/panel/gauge/module.tsx +++ b/public/app/plugins/panel/gauge/module.tsx @@ -1,6 +1,6 @@ import React, { PureComponent } from 'react'; -import { NullValueMode, PanelProps } from '../../../types'; import Gauge from 'app/viz/Gauge'; +import { NullValueMode, PanelProps } from 'app/types'; import { getTimeSeriesVMs } from 'app/viz/state/timeSeries'; export interface Options {}