riemann-dash 0.2.12 → 0.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile.lock +14 -46
- data/README.markdown +1 -1
- data/lib/riemann/dash/public/favicon.ico +0 -0
- data/lib/riemann/dash/public/sounds/beep.wav +0 -0
- data/lib/riemann/dash/public/sounds/geiger.wav +0 -0
- data/lib/riemann/dash/public/toolbar.js +9 -0
- data/lib/riemann/dash/public/vendor/PriorityQueue.js +5 -3
- data/lib/riemann/dash/public/vendor/flot/jquery.flot.tooltip.js +601 -0
- data/lib/riemann/dash/public/vendor/flot/jquery.flot.tooltip.min.js +12 -0
- data/lib/riemann/dash/public/views/flot.js +44 -5
- data/lib/riemann/dash/public/views/geiger.js +151 -0
- data/lib/riemann/dash/public/views/help.js +3 -2
- data/lib/riemann/dash/public/views/log.js +1 -1
- data/lib/riemann/dash/version.rb +1 -1
- data/lib/riemann/dash/views/css.scss +1 -1
- data/lib/riemann/dash/views/index.erubis +4 -0
- data/riemann-dash.gemspec +1 -1
- metadata +23 -29
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c6101ce9bb7b5d9c11c24673be2a5b3c0399f2a3
|
4
|
+
data.tar.gz: e19a97d12f65736cb9137fef3f1dc6b4bcfb59e7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b762f4b990ec0375e49eab17659ad17ecc03e11c6f3a009aa5045390cff70aafdf60f0a26dca9ed0617b78ed254ad50728445e617060ab9e1964678e385f6c9c
|
7
|
+
data.tar.gz: 7ed47f5330e26204182463aafdadb2371c6d74bbeb51a2c9882259f6aa594f69a3a67d94ea3c572a9a4669a97a092d2a30978df9e01df783566d72eee2b253a0
|
data/Gemfile.lock
CHANGED
@@ -1,70 +1,35 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
riemann-dash (0.2.
|
4
|
+
riemann-dash (0.2.13)
|
5
5
|
erubis (>= 2.7.0)
|
6
|
-
fog
|
7
6
|
multi_json (= 1.3.6)
|
8
|
-
riemann-client (>= 0.0.7)
|
9
7
|
sass (>= 3.1.14)
|
10
|
-
sinatra (
|
11
|
-
|
8
|
+
sinatra (~> 1.4.5)
|
9
|
+
webrick (~> 1.3.1)
|
12
10
|
|
13
11
|
GEM
|
14
12
|
remote: https://rubygems.org/
|
15
13
|
specs:
|
16
|
-
beefcake (0.5.0)
|
17
|
-
builder (3.2.2)
|
18
14
|
coderay (1.0.9)
|
19
|
-
daemons (1.1.9)
|
20
15
|
erubis (2.7.0)
|
21
|
-
eventmachine (1.0.3)
|
22
|
-
excon (0.31.0)
|
23
|
-
fog (1.19.0)
|
24
|
-
builder
|
25
|
-
excon (~> 0.31.0)
|
26
|
-
formatador (~> 0.2.0)
|
27
|
-
mime-types
|
28
|
-
multi_json (~> 1.0)
|
29
|
-
net-scp (~> 1.1)
|
30
|
-
net-ssh (>= 2.1.3)
|
31
|
-
nokogiri (~> 1.5)
|
32
|
-
ruby-hmac
|
33
|
-
formatador (0.2.4)
|
34
16
|
method_source (0.8.1)
|
35
|
-
mime-types (2.0)
|
36
|
-
mini_portile (0.5.2)
|
37
|
-
mtrc (0.0.4)
|
38
17
|
multi_json (1.3.6)
|
39
|
-
net-scp (1.1.2)
|
40
|
-
net-ssh (>= 2.6.5)
|
41
|
-
net-ssh (2.7.0)
|
42
|
-
nokogiri (1.6.1)
|
43
|
-
mini_portile (~> 0.5.0)
|
44
18
|
pry (0.9.12)
|
45
19
|
coderay (~> 1.0.5)
|
46
20
|
method_source (~> 0.8)
|
47
21
|
slop (~> 3.4)
|
48
|
-
rack (1.
|
49
|
-
rack-protection (1.5.
|
22
|
+
rack (1.6.4)
|
23
|
+
rack-protection (1.5.3)
|
50
24
|
rack
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
trollop (>= 1.16.2)
|
55
|
-
ruby-hmac (0.4.0)
|
56
|
-
sass (3.3.2)
|
57
|
-
sinatra (1.4.4)
|
58
|
-
rack (~> 1.4)
|
25
|
+
sass (3.4.22)
|
26
|
+
sinatra (1.4.7)
|
27
|
+
rack (~> 1.5)
|
59
28
|
rack-protection (~> 1.4)
|
60
|
-
tilt (
|
29
|
+
tilt (>= 1.3, < 3)
|
61
30
|
slop (3.4.3)
|
62
|
-
|
63
|
-
|
64
|
-
eventmachine (>= 1.0.0)
|
65
|
-
rack (>= 1.0.0)
|
66
|
-
tilt (1.4.1)
|
67
|
-
trollop (2.0)
|
31
|
+
tilt (2.0.5)
|
32
|
+
webrick (1.3.1)
|
68
33
|
|
69
34
|
PLATFORMS
|
70
35
|
ruby
|
@@ -72,3 +37,6 @@ PLATFORMS
|
|
72
37
|
DEPENDENCIES
|
73
38
|
pry
|
74
39
|
riemann-dash!
|
40
|
+
|
41
|
+
BUNDLED WITH
|
42
|
+
1.10.6
|
data/README.markdown
CHANGED
Binary file
|
Binary file
|
Binary file
|
@@ -3,6 +3,14 @@ var toolbar = (function() {
|
|
3
3
|
var toolbar = $('#toolbar');
|
4
4
|
var form = $('<form/>');
|
5
5
|
toolbar.append(form);
|
6
|
+
|
7
|
+
// Method to adjust the position of the view div
|
8
|
+
var sizeAdjust = function() {
|
9
|
+
$('#view').css('top', toolbar.height() + "px");
|
10
|
+
};
|
11
|
+
$( window ).resize(function() {
|
12
|
+
sizeAdjust();
|
13
|
+
});
|
6
14
|
|
7
15
|
var pager = $('<div class="pager">');
|
8
16
|
var load = $('<div class="load"><div class="bar load1" /><div class="bar load5" /><span title="1- and 5-second subscription manager load averages">Load</span></div>');
|
@@ -134,6 +142,7 @@ var toolbar = (function() {
|
|
134
142
|
});
|
135
143
|
|
136
144
|
pager.append(add);
|
145
|
+
sizeAdjust();
|
137
146
|
};
|
138
147
|
|
139
148
|
// Returns a tile for a workspace.
|
@@ -7,8 +7,9 @@
|
|
7
7
|
* @author Augusto Pascutti
|
8
8
|
*/
|
9
9
|
var QueueItem = function(v, p) {
|
10
|
-
this.value
|
11
|
-
this.priority
|
10
|
+
this.value = v;
|
11
|
+
this.priority = p;
|
12
|
+
this.value_JSON = JSON.stringify(v);
|
12
13
|
};
|
13
14
|
|
14
15
|
/**
|
@@ -64,8 +65,9 @@ PriorityQueue.prototype = {
|
|
64
65
|
known = false;
|
65
66
|
idx = 0;
|
66
67
|
|
68
|
+
var value_JSON = JSON.stringify(value);
|
67
69
|
this._queue.forEach(function() {
|
68
|
-
if (
|
70
|
+
if (this._queue[idx].value_JSON === value_JSON) {
|
69
71
|
this._queue[idx].priority = priority;
|
70
72
|
known = true;
|
71
73
|
return;
|
@@ -0,0 +1,601 @@
|
|
1
|
+
/*
|
2
|
+
* jquery.flot.tooltip
|
3
|
+
*
|
4
|
+
* description: easy-to-use tooltips for Flot charts
|
5
|
+
* version: 0.8.6
|
6
|
+
* authors: Krzysztof Urbas @krzysu [myviews.pl],Evan Steinkerchner @Roundaround
|
7
|
+
* website: https://github.com/krzysu/flot.tooltip
|
8
|
+
*
|
9
|
+
* build on 2016-02-25
|
10
|
+
* released under MIT License, 2012
|
11
|
+
*/
|
12
|
+
(function ($) {
|
13
|
+
// plugin options, default values
|
14
|
+
var defaultOptions = {
|
15
|
+
tooltip: {
|
16
|
+
show: false,
|
17
|
+
cssClass: "flotTip",
|
18
|
+
content: "%s | X: %x | Y: %y",
|
19
|
+
// allowed templates are:
|
20
|
+
// %s -> series label,
|
21
|
+
// %c -> series color,
|
22
|
+
// %lx -> x axis label (requires flot-axislabels plugin https://github.com/markrcote/flot-axislabels),
|
23
|
+
// %ly -> y axis label (requires flot-axislabels plugin https://github.com/markrcote/flot-axislabels),
|
24
|
+
// %x -> X value,
|
25
|
+
// %y -> Y value,
|
26
|
+
// %x.2 -> precision of X value,
|
27
|
+
// %p -> percent
|
28
|
+
// %n -> value (not percent) of pie chart
|
29
|
+
xDateFormat: null,
|
30
|
+
yDateFormat: null,
|
31
|
+
monthNames: null,
|
32
|
+
dayNames: null,
|
33
|
+
shifts: {
|
34
|
+
x: 10,
|
35
|
+
y: 20
|
36
|
+
},
|
37
|
+
defaultTheme: true,
|
38
|
+
snap: true,
|
39
|
+
lines: false,
|
40
|
+
clickTips: false,
|
41
|
+
|
42
|
+
// callbacks
|
43
|
+
onHover: function (flotItem, $tooltipEl) {},
|
44
|
+
|
45
|
+
$compat: false
|
46
|
+
}
|
47
|
+
};
|
48
|
+
|
49
|
+
// dummy default options object for legacy code (<0.8.5) - is deleted later
|
50
|
+
defaultOptions.tooltipOpts = defaultOptions.tooltip;
|
51
|
+
|
52
|
+
// object
|
53
|
+
var FlotTooltip = function (plot) {
|
54
|
+
// variables
|
55
|
+
this.tipPosition = {x: 0, y: 0};
|
56
|
+
|
57
|
+
this.init(plot);
|
58
|
+
};
|
59
|
+
|
60
|
+
// main plugin function
|
61
|
+
FlotTooltip.prototype.init = function (plot) {
|
62
|
+
var that = this;
|
63
|
+
|
64
|
+
// detect other flot plugins
|
65
|
+
var plotPluginsLength = $.plot.plugins.length;
|
66
|
+
this.plotPlugins = [];
|
67
|
+
|
68
|
+
if (plotPluginsLength) {
|
69
|
+
for (var p = 0; p < plotPluginsLength; p++) {
|
70
|
+
this.plotPlugins.push($.plot.plugins[p].name);
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
plot.hooks.bindEvents.push(function (plot, eventHolder) {
|
75
|
+
|
76
|
+
// get plot options
|
77
|
+
that.plotOptions = plot.getOptions();
|
78
|
+
|
79
|
+
// for legacy (<0.8.5) implementations
|
80
|
+
if (typeof(that.plotOptions.tooltip) === 'boolean') {
|
81
|
+
that.plotOptions.tooltipOpts.show = that.plotOptions.tooltip;
|
82
|
+
that.plotOptions.tooltip = that.plotOptions.tooltipOpts;
|
83
|
+
delete that.plotOptions.tooltipOpts;
|
84
|
+
}
|
85
|
+
|
86
|
+
// if not enabled return
|
87
|
+
if (that.plotOptions.tooltip.show === false || typeof that.plotOptions.tooltip.show === 'undefined') return;
|
88
|
+
|
89
|
+
// shortcut to access tooltip options
|
90
|
+
that.tooltipOptions = that.plotOptions.tooltip;
|
91
|
+
|
92
|
+
if (that.tooltipOptions.$compat) {
|
93
|
+
that.wfunc = 'width';
|
94
|
+
that.hfunc = 'height';
|
95
|
+
} else {
|
96
|
+
that.wfunc = 'innerWidth';
|
97
|
+
that.hfunc = 'innerHeight';
|
98
|
+
}
|
99
|
+
|
100
|
+
// create tooltip DOM element
|
101
|
+
var $tip = that.getDomElement();
|
102
|
+
|
103
|
+
// bind event
|
104
|
+
$( plot.getPlaceholder() ).bind("plothover", plothover);
|
105
|
+
if (that.tooltipOptions.clickTips) {
|
106
|
+
$( plot.getPlaceholder() ).bind("plotclick", plotclick);
|
107
|
+
}
|
108
|
+
that.clickmode = false;
|
109
|
+
|
110
|
+
$(eventHolder).bind('mousemove', mouseMove);
|
111
|
+
});
|
112
|
+
|
113
|
+
plot.hooks.shutdown.push(function (plot, eventHolder){
|
114
|
+
$(plot.getPlaceholder()).unbind("plothover", plothover);
|
115
|
+
$(plot.getPlaceholder()).unbind("plotclick", plotclick);
|
116
|
+
plot.removeTooltip();
|
117
|
+
$(eventHolder).unbind("mousemove", mouseMove);
|
118
|
+
});
|
119
|
+
|
120
|
+
function mouseMove(e){
|
121
|
+
var pos = {};
|
122
|
+
pos.x = e.pageX;
|
123
|
+
pos.y = e.pageY;
|
124
|
+
plot.setTooltipPosition(pos);
|
125
|
+
}
|
126
|
+
|
127
|
+
/**
|
128
|
+
* open the tooltip (if not already open) and freeze it on the current position till the next click
|
129
|
+
*/
|
130
|
+
function plotclick(event, pos, item) {
|
131
|
+
if (! that.clickmode) {
|
132
|
+
// it is the click activating the clicktip
|
133
|
+
plothover(event, pos, item);
|
134
|
+
if (that.getDomElement().is(":visible")) {
|
135
|
+
$(plot.getPlaceholder()).unbind("plothover", plothover);
|
136
|
+
that.clickmode = true;
|
137
|
+
}
|
138
|
+
} else {
|
139
|
+
// it is the click deactivating the clicktip
|
140
|
+
$( plot.getPlaceholder() ).bind("plothover", plothover);
|
141
|
+
plot.hideTooltip();
|
142
|
+
that.clickmode = false;
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
function plothover(event, pos, item) {
|
147
|
+
// Simple distance formula.
|
148
|
+
var lineDistance = function (p1x, p1y, p2x, p2y) {
|
149
|
+
return Math.sqrt((p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y));
|
150
|
+
};
|
151
|
+
|
152
|
+
// Here is some voodoo magic for determining the distance to a line form a given point {x, y}.
|
153
|
+
var dotLineLength = function (x, y, x0, y0, x1, y1, o) {
|
154
|
+
if (o && !(o =
|
155
|
+
function (x, y, x0, y0, x1, y1) {
|
156
|
+
if (typeof x0 !== 'undefined') return { x: x0, y: y };
|
157
|
+
else if (typeof y0 !== 'undefined') return { x: x, y: y0 };
|
158
|
+
|
159
|
+
var left,
|
160
|
+
tg = -1 / ((y1 - y0) / (x1 - x0));
|
161
|
+
|
162
|
+
return {
|
163
|
+
x: left = (x1 * (x * tg - y + y0) + x0 * (x * -tg + y - y1)) / (tg * (x1 - x0) + y0 - y1),
|
164
|
+
y: tg * left - tg * x + y
|
165
|
+
};
|
166
|
+
} (x, y, x0, y0, x1, y1),
|
167
|
+
o.x >= Math.min(x0, x1) && o.x <= Math.max(x0, x1) && o.y >= Math.min(y0, y1) && o.y <= Math.max(y0, y1))
|
168
|
+
) {
|
169
|
+
var l1 = lineDistance(x, y, x0, y0), l2 = lineDistance(x, y, x1, y1);
|
170
|
+
return l1 > l2 ? l2 : l1;
|
171
|
+
} else {
|
172
|
+
var a = y0 - y1, b = x1 - x0, c = x0 * y1 - y0 * x1;
|
173
|
+
return Math.abs(a * x + b * y + c) / Math.sqrt(a * a + b * b);
|
174
|
+
}
|
175
|
+
};
|
176
|
+
|
177
|
+
if (item) {
|
178
|
+
plot.showTooltip(item, that.tooltipOptions.snap ? item : pos);
|
179
|
+
} else if (that.plotOptions.series.lines.show && that.tooltipOptions.lines === true) {
|
180
|
+
var maxDistance = that.plotOptions.grid.mouseActiveRadius;
|
181
|
+
|
182
|
+
var closestTrace = {
|
183
|
+
distance: maxDistance + 1
|
184
|
+
};
|
185
|
+
|
186
|
+
var ttPos = pos;
|
187
|
+
|
188
|
+
$.each(plot.getData(), function (i, series) {
|
189
|
+
var xBeforeIndex = 0,
|
190
|
+
xAfterIndex = -1;
|
191
|
+
|
192
|
+
// Our search here assumes our data is sorted via the x-axis.
|
193
|
+
// TODO: Improve efficiency somehow - search smaller sets of data.
|
194
|
+
for (var j = 1; j < series.data.length; j++) {
|
195
|
+
if (series.data[j - 1][0] <= pos.x && series.data[j][0] >= pos.x) {
|
196
|
+
xBeforeIndex = j - 1;
|
197
|
+
xAfterIndex = j;
|
198
|
+
}
|
199
|
+
}
|
200
|
+
|
201
|
+
if (xAfterIndex === -1) {
|
202
|
+
plot.hideTooltip();
|
203
|
+
return;
|
204
|
+
}
|
205
|
+
|
206
|
+
var pointPrev = { x: series.data[xBeforeIndex][0], y: series.data[xBeforeIndex][1] },
|
207
|
+
pointNext = { x: series.data[xAfterIndex][0], y: series.data[xAfterIndex][1] };
|
208
|
+
|
209
|
+
var distToLine = dotLineLength(series.xaxis.p2c(pos.x), series.yaxis.p2c(pos.y), series.xaxis.p2c(pointPrev.x),
|
210
|
+
series.yaxis.p2c(pointPrev.y), series.xaxis.p2c(pointNext.x), series.yaxis.p2c(pointNext.y), false);
|
211
|
+
|
212
|
+
if (distToLine < closestTrace.distance) {
|
213
|
+
|
214
|
+
var closestIndex = lineDistance(pointPrev.x, pointPrev.y, pos.x, pos.y) <
|
215
|
+
lineDistance(pos.x, pos.y, pointNext.x, pointNext.y) ? xBeforeIndex : xAfterIndex;
|
216
|
+
|
217
|
+
var pointSize = series.datapoints.pointsize;
|
218
|
+
|
219
|
+
// Calculate the point on the line vertically closest to our cursor.
|
220
|
+
var pointOnLine = [
|
221
|
+
pos.x,
|
222
|
+
pointPrev.y + ((pointNext.y - pointPrev.y) * ((pos.x - pointPrev.x) / (pointNext.x - pointPrev.x)))
|
223
|
+
];
|
224
|
+
|
225
|
+
var item = {
|
226
|
+
datapoint: pointOnLine,
|
227
|
+
dataIndex: closestIndex,
|
228
|
+
series: series,
|
229
|
+
seriesIndex: i
|
230
|
+
};
|
231
|
+
|
232
|
+
closestTrace = {
|
233
|
+
distance: distToLine,
|
234
|
+
item: item
|
235
|
+
};
|
236
|
+
|
237
|
+
if (that.tooltipOptions.snap) {
|
238
|
+
ttPos = {
|
239
|
+
pageX: series.xaxis.p2c(pointOnLine[0]),
|
240
|
+
pageY: series.yaxis.p2c(pointOnLine[1])
|
241
|
+
};
|
242
|
+
}
|
243
|
+
}
|
244
|
+
});
|
245
|
+
|
246
|
+
if (closestTrace.distance < maxDistance + 1)
|
247
|
+
plot.showTooltip(closestTrace.item, ttPos);
|
248
|
+
else
|
249
|
+
plot.hideTooltip();
|
250
|
+
} else {
|
251
|
+
plot.hideTooltip();
|
252
|
+
}
|
253
|
+
}
|
254
|
+
|
255
|
+
// Quick little function for setting the tooltip position.
|
256
|
+
plot.setTooltipPosition = function (pos) {
|
257
|
+
var $tip = that.getDomElement();
|
258
|
+
|
259
|
+
var totalTipWidth = $tip.outerWidth() + that.tooltipOptions.shifts.x;
|
260
|
+
var totalTipHeight = $tip.outerHeight() + that.tooltipOptions.shifts.y;
|
261
|
+
if ((pos.x - $(window).scrollLeft()) > ($(window)[that.wfunc]() - totalTipWidth)) {
|
262
|
+
pos.x -= totalTipWidth;
|
263
|
+
}
|
264
|
+
if ((pos.y - $(window).scrollTop()) > ($(window)[that.hfunc]() - totalTipHeight)) {
|
265
|
+
pos.y -= totalTipHeight;
|
266
|
+
}
|
267
|
+
|
268
|
+
/*
|
269
|
+
The section applies the new positioning ONLY if pos.x and pos.y
|
270
|
+
are numbers. If they are undefined or not a number, use the last
|
271
|
+
known numerical position. This hack fixes a bug that kept pie
|
272
|
+
charts from keeping their tooltip positioning.
|
273
|
+
*/
|
274
|
+
|
275
|
+
if (isNaN(pos.x)) {
|
276
|
+
that.tipPosition.x = that.tipPosition.xPrev;
|
277
|
+
}
|
278
|
+
else {
|
279
|
+
that.tipPosition.x = pos.x;
|
280
|
+
that.tipPosition.xPrev = pos.x;
|
281
|
+
}
|
282
|
+
if (isNaN(pos.y)) {
|
283
|
+
that.tipPosition.y = that.tipPosition.yPrev;
|
284
|
+
}
|
285
|
+
else {
|
286
|
+
that.tipPosition.y = pos.y;
|
287
|
+
that.tipPosition.yPrev = pos.y;
|
288
|
+
}
|
289
|
+
|
290
|
+
};
|
291
|
+
|
292
|
+
// Quick little function for showing the tooltip.
|
293
|
+
plot.showTooltip = function (target, position, targetPosition) {
|
294
|
+
var $tip = that.getDomElement();
|
295
|
+
|
296
|
+
// convert tooltip content template to real tipText
|
297
|
+
var tipText = that.stringFormat(that.tooltipOptions.content, target);
|
298
|
+
if (tipText === '')
|
299
|
+
return;
|
300
|
+
|
301
|
+
$tip.html(tipText);
|
302
|
+
plot.setTooltipPosition({ x: position.pageX, y: position.pageY });
|
303
|
+
$tip.css({
|
304
|
+
left: that.tipPosition.x + that.tooltipOptions.shifts.x,
|
305
|
+
top: that.tipPosition.y + that.tooltipOptions.shifts.y
|
306
|
+
}).show();
|
307
|
+
|
308
|
+
// run callback
|
309
|
+
if (typeof that.tooltipOptions.onHover === 'function') {
|
310
|
+
that.tooltipOptions.onHover(target, $tip);
|
311
|
+
}
|
312
|
+
};
|
313
|
+
|
314
|
+
// Quick little function for hiding the tooltip.
|
315
|
+
plot.hideTooltip = function () {
|
316
|
+
that.getDomElement().hide().html('');
|
317
|
+
};
|
318
|
+
|
319
|
+
plot.removeTooltip = function() {
|
320
|
+
that.getDomElement().remove();
|
321
|
+
};
|
322
|
+
};
|
323
|
+
|
324
|
+
/**
|
325
|
+
* get or create tooltip DOM element
|
326
|
+
* @return jQuery object
|
327
|
+
*/
|
328
|
+
FlotTooltip.prototype.getDomElement = function () {
|
329
|
+
var $tip = $('.' + this.tooltipOptions.cssClass);
|
330
|
+
|
331
|
+
if( $tip.length === 0 ){
|
332
|
+
$tip = $('<div />').addClass(this.tooltipOptions.cssClass);
|
333
|
+
$tip.appendTo('body').hide().css({position: 'absolute'});
|
334
|
+
|
335
|
+
if(this.tooltipOptions.defaultTheme) {
|
336
|
+
$tip.css({
|
337
|
+
'background': '#fff',
|
338
|
+
'z-index': '1040',
|
339
|
+
'padding': '0.4em 0.6em',
|
340
|
+
'border-radius': '0.5em',
|
341
|
+
'font-size': '0.8em',
|
342
|
+
'border': '1px solid #111',
|
343
|
+
'display': 'none',
|
344
|
+
'white-space': 'nowrap'
|
345
|
+
});
|
346
|
+
}
|
347
|
+
}
|
348
|
+
|
349
|
+
return $tip;
|
350
|
+
};
|
351
|
+
|
352
|
+
/**
|
353
|
+
* core function, create tooltip content
|
354
|
+
* @param {string} content - template with tooltip content
|
355
|
+
* @param {object} item - Flot item
|
356
|
+
* @return {string} real tooltip content for current item
|
357
|
+
*/
|
358
|
+
FlotTooltip.prototype.stringFormat = function (content, item) {
|
359
|
+
var percentPattern = /%p\.{0,1}(\d{0,})/;
|
360
|
+
var seriesPattern = /%s/;
|
361
|
+
var colorPattern = /%c/;
|
362
|
+
var xLabelPattern = /%lx/; // requires flot-axislabels plugin https://github.com/markrcote/flot-axislabels, will be ignored if plugin isn't loaded
|
363
|
+
var yLabelPattern = /%ly/; // requires flot-axislabels plugin https://github.com/markrcote/flot-axislabels, will be ignored if plugin isn't loaded
|
364
|
+
var xPattern = /%x\.{0,1}(\d{0,})/;
|
365
|
+
var yPattern = /%y\.{0,1}(\d{0,})/;
|
366
|
+
var xPatternWithoutPrecision = "%x";
|
367
|
+
var yPatternWithoutPrecision = "%y";
|
368
|
+
var customTextPattern = "%ct";
|
369
|
+
var nPiePattern = "%n";
|
370
|
+
|
371
|
+
var x, y, customText, p, n;
|
372
|
+
|
373
|
+
// for threshold plugin we need to read data from different place
|
374
|
+
if (typeof item.series.threshold !== "undefined") {
|
375
|
+
x = item.datapoint[0];
|
376
|
+
y = item.datapoint[1];
|
377
|
+
customText = item.datapoint[2];
|
378
|
+
}
|
379
|
+
|
380
|
+
// for CurvedLines plugin we need to read data from different place
|
381
|
+
else if (typeof item.series.curvedLines !== "undefined") {
|
382
|
+
x = item.datapoint[0];
|
383
|
+
y = item.datapoint[1];
|
384
|
+
}
|
385
|
+
|
386
|
+
else if (typeof item.series.lines !== "undefined" && item.series.lines.steps) {
|
387
|
+
x = item.series.datapoints.points[item.dataIndex * 2];
|
388
|
+
y = item.series.datapoints.points[item.dataIndex * 2 + 1];
|
389
|
+
// TODO: where to find custom text in this variant?
|
390
|
+
customText = "";
|
391
|
+
} else {
|
392
|
+
x = item.series.data[item.dataIndex][0];
|
393
|
+
y = item.series.data[item.dataIndex][1];
|
394
|
+
customText = item.series.data[item.dataIndex][2];
|
395
|
+
}
|
396
|
+
|
397
|
+
// I think this is only in case of threshold plugin
|
398
|
+
if (item.series.label === null && item.series.originSeries) {
|
399
|
+
item.series.label = item.series.originSeries.label;
|
400
|
+
}
|
401
|
+
|
402
|
+
// if it is a function callback get the content string
|
403
|
+
if (typeof(content) === 'function') {
|
404
|
+
content = content(item.series.label, x, y, item);
|
405
|
+
}
|
406
|
+
|
407
|
+
// the case where the passed content is equal to false
|
408
|
+
if (typeof(content) === 'boolean' && !content) {
|
409
|
+
return '';
|
410
|
+
}
|
411
|
+
|
412
|
+
/* replacement of %ct and other multi-character templates must
|
413
|
+
precede the replacement of single-character templates
|
414
|
+
to avoid conflict between '%c' and '%ct' and similar substrings
|
415
|
+
*/
|
416
|
+
if (customText)
|
417
|
+
content = content.replace(customTextPattern, customText);
|
418
|
+
|
419
|
+
// percent match for pie charts and stacked percent
|
420
|
+
if (typeof (item.series.percent) !== 'undefined') {
|
421
|
+
p = item.series.percent;
|
422
|
+
} else if (typeof (item.series.percents) !== 'undefined') {
|
423
|
+
p = item.series.percents[item.dataIndex];
|
424
|
+
}
|
425
|
+
if (typeof p === 'number') {
|
426
|
+
content = this.adjustValPrecision(percentPattern, content, p);
|
427
|
+
}
|
428
|
+
|
429
|
+
// replace %n with number of items represented by slice in pie charts
|
430
|
+
if (item.series.hasOwnProperty('pie')) {
|
431
|
+
if (typeof (item.series.data[0][1] !== 'undefined')) {
|
432
|
+
n = item.series.data[0][1];
|
433
|
+
}
|
434
|
+
}
|
435
|
+
if (typeof n === 'number') {
|
436
|
+
content = content.replace(nPiePattern, n);
|
437
|
+
}
|
438
|
+
|
439
|
+
// series match
|
440
|
+
if (typeof(item.series.label) !== 'undefined') {
|
441
|
+
content = content.replace(seriesPattern, item.series.label);
|
442
|
+
} else {
|
443
|
+
//remove %s if label is undefined
|
444
|
+
content = content.replace(seriesPattern, "");
|
445
|
+
}
|
446
|
+
|
447
|
+
// color match
|
448
|
+
if (typeof(item.series.color) !== 'undefined') {
|
449
|
+
content = content.replace(colorPattern, item.series.color);
|
450
|
+
} else {
|
451
|
+
//remove %s if color is undefined
|
452
|
+
content = content.replace(colorPattern, "");
|
453
|
+
}
|
454
|
+
|
455
|
+
// x axis label match
|
456
|
+
if (this.hasAxisLabel('xaxis', item)) {
|
457
|
+
content = content.replace(xLabelPattern, item.series.xaxis.options.axisLabel);
|
458
|
+
} else {
|
459
|
+
//remove %lx if axis label is undefined or axislabels plugin not present
|
460
|
+
content = content.replace(xLabelPattern, "");
|
461
|
+
}
|
462
|
+
|
463
|
+
// y axis label match
|
464
|
+
if (this.hasAxisLabel('yaxis', item)) {
|
465
|
+
content = content.replace(yLabelPattern, item.series.yaxis.options.axisLabel);
|
466
|
+
} else {
|
467
|
+
//remove %ly if axis label is undefined or axislabels plugin not present
|
468
|
+
content = content.replace(yLabelPattern, "");
|
469
|
+
}
|
470
|
+
|
471
|
+
// time mode axes with custom dateFormat
|
472
|
+
if (this.isTimeMode('xaxis', item) && this.isXDateFormat(item)) {
|
473
|
+
content = content.replace(xPattern, this.timestampToDate(x, this.tooltipOptions.xDateFormat, item.series.xaxis.options));
|
474
|
+
}
|
475
|
+
if (this.isTimeMode('yaxis', item) && this.isYDateFormat(item)) {
|
476
|
+
content = content.replace(yPattern, this.timestampToDate(y, this.tooltipOptions.yDateFormat, item.series.yaxis.options));
|
477
|
+
}
|
478
|
+
|
479
|
+
// set precision if defined
|
480
|
+
if (typeof x === 'number') {
|
481
|
+
content = this.adjustValPrecision(xPattern, content, x);
|
482
|
+
}
|
483
|
+
if (typeof y === 'number') {
|
484
|
+
content = this.adjustValPrecision(yPattern, content, y);
|
485
|
+
}
|
486
|
+
|
487
|
+
// change x from number to given label, if given
|
488
|
+
if (typeof item.series.xaxis.ticks !== 'undefined') {
|
489
|
+
|
490
|
+
var ticks;
|
491
|
+
if (this.hasRotatedXAxisTicks(item)) {
|
492
|
+
// xaxis.ticks will be an empty array if tickRotor is being used, but the values are available in rotatedTicks
|
493
|
+
ticks = 'rotatedTicks';
|
494
|
+
} else {
|
495
|
+
ticks = 'ticks';
|
496
|
+
}
|
497
|
+
|
498
|
+
// see https://github.com/krzysu/flot.tooltip/issues/65
|
499
|
+
var tickIndex = item.dataIndex + item.seriesIndex;
|
500
|
+
|
501
|
+
for (var xIndex in item.series.xaxis[ticks]) {
|
502
|
+
if (item.series.xaxis[ticks].hasOwnProperty(tickIndex) && !this.isTimeMode('xaxis', item)) {
|
503
|
+
var valueX = (this.isCategoriesMode('xaxis', item)) ? item.series.xaxis[ticks][tickIndex].label : item.series.xaxis[ticks][tickIndex].v;
|
504
|
+
if (valueX === x) {
|
505
|
+
content = content.replace(xPattern, item.series.xaxis[ticks][tickIndex].label.replace(/\$/g, '$$$$'));
|
506
|
+
}
|
507
|
+
}
|
508
|
+
}
|
509
|
+
}
|
510
|
+
|
511
|
+
// change y from number to given label, if given
|
512
|
+
if (typeof item.series.yaxis.ticks !== 'undefined') {
|
513
|
+
for (var yIndex in item.series.yaxis.ticks) {
|
514
|
+
if (item.series.yaxis.ticks.hasOwnProperty(yIndex)) {
|
515
|
+
var valueY = (this.isCategoriesMode('yaxis', item)) ? item.series.yaxis.ticks[yIndex].label : item.series.yaxis.ticks[yIndex].v;
|
516
|
+
if (valueY === y) {
|
517
|
+
content = content.replace(yPattern, item.series.yaxis.ticks[yIndex].label.replace(/\$/g, '$$$$'));
|
518
|
+
}
|
519
|
+
}
|
520
|
+
}
|
521
|
+
}
|
522
|
+
|
523
|
+
// if no value customization, use tickFormatter by default
|
524
|
+
if (typeof item.series.xaxis.tickFormatter !== 'undefined') {
|
525
|
+
//escape dollar
|
526
|
+
content = content.replace(xPatternWithoutPrecision, item.series.xaxis.tickFormatter(x, item.series.xaxis).replace(/\$/g, '$$'));
|
527
|
+
}
|
528
|
+
if (typeof item.series.yaxis.tickFormatter !== 'undefined') {
|
529
|
+
//escape dollar
|
530
|
+
content = content.replace(yPatternWithoutPrecision, item.series.yaxis.tickFormatter(y, item.series.yaxis).replace(/\$/g, '$$'));
|
531
|
+
}
|
532
|
+
|
533
|
+
return content;
|
534
|
+
};
|
535
|
+
|
536
|
+
// helpers just for readability
|
537
|
+
FlotTooltip.prototype.isTimeMode = function (axisName, item) {
|
538
|
+
return (typeof item.series[axisName].options.mode !== 'undefined' && item.series[axisName].options.mode === 'time');
|
539
|
+
};
|
540
|
+
|
541
|
+
FlotTooltip.prototype.isXDateFormat = function (item) {
|
542
|
+
return (typeof this.tooltipOptions.xDateFormat !== 'undefined' && this.tooltipOptions.xDateFormat !== null);
|
543
|
+
};
|
544
|
+
|
545
|
+
FlotTooltip.prototype.isYDateFormat = function (item) {
|
546
|
+
return (typeof this.tooltipOptions.yDateFormat !== 'undefined' && this.tooltipOptions.yDateFormat !== null);
|
547
|
+
};
|
548
|
+
|
549
|
+
FlotTooltip.prototype.isCategoriesMode = function (axisName, item) {
|
550
|
+
return (typeof item.series[axisName].options.mode !== 'undefined' && item.series[axisName].options.mode === 'categories');
|
551
|
+
};
|
552
|
+
|
553
|
+
//
|
554
|
+
FlotTooltip.prototype.timestampToDate = function (tmst, dateFormat, options) {
|
555
|
+
var theDate = $.plot.dateGenerator(tmst, options);
|
556
|
+
return $.plot.formatDate(theDate, dateFormat, this.tooltipOptions.monthNames, this.tooltipOptions.dayNames);
|
557
|
+
};
|
558
|
+
|
559
|
+
//
|
560
|
+
FlotTooltip.prototype.adjustValPrecision = function (pattern, content, value) {
|
561
|
+
|
562
|
+
var precision;
|
563
|
+
var matchResult = content.match(pattern);
|
564
|
+
if( matchResult !== null ) {
|
565
|
+
if(RegExp.$1 !== '') {
|
566
|
+
precision = RegExp.$1;
|
567
|
+
value = value.toFixed(precision);
|
568
|
+
|
569
|
+
// only replace content if precision exists, in other case use thickformater
|
570
|
+
content = content.replace(pattern, value);
|
571
|
+
}
|
572
|
+
}
|
573
|
+
return content;
|
574
|
+
};
|
575
|
+
|
576
|
+
// other plugins detection below
|
577
|
+
|
578
|
+
// check if flot-axislabels plugin (https://github.com/markrcote/flot-axislabels) is used and that an axis label is given
|
579
|
+
FlotTooltip.prototype.hasAxisLabel = function (axisName, item) {
|
580
|
+
return ($.inArray('axisLabels', this.plotPlugins) !== -1 && typeof item.series[axisName].options.axisLabel !== 'undefined' && item.series[axisName].options.axisLabel.length > 0);
|
581
|
+
};
|
582
|
+
|
583
|
+
// check whether flot-tickRotor, a plugin which allows rotation of X-axis ticks, is being used
|
584
|
+
FlotTooltip.prototype.hasRotatedXAxisTicks = function (item) {
|
585
|
+
return ($.inArray('tickRotor',this.plotPlugins) !== -1 && typeof item.series.xaxis.rotatedTicks !== 'undefined');
|
586
|
+
};
|
587
|
+
|
588
|
+
//
|
589
|
+
var init = function (plot) {
|
590
|
+
new FlotTooltip(plot);
|
591
|
+
};
|
592
|
+
|
593
|
+
// define Flot plugin
|
594
|
+
$.plot.plugins.push({
|
595
|
+
init: init,
|
596
|
+
options: defaultOptions,
|
597
|
+
name: 'tooltip',
|
598
|
+
version: '0.8.5'
|
599
|
+
});
|
600
|
+
|
601
|
+
})(jQuery);
|
@@ -0,0 +1,12 @@
|
|
1
|
+
/*
|
2
|
+
* jquery.flot.tooltip
|
3
|
+
*
|
4
|
+
* description: easy-to-use tooltips for Flot charts
|
5
|
+
* version: 0.8.6
|
6
|
+
* authors: Krzysztof Urbas @krzysu [myviews.pl],Evan Steinkerchner @Roundaround
|
7
|
+
* website: https://github.com/krzysu/flot.tooltip
|
8
|
+
*
|
9
|
+
* build on 2016-02-25
|
10
|
+
* released under MIT License, 2012
|
11
|
+
*/
|
12
|
+
!function(a){var b={tooltip:{show:!1,cssClass:"flotTip",content:"%s | X: %x | Y: %y",xDateFormat:null,yDateFormat:null,monthNames:null,dayNames:null,shifts:{x:10,y:20},defaultTheme:!0,snap:!0,lines:!1,clickTips:!1,onHover:function(a,b){},$compat:!1}};b.tooltipOpts=b.tooltip;var c=function(a){this.tipPosition={x:0,y:0},this.init(a)};c.prototype.init=function(b){function c(a){var c={};c.x=a.pageX,c.y=a.pageY,b.setTooltipPosition(c)}function d(c,d,g){f.clickmode?(a(b.getPlaceholder()).bind("plothover",e),b.hideTooltip(),f.clickmode=!1):(e(c,d,g),f.getDomElement().is(":visible")&&(a(b.getPlaceholder()).unbind("plothover",e),f.clickmode=!0))}function e(c,d,e){var g=function(a,b,c,d){return Math.sqrt((c-a)*(c-a)+(d-b)*(d-b))},h=function(a,b,c,d,e,f,h){if(!h||(h=function(a,b,c,d,e,f){if("undefined"!=typeof c)return{x:c,y:b};if("undefined"!=typeof d)return{x:a,y:d};var g,h=-1/((f-d)/(e-c));return{x:g=(e*(a*h-b+d)+c*(a*-h+b-f))/(h*(e-c)+d-f),y:h*g-h*a+b}}(a,b,c,d,e,f),h.x>=Math.min(c,e)&&h.x<=Math.max(c,e)&&h.y>=Math.min(d,f)&&h.y<=Math.max(d,f))){var i=d-f,j=e-c,k=c*f-d*e;return Math.abs(i*a+j*b+k)/Math.sqrt(i*i+j*j)}var l=g(a,b,c,d),m=g(a,b,e,f);return l>m?m:l};if(e)b.showTooltip(e,f.tooltipOptions.snap?e:d);else if(f.plotOptions.series.lines.show&&f.tooltipOptions.lines===!0){var i=f.plotOptions.grid.mouseActiveRadius,j={distance:i+1},k=d;a.each(b.getData(),function(a,c){for(var e=0,i=-1,l=1;l<c.data.length;l++)c.data[l-1][0]<=d.x&&c.data[l][0]>=d.x&&(e=l-1,i=l);if(-1===i)return void b.hideTooltip();var m={x:c.data[e][0],y:c.data[e][1]},n={x:c.data[i][0],y:c.data[i][1]},o=h(c.xaxis.p2c(d.x),c.yaxis.p2c(d.y),c.xaxis.p2c(m.x),c.yaxis.p2c(m.y),c.xaxis.p2c(n.x),c.yaxis.p2c(n.y),!1);if(o<j.distance){var p=g(m.x,m.y,d.x,d.y)<g(d.x,d.y,n.x,n.y)?e:i,q=(c.datapoints.pointsize,[d.x,m.y+(n.y-m.y)*((d.x-m.x)/(n.x-m.x))]),r={datapoint:q,dataIndex:p,series:c,seriesIndex:a};j={distance:o,item:r},f.tooltipOptions.snap&&(k={pageX:c.xaxis.p2c(q[0]),pageY:c.yaxis.p2c(q[1])})}}),j.distance<i+1?b.showTooltip(j.item,k):b.hideTooltip()}else b.hideTooltip()}var f=this,g=a.plot.plugins.length;if(this.plotPlugins=[],g)for(var h=0;g>h;h++)this.plotPlugins.push(a.plot.plugins[h].name);b.hooks.bindEvents.push(function(b,g){if(f.plotOptions=b.getOptions(),"boolean"==typeof f.plotOptions.tooltip&&(f.plotOptions.tooltipOpts.show=f.plotOptions.tooltip,f.plotOptions.tooltip=f.plotOptions.tooltipOpts,delete f.plotOptions.tooltipOpts),f.plotOptions.tooltip.show!==!1&&"undefined"!=typeof f.plotOptions.tooltip.show){f.tooltipOptions=f.plotOptions.tooltip,f.tooltipOptions.$compat?(f.wfunc="width",f.hfunc="height"):(f.wfunc="innerWidth",f.hfunc="innerHeight");f.getDomElement();a(b.getPlaceholder()).bind("plothover",e),f.tooltipOptions.clickTips&&a(b.getPlaceholder()).bind("plotclick",d),f.clickmode=!1,a(g).bind("mousemove",c)}}),b.hooks.shutdown.push(function(b,f){a(b.getPlaceholder()).unbind("plothover",e),a(b.getPlaceholder()).unbind("plotclick",d),b.removeTooltip(),a(f).unbind("mousemove",c)}),b.setTooltipPosition=function(b){var c=f.getDomElement(),d=c.outerWidth()+f.tooltipOptions.shifts.x,e=c.outerHeight()+f.tooltipOptions.shifts.y;b.x-a(window).scrollLeft()>a(window)[f.wfunc]()-d&&(b.x-=d),b.y-a(window).scrollTop()>a(window)[f.hfunc]()-e&&(b.y-=e),isNaN(b.x)?f.tipPosition.x=f.tipPosition.xPrev:(f.tipPosition.x=b.x,f.tipPosition.xPrev=b.x),isNaN(b.y)?f.tipPosition.y=f.tipPosition.yPrev:(f.tipPosition.y=b.y,f.tipPosition.yPrev=b.y)},b.showTooltip=function(a,c,d){var e=f.getDomElement(),g=f.stringFormat(f.tooltipOptions.content,a);""!==g&&(e.html(g),b.setTooltipPosition({x:c.pageX,y:c.pageY}),e.css({left:f.tipPosition.x+f.tooltipOptions.shifts.x,top:f.tipPosition.y+f.tooltipOptions.shifts.y}).show(),"function"==typeof f.tooltipOptions.onHover&&f.tooltipOptions.onHover(a,e))},b.hideTooltip=function(){f.getDomElement().hide().html("")},b.removeTooltip=function(){f.getDomElement().remove()}},c.prototype.getDomElement=function(){var b=a("."+this.tooltipOptions.cssClass);return 0===b.length&&(b=a("<div />").addClass(this.tooltipOptions.cssClass),b.appendTo("body").hide().css({position:"absolute"}),this.tooltipOptions.defaultTheme&&b.css({background:"#fff","z-index":"1040",padding:"0.4em 0.6em","border-radius":"0.5em","font-size":"0.8em",border:"1px solid #111",display:"none","white-space":"nowrap"})),b},c.prototype.stringFormat=function(a,b){var c,d,e,f,g,h=/%p\.{0,1}(\d{0,})/,i=/%s/,j=/%c/,k=/%lx/,l=/%ly/,m=/%x\.{0,1}(\d{0,})/,n=/%y\.{0,1}(\d{0,})/,o="%x",p="%y",q="%ct",r="%n";if("undefined"!=typeof b.series.threshold?(c=b.datapoint[0],d=b.datapoint[1],e=b.datapoint[2]):"undefined"!=typeof b.series.curvedLines?(c=b.datapoint[0],d=b.datapoint[1]):"undefined"!=typeof b.series.lines&&b.series.lines.steps?(c=b.series.datapoints.points[2*b.dataIndex],d=b.series.datapoints.points[2*b.dataIndex+1],e=""):(c=b.series.data[b.dataIndex][0],d=b.series.data[b.dataIndex][1],e=b.series.data[b.dataIndex][2]),null===b.series.label&&b.series.originSeries&&(b.series.label=b.series.originSeries.label),"function"==typeof a&&(a=a(b.series.label,c,d,b)),"boolean"==typeof a&&!a)return"";if(e&&(a=a.replace(q,e)),"undefined"!=typeof b.series.percent?f=b.series.percent:"undefined"!=typeof b.series.percents&&(f=b.series.percents[b.dataIndex]),"number"==typeof f&&(a=this.adjustValPrecision(h,a,f)),b.series.hasOwnProperty("pie")&&(g=b.series.data[0][1]),"number"==typeof g&&(a=a.replace(r,g)),a="undefined"!=typeof b.series.label?a.replace(i,b.series.label):a.replace(i,""),a="undefined"!=typeof b.series.color?a.replace(j,b.series.color):a.replace(j,""),a=this.hasAxisLabel("xaxis",b)?a.replace(k,b.series.xaxis.options.axisLabel):a.replace(k,""),a=this.hasAxisLabel("yaxis",b)?a.replace(l,b.series.yaxis.options.axisLabel):a.replace(l,""),this.isTimeMode("xaxis",b)&&this.isXDateFormat(b)&&(a=a.replace(m,this.timestampToDate(c,this.tooltipOptions.xDateFormat,b.series.xaxis.options))),this.isTimeMode("yaxis",b)&&this.isYDateFormat(b)&&(a=a.replace(n,this.timestampToDate(d,this.tooltipOptions.yDateFormat,b.series.yaxis.options))),"number"==typeof c&&(a=this.adjustValPrecision(m,a,c)),"number"==typeof d&&(a=this.adjustValPrecision(n,a,d)),"undefined"!=typeof b.series.xaxis.ticks){var s;s=this.hasRotatedXAxisTicks(b)?"rotatedTicks":"ticks";var t=b.dataIndex+b.seriesIndex;for(var u in b.series.xaxis[s])if(b.series.xaxis[s].hasOwnProperty(t)&&!this.isTimeMode("xaxis",b)){var v=this.isCategoriesMode("xaxis",b)?b.series.xaxis[s][t].label:b.series.xaxis[s][t].v;v===c&&(a=a.replace(m,b.series.xaxis[s][t].label.replace(/\$/g,"$$$$")))}}if("undefined"!=typeof b.series.yaxis.ticks)for(var w in b.series.yaxis.ticks)if(b.series.yaxis.ticks.hasOwnProperty(w)){var x=this.isCategoriesMode("yaxis",b)?b.series.yaxis.ticks[w].label:b.series.yaxis.ticks[w].v;x===d&&(a=a.replace(n,b.series.yaxis.ticks[w].label.replace(/\$/g,"$$$$")))}return"undefined"!=typeof b.series.xaxis.tickFormatter&&(a=a.replace(o,b.series.xaxis.tickFormatter(c,b.series.xaxis).replace(/\$/g,"$$"))),"undefined"!=typeof b.series.yaxis.tickFormatter&&(a=a.replace(p,b.series.yaxis.tickFormatter(d,b.series.yaxis).replace(/\$/g,"$$"))),a},c.prototype.isTimeMode=function(a,b){return"undefined"!=typeof b.series[a].options.mode&&"time"===b.series[a].options.mode},c.prototype.isXDateFormat=function(a){return"undefined"!=typeof this.tooltipOptions.xDateFormat&&null!==this.tooltipOptions.xDateFormat},c.prototype.isYDateFormat=function(a){return"undefined"!=typeof this.tooltipOptions.yDateFormat&&null!==this.tooltipOptions.yDateFormat},c.prototype.isCategoriesMode=function(a,b){return"undefined"!=typeof b.series[a].options.mode&&"categories"===b.series[a].options.mode},c.prototype.timestampToDate=function(b,c,d){var e=a.plot.dateGenerator(b,d);return a.plot.formatDate(e,c,this.tooltipOptions.monthNames,this.tooltipOptions.dayNames)},c.prototype.adjustValPrecision=function(a,b,c){var d,e=b.match(a);return null!==e&&""!==RegExp.$1&&(d=RegExp.$1,c=c.toFixed(d),b=b.replace(a,c)),b},c.prototype.hasAxisLabel=function(b,c){return-1!==a.inArray("axisLabels",this.plotPlugins)&&"undefined"!=typeof c.series[b].options.axisLabel&&c.series[b].options.axisLabel.length>0},c.prototype.hasRotatedXAxisTicks=function(b){return-1!==a.inArray("tickRotor",this.plotPlugins)&&"undefined"!=typeof b.series.xaxis.rotatedTicks};var d=function(a){new c(a)};a.plot.plugins.push({init:d,options:b,name:"tooltip",version:"0.8.5"})}(jQuery);
|
@@ -10,6 +10,7 @@
|
|
10
10
|
this.graphType = json.graphType || 'line';
|
11
11
|
this.stackMode = json.stackMode || 'false';
|
12
12
|
this.lineWidth = json.lineWidth || 1;
|
13
|
+
this.tooltips = json.tooltips || 'metric';
|
13
14
|
this.timeRange = (json.timeRange * 1000) || 300000;
|
14
15
|
|
15
16
|
this.font = {
|
@@ -82,7 +83,7 @@
|
|
82
83
|
|
83
84
|
// Initialize Flot
|
84
85
|
this.container.empty();
|
85
|
-
|
86
|
+
var plotOptions = {
|
86
87
|
legend: {
|
87
88
|
position: "nw",
|
88
89
|
backgroundOpacity: 0.7,
|
@@ -91,7 +92,7 @@
|
|
91
92
|
borderWidth: 1,
|
92
93
|
borderColor: "#aaa",
|
93
94
|
color: "#444",
|
94
|
-
backgroundColor: '#fff'
|
95
|
+
backgroundColor: '#fff',
|
95
96
|
},
|
96
97
|
yaxis: {
|
97
98
|
font: this.font,
|
@@ -104,7 +105,36 @@
|
|
104
105
|
min: t - this.timeRange,
|
105
106
|
max: t
|
106
107
|
}
|
107
|
-
}
|
108
|
+
};
|
109
|
+
|
110
|
+
var tooltipCommon = {
|
111
|
+
grid: {
|
112
|
+
hoverable: true,
|
113
|
+
autoHighlight: true,
|
114
|
+
}
|
115
|
+
};
|
116
|
+
|
117
|
+
var tooltipOption = {
|
118
|
+
metric: {
|
119
|
+
tooltip: {
|
120
|
+
show: true,
|
121
|
+
content: "<b>%s</b><br />%x<br />%y",
|
122
|
+
}
|
123
|
+
},
|
124
|
+
simple: {
|
125
|
+
tooltip: {
|
126
|
+
show: true,
|
127
|
+
content: "<b>%s</b>",
|
128
|
+
}
|
129
|
+
}
|
130
|
+
};
|
131
|
+
|
132
|
+
if (this.tooltips != 'false') {
|
133
|
+
_.merge(plotOptions, tooltipCommon);
|
134
|
+
_.merge(plotOptions, tooltipOption[this.tooltips]);
|
135
|
+
}
|
136
|
+
|
137
|
+
this.graph = $.plot(this.container, this.data, plotOptions);
|
108
138
|
};
|
109
139
|
|
110
140
|
// Called as the clock advances to new times.
|
@@ -246,7 +276,8 @@
|
|
246
276
|
max: this.max,
|
247
277
|
timeRange: this.timeRange / 1000,
|
248
278
|
graphType: this.graphType,
|
249
|
-
stackMode: this.stackMode
|
279
|
+
stackMode: this.stackMode,
|
280
|
+
tooltips: this.tooltips,
|
250
281
|
});
|
251
282
|
};
|
252
283
|
|
@@ -263,7 +294,15 @@
|
|
263
294
|
'<select name="stackMode">' +
|
264
295
|
'<option value="true" {% if(stackMode == \'true\') print(\'selected\') %}>Stacked</option>' +
|
265
296
|
'<option value="false" {% if(stackMode == \'false\') print(\'selected\') %}>Normal</option>' +
|
266
|
-
'</select
|
297
|
+
'</select>' +
|
298
|
+
'<br />' +
|
299
|
+
'<label for="tooltips">Tooltips</label>' +
|
300
|
+
'<select name="tooltips">' +
|
301
|
+
'<option value="metric" {% if(tooltips == \'metric\') print(\'selected\') %}>With metric</option>' +
|
302
|
+
'<option value="simple" {% if(tooltips == \'simple\') print(\'selected\') %}>Simple</option>' +
|
303
|
+
'<option value="false" {% if(tooltips == \'false\') print(\'selected\') %}>Disabled</option>' +
|
304
|
+
'</select>' +
|
305
|
+
'<br />' +
|
267
306
|
'<label for="query">query</label>' +
|
268
307
|
'<textarea type="text" class="query" name="query">{{ query }}</textarea><br />' +
|
269
308
|
'<label for="timeRange">Time range (s)</label>' +
|
@@ -0,0 +1,151 @@
|
|
1
|
+
var GlobalAudioContext = new (window.AudioContext || window.webkitAudioContext)();
|
2
|
+
|
3
|
+
(function() {
|
4
|
+
var Geiger = function(json) {
|
5
|
+
// Init
|
6
|
+
view.View.call(this, json);
|
7
|
+
|
8
|
+
this.clickFocusable = true;
|
9
|
+
this.selfid = Math.floor(Math.random() * 255);
|
10
|
+
|
11
|
+
var self = this;
|
12
|
+
|
13
|
+
// Config
|
14
|
+
this.title = json.title;
|
15
|
+
this.query = json.query;
|
16
|
+
this.muted = json.muted || false;
|
17
|
+
this.volume = parseFloat(json.volume || 0.2);
|
18
|
+
this.sound = json.sound || 'sounds/geiger.wav';
|
19
|
+
this.muted = json.muted || false;
|
20
|
+
|
21
|
+
// State
|
22
|
+
this.currentEvent = null;
|
23
|
+
this.shouldPlay = false;
|
24
|
+
this.soundBuffer = null;
|
25
|
+
|
26
|
+
// HTML
|
27
|
+
this.el.append(
|
28
|
+
'<div class="box">' +
|
29
|
+
'<h2 class="quickfit"></h2>' +
|
30
|
+
'<button class="sound-mute" type="button">Mute</button><br />' +
|
31
|
+
'</div>'
|
32
|
+
);
|
33
|
+
|
34
|
+
this.box = this.el.find('.box');
|
35
|
+
this.el.find('h2').text(this.title);
|
36
|
+
|
37
|
+
this.mute_button = this.el.find('.sound-mute');
|
38
|
+
this.mute_button.text(this.muted ? 'Unmute' : 'Mute');
|
39
|
+
this.mute_button.click(function () {
|
40
|
+
self.muted = !self.muted;
|
41
|
+
self.mute_button.text(self.muted ? 'Unmute' : 'Mute');
|
42
|
+
});
|
43
|
+
|
44
|
+
if (!json.virtual) {
|
45
|
+
// Virtual instance of the geiger counter should not produce any sounds.
|
46
|
+
// Moreover, to save resources, I will not create audio nodes and will
|
47
|
+
// not load data.
|
48
|
+
this.gainer = GlobalAudioContext.createGain();
|
49
|
+
|
50
|
+
this.gainer.gain.value = Math.pow(this.volume, 2);
|
51
|
+
this.gainer.connect(GlobalAudioContext.destination);
|
52
|
+
|
53
|
+
this.compressor = GlobalAudioContext.createDynamicsCompressor();
|
54
|
+
this.compressor.threshold.value = 0;
|
55
|
+
this.compressor.knee.value = 0;
|
56
|
+
this.compressor.ratio.value = 20;
|
57
|
+
this.compressor.attack.value = 0;
|
58
|
+
this.compressor.release.value = 2;
|
59
|
+
this.compressor.connect(this.gainer);
|
60
|
+
|
61
|
+
this.request = new XMLHttpRequest();
|
62
|
+
this.request.open('GET', this.sound, true);
|
63
|
+
this.request.responseType = 'arraybuffer';
|
64
|
+
|
65
|
+
this.request.onload = function () {
|
66
|
+
if (this.status != 200) {
|
67
|
+
toastr.warning ("Could not load sound " + self.sound + ", HTTP status " + this.status);
|
68
|
+
}
|
69
|
+
|
70
|
+
GlobalAudioContext.decodeAudioData(this.response, function (buffer) {
|
71
|
+
self.soundBuffer = buffer;
|
72
|
+
self.shouldPlay = true;
|
73
|
+
});
|
74
|
+
};
|
75
|
+
|
76
|
+
this.request.onerror = function () {
|
77
|
+
toastr.warning ("Could not load sound " + self.sound + ", general error");
|
78
|
+
}
|
79
|
+
|
80
|
+
this.request.send();
|
81
|
+
|
82
|
+
if (this.query) {
|
83
|
+
var me = this;
|
84
|
+
this.sub = subs.subscribe(this.query, function(e) {
|
85
|
+
self.playSound();
|
86
|
+
self.currentEvent = e;
|
87
|
+
});
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
view.inherit(view.View, Geiger);
|
93
|
+
view.Geiger = Geiger;
|
94
|
+
view.types.Geiger = Geiger;
|
95
|
+
|
96
|
+
Geiger.prototype.json = function() {
|
97
|
+
return $.extend(view.View.prototype.json.call(this), {
|
98
|
+
type: 'Geiger',
|
99
|
+
title: this.title,
|
100
|
+
query: this.query,
|
101
|
+
volume: this.volume,
|
102
|
+
sound: this.sound,
|
103
|
+
muted: this.muted
|
104
|
+
});
|
105
|
+
}
|
106
|
+
|
107
|
+
Geiger.prototype.playSound = function() {
|
108
|
+
if (!this.shouldPlay || this.muted) {
|
109
|
+
return;
|
110
|
+
}
|
111
|
+
|
112
|
+
source = GlobalAudioContext.createBufferSource();
|
113
|
+
source.buffer = this.soundBuffer;
|
114
|
+
source.connect(this.compressor);
|
115
|
+
source.start();
|
116
|
+
}
|
117
|
+
|
118
|
+
|
119
|
+
var editTemplate = _.template(
|
120
|
+
"<label for='title'>Title</label>" +
|
121
|
+
"<input type='text' name='title' value='{{title}}' /><br />" +
|
122
|
+
"<label for='query'>Query</label>" +
|
123
|
+
'<textarea type="text" name="query" class="query">{{query}}</textarea>' +
|
124
|
+
"<label for='sound'>Sound</label>" +
|
125
|
+
"<input type='text' name='sound' value='{{sound}}' /><br />" +
|
126
|
+
"<label for='volume'>Volume</label>" +
|
127
|
+
"<input type='range' name='volume' min='0' max='1' step='0.05' value='{{volume}}' />" );
|
128
|
+
|
129
|
+
Geiger.prototype.editForm = function() {
|
130
|
+
return editTemplate(this);
|
131
|
+
}
|
132
|
+
|
133
|
+
Geiger.prototype.shutdownSound = function() {
|
134
|
+
this.shouldPlay = false;
|
135
|
+
this.gainer.disconnect();
|
136
|
+
this.compressor.disconnect();
|
137
|
+
this.gainer = null;
|
138
|
+
this.compressor = null;
|
139
|
+
|
140
|
+
this.soundBuffer = null;
|
141
|
+
}
|
142
|
+
|
143
|
+
Geiger.prototype.delete = function() {
|
144
|
+
if (this.sub) {
|
145
|
+
subs.unsubscribe(this.sub);
|
146
|
+
}
|
147
|
+
|
148
|
+
this.shutdownSound();
|
149
|
+
return view.View.prototype.delete.call(this);
|
150
|
+
}
|
151
|
+
})();
|
@@ -5,8 +5,9 @@
|
|
5
5
|
this.el.addClass("help");
|
6
6
|
this.el.append('<div class="box">' +
|
7
7
|
"<p>Welcome to Riemann-Dash.</p>" +
|
8
|
-
"<p>Need a refresher on the query language? See the <a href=\"https://github.com/
|
9
|
-
"<p>
|
8
|
+
"<p>Need a refresher on the query language? See the <a href=\"https://github.com/riemann/riemann/blob/master/test/riemann/query_test.clj\">query tests</a> for examples, or read the <a href=\"https://github.com/riemann/riemann/blob/master/resources/query.g4\">spec</a>.</p>" +
|
9
|
+
"<p>Double-click a workspace to rename it.</p>" +
|
10
|
+
"<p>Press <b>Control/Meta+click</b> to select a view (<b>Option+Command+click</b> on a Mac). Escape unfocuses. Use the arrow keys to move a view. Use Control+arrow to <i>split</i> a view in the given direction.</p>" +
|
10
11
|
"<p>To edit a view, hit e. Use enter, or click 'apply', to apply your changes. Escape cancels.</p>" +
|
11
12
|
"<p>To save your changes to the server, press s. To display the configuration, press c.</p>" +
|
12
13
|
"<p>You can refresh the page, or press r to reload.</p>" +
|
@@ -24,7 +24,7 @@
|
|
24
24
|
this.log = this.el.find('tbody');
|
25
25
|
|
26
26
|
// Line template
|
27
|
-
this.lineTemplate = _.template("<tr><td>{{host}}</td><td>{{service}}</td><td>{{state}}</td><td>{{metric}}</td><td>{{description}}</td></tr>");
|
27
|
+
this.lineTemplate = _.template("<tr><td>{{-host}}</td><td>{{-service}}</td><td>{{-state}}</td><td>{{-metric}}</td><td>{{-description}}</td></tr>");
|
28
28
|
|
29
29
|
// When scrolling occurs, toggle tracking state.
|
30
30
|
this.scroll.scroll(function(e) {
|
data/lib/riemann/dash/version.rb
CHANGED
@@ -5,6 +5,8 @@
|
|
5
5
|
<title>riemann</title>
|
6
6
|
<link rel="stylesheet" type="text/css" href="vendor/toastr/toastr.css" />
|
7
7
|
<link rel="stylesheet" type="text/css" href="css" />
|
8
|
+
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
|
9
|
+
<link rel="icon" href="/favicon.ico" type="image/x-icon">
|
8
10
|
</head>
|
9
11
|
<body>
|
10
12
|
<div id="toolbar"></div>
|
@@ -25,6 +27,7 @@
|
|
25
27
|
<script src="vendor/flot/jquery.flot.canvas.min.js"></script>
|
26
28
|
<script src="vendor/flot/jquery.flot.time.min.js"></script>
|
27
29
|
<script src="vendor/flot/jquery.flot.stack.min.js"></script>
|
30
|
+
<script src="vendor/flot/jquery.flot.tooltip.min.js"></script>
|
28
31
|
<script src="vendor/PriorityQueue.js"></script>
|
29
32
|
<script src="vendor/gauge.min.js"></script>
|
30
33
|
<script src="vendor/jquery.gauge.js"></script>
|
@@ -55,6 +58,7 @@
|
|
55
58
|
<script src="views/list.js"></script>
|
56
59
|
<script src="views/help.js"></script>
|
57
60
|
<script src="views/gauge.js"></script>
|
61
|
+
<script src="views/geiger.js"></script>
|
58
62
|
<script src="views/dial.js"></script>
|
59
63
|
<script src="views/grid.js"></script>
|
60
64
|
<script src="views/iframe.js"></script>
|
data/riemann-dash.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |gem|
|
|
12
12
|
gem.email = ['aphyr@aphyr.com']
|
13
13
|
gem.description = %q{HTTP dashboard for the distributed event system Riemann.}
|
14
14
|
gem.summary = gem.description
|
15
|
-
gem.homepage = 'https://github.com/
|
15
|
+
gem.homepage = 'https://github.com/riemann/riemann-dash'
|
16
16
|
gem.platform = Gem::Platform::RUBY
|
17
17
|
|
18
18
|
gem.add_dependency 'erubis', '>= 2.7.0'
|
metadata
CHANGED
@@ -1,84 +1,74 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: riemann-dash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
5
|
-
prerelease:
|
4
|
+
version: 0.2.13
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Kyle Kingsbury
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2016-06-26 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: erubis
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: 2.7.0
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: 2.7.0
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: sinatra
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- - ~>
|
31
|
+
- - "~>"
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: 1.4.5
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- - ~>
|
38
|
+
- - "~>"
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: 1.4.5
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: sass
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - ">="
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: 3.1.14
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - ">="
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: 3.1.14
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: webrick
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- - ~>
|
59
|
+
- - "~>"
|
68
60
|
- !ruby/object:Gem::Version
|
69
61
|
version: 1.3.1
|
70
62
|
type: :runtime
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- - ~>
|
66
|
+
- - "~>"
|
76
67
|
- !ruby/object:Gem::Version
|
77
68
|
version: 1.3.1
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: multi_json
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
73
|
- - '='
|
84
74
|
- !ruby/object:Gem::Version
|
@@ -86,7 +76,6 @@ dependencies:
|
|
86
76
|
type: :runtime
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
80
|
- - '='
|
92
81
|
- !ruby/object:Gem::Version
|
@@ -99,7 +88,7 @@ executables:
|
|
99
88
|
extensions: []
|
100
89
|
extra_rdoc_files: []
|
101
90
|
files:
|
102
|
-
- .gitignore
|
91
|
+
- ".gitignore"
|
103
92
|
- Gemfile
|
104
93
|
- Gemfile.lock
|
105
94
|
- LICENSE
|
@@ -119,10 +108,13 @@ files:
|
|
119
108
|
- lib/riemann/dash/public/clock.js
|
120
109
|
- lib/riemann/dash/public/dash.js
|
121
110
|
- lib/riemann/dash/public/eventPane.js
|
111
|
+
- lib/riemann/dash/public/favicon.ico
|
122
112
|
- lib/riemann/dash/public/format.js
|
123
113
|
- lib/riemann/dash/public/keys.js
|
124
114
|
- lib/riemann/dash/public/persistence.js
|
125
115
|
- lib/riemann/dash/public/profile.js
|
116
|
+
- lib/riemann/dash/public/sounds/beep.wav
|
117
|
+
- lib/riemann/dash/public/sounds/geiger.wav
|
126
118
|
- lib/riemann/dash/public/strings.js
|
127
119
|
- lib/riemann/dash/public/subs.js
|
128
120
|
- lib/riemann/dash/public/toolbar.js
|
@@ -161,6 +153,8 @@ files:
|
|
161
153
|
- lib/riemann/dash/public/vendor/flot/jquery.flot.threshold.min.js
|
162
154
|
- lib/riemann/dash/public/vendor/flot/jquery.flot.time.js
|
163
155
|
- lib/riemann/dash/public/vendor/flot/jquery.flot.time.min.js
|
156
|
+
- lib/riemann/dash/public/vendor/flot/jquery.flot.tooltip.js
|
157
|
+
- lib/riemann/dash/public/vendor/flot/jquery.flot.tooltip.min.js
|
164
158
|
- lib/riemann/dash/public/vendor/gauge.min.js
|
165
159
|
- lib/riemann/dash/public/vendor/jquery.gauge.js
|
166
160
|
- lib/riemann/dash/public/vendor/jquery/jquery-1.9.1.min.js
|
@@ -176,6 +170,7 @@ files:
|
|
176
170
|
- lib/riemann/dash/public/views/dial.js
|
177
171
|
- lib/riemann/dash/public/views/flot.js
|
178
172
|
- lib/riemann/dash/public/views/gauge.js
|
173
|
+
- lib/riemann/dash/public/views/geiger.js
|
179
174
|
- lib/riemann/dash/public/views/grid.js
|
180
175
|
- lib/riemann/dash/public/views/help.js
|
181
176
|
- lib/riemann/dash/public/views/iframe.js
|
@@ -200,29 +195,28 @@ files:
|
|
200
195
|
- test/fixtures/ws_config/dummy_config.json
|
201
196
|
- test/fixtures/ws_config/pretty_printed_config.json
|
202
197
|
- test/test_helper.rb
|
203
|
-
homepage: https://github.com/
|
198
|
+
homepage: https://github.com/riemann/riemann-dash
|
204
199
|
licenses: []
|
200
|
+
metadata: {}
|
205
201
|
post_install_message:
|
206
202
|
rdoc_options: []
|
207
203
|
require_paths:
|
208
204
|
- lib
|
209
205
|
required_ruby_version: !ruby/object:Gem::Requirement
|
210
|
-
none: false
|
211
206
|
requirements:
|
212
|
-
- -
|
207
|
+
- - ">="
|
213
208
|
- !ruby/object:Gem::Version
|
214
209
|
version: '0'
|
215
210
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
216
|
-
none: false
|
217
211
|
requirements:
|
218
|
-
- -
|
212
|
+
- - ">="
|
219
213
|
- !ruby/object:Gem::Version
|
220
214
|
version: '0'
|
221
215
|
requirements: []
|
222
216
|
rubyforge_project: riemann-dash
|
223
|
-
rubygems_version:
|
217
|
+
rubygems_version: 2.4.5
|
224
218
|
signing_key:
|
225
|
-
specification_version:
|
219
|
+
specification_version: 4
|
226
220
|
summary: HTTP dashboard for the distributed event system Riemann.
|
227
221
|
test_files:
|
228
222
|
- test/browser_config_test.rb
|