elasticsearch-paramedic-rack 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +38 -0
- data/Rakefile +24 -0
- data/elasticsearch-paramedic-rack.gemspec +24 -0
- data/lib/elasticsearch-paramedic-rack.rb +10 -0
- data/lib/elasticsearch-paramedic-rack/middelware.rb +23 -0
- data/lib/elasticsearch-paramedic-rack/version.rb +7 -0
- data/public/elasticsearch-paramedic/audio/alert-green.mp3 +0 -0
- data/public/elasticsearch-paramedic/audio/alert-red.mp3 +0 -0
- data/public/elasticsearch-paramedic/audio/alert-yellow.mp3 +0 -0
- data/public/elasticsearch-paramedic/css/app.css +312 -0
- data/public/elasticsearch-paramedic/css/libs/cubism.css +57 -0
- data/public/elasticsearch-paramedic/css/libs/style.css +499 -0
- data/public/elasticsearch-paramedic/img/apple-touch-icon.png +0 -0
- data/public/elasticsearch-paramedic/img/glyphicons-halflings-white.png +0 -0
- data/public/elasticsearch-paramedic/img/glyphicons-halflings.png +0 -0
- data/public/elasticsearch-paramedic/img/spinner.gif +0 -0
- data/public/elasticsearch-paramedic/index.html +196 -0
- data/public/elasticsearch-paramedic/js/app.js +474 -0
- data/public/elasticsearch-paramedic/js/cubism.js +109 -0
- data/public/elasticsearch-paramedic/js/libs/colorbrewer.min.js +1 -0
- data/public/elasticsearch-paramedic/js/libs/cubism.elasticsearch.js +273 -0
- data/public/elasticsearch-paramedic/js/libs/cubism.v1.js +986 -0
- data/public/elasticsearch-paramedic/js/libs/cubism.v1.min.js +1 -0
- data/public/elasticsearch-paramedic/js/libs/d3.v2.min.js +4 -0
- data/public/elasticsearch-paramedic/js/libs/ember-0.9.8.js +20150 -0
- data/public/elasticsearch-paramedic/js/libs/ember-0.9.8.min.js +14 -0
- data/public/elasticsearch-paramedic/js/libs/jquery-1.7.2.min.js +4 -0
- data/test/middelware_test.rb +63 -0
- data/test/test_helper.rb +12 -0
- metadata +134 -0
@@ -0,0 +1,109 @@
|
|
1
|
+
var App = App || Em.Application.create({});
|
2
|
+
|
3
|
+
App.Cubism = Ember.Object.create({
|
4
|
+
|
5
|
+
// ElasticSearch extension instance
|
6
|
+
elasticsearch: {},
|
7
|
+
|
8
|
+
// Cubism.js context
|
9
|
+
context: {},
|
10
|
+
|
11
|
+
// Chart canvas
|
12
|
+
chart: d3.select("#chart").append("div").attr("id", "chart-inner"),
|
13
|
+
|
14
|
+
// Function to add new horizon chart
|
15
|
+
add_chart: function(metrics, options) {
|
16
|
+
var options = options || {colors: 'Greens'}
|
17
|
+
|
18
|
+
this.chart.selectAll(".horizon")
|
19
|
+
.data(metrics, function(d) { return d.toString(); })
|
20
|
+
.enter().append("div")
|
21
|
+
.attr("class", "horizon")
|
22
|
+
.call(this.context.horizon()
|
23
|
+
.height(25)
|
24
|
+
.colors(function() { return colorbrewer[options['colors']][8] })
|
25
|
+
)
|
26
|
+
return this.chart;
|
27
|
+
},
|
28
|
+
|
29
|
+
// Setup the whole chart
|
30
|
+
setup: function() {
|
31
|
+
var self = this
|
32
|
+
|
33
|
+
// Setup context
|
34
|
+
self.__setup_context()
|
35
|
+
|
36
|
+
// Top axis
|
37
|
+
if ( d3.select("#chart .axis.top").empty() )
|
38
|
+
self.chart.append("div")
|
39
|
+
.attr("class", "axis top")
|
40
|
+
.call(self.context.axis().orient("top"));
|
41
|
+
|
42
|
+
// Rule
|
43
|
+
if ( d3.select("#chart .rule").empty() )
|
44
|
+
self.chart.append("div")
|
45
|
+
.attr("class", "rule")
|
46
|
+
.call(self.context.rule());
|
47
|
+
|
48
|
+
// Move the rule with mouse
|
49
|
+
self.context.on("focus", function(i) { d3.selectAll(".value").style("right", i == null ? null : self.context.size() - i + "px"); })
|
50
|
+
|
51
|
+
// Draw the chart(s)
|
52
|
+
self.__draw()
|
53
|
+
|
54
|
+
return self
|
55
|
+
},
|
56
|
+
|
57
|
+
// Remove the chart and re-draw it
|
58
|
+
reset: function() {
|
59
|
+
var self = this
|
60
|
+
|
61
|
+
// Re-insert the chart element
|
62
|
+
d3.select("#chart-inner").remove()
|
63
|
+
self.chart = d3.select("#chart").append("div").attr("id", "chart-inner")
|
64
|
+
|
65
|
+
// Re-initialize everything
|
66
|
+
self.setup()
|
67
|
+
return self
|
68
|
+
},
|
69
|
+
|
70
|
+
// Start the polling/animation
|
71
|
+
start: function() {
|
72
|
+
if (this.context.start) this.context.start()
|
73
|
+
},
|
74
|
+
|
75
|
+
// Stop the polling/animation
|
76
|
+
stop: function() {
|
77
|
+
if (this.context.stop) this.context.stop()
|
78
|
+
},
|
79
|
+
|
80
|
+
// Draw the metrics
|
81
|
+
__draw: function() {
|
82
|
+
var self = this
|
83
|
+
|
84
|
+
self.elasticsearch = cubism.elasticsearch(self.context, {host: App.elasticsearch_url}, function() {
|
85
|
+
[
|
86
|
+
{ metrics: this.metrics("os.cpu.user"), colors: 'Greens' },
|
87
|
+
{ metrics: this.metrics("process.cpu.percent"), colors: 'Greens' },
|
88
|
+
{ metrics: this.metrics("jvm.mem.heap_used_in_bytes"), colors: 'Blues' },
|
89
|
+
{ metrics: this.metrics("http.current_open"), colors: 'Oranges' },
|
90
|
+
{ metrics: this.metrics("indices.indexing.index_current"), colors: 'Spectral' },
|
91
|
+
{ metrics: this.metrics("indices.search.query_current"), colors: 'YlOrRd' }
|
92
|
+
].forEach(
|
93
|
+
function(group) { self.add_chart(group.metrics, {colors: group.colors}) }
|
94
|
+
)
|
95
|
+
|
96
|
+
return self
|
97
|
+
});
|
98
|
+
},
|
99
|
+
|
100
|
+
__setup_context: function() {
|
101
|
+
this.context = cubism.context()
|
102
|
+
.serverDelay(0)
|
103
|
+
.clientDelay(0)
|
104
|
+
.step(1000)
|
105
|
+
.size($("#chart").width())
|
106
|
+
}
|
107
|
+
|
108
|
+
});
|
109
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
var colorbrewer={YlGn:{3:["rgb(247,252,185)","rgb(173,221,142)","rgb(49,163,84)"],4:["rgb(255,255,204)","rgb(194,230,153)","rgb(120,198,121)","rgb(35,132,67)"],5:["rgb(255,255,204)","rgb(194,230,153)","rgb(120,198,121)","rgb(49,163,84)","rgb(0,104,55)"],6:["rgb(255,255,204)","rgb(217,240,163)","rgb(173,221,142)","rgb(120,198,121)","rgb(49,163,84)","rgb(0,104,55)"],7:["rgb(255,255,204)","rgb(217,240,163)","rgb(173,221,142)","rgb(120,198,121)","rgb(65,171,93)","rgb(35,132,67)","rgb(0,90,50)"],8:["rgb(255,255,229)","rgb(247,252,185)","rgb(217,240,163)","rgb(173,221,142)","rgb(120,198,121)","rgb(65,171,93)","rgb(35,132,67)","rgb(0,90,50)"],9:["rgb(255,255,229)","rgb(247,252,185)","rgb(217,240,163)","rgb(173,221,142)","rgb(120,198,121)","rgb(65,171,93)","rgb(35,132,67)","rgb(0,104,55)","rgb(0,69,41)"]},YlGnBu:{3:["rgb(237,248,177)","rgb(127,205,187)","rgb(44,127,184)"],4:["rgb(255,255,204)","rgb(161,218,180)","rgb(65,182,196)","rgb(34,94,168)"],5:["rgb(255,255,204)","rgb(161,218,180)","rgb(65,182,196)","rgb(44,127,184)","rgb(37,52,148)"],6:["rgb(255,255,204)","rgb(199,233,180)","rgb(127,205,187)","rgb(65,182,196)","rgb(44,127,184)","rgb(37,52,148)"],7:["rgb(255,255,204)","rgb(199,233,180)","rgb(127,205,187)","rgb(65,182,196)","rgb(29,145,192)","rgb(34,94,168)","rgb(12,44,132)"],8:["rgb(255,255,217)","rgb(237,248,177)","rgb(199,233,180)","rgb(127,205,187)","rgb(65,182,196)","rgb(29,145,192)","rgb(34,94,168)","rgb(12,44,132)"],9:["rgb(255,255,217)","rgb(237,248,177)","rgb(199,233,180)","rgb(127,205,187)","rgb(65,182,196)","rgb(29,145,192)","rgb(34,94,168)","rgb(37,52,148)","rgb(8,29,88)"]},GnBu:{3:["rgb(224,243,219)","rgb(168,221,181)","rgb(67,162,202)"],4:["rgb(240,249,232)","rgb(186,228,188)","rgb(123,204,196)","rgb(43,140,190)"],5:["rgb(240,249,232)","rgb(186,228,188)","rgb(123,204,196)","rgb(67,162,202)","rgb(8,104,172)"],6:["rgb(240,249,232)","rgb(204,235,197)","rgb(168,221,181)","rgb(123,204,196)","rgb(67,162,202)","rgb(8,104,172)"],7:["rgb(240,249,232)","rgb(204,235,197)","rgb(168,221,181)","rgb(123,204,196)","rgb(78,179,211)","rgb(43,140,190)","rgb(8,88,158)"],8:["rgb(247,252,240)","rgb(224,243,219)","rgb(204,235,197)","rgb(168,221,181)","rgb(123,204,196)","rgb(78,179,211)","rgb(43,140,190)","rgb(8,88,158)"],9:["rgb(247,252,240)","rgb(224,243,219)","rgb(204,235,197)","rgb(168,221,181)","rgb(123,204,196)","rgb(78,179,211)","rgb(43,140,190)","rgb(8,104,172)","rgb(8,64,129)"]},BuGn:{3:["rgb(229,245,249)","rgb(153,216,201)","rgb(44,162,95)"],4:["rgb(237,248,251)","rgb(178,226,226)","rgb(102,194,164)","rgb(35,139,69)"],5:["rgb(237,248,251)","rgb(178,226,226)","rgb(102,194,164)","rgb(44,162,95)","rgb(0,109,44)"],6:["rgb(237,248,251)","rgb(204,236,230)","rgb(153,216,201)","rgb(102,194,164)","rgb(44,162,95)","rgb(0,109,44)"],7:["rgb(237,248,251)","rgb(204,236,230)","rgb(153,216,201)","rgb(102,194,164)","rgb(65,174,118)","rgb(35,139,69)","rgb(0,88,36)"],8:["rgb(247,252,253)","rgb(229,245,249)","rgb(204,236,230)","rgb(153,216,201)","rgb(102,194,164)","rgb(65,174,118)","rgb(35,139,69)","rgb(0,88,36)"],9:["rgb(247,252,253)","rgb(229,245,249)","rgb(204,236,230)","rgb(153,216,201)","rgb(102,194,164)","rgb(65,174,118)","rgb(35,139,69)","rgb(0,109,44)","rgb(0,68,27)"]},PuBuGn:{3:["rgb(236,226,240)","rgb(166,189,219)","rgb(28,144,153)"],4:["rgb(246,239,247)","rgb(189,201,225)","rgb(103,169,207)","rgb(2,129,138)"],5:["rgb(246,239,247)","rgb(189,201,225)","rgb(103,169,207)","rgb(28,144,153)","rgb(1,108,89)"],6:["rgb(246,239,247)","rgb(208,209,230)","rgb(166,189,219)","rgb(103,169,207)","rgb(28,144,153)","rgb(1,108,89)"],7:["rgb(246,239,247)","rgb(208,209,230)","rgb(166,189,219)","rgb(103,169,207)","rgb(54,144,192)","rgb(2,129,138)","rgb(1,100,80)"],8:["rgb(255,247,251)","rgb(236,226,240)","rgb(208,209,230)","rgb(166,189,219)","rgb(103,169,207)","rgb(54,144,192)","rgb(2,129,138)","rgb(1,100,80)"],9:["rgb(255,247,251)","rgb(236,226,240)","rgb(208,209,230)","rgb(166,189,219)","rgb(103,169,207)","rgb(54,144,192)","rgb(2,129,138)","rgb(1,108,89)","rgb(1,70,54)"]},PuBu:{3:["rgb(236,231,242)","rgb(166,189,219)","rgb(43,140,190)"],4:["rgb(241,238,246)","rgb(189,201,225)","rgb(116,169,207)","rgb(5,112,176)"],5:["rgb(241,238,246)","rgb(189,201,225)","rgb(116,169,207)","rgb(43,140,190)","rgb(4,90,141)"],6:["rgb(241,238,246)","rgb(208,209,230)","rgb(166,189,219)","rgb(116,169,207)","rgb(43,140,190)","rgb(4,90,141)"],7:["rgb(241,238,246)","rgb(208,209,230)","rgb(166,189,219)","rgb(116,169,207)","rgb(54,144,192)","rgb(5,112,176)","rgb(3,78,123)"],8:["rgb(255,247,251)","rgb(236,231,242)","rgb(208,209,230)","rgb(166,189,219)","rgb(116,169,207)","rgb(54,144,192)","rgb(5,112,176)","rgb(3,78,123)"],9:["rgb(255,247,251)","rgb(236,231,242)","rgb(208,209,230)","rgb(166,189,219)","rgb(116,169,207)","rgb(54,144,192)","rgb(5,112,176)","rgb(4,90,141)","rgb(2,56,88)"]},BuPu:{3:["rgb(224,236,244)","rgb(158,188,218)","rgb(136,86,167)"],4:["rgb(237,248,251)","rgb(179,205,227)","rgb(140,150,198)","rgb(136,65,157)"],5:["rgb(237,248,251)","rgb(179,205,227)","rgb(140,150,198)","rgb(136,86,167)","rgb(129,15,124)"],6:["rgb(237,248,251)","rgb(191,211,230)","rgb(158,188,218)","rgb(140,150,198)","rgb(136,86,167)","rgb(129,15,124)"],7:["rgb(237,248,251)","rgb(191,211,230)","rgb(158,188,218)","rgb(140,150,198)","rgb(140,107,177)","rgb(136,65,157)","rgb(110,1,107)"],8:["rgb(247,252,253)","rgb(224,236,244)","rgb(191,211,230)","rgb(158,188,218)","rgb(140,150,198)","rgb(140,107,177)","rgb(136,65,157)","rgb(110,1,107)"],9:["rgb(247,252,253)","rgb(224,236,244)","rgb(191,211,230)","rgb(158,188,218)","rgb(140,150,198)","rgb(140,107,177)","rgb(136,65,157)","rgb(129,15,124)","rgb(77,0,75)"]},RdPu:{3:["rgb(253,224,221)","rgb(250,159,181)","rgb(197,27,138)"],4:["rgb(254,235,226)","rgb(251,180,185)","rgb(247,104,161)","rgb(174,1,126)"],5:["rgb(254,235,226)","rgb(251,180,185)","rgb(247,104,161)","rgb(197,27,138)","rgb(122,1,119)"],6:["rgb(254,235,226)","rgb(252,197,192)","rgb(250,159,181)","rgb(247,104,161)","rgb(197,27,138)","rgb(122,1,119)"],7:["rgb(254,235,226)","rgb(252,197,192)","rgb(250,159,181)","rgb(247,104,161)","rgb(221,52,151)","rgb(174,1,126)","rgb(122,1,119)"],8:["rgb(255,247,243)","rgb(253,224,221)","rgb(252,197,192)","rgb(250,159,181)","rgb(247,104,161)","rgb(221,52,151)","rgb(174,1,126)","rgb(122,1,119)"],9:["rgb(255,247,243)","rgb(253,224,221)","rgb(252,197,192)","rgb(250,159,181)","rgb(247,104,161)","rgb(221,52,151)","rgb(174,1,126)","rgb(122,1,119)","rgb(73,0,106)"]},PuRd:{3:["rgb(231,225,239)","rgb(201,148,199)","rgb(221,28,119)"],4:["rgb(241,238,246)","rgb(215,181,216)","rgb(223,101,176)","rgb(206,18,86)"],5:["rgb(241,238,246)","rgb(215,181,216)","rgb(223,101,176)","rgb(221,28,119)","rgb(152,0,67)"],6:["rgb(241,238,246)","rgb(212,185,218)","rgb(201,148,199)","rgb(223,101,176)","rgb(221,28,119)","rgb(152,0,67)"],7:["rgb(241,238,246)","rgb(212,185,218)","rgb(201,148,199)","rgb(223,101,176)","rgb(231,41,138)","rgb(206,18,86)","rgb(145,0,63)"],8:["rgb(247,244,249)","rgb(231,225,239)","rgb(212,185,218)","rgb(201,148,199)","rgb(223,101,176)","rgb(231,41,138)","rgb(206,18,86)","rgb(145,0,63)"],9:["rgb(247,244,249)","rgb(231,225,239)","rgb(212,185,218)","rgb(201,148,199)","rgb(223,101,176)","rgb(231,41,138)","rgb(206,18,86)","rgb(152,0,67)","rgb(103,0,31)"]},OrRd:{3:["rgb(254,232,200)","rgb(253,187,132)","rgb(227,74,51)"],4:["rgb(254,240,217)","rgb(253,204,138)","rgb(252,141,89)","rgb(215,48,31)"],5:["rgb(254,240,217)","rgb(253,204,138)","rgb(252,141,89)","rgb(227,74,51)","rgb(179,0,0)"],6:["rgb(254,240,217)","rgb(253,212,158)","rgb(253,187,132)","rgb(252,141,89)","rgb(227,74,51)","rgb(179,0,0)"],7:["rgb(254,240,217)","rgb(253,212,158)","rgb(253,187,132)","rgb(252,141,89)","rgb(239,101,72)","rgb(215,48,31)","rgb(153,0,0)"],8:["rgb(255,247,236)","rgb(254,232,200)","rgb(253,212,158)","rgb(253,187,132)","rgb(252,141,89)","rgb(239,101,72)","rgb(215,48,31)","rgb(153,0,0)"],9:["rgb(255,247,236)","rgb(254,232,200)","rgb(253,212,158)","rgb(253,187,132)","rgb(252,141,89)","rgb(239,101,72)","rgb(215,48,31)","rgb(179,0,0)","rgb(127,0,0)"]},YlOrRd:{3:["rgb(255,237,160)","rgb(254,178,76)","rgb(240,59,32)"],4:["rgb(255,255,178)","rgb(254,204,92)","rgb(253,141,60)","rgb(227,26,28)"],5:["rgb(255,255,178)","rgb(254,204,92)","rgb(253,141,60)","rgb(240,59,32)","rgb(189,0,38)"],6:["rgb(255,255,178)","rgb(254,217,118)","rgb(254,178,76)","rgb(253,141,60)","rgb(240,59,32)","rgb(189,0,38)"],7:["rgb(255,255,178)","rgb(254,217,118)","rgb(254,178,76)","rgb(253,141,60)","rgb(252,78,42)","rgb(227,26,28)","rgb(177,0,38)"],8:["rgb(255,255,204)","rgb(255,237,160)","rgb(254,217,118)","rgb(254,178,76)","rgb(253,141,60)","rgb(252,78,42)","rgb(227,26,28)","rgb(177,0,38)"],9:["rgb(255,255,204)","rgb(255,237,160)","rgb(254,217,118)","rgb(254,178,76)","rgb(253,141,60)","rgb(252,78,42)","rgb(227,26,28)","rgb(189,0,38)","rgb(128,0,38)"]},YlOrBr:{3:["rgb(255,247,188)","rgb(254,196,79)","rgb(217,95,14)"],4:["rgb(255,255,212)","rgb(254,217,142)","rgb(254,153,41)","rgb(204,76,2)"],5:["rgb(255,255,212)","rgb(254,217,142)","rgb(254,153,41)","rgb(217,95,14)","rgb(153,52,4)"],6:["rgb(255,255,212)","rgb(254,227,145)","rgb(254,196,79)","rgb(254,153,41)","rgb(217,95,14)","rgb(153,52,4)"],7:["rgb(255,255,212)","rgb(254,227,145)","rgb(254,196,79)","rgb(254,153,41)","rgb(236,112,20)","rgb(204,76,2)","rgb(140,45,4)"],8:["rgb(255,255,229)","rgb(255,247,188)","rgb(254,227,145)","rgb(254,196,79)","rgb(254,153,41)","rgb(236,112,20)","rgb(204,76,2)","rgb(140,45,4)"],9:["rgb(255,255,229)","rgb(255,247,188)","rgb(254,227,145)","rgb(254,196,79)","rgb(254,153,41)","rgb(236,112,20)","rgb(204,76,2)","rgb(153,52,4)","rgb(102,37,6)"]},Purples:{3:["rgb(239,237,245)","rgb(188,189,220)","rgb(117,107,177)"],4:["rgb(242,240,247)","rgb(203,201,226)","rgb(158,154,200)","rgb(106,81,163)"],5:["rgb(242,240,247)","rgb(203,201,226)","rgb(158,154,200)","rgb(117,107,177)","rgb(84,39,143)"],6:["rgb(242,240,247)","rgb(218,218,235)","rgb(188,189,220)","rgb(158,154,200)","rgb(117,107,177)","rgb(84,39,143)"],7:["rgb(242,240,247)","rgb(218,218,235)","rgb(188,189,220)","rgb(158,154,200)","rgb(128,125,186)","rgb(106,81,163)","rgb(74,20,134)"],8:["rgb(252,251,253)","rgb(239,237,245)","rgb(218,218,235)","rgb(188,189,220)","rgb(158,154,200)","rgb(128,125,186)","rgb(106,81,163)","rgb(74,20,134)"],9:["rgb(252,251,253)","rgb(239,237,245)","rgb(218,218,235)","rgb(188,189,220)","rgb(158,154,200)","rgb(128,125,186)","rgb(106,81,163)","rgb(84,39,143)","rgb(63,0,125)"]},Blues:{3:["rgb(222,235,247)","rgb(158,202,225)","rgb(49,130,189)"],4:["rgb(239,243,255)","rgb(189,215,231)","rgb(107,174,214)","rgb(33,113,181)"],5:["rgb(239,243,255)","rgb(189,215,231)","rgb(107,174,214)","rgb(49,130,189)","rgb(8,81,156)"],6:["rgb(239,243,255)","rgb(198,219,239)","rgb(158,202,225)","rgb(107,174,214)","rgb(49,130,189)","rgb(8,81,156)"],7:["rgb(239,243,255)","rgb(198,219,239)","rgb(158,202,225)","rgb(107,174,214)","rgb(66,146,198)","rgb(33,113,181)","rgb(8,69,148)"],8:["rgb(247,251,255)","rgb(222,235,247)","rgb(198,219,239)","rgb(158,202,225)","rgb(107,174,214)","rgb(66,146,198)","rgb(33,113,181)","rgb(8,69,148)"],9:["rgb(247,251,255)","rgb(222,235,247)","rgb(198,219,239)","rgb(158,202,225)","rgb(107,174,214)","rgb(66,146,198)","rgb(33,113,181)","rgb(8,81,156)","rgb(8,48,107)"]},Greens:{3:["rgb(229,245,224)","rgb(161,217,155)","rgb(49,163,84)"],4:["rgb(237,248,233)","rgb(186,228,179)","rgb(116,196,118)","rgb(35,139,69)"],5:["rgb(237,248,233)","rgb(186,228,179)","rgb(116,196,118)","rgb(49,163,84)","rgb(0,109,44)"],6:["rgb(237,248,233)","rgb(199,233,192)","rgb(161,217,155)","rgb(116,196,118)","rgb(49,163,84)","rgb(0,109,44)"],7:["rgb(237,248,233)","rgb(199,233,192)","rgb(161,217,155)","rgb(116,196,118)","rgb(65,171,93)","rgb(35,139,69)","rgb(0,90,50)"],8:["rgb(247,252,245)","rgb(229,245,224)","rgb(199,233,192)","rgb(161,217,155)","rgb(116,196,118)","rgb(65,171,93)","rgb(35,139,69)","rgb(0,90,50)"],9:["rgb(247,252,245)","rgb(229,245,224)","rgb(199,233,192)","rgb(161,217,155)","rgb(116,196,118)","rgb(65,171,93)","rgb(35,139,69)","rgb(0,109,44)","rgb(0,68,27)"]},Oranges:{3:["rgb(254,230,206)","rgb(253,174,107)","rgb(230,85,13)"],4:["rgb(254,237,222)","rgb(253,190,133)","rgb(253,141,60)","rgb(217,71,1)"],5:["rgb(254,237,222)","rgb(253,190,133)","rgb(253,141,60)","rgb(230,85,13)","rgb(166,54,3)"],6:["rgb(254,237,222)","rgb(253,208,162)","rgb(253,174,107)","rgb(253,141,60)","rgb(230,85,13)","rgb(166,54,3)"],7:["rgb(254,237,222)","rgb(253,208,162)","rgb(253,174,107)","rgb(253,141,60)","rgb(241,105,19)","rgb(217,72,1)","rgb(140,45,4)"],8:["rgb(255,245,235)","rgb(254,230,206)","rgb(253,208,162)","rgb(253,174,107)","rgb(253,141,60)","rgb(241,105,19)","rgb(217,72,1)","rgb(140,45,4)"],9:["rgb(255,245,235)","rgb(254,230,206)","rgb(253,208,162)","rgb(253,174,107)","rgb(253,141,60)","rgb(241,105,19)","rgb(217,72,1)","rgb(166,54,3)","rgb(127,39,4)"]},Reds:{3:["rgb(254,224,210)","rgb(252,146,114)","rgb(222,45,38)"],4:["rgb(254,229,217)","rgb(252,174,145)","rgb(251,106,74)","rgb(203,24,29)"],5:["rgb(254,229,217)","rgb(252,174,145)","rgb(251,106,74)","rgb(222,45,38)","rgb(165,15,21)"],6:["rgb(254,229,217)","rgb(252,187,161)","rgb(252,146,114)","rgb(251,106,74)","rgb(222,45,38)","rgb(165,15,21)"],7:["rgb(254,229,217)","rgb(252,187,161)","rgb(252,146,114)","rgb(251,106,74)","rgb(239,59,44)","rgb(203,24,29)","rgb(153,0,13)"],8:["rgb(255,245,240)","rgb(254,224,210)","rgb(252,187,161)","rgb(252,146,114)","rgb(251,106,74)","rgb(239,59,44)","rgb(203,24,29)","rgb(153,0,13)"],9:["rgb(255,245,240)","rgb(254,224,210)","rgb(252,187,161)","rgb(252,146,114)","rgb(251,106,74)","rgb(239,59,44)","rgb(203,24,29)","rgb(165,15,21)","rgb(103,0,13)"]},Greys:{3:["rgb(240,240,240)","rgb(189,189,189)","rgb(99,99,99)"],4:["rgb(247,247,247)","rgb(204,204,204)","rgb(150,150,150)","rgb(82,82,82)"],5:["rgb(247,247,247)","rgb(204,204,204)","rgb(150,150,150)","rgb(99,99,99)","rgb(37,37,37)"],6:["rgb(247,247,247)","rgb(217,217,217)","rgb(189,189,189)","rgb(150,150,150)","rgb(99,99,99)","rgb(37,37,37)"],7:["rgb(247,247,247)","rgb(217,217,217)","rgb(189,189,189)","rgb(150,150,150)","rgb(115,115,115)","rgb(82,82,82)","rgb(37,37,37)"],8:["rgb(255,255,255)","rgb(240,240,240)","rgb(217,217,217)","rgb(189,189,189)","rgb(150,150,150)","rgb(115,115,115)","rgb(82,82,82)","rgb(37,37,37)"],9:["rgb(255,255,255)","rgb(240,240,240)","rgb(217,217,217)","rgb(189,189,189)","rgb(150,150,150)","rgb(115,115,115)","rgb(82,82,82)","rgb(37,37,37)","rgb(0,0,0)"]},PuOr:{3:["rgb(241,163,64)","rgb(247,247,247)","rgb(153,142,195)"],4:["rgb(230,97,1)","rgb(253,184,99)","rgb(178,171,210)","rgb(94,60,153)"],5:["rgb(230,97,1)","rgb(253,184,99)","rgb(247,247,247)","rgb(178,171,210)","rgb(94,60,153)"],6:["rgb(179,88,6)","rgb(241,163,64)","rgb(254,224,182)","rgb(216,218,235)","rgb(153,142,195)","rgb(84,39,136)"],7:["rgb(179,88,6)","rgb(241,163,64)","rgb(254,224,182)","rgb(247,247,247)","rgb(216,218,235)","rgb(153,142,195)","rgb(84,39,136)"],8:["rgb(179,88,6)","rgb(224,130,20)","rgb(253,184,99)","rgb(254,224,182)","rgb(216,218,235)","rgb(178,171,210)","rgb(128,115,172)","rgb(84,39,136)"],9:["rgb(179,88,6)","rgb(224,130,20)","rgb(253,184,99)","rgb(254,224,182)","rgb(247,247,247)","rgb(216,218,235)","rgb(178,171,210)","rgb(128,115,172)","rgb(84,39,136)"],10:["rgb(127,59,8)","rgb(179,88,6)","rgb(224,130,20)","rgb(253,184,99)","rgb(254,224,182)","rgb(216,218,235)","rgb(178,171,210)","rgb(128,115,172)","rgb(84,39,136)","rgb(45,0,75)"],11:["rgb(127,59,8)","rgb(179,88,6)","rgb(224,130,20)","rgb(253,184,99)","rgb(254,224,182)","rgb(247,247,247)","rgb(216,218,235)","rgb(178,171,210)","rgb(128,115,172)","rgb(84,39,136)","rgb(45,0,75)"]},BrBG:{3:["rgb(216,179,101)","rgb(245,245,245)","rgb(90,180,172)"],4:["rgb(166,97,26)","rgb(223,194,125)","rgb(128,205,193)","rgb(1,133,113)"],5:["rgb(166,97,26)","rgb(223,194,125)","rgb(245,245,245)","rgb(128,205,193)","rgb(1,133,113)"],6:["rgb(140,81,10)","rgb(216,179,101)","rgb(246,232,195)","rgb(199,234,229)","rgb(90,180,172)","rgb(1,102,94)"],7:["rgb(140,81,10)","rgb(216,179,101)","rgb(246,232,195)","rgb(245,245,245)","rgb(199,234,229)","rgb(90,180,172)","rgb(1,102,94)"],8:["rgb(140,81,10)","rgb(191,129,45)","rgb(223,194,125)","rgb(246,232,195)","rgb(199,234,229)","rgb(128,205,193)","rgb(53,151,143)","rgb(1,102,94)"],9:["rgb(140,81,10)","rgb(191,129,45)","rgb(223,194,125)","rgb(246,232,195)","rgb(245,245,245)","rgb(199,234,229)","rgb(128,205,193)","rgb(53,151,143)","rgb(1,102,94)"],10:["rgb(84,48,5)","rgb(140,81,10)","rgb(191,129,45)","rgb(223,194,125)","rgb(246,232,195)","rgb(199,234,229)","rgb(128,205,193)","rgb(53,151,143)","rgb(1,102,94)","rgb(0,60,48)"],11:["rgb(84,48,5)","rgb(140,81,10)","rgb(191,129,45)","rgb(223,194,125)","rgb(246,232,195)","rgb(245,245,245)","rgb(199,234,229)","rgb(128,205,193)","rgb(53,151,143)","rgb(1,102,94)","rgb(0,60,48)"]},PRGn:{3:["rgb(175,141,195)","rgb(247,247,247)","rgb(127,191,123)"],4:["rgb(123,50,148)","rgb(194,165,207)","rgb(166,219,160)","rgb(0,136,55)"],5:["rgb(123,50,148)","rgb(194,165,207)","rgb(247,247,247)","rgb(166,219,160)","rgb(0,136,55)"],6:["rgb(118,42,131)","rgb(175,141,195)","rgb(231,212,232)","rgb(217,240,211)","rgb(127,191,123)","rgb(27,120,55)"],7:["rgb(118,42,131)","rgb(175,141,195)","rgb(231,212,232)","rgb(247,247,247)","rgb(217,240,211)","rgb(127,191,123)","rgb(27,120,55)"],8:["rgb(118,42,131)","rgb(153,112,171)","rgb(194,165,207)","rgb(231,212,232)","rgb(217,240,211)","rgb(166,219,160)","rgb(90,174,97)","rgb(27,120,55)"],9:["rgb(118,42,131)","rgb(153,112,171)","rgb(194,165,207)","rgb(231,212,232)","rgb(247,247,247)","rgb(217,240,211)","rgb(166,219,160)","rgb(90,174,97)","rgb(27,120,55)"],10:["rgb(64,0,75)","rgb(118,42,131)","rgb(153,112,171)","rgb(194,165,207)","rgb(231,212,232)","rgb(217,240,211)","rgb(166,219,160)","rgb(90,174,97)","rgb(27,120,55)","rgb(0,68,27)"],11:["rgb(64,0,75)","rgb(118,42,131)","rgb(153,112,171)","rgb(194,165,207)","rgb(231,212,232)","rgb(247,247,247)","rgb(217,240,211)","rgb(166,219,160)","rgb(90,174,97)","rgb(27,120,55)","rgb(0,68,27)"]},PiYG:{3:["rgb(233,163,201)","rgb(247,247,247)","rgb(161,215,106)"],4:["rgb(208,28,139)","rgb(241,182,218)","rgb(184,225,134)","rgb(77,172,38)"],5:["rgb(208,28,139)","rgb(241,182,218)","rgb(247,247,247)","rgb(184,225,134)","rgb(77,172,38)"],6:["rgb(197,27,125)","rgb(233,163,201)","rgb(253,224,239)","rgb(230,245,208)","rgb(161,215,106)","rgb(77,146,33)"],7:["rgb(197,27,125)","rgb(233,163,201)","rgb(253,224,239)","rgb(247,247,247)","rgb(230,245,208)","rgb(161,215,106)","rgb(77,146,33)"],8:["rgb(197,27,125)","rgb(222,119,174)","rgb(241,182,218)","rgb(253,224,239)","rgb(230,245,208)","rgb(184,225,134)","rgb(127,188,65)","rgb(77,146,33)"],9:["rgb(197,27,125)","rgb(222,119,174)","rgb(241,182,218)","rgb(253,224,239)","rgb(247,247,247)","rgb(230,245,208)","rgb(184,225,134)","rgb(127,188,65)","rgb(77,146,33)"],10:["rgb(142,1,82)","rgb(197,27,125)","rgb(222,119,174)","rgb(241,182,218)","rgb(253,224,239)","rgb(230,245,208)","rgb(184,225,134)","rgb(127,188,65)","rgb(77,146,33)","rgb(39,100,25)"],11:["rgb(142,1,82)","rgb(197,27,125)","rgb(222,119,174)","rgb(241,182,218)","rgb(253,224,239)","rgb(247,247,247)","rgb(230,245,208)","rgb(184,225,134)","rgb(127,188,65)","rgb(77,146,33)","rgb(39,100,25)"]},RdBu:{3:["rgb(239,138,98)","rgb(247,247,247)","rgb(103,169,207)"],4:["rgb(202,0,32)","rgb(244,165,130)","rgb(146,197,222)","rgb(5,113,176)"],5:["rgb(202,0,32)","rgb(244,165,130)","rgb(247,247,247)","rgb(146,197,222)","rgb(5,113,176)"],6:["rgb(178,24,43)","rgb(239,138,98)","rgb(253,219,199)","rgb(209,229,240)","rgb(103,169,207)","rgb(33,102,172)"],7:["rgb(178,24,43)","rgb(239,138,98)","rgb(253,219,199)","rgb(247,247,247)","rgb(209,229,240)","rgb(103,169,207)","rgb(33,102,172)"],8:["rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(209,229,240)","rgb(146,197,222)","rgb(67,147,195)","rgb(33,102,172)"],9:["rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(247,247,247)","rgb(209,229,240)","rgb(146,197,222)","rgb(67,147,195)","rgb(33,102,172)"],10:["rgb(103,0,31)","rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(209,229,240)","rgb(146,197,222)","rgb(67,147,195)","rgb(33,102,172)","rgb(5,48,97)"],11:["rgb(103,0,31)","rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(247,247,247)","rgb(209,229,240)","rgb(146,197,222)","rgb(67,147,195)","rgb(33,102,172)","rgb(5,48,97)"]},RdGy:{3:["rgb(239,138,98)","rgb(255,255,255)","rgb(153,153,153)"],4:["rgb(202,0,32)","rgb(244,165,130)","rgb(186,186,186)","rgb(64,64,64)"],5:["rgb(202,0,32)","rgb(244,165,130)","rgb(255,255,255)","rgb(186,186,186)","rgb(64,64,64)"],6:["rgb(178,24,43)","rgb(239,138,98)","rgb(253,219,199)","rgb(224,224,224)","rgb(153,153,153)","rgb(77,77,77)"],7:["rgb(178,24,43)","rgb(239,138,98)","rgb(253,219,199)","rgb(255,255,255)","rgb(224,224,224)","rgb(153,153,153)","rgb(77,77,77)"],8:["rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(224,224,224)","rgb(186,186,186)","rgb(135,135,135)","rgb(77,77,77)"],9:["rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(255,255,255)","rgb(224,224,224)","rgb(186,186,186)","rgb(135,135,135)","rgb(77,77,77)"],10:["rgb(103,0,31)","rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(224,224,224)","rgb(186,186,186)","rgb(135,135,135)","rgb(77,77,77)","rgb(26,26,26)"],11:["rgb(103,0,31)","rgb(178,24,43)","rgb(214,96,77)","rgb(244,165,130)","rgb(253,219,199)","rgb(255,255,255)","rgb(224,224,224)","rgb(186,186,186)","rgb(135,135,135)","rgb(77,77,77)","rgb(26,26,26)"]},RdYlBu:{3:["rgb(252,141,89)","rgb(255,255,191)","rgb(145,191,219)"],4:["rgb(215,25,28)","rgb(253,174,97)","rgb(171,217,233)","rgb(44,123,182)"],5:["rgb(215,25,28)","rgb(253,174,97)","rgb(255,255,191)","rgb(171,217,233)","rgb(44,123,182)"],6:["rgb(215,48,39)","rgb(252,141,89)","rgb(254,224,144)","rgb(224,243,248)","rgb(145,191,219)","rgb(69,117,180)"],7:["rgb(215,48,39)","rgb(252,141,89)","rgb(254,224,144)","rgb(255,255,191)","rgb(224,243,248)","rgb(145,191,219)","rgb(69,117,180)"],8:["rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,144)","rgb(224,243,248)","rgb(171,217,233)","rgb(116,173,209)","rgb(69,117,180)"],9:["rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,144)","rgb(255,255,191)","rgb(224,243,248)","rgb(171,217,233)","rgb(116,173,209)","rgb(69,117,180)"],10:["rgb(165,0,38)","rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,144)","rgb(224,243,248)","rgb(171,217,233)","rgb(116,173,209)","rgb(69,117,180)","rgb(49,54,149)"],11:["rgb(165,0,38)","rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,144)","rgb(255,255,191)","rgb(224,243,248)","rgb(171,217,233)","rgb(116,173,209)","rgb(69,117,180)","rgb(49,54,149)"]},Spectral:{3:["rgb(252,141,89)","rgb(255,255,191)","rgb(153,213,148)"],4:["rgb(215,25,28)","rgb(253,174,97)","rgb(171,221,164)","rgb(43,131,186)"],5:["rgb(215,25,28)","rgb(253,174,97)","rgb(255,255,191)","rgb(171,221,164)","rgb(43,131,186)"],6:["rgb(213,62,79)","rgb(252,141,89)","rgb(254,224,139)","rgb(230,245,152)","rgb(153,213,148)","rgb(50,136,189)"],7:["rgb(213,62,79)","rgb(252,141,89)","rgb(254,224,139)","rgb(255,255,191)","rgb(230,245,152)","rgb(153,213,148)","rgb(50,136,189)"],8:["rgb(213,62,79)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(230,245,152)","rgb(171,221,164)","rgb(102,194,165)","rgb(50,136,189)"],9:["rgb(213,62,79)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(255,255,191)","rgb(230,245,152)","rgb(171,221,164)","rgb(102,194,165)","rgb(50,136,189)"],10:["rgb(158,1,66)","rgb(213,62,79)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(230,245,152)","rgb(171,221,164)","rgb(102,194,165)","rgb(50,136,189)","rgb(94,79,162)"],11:["rgb(158,1,66)","rgb(213,62,79)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(255,255,191)","rgb(230,245,152)","rgb(171,221,164)","rgb(102,194,165)","rgb(50,136,189)","rgb(94,79,162)"]},RdYlGn:{3:["rgb(252,141,89)","rgb(255,255,191)","rgb(145,207,96)"],4:["rgb(215,25,28)","rgb(253,174,97)","rgb(166,217,106)","rgb(26,150,65)"],5:["rgb(215,25,28)","rgb(253,174,97)","rgb(255,255,191)","rgb(166,217,106)","rgb(26,150,65)"],6:["rgb(215,48,39)","rgb(252,141,89)","rgb(254,224,139)","rgb(217,239,139)","rgb(145,207,96)","rgb(26,152,80)"],7:["rgb(215,48,39)","rgb(252,141,89)","rgb(254,224,139)","rgb(255,255,191)","rgb(217,239,139)","rgb(145,207,96)","rgb(26,152,80)"],8:["rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(217,239,139)","rgb(166,217,106)","rgb(102,189,99)","rgb(26,152,80)"],9:["rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(255,255,191)","rgb(217,239,139)","rgb(166,217,106)","rgb(102,189,99)","rgb(26,152,80)"],10:["rgb(165,0,38)","rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(217,239,139)","rgb(166,217,106)","rgb(102,189,99)","rgb(26,152,80)","rgb(0,104,55)"],11:["rgb(165,0,38)","rgb(215,48,39)","rgb(244,109,67)","rgb(253,174,97)","rgb(254,224,139)","rgb(255,255,191)","rgb(217,239,139)","rgb(166,217,106)","rgb(102,189,99)","rgb(26,152,80)","rgb(0,104,55)"]}};
|
@@ -0,0 +1,273 @@
|
|
1
|
+
// # Cubism.ElasticSearch #
|
2
|
+
//
|
3
|
+
// `cubism.elasticsearch` is an extension for the
|
4
|
+
// [_Cubism.js_](http://square.github.com/cubism/) visualization platform
|
5
|
+
// to display statistics from the _ElasticSearch_
|
6
|
+
// ["Nodes Stats API"](http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-stats.html).
|
7
|
+
//
|
8
|
+
// ## Usage ##
|
9
|
+
//
|
10
|
+
// Setup a Cubism context, and pass it to the `cubism.elasticsearch` function:
|
11
|
+
//
|
12
|
+
// var context = cubism.context(),
|
13
|
+
// elasticsearch = cubism.elasticsearch(context, {host: "http://localhost:9200"}, function() {...})
|
14
|
+
//
|
15
|
+
// Use the `metric` function to return a specific metric from a _ElasticSearch_ node in the callback function:
|
16
|
+
//
|
17
|
+
// this.metric("os.cpu.user")
|
18
|
+
//
|
19
|
+
// By default, metric is returned from the first node (`0`).
|
20
|
+
//
|
21
|
+
// You may use the node's ID or a number giving it's position:
|
22
|
+
//
|
23
|
+
// this.metric("os.cpu.user", "USNEtnCWQW-5oG3Gf9J8Hg")
|
24
|
+
// this.metric("os.cpu.user", 0)
|
25
|
+
//
|
26
|
+
// You can use any valid path in the JSON returned from the _ElasticSearch_:
|
27
|
+
//
|
28
|
+
// var basic_metrics = [
|
29
|
+
// this.metric("os.cpu.user"),
|
30
|
+
// this.metric("process.cpu.percent"),
|
31
|
+
// this.metric("fs.data[0].disk_reads")
|
32
|
+
// // ...
|
33
|
+
// ]
|
34
|
+
//
|
35
|
+
// Pass the returned metrics as the `data` collection to the _horizon_ chart
|
36
|
+
// (https://github.com/square/cubism/wiki/Horizon#wiki-_horizon):
|
37
|
+
//
|
38
|
+
// var context = cubism.context(),
|
39
|
+
// elasticsearch = cubism.elasticsearch(context, {host: "http://localhost:9200"}, function() {
|
40
|
+
// chart.selectAll(".horizon")
|
41
|
+
// .data([elasticsearch.metric("os.cpu.user"]), function(d) { return d.toString(); })
|
42
|
+
// .enter().append("div")
|
43
|
+
// .attr("class", "horizon")
|
44
|
+
// .call(context.horizon())
|
45
|
+
// });
|
46
|
+
//
|
47
|
+
//
|
48
|
+
// Use the `metrics` function to return an array with the specified metric from all nodes in the cluster:
|
49
|
+
//
|
50
|
+
// this.metrics("os.cpu.user")
|
51
|
+
//
|
52
|
+
// To display metrics from all nodes, simply pass them as the `data` collection:
|
53
|
+
//
|
54
|
+
// var context = cubism.context(),
|
55
|
+
// elasticsearch = cubism.elasticsearch(context, {host: "http://localhost:9200"}, function() {
|
56
|
+
// chart.selectAll(".horizon")
|
57
|
+
// .data(elasticsearch.metrics("os.cpu.user"), function(d) { return d.toString(); })
|
58
|
+
// .enter().append("div")
|
59
|
+
// .attr("class", "horizon")
|
60
|
+
// .call(context.horizon())
|
61
|
+
// chart.selectAll(".horizon")
|
62
|
+
// .data(elasticsearch.metrics("process.cpu.percent"), function(d) { return d.toString(); })
|
63
|
+
// .enter().append("div")
|
64
|
+
// .attr("class", "horizon")
|
65
|
+
// .call(context.horizon())
|
66
|
+
// });
|
67
|
+
//
|
68
|
+
// Supposed you have a convenience function to add a metric to the chart, such as,
|
69
|
+
//
|
70
|
+
// // Function to add new chart
|
71
|
+
// //
|
72
|
+
// chart.add = function(metrics) {
|
73
|
+
// chart.selectAll(".horizon")
|
74
|
+
// .data(metrics, function(d) { return d.toString(); })
|
75
|
+
// .enter().append("div")
|
76
|
+
// .attr("class", "horizon")
|
77
|
+
// .call(context.horizon())
|
78
|
+
// return chart;
|
79
|
+
// };
|
80
|
+
//
|
81
|
+
// then adding a new metric is simply a matter of pasing it the result of `elasticsearch.metrics()` function:
|
82
|
+
//
|
83
|
+
// var context = cubism.context(),
|
84
|
+
// elasticsearch = cubism.elasticsearch(context, {host: "http://localhost:9200"}, function() {
|
85
|
+
// chart.add( elasticsearch.metrics("os.cpu.user") )
|
86
|
+
// chart.add( elasticsearch.metrics("process.cpu.percent") )
|
87
|
+
// // ...
|
88
|
+
// });
|
89
|
+
//
|
90
|
+
|
91
|
+
var cubism = ('undefined' == typeof cubism) ? {} : cubism;
|
92
|
+
|
93
|
+
// An ElasticSearch extension for Cubism.js
|
94
|
+
//
|
95
|
+
// Arguments
|
96
|
+
// ---------
|
97
|
+
//
|
98
|
+
// * `context` -- The Cubism.js context [https://github.com/square/cubism/wiki/Context]
|
99
|
+
// * `options` -- Options (eg. ElasticSearch URL)
|
100
|
+
// * `callback` -- Callback to execute after loading cluster info (eg. adding charts)
|
101
|
+
//
|
102
|
+
// Usage
|
103
|
+
// -----
|
104
|
+
//
|
105
|
+
// var context = cubism.context(),
|
106
|
+
//
|
107
|
+
// elasticsearch = cubism.elasticsearch(
|
108
|
+
// context,
|
109
|
+
//
|
110
|
+
// {host: "http://localhost:9200"},
|
111
|
+
//
|
112
|
+
// function() {
|
113
|
+
//
|
114
|
+
// chart.selectAll(".horizon")
|
115
|
+
//
|
116
|
+
// // Overall CPU (user)
|
117
|
+
// //
|
118
|
+
// .data(elasticsearch.metrics("os.cpu.user"), function(d) { return d.toString(); })
|
119
|
+
//
|
120
|
+
// .enter().append("div")
|
121
|
+
// .attr("class", "horizon")
|
122
|
+
// .call(context.horizon())
|
123
|
+
//
|
124
|
+
// chart.selectAll(".horizon")
|
125
|
+
//
|
126
|
+
// // CPU consumed by ElasticSearch
|
127
|
+
// //
|
128
|
+
// .data(elasticsearch.metrics("process.cpu.percent"), function(d) { return d.toString(); })
|
129
|
+
//
|
130
|
+
// .enter().append("div")
|
131
|
+
// .attr("class", "horizon")
|
132
|
+
// .call(context.horizon())
|
133
|
+
//
|
134
|
+
// chart.selectAll(".horizon")
|
135
|
+
//
|
136
|
+
// // Number of documents on a specific node
|
137
|
+
// //
|
138
|
+
// .data([elasticsearch.metric("indices.docs.count", "USNEtnCWQW-5oG3Gf9J8Hg"]),
|
139
|
+
// function(d) { return d.toString(); })
|
140
|
+
//
|
141
|
+
// .enter().append("div")
|
142
|
+
// .attr("class", "horizon")
|
143
|
+
// .call(context.horizon())
|
144
|
+
// });
|
145
|
+
//
|
146
|
+
cubism.elasticsearch = function(context, options, callback) {
|
147
|
+
if (!context) throw new Error("Please pass a valid Cubism context instance as the first argument");
|
148
|
+
|
149
|
+
options = options || {}
|
150
|
+
if (!options.host) options.host = "http://localhost:9200";
|
151
|
+
|
152
|
+
var source = {},
|
153
|
+
context = context,
|
154
|
+
initialized_metrics = {};
|
155
|
+
|
156
|
+
source.cluster = {};
|
157
|
+
source.node_names = {};
|
158
|
+
|
159
|
+
// Returns a function, which will return data for the Cubism horizon chart callbacks.
|
160
|
+
//
|
161
|
+
var __cubism_metric_callback = function(node, expression) {
|
162
|
+
return function(start, stop, step, callback) {
|
163
|
+
var values = [],
|
164
|
+
value = 0,
|
165
|
+
start = +start,
|
166
|
+
stop = +stop,
|
167
|
+
metric_id = node.id+'-'+expression
|
168
|
+
|
169
|
+
d3.json(source.url(), function(data) {
|
170
|
+
if (!data) return callback(new Error("Unable to load data from ElasticSearch!"))
|
171
|
+
if (!data.nodes[node.id]) return callback(new Error("Unable to find node " + node.id + "!"))
|
172
|
+
|
173
|
+
var value = eval("data.nodes['"+node.id+"']." + expression) // data.nodes[<NAME>].os.cpu.user
|
174
|
+
// console.log(expression + ': ' + value)
|
175
|
+
|
176
|
+
// Cubism.js expects a value for every "slot" based on the `start` and `stop` parameters, because
|
177
|
+
// it assumes a backend such as [_Graphite_](https://github.com/square/cubism/wiki/Graphite),
|
178
|
+
// which is able to return values stored over time.
|
179
|
+
//
|
180
|
+
// In _ElasticSearch_, we don't have any data stored: we poll the API repeatedly.
|
181
|
+
//
|
182
|
+
// On first call, Cubism.js calls the metric callback function with a large `start` and `stop` gap,
|
183
|
+
// based on the `step` and `size` values of your chart. This would spoil the chart with a useless
|
184
|
+
// "thick colored line".
|
185
|
+
//
|
186
|
+
// So: if we have already initialized this metric, push the same value to all the "slots",
|
187
|
+
// because this is what Cubism.js expects...
|
188
|
+
if (initialized_metrics[metric_id]) {
|
189
|
+
while (start < stop) {
|
190
|
+
start += step;
|
191
|
+
values.push(value);
|
192
|
+
}
|
193
|
+
}
|
194
|
+
// ... otherwise mark this metric as initialized and fill the empty / "historical" slots with empty values.
|
195
|
+
else {
|
196
|
+
initialized_metrics[metric_id] = true;
|
197
|
+
while (start < (stop - step)) {
|
198
|
+
start += step;
|
199
|
+
values.push(NaN);
|
200
|
+
}
|
201
|
+
values.push(value);
|
202
|
+
}
|
203
|
+
|
204
|
+
callback(null, values)
|
205
|
+
});
|
206
|
+
}
|
207
|
+
}
|
208
|
+
|
209
|
+
// Load information about ElasticSearch nodes from the Nodes Info API
|
210
|
+
// [http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-info.html]
|
211
|
+
//
|
212
|
+
d3.json(options.host + "/_cluster/nodes", function(cluster) {
|
213
|
+
source.cluster = cluster
|
214
|
+
source.node_names = d3.keys(cluster.nodes)
|
215
|
+
|
216
|
+
// Returns a metric for specific node
|
217
|
+
//
|
218
|
+
// Arguments
|
219
|
+
// ---------
|
220
|
+
//
|
221
|
+
// * `expression` -- A valid path in the ElasticSearch JSON response (eg. `os.cpu.user`)
|
222
|
+
// * `n` -- A node specification. Can be either node ID (eg. `USNEtnCWQW-5oG3Gf9J8Hg`),
|
223
|
+
// or a number giving position in response (eg. `0`)
|
224
|
+
//
|
225
|
+
// For usage, see documentation for `cubism.elasticsearch`
|
226
|
+
//
|
227
|
+
source.metric = function(expression, n) {
|
228
|
+
var n = n || 0,
|
229
|
+
node_id = ("number" == typeof n) ? source.node_names[n] : n,
|
230
|
+
node = source.cluster.nodes[node_id];
|
231
|
+
|
232
|
+
var metric = context.metric(__cubism_metric_callback(node, expression), expression + " [" + node.name + "]");
|
233
|
+
|
234
|
+
return metric;
|
235
|
+
};
|
236
|
+
|
237
|
+
// Returns a metric across all nodes
|
238
|
+
//
|
239
|
+
// Arguments
|
240
|
+
// ---------
|
241
|
+
//
|
242
|
+
// * `expression` -- A valid path in the ElasticSearch JSON response (eg. `os.cpu.user`)
|
243
|
+
//
|
244
|
+
// For usage, see documentation for `cubism.elasticsearch`
|
245
|
+
//
|
246
|
+
source.metrics = function(expression) {
|
247
|
+
var metrics = [],
|
248
|
+
ordered_nodes = [];
|
249
|
+
for ( var n in source.cluster.nodes )
|
250
|
+
{ var o = source.cluster.nodes[n]; o.id = n; ordered_nodes.push(o) }
|
251
|
+
|
252
|
+
ordered_nodes = ordered_nodes.sort(function(a,b) {
|
253
|
+
if (a.name < b.name) return -1;
|
254
|
+
if (a.name > b.name) return 1;
|
255
|
+
return 0;
|
256
|
+
});
|
257
|
+
|
258
|
+
ordered_nodes.forEach( function(node) {
|
259
|
+
var metric = context.metric(__cubism_metric_callback(node, expression), expression + " [" + node.name + "]");
|
260
|
+
metrics.push(metric)
|
261
|
+
})
|
262
|
+
|
263
|
+
return metrics;
|
264
|
+
};
|
265
|
+
|
266
|
+
callback.call(source)
|
267
|
+
})
|
268
|
+
|
269
|
+
source.toString = function() { return options.host };
|
270
|
+
source.url = function() { return options.host + "/_cluster/nodes/stats?all" };
|
271
|
+
|
272
|
+
return source;
|
273
|
+
};
|
@@ -0,0 +1,986 @@
|
|
1
|
+
(function(exports){
|
2
|
+
var cubism = exports.cubism = {version: "1.0.1"};
|
3
|
+
var cubism_id = 0;
|
4
|
+
function cubism_identity(d) { return d; }
|
5
|
+
cubism.option = function(name, defaultValue) {
|
6
|
+
var values = cubism.options(name);
|
7
|
+
return values.length ? values[0] : defaultValue;
|
8
|
+
};
|
9
|
+
|
10
|
+
cubism.options = function(name, defaultValues) {
|
11
|
+
var options = location.search.substring(1).split("&"),
|
12
|
+
values = [],
|
13
|
+
i = -1,
|
14
|
+
n = options.length,
|
15
|
+
o;
|
16
|
+
while (++i < n) {
|
17
|
+
if ((o = options[i].split("="))[0] == name) {
|
18
|
+
values.push(decodeURIComponent(o[1]));
|
19
|
+
}
|
20
|
+
}
|
21
|
+
return values.length || arguments.length < 2 ? values : defaultValues;
|
22
|
+
};
|
23
|
+
cubism.context = function() {
|
24
|
+
var context = new cubism_context,
|
25
|
+
step = 1e4, // ten seconds, in milliseconds
|
26
|
+
size = 1440, // four hours at ten seconds, in pixels
|
27
|
+
start0, stop0, // the start and stop for the previous change event
|
28
|
+
start1, stop1, // the start and stop for the next prepare event
|
29
|
+
serverDelay = 5e3,
|
30
|
+
clientDelay = 5e3,
|
31
|
+
event = d3.dispatch("prepare", "beforechange", "change", "focus"),
|
32
|
+
scale = context.scale = d3.time.scale().range([0, size]),
|
33
|
+
timeout,
|
34
|
+
focus;
|
35
|
+
|
36
|
+
function update() {
|
37
|
+
var now = Date.now();
|
38
|
+
stop0 = new Date(Math.floor((now - serverDelay - clientDelay) / step) * step);
|
39
|
+
start0 = new Date(stop0 - size * step);
|
40
|
+
stop1 = new Date(Math.floor((now - serverDelay) / step) * step);
|
41
|
+
start1 = new Date(stop1 - size * step);
|
42
|
+
scale.domain([start0, stop0]);
|
43
|
+
return context;
|
44
|
+
}
|
45
|
+
|
46
|
+
context.start = function() {
|
47
|
+
if (timeout) clearTimeout(timeout);
|
48
|
+
var delay = +stop1 + serverDelay - Date.now();
|
49
|
+
|
50
|
+
// If we're too late for the first prepare event, skip it.
|
51
|
+
if (delay < clientDelay) delay += step;
|
52
|
+
|
53
|
+
timeout = setTimeout(function prepare() {
|
54
|
+
stop1 = new Date(Math.floor((Date.now() - serverDelay) / step) * step);
|
55
|
+
start1 = new Date(stop1 - size * step);
|
56
|
+
event.prepare.call(context, start1, stop1);
|
57
|
+
|
58
|
+
setTimeout(function() {
|
59
|
+
scale.domain([start0 = start1, stop0 = stop1]);
|
60
|
+
event.beforechange.call(context, start1, stop1);
|
61
|
+
event.change.call(context, start1, stop1);
|
62
|
+
event.focus.call(context, focus);
|
63
|
+
}, clientDelay);
|
64
|
+
|
65
|
+
timeout = setTimeout(prepare, step);
|
66
|
+
}, delay);
|
67
|
+
return context;
|
68
|
+
};
|
69
|
+
|
70
|
+
context.stop = function() {
|
71
|
+
timeout = clearTimeout(timeout);
|
72
|
+
return context;
|
73
|
+
};
|
74
|
+
|
75
|
+
timeout = setTimeout(context.start, 10);
|
76
|
+
|
77
|
+
// Set or get the step interval in milliseconds.
|
78
|
+
// Defaults to ten seconds.
|
79
|
+
context.step = function(_) {
|
80
|
+
if (!arguments.length) return step;
|
81
|
+
step = +_;
|
82
|
+
return update();
|
83
|
+
};
|
84
|
+
|
85
|
+
// Set or get the context size (the count of metric values).
|
86
|
+
// Defaults to 1440 (four hours at ten seconds).
|
87
|
+
context.size = function(_) {
|
88
|
+
if (!arguments.length) return size;
|
89
|
+
scale.range([0, size = +_]);
|
90
|
+
return update();
|
91
|
+
};
|
92
|
+
|
93
|
+
// The server delay is the amount of time we wait for the server to compute a
|
94
|
+
// metric. This delay may result from clock skew or from delays collecting
|
95
|
+
// metrics from various hosts. Defaults to 4 seconds.
|
96
|
+
context.serverDelay = function(_) {
|
97
|
+
if (!arguments.length) return serverDelay;
|
98
|
+
serverDelay = +_;
|
99
|
+
return update();
|
100
|
+
};
|
101
|
+
|
102
|
+
// The client delay is the amount of additional time we wait to fetch those
|
103
|
+
// metrics from the server. The client and server delay combined represent the
|
104
|
+
// age of the most recent displayed metric. Defaults to 1 second.
|
105
|
+
context.clientDelay = function(_) {
|
106
|
+
if (!arguments.length) return clientDelay;
|
107
|
+
clientDelay = +_;
|
108
|
+
return update();
|
109
|
+
};
|
110
|
+
|
111
|
+
// Sets the focus to the specified index, and dispatches a "focus" event.
|
112
|
+
context.focus = function(i) {
|
113
|
+
event.focus.call(context, focus = i);
|
114
|
+
return context;
|
115
|
+
};
|
116
|
+
|
117
|
+
// Add, remove or get listeners for events.
|
118
|
+
context.on = function(type, listener) {
|
119
|
+
if (arguments.length < 2) return event.on(type);
|
120
|
+
|
121
|
+
event.on(type, listener);
|
122
|
+
|
123
|
+
// Notify the listener of the current start and stop time, as appropriate.
|
124
|
+
// This way, metrics can make requests for data immediately,
|
125
|
+
// and likewise the axis can display itself synchronously.
|
126
|
+
if (listener != null) {
|
127
|
+
if (/^prepare(\.|$)/.test(type)) listener.call(context, start1, stop1);
|
128
|
+
if (/^beforechange(\.|$)/.test(type)) listener.call(context, start0, stop0);
|
129
|
+
if (/^change(\.|$)/.test(type)) listener.call(context, start0, stop0);
|
130
|
+
if (/^focus(\.|$)/.test(type)) listener.call(context, focus);
|
131
|
+
}
|
132
|
+
|
133
|
+
return context;
|
134
|
+
};
|
135
|
+
|
136
|
+
d3.select(window).on("keydown.context-" + ++cubism_id, function() {
|
137
|
+
switch (!d3.event.metaKey && d3.event.keyCode) {
|
138
|
+
case 37: // left
|
139
|
+
if (focus == null) focus = size - 1;
|
140
|
+
if (focus > 0) context.focus(--focus);
|
141
|
+
break;
|
142
|
+
case 39: // right
|
143
|
+
if (focus == null) focus = size - 2;
|
144
|
+
if (focus < size - 1) context.focus(++focus);
|
145
|
+
break;
|
146
|
+
default: return;
|
147
|
+
}
|
148
|
+
d3.event.preventDefault();
|
149
|
+
});
|
150
|
+
|
151
|
+
return update();
|
152
|
+
};
|
153
|
+
|
154
|
+
function cubism_context() {}
|
155
|
+
|
156
|
+
var cubism_contextPrototype = cubism_context.prototype;
|
157
|
+
|
158
|
+
cubism_contextPrototype.constant = function(value) {
|
159
|
+
return new cubism_metricConstant(this, +value);
|
160
|
+
};
|
161
|
+
cubism_contextPrototype.cube = function(host) {
|
162
|
+
if (!arguments.length) host = "";
|
163
|
+
var source = {},
|
164
|
+
context = this;
|
165
|
+
|
166
|
+
source.metric = function(expression) {
|
167
|
+
return context.metric(function(start, stop, step, callback) {
|
168
|
+
d3.json(host + "/1.0/metric"
|
169
|
+
+ "?expression=" + encodeURIComponent(expression)
|
170
|
+
+ "&start=" + cubism_cubeFormatDate(start)
|
171
|
+
+ "&stop=" + cubism_cubeFormatDate(stop)
|
172
|
+
+ "&step=" + step, function(data) {
|
173
|
+
if (!data) return callback(new Error("unable to load data"));
|
174
|
+
callback(null, data.map(function(d) { return d.value; }));
|
175
|
+
});
|
176
|
+
}, expression += "");
|
177
|
+
};
|
178
|
+
|
179
|
+
// Returns the Cube host.
|
180
|
+
source.toString = function() {
|
181
|
+
return host;
|
182
|
+
};
|
183
|
+
|
184
|
+
return source;
|
185
|
+
};
|
186
|
+
|
187
|
+
var cubism_cubeFormatDate = d3.time.format.iso;
|
188
|
+
cubism_contextPrototype.graphite = function(host) {
|
189
|
+
if (!arguments.length) host = "";
|
190
|
+
var source = {},
|
191
|
+
context = this;
|
192
|
+
|
193
|
+
source.metric = function(expression) {
|
194
|
+
return context.metric(function(start, stop, step, callback) {
|
195
|
+
d3.text(host + "/render?format=raw"
|
196
|
+
+ "&target=" + encodeURIComponent("alias(" + expression + ",'')")
|
197
|
+
+ "&from=" + cubism_graphiteFormatDate(start - 2 * step) // off-by-two?
|
198
|
+
+ "&until=" + cubism_graphiteFormatDate(stop - 1000), function(text) {
|
199
|
+
if (!text) return callback(new Error("unable to load data"));
|
200
|
+
callback(null, cubism_graphiteParse(text));
|
201
|
+
});
|
202
|
+
}, expression += "");
|
203
|
+
};
|
204
|
+
|
205
|
+
source.find = function(pattern, callback) {
|
206
|
+
d3.json(host + "/metrics/find?format=completer"
|
207
|
+
+ "&query=" + encodeURIComponent(pattern), function(result) {
|
208
|
+
if (!result) return callback(new Error("unable to find metrics"));
|
209
|
+
callback(null, result.metrics.map(function(d) { return d.path; }));
|
210
|
+
});
|
211
|
+
};
|
212
|
+
|
213
|
+
// Returns the graphite host.
|
214
|
+
source.toString = function() {
|
215
|
+
return host;
|
216
|
+
};
|
217
|
+
|
218
|
+
return source;
|
219
|
+
};
|
220
|
+
|
221
|
+
// Graphite understands seconds since UNIX epoch.
|
222
|
+
function cubism_graphiteFormatDate(time) {
|
223
|
+
return Math.floor(time / 1000);
|
224
|
+
}
|
225
|
+
|
226
|
+
// Helper method for parsing graphite's raw format.
|
227
|
+
function cubism_graphiteParse(text) {
|
228
|
+
var i = text.indexOf("|"),
|
229
|
+
meta = text.substring(0, i),
|
230
|
+
c = meta.lastIndexOf(","),
|
231
|
+
b = meta.lastIndexOf(",", c - 1),
|
232
|
+
a = meta.lastIndexOf(",", b - 1),
|
233
|
+
start = meta.substring(a + 1, b) * 1000,
|
234
|
+
step = meta.substring(c + 1) * 1000;
|
235
|
+
return text
|
236
|
+
.substring(i + 1)
|
237
|
+
.split(",")
|
238
|
+
.slice(1) // the first value is always None?
|
239
|
+
.map(function(d) { return +d; });
|
240
|
+
}
|
241
|
+
function cubism_metric(context) {
|
242
|
+
if (!(context instanceof cubism_context)) throw new Error("invalid context");
|
243
|
+
this.context = context;
|
244
|
+
}
|
245
|
+
|
246
|
+
var cubism_metricPrototype = cubism_metric.prototype;
|
247
|
+
|
248
|
+
cubism_metricPrototype.valueAt = function() {
|
249
|
+
return NaN;
|
250
|
+
};
|
251
|
+
|
252
|
+
cubism_metricPrototype.alias = function(name) {
|
253
|
+
this.toString = function() { return name; };
|
254
|
+
return this;
|
255
|
+
};
|
256
|
+
|
257
|
+
cubism_metricPrototype.extent = function() {
|
258
|
+
var i = 0,
|
259
|
+
n = this.context.size(),
|
260
|
+
value,
|
261
|
+
min = Infinity,
|
262
|
+
max = -Infinity;
|
263
|
+
while (++i < n) {
|
264
|
+
value = this.valueAt(i);
|
265
|
+
if (value < min) min = value;
|
266
|
+
if (value > max) max = value;
|
267
|
+
}
|
268
|
+
return [min, max];
|
269
|
+
};
|
270
|
+
|
271
|
+
cubism_metricPrototype.on = function(type, listener) {
|
272
|
+
return arguments.length < 2 ? null : this;
|
273
|
+
};
|
274
|
+
|
275
|
+
cubism_metricPrototype.shift = function() {
|
276
|
+
return this;
|
277
|
+
};
|
278
|
+
|
279
|
+
cubism_metricPrototype.on = function() {
|
280
|
+
return arguments.length < 2 ? null : this;
|
281
|
+
};
|
282
|
+
|
283
|
+
cubism_contextPrototype.metric = function(request, name) {
|
284
|
+
var context = this,
|
285
|
+
metric = new cubism_metric(context),
|
286
|
+
id = ".metric-" + ++cubism_id,
|
287
|
+
start = -Infinity,
|
288
|
+
stop,
|
289
|
+
step = context.step(),
|
290
|
+
size = context.size(),
|
291
|
+
values = [],
|
292
|
+
event = d3.dispatch("change"),
|
293
|
+
listening = 0,
|
294
|
+
fetching;
|
295
|
+
|
296
|
+
// Prefetch new data into a temporary array.
|
297
|
+
function prepare(start1, stop) {
|
298
|
+
var steps = Math.min(size, Math.round((start1 - start) / step));
|
299
|
+
if (!steps || fetching) return; // already fetched, or fetching!
|
300
|
+
fetching = true;
|
301
|
+
steps = Math.min(size, steps + cubism_metricOverlap);
|
302
|
+
var start0 = new Date(stop - steps * step);
|
303
|
+
request(start0, stop, step, function(error, data) {
|
304
|
+
fetching = false;
|
305
|
+
if (error) return console.warn(error);
|
306
|
+
var i = isFinite(start) ? Math.round((start0 - start) / step) : 0;
|
307
|
+
for (var j = 0, m = data.length; j < m; ++j) values[j + i] = data[j];
|
308
|
+
event.change.call(metric, start, stop);
|
309
|
+
});
|
310
|
+
}
|
311
|
+
|
312
|
+
// When the context changes, switch to the new data, ready-or-not!
|
313
|
+
function beforechange(start1, stop1) {
|
314
|
+
if (!isFinite(start)) start = start1;
|
315
|
+
values.splice(0, Math.max(0, Math.min(size, Math.round((start1 - start) / step))));
|
316
|
+
start = start1;
|
317
|
+
stop = stop1;
|
318
|
+
}
|
319
|
+
|
320
|
+
//
|
321
|
+
metric.valueAt = function(i) {
|
322
|
+
return values[i];
|
323
|
+
};
|
324
|
+
|
325
|
+
//
|
326
|
+
metric.shift = function(offset) {
|
327
|
+
return context.metric(cubism_metricShift(request, +offset));
|
328
|
+
};
|
329
|
+
|
330
|
+
//
|
331
|
+
metric.on = function(type, listener) {
|
332
|
+
if (!arguments.length) return event.on(type);
|
333
|
+
|
334
|
+
// If there are no listeners, then stop listening to the context,
|
335
|
+
// and avoid unnecessary fetches.
|
336
|
+
if (listener == null) {
|
337
|
+
if (event.on(type) != null && --listening == 0) {
|
338
|
+
context.on("prepare" + id, null).on("beforechange" + id, null);
|
339
|
+
}
|
340
|
+
} else {
|
341
|
+
if (event.on(type) == null && ++listening == 1) {
|
342
|
+
context.on("prepare" + id, prepare).on("beforechange" + id, beforechange);
|
343
|
+
}
|
344
|
+
}
|
345
|
+
|
346
|
+
event.on(type, listener);
|
347
|
+
|
348
|
+
// Notify the listener of the current start and stop time, as appropriate.
|
349
|
+
// This way, charts can display synchronous metrics immediately.
|
350
|
+
if (listener != null) {
|
351
|
+
if (/^change(\.|$)/.test(type)) listener.call(context, start, stop);
|
352
|
+
}
|
353
|
+
|
354
|
+
return metric;
|
355
|
+
};
|
356
|
+
|
357
|
+
//
|
358
|
+
if (arguments.length > 1) metric.toString = function() {
|
359
|
+
return name;
|
360
|
+
};
|
361
|
+
|
362
|
+
return metric;
|
363
|
+
};
|
364
|
+
|
365
|
+
// Number of metric to refetch each period, in case of lag.
|
366
|
+
var cubism_metricOverlap = 6;
|
367
|
+
|
368
|
+
// Wraps the specified request implementation, and shifts time by the given offset.
|
369
|
+
function cubism_metricShift(request, offset) {
|
370
|
+
return function(start, stop, step, callback) {
|
371
|
+
request(new Date(+start + offset), new Date(+stop + offset), step, callback);
|
372
|
+
};
|
373
|
+
}
|
374
|
+
function cubism_metricConstant(context, value) {
|
375
|
+
cubism_metric.call(this, context);
|
376
|
+
value = +value;
|
377
|
+
var name = value + "";
|
378
|
+
this.valueOf = function() { return value; };
|
379
|
+
this.toString = function() { return name; };
|
380
|
+
}
|
381
|
+
|
382
|
+
var cubism_metricConstantPrototype = cubism_metricConstant.prototype = Object.create(cubism_metric.prototype);
|
383
|
+
|
384
|
+
cubism_metricConstantPrototype.valueAt = function() {
|
385
|
+
return +this;
|
386
|
+
};
|
387
|
+
|
388
|
+
cubism_metricConstantPrototype.extent = function() {
|
389
|
+
return [+this, +this];
|
390
|
+
};
|
391
|
+
function cubism_metricOperator(name, operate) {
|
392
|
+
|
393
|
+
function cubism_metricOperator(left, right) {
|
394
|
+
if (!(right instanceof cubism_metric)) right = new cubism_metricConstant(left.context, right);
|
395
|
+
else if (left.context !== right.context) throw new Error("mismatch context");
|
396
|
+
cubism_metric.call(this, left.context);
|
397
|
+
this.left = left;
|
398
|
+
this.right = right;
|
399
|
+
this.toString = function() { return left + " " + name + " " + right; };
|
400
|
+
}
|
401
|
+
|
402
|
+
var cubism_metricOperatorPrototype = cubism_metricOperator.prototype = Object.create(cubism_metric.prototype);
|
403
|
+
|
404
|
+
cubism_metricOperatorPrototype.valueAt = function(i) {
|
405
|
+
return operate(this.left.valueAt(i), this.right.valueAt(i));
|
406
|
+
};
|
407
|
+
|
408
|
+
cubism_metricOperatorPrototype.shift = function(offset) {
|
409
|
+
return new cubism_metricOperator(this.left.shift(offset), this.right.shift(offset));
|
410
|
+
};
|
411
|
+
|
412
|
+
cubism_metricOperatorPrototype.on = function(type, listener) {
|
413
|
+
if (arguments.length < 2) return this.left.on(type);
|
414
|
+
this.left.on(type, listener);
|
415
|
+
this.right.on(type, listener);
|
416
|
+
return this;
|
417
|
+
};
|
418
|
+
|
419
|
+
return function(right) {
|
420
|
+
return new cubism_metricOperator(this, right);
|
421
|
+
};
|
422
|
+
}
|
423
|
+
|
424
|
+
cubism_metricPrototype.add = cubism_metricOperator("+", function(left, right) {
|
425
|
+
return left + right;
|
426
|
+
});
|
427
|
+
|
428
|
+
cubism_metricPrototype.subtract = cubism_metricOperator("-", function(left, right) {
|
429
|
+
return left - right;
|
430
|
+
});
|
431
|
+
|
432
|
+
cubism_metricPrototype.multiply = cubism_metricOperator("*", function(left, right) {
|
433
|
+
return left * right;
|
434
|
+
});
|
435
|
+
|
436
|
+
cubism_metricPrototype.divide = cubism_metricOperator("/", function(left, right) {
|
437
|
+
return left / right;
|
438
|
+
});
|
439
|
+
cubism_contextPrototype.horizon = function() {
|
440
|
+
var context = this,
|
441
|
+
mode = "offset",
|
442
|
+
buffer = document.createElement("canvas"),
|
443
|
+
width = buffer.width = context.size(),
|
444
|
+
height = buffer.height = 30,
|
445
|
+
scale = d3.scale.linear().interpolate(d3.interpolateRound),
|
446
|
+
metric = cubism_identity,
|
447
|
+
extent = null,
|
448
|
+
title = cubism_identity,
|
449
|
+
format = d3.format(".2s"),
|
450
|
+
colors = ["#08519c","#3182bd","#6baed6","#bdd7e7","#bae4b3","#74c476","#31a354","#006d2c"];
|
451
|
+
|
452
|
+
function horizon(selection) {
|
453
|
+
|
454
|
+
selection
|
455
|
+
.on("mousemove.horizon", function() { context.focus(d3.mouse(this)[0]); })
|
456
|
+
.on("mouseout.horizon", function() { context.focus(null); });
|
457
|
+
|
458
|
+
selection.append("canvas")
|
459
|
+
.attr("width", width)
|
460
|
+
.attr("height", height);
|
461
|
+
|
462
|
+
selection.append("span")
|
463
|
+
.attr("class", "title")
|
464
|
+
.text(title);
|
465
|
+
|
466
|
+
selection.append("span")
|
467
|
+
.attr("class", "value");
|
468
|
+
|
469
|
+
selection.each(function(d, i) {
|
470
|
+
var that = this,
|
471
|
+
id = ++cubism_id,
|
472
|
+
metric_ = typeof metric === "function" ? metric.call(that, d, i) : metric,
|
473
|
+
colors_ = typeof colors === "function" ? colors.call(that, d, i) : colors,
|
474
|
+
extent_ = typeof extent === "function" ? extent.call(that, d, i) : extent,
|
475
|
+
start = -Infinity,
|
476
|
+
step = context.step(),
|
477
|
+
canvas = d3.select(that).select("canvas"),
|
478
|
+
span = d3.select(that).select(".value"),
|
479
|
+
max_,
|
480
|
+
m = colors_.length >> 1,
|
481
|
+
ready;
|
482
|
+
|
483
|
+
canvas.datum({id: id, metric: metric_});
|
484
|
+
canvas = canvas.node().getContext("2d");
|
485
|
+
|
486
|
+
function change(start1, stop) {
|
487
|
+
canvas.save();
|
488
|
+
|
489
|
+
// compute the new extent and ready flag
|
490
|
+
var extent = metric_.extent();
|
491
|
+
ready = extent.every(isFinite);
|
492
|
+
if (extent_ != null) extent = extent_;
|
493
|
+
|
494
|
+
// if this is an update (with no extent change), copy old values!
|
495
|
+
var i0 = 0, max = Math.max(-extent[0], extent[1]);
|
496
|
+
if (this === context) {
|
497
|
+
if (max == max_) {
|
498
|
+
i0 = width - cubism_metricOverlap;
|
499
|
+
var dx = (start1 - start) / step;
|
500
|
+
if (dx < width) {
|
501
|
+
var canvas0 = buffer.getContext("2d");
|
502
|
+
canvas0.clearRect(0, 0, width, height);
|
503
|
+
canvas0.drawImage(canvas.canvas, dx, 0, width - dx, height, 0, 0, width - dx, height);
|
504
|
+
canvas.clearRect(0, 0, width, height);
|
505
|
+
canvas.drawImage(canvas0.canvas, 0, 0);
|
506
|
+
}
|
507
|
+
}
|
508
|
+
start = start1;
|
509
|
+
}
|
510
|
+
|
511
|
+
// update the domain
|
512
|
+
scale.domain([0, max_ = max]);
|
513
|
+
|
514
|
+
// clear for the new data
|
515
|
+
canvas.clearRect(i0, 0, width - i0, height);
|
516
|
+
|
517
|
+
// record whether there are negative values to display
|
518
|
+
var negative;
|
519
|
+
|
520
|
+
// positive bands
|
521
|
+
for (var j = 0; j < m; ++j) {
|
522
|
+
canvas.fillStyle = colors_[m + j];
|
523
|
+
|
524
|
+
// Adjust the range based on the current band index.
|
525
|
+
var y0 = (j - m + 1) * height;
|
526
|
+
scale.range([m * height + y0, y0]);
|
527
|
+
y0 = scale(0);
|
528
|
+
|
529
|
+
for (var i = i0, n = width, y1; i < n; ++i) {
|
530
|
+
y1 = metric_.valueAt(i);
|
531
|
+
if (y1 <= 0) { negative = true; continue; }
|
532
|
+
canvas.fillRect(i, y1 = scale(y1), 1, y0 - y1);
|
533
|
+
}
|
534
|
+
}
|
535
|
+
|
536
|
+
if (negative) {
|
537
|
+
// enable offset mode
|
538
|
+
if (mode === "offset") {
|
539
|
+
canvas.translate(0, height);
|
540
|
+
canvas.scale(1, -1);
|
541
|
+
}
|
542
|
+
|
543
|
+
// negative bands
|
544
|
+
for (var j = 0; j < m; ++j) {
|
545
|
+
canvas.fillStyle = colors_[m - 1 - j];
|
546
|
+
|
547
|
+
// Adjust the range based on the current band index.
|
548
|
+
var y0 = (j - m + 1) * height;
|
549
|
+
scale.range([m * height + y0, y0]);
|
550
|
+
y0 = scale(0);
|
551
|
+
|
552
|
+
for (var i = i0, n = width, y1; i < n; ++i) {
|
553
|
+
y1 = metric_.valueAt(i);
|
554
|
+
if (y1 >= 0) continue;
|
555
|
+
canvas.fillRect(i, scale(-y1), 1, y0 - scale(-y1));
|
556
|
+
}
|
557
|
+
}
|
558
|
+
}
|
559
|
+
|
560
|
+
canvas.restore();
|
561
|
+
}
|
562
|
+
|
563
|
+
function focus(i) {
|
564
|
+
if (i == null) i = width - 1;
|
565
|
+
var value = metric_.valueAt(i);
|
566
|
+
span.datum(value).text(isNaN(value) ? null : format);
|
567
|
+
}
|
568
|
+
|
569
|
+
// Update the chart when the context changes.
|
570
|
+
context.on("change.horizon-" + id, change);
|
571
|
+
context.on("focus.horizon-" + id, focus);
|
572
|
+
|
573
|
+
// Display the first metric change immediately,
|
574
|
+
// but defer subsequent updates to the canvas change.
|
575
|
+
// Note that someone still needs to listen to the metric,
|
576
|
+
// so that it continues to update automatically.
|
577
|
+
metric_.on("change.horizon-" + id, function(start, stop) {
|
578
|
+
change(start, stop), focus();
|
579
|
+
if (ready) metric_.on("change.horizon-" + id, cubism_identity);
|
580
|
+
});
|
581
|
+
});
|
582
|
+
}
|
583
|
+
|
584
|
+
horizon.remove = function(selection) {
|
585
|
+
|
586
|
+
selection
|
587
|
+
.on("mousemove.horizon", null)
|
588
|
+
.on("mouseout.horizon", null);
|
589
|
+
|
590
|
+
selection.selectAll("canvas")
|
591
|
+
.each(remove)
|
592
|
+
.remove();
|
593
|
+
|
594
|
+
selection.selectAll(".title,.value")
|
595
|
+
.remove();
|
596
|
+
|
597
|
+
function remove(d) {
|
598
|
+
d.metric.on("change.horizon-" + d.id, null);
|
599
|
+
context.on("change.horizon-" + d.id, null);
|
600
|
+
context.on("focus.horizon-" + d.id, null);
|
601
|
+
}
|
602
|
+
};
|
603
|
+
|
604
|
+
horizon.mode = function(_) {
|
605
|
+
if (!arguments.length) return mode;
|
606
|
+
mode = _ + "";
|
607
|
+
return horizon;
|
608
|
+
};
|
609
|
+
|
610
|
+
horizon.height = function(_) {
|
611
|
+
if (!arguments.length) return height;
|
612
|
+
buffer.height = height = +_;
|
613
|
+
return horizon;
|
614
|
+
};
|
615
|
+
|
616
|
+
horizon.metric = function(_) {
|
617
|
+
if (!arguments.length) return metric;
|
618
|
+
metric = _;
|
619
|
+
return horizon;
|
620
|
+
};
|
621
|
+
|
622
|
+
horizon.scale = function(_) {
|
623
|
+
if (!arguments.length) return scale;
|
624
|
+
scale = _;
|
625
|
+
return horizon;
|
626
|
+
};
|
627
|
+
|
628
|
+
horizon.extent = function(_) {
|
629
|
+
if (!arguments.length) return extent;
|
630
|
+
extent = _;
|
631
|
+
return horizon;
|
632
|
+
};
|
633
|
+
|
634
|
+
horizon.title = function(_) {
|
635
|
+
if (!arguments.length) return title;
|
636
|
+
title = _;
|
637
|
+
return horizon;
|
638
|
+
};
|
639
|
+
|
640
|
+
horizon.format = function(_) {
|
641
|
+
if (!arguments.length) return format;
|
642
|
+
format = _;
|
643
|
+
return horizon;
|
644
|
+
};
|
645
|
+
|
646
|
+
horizon.colors = function(_) {
|
647
|
+
if (!arguments.length) return colors;
|
648
|
+
colors = _;
|
649
|
+
return horizon;
|
650
|
+
};
|
651
|
+
|
652
|
+
return horizon;
|
653
|
+
};
|
654
|
+
cubism_contextPrototype.comparison = function() {
|
655
|
+
var context = this,
|
656
|
+
width = context.size(),
|
657
|
+
height = 120,
|
658
|
+
scale = d3.scale.linear().interpolate(d3.interpolateRound),
|
659
|
+
primary = function(d) { return d[0]; },
|
660
|
+
secondary = function(d) { return d[1]; },
|
661
|
+
extent = null,
|
662
|
+
title = cubism_identity,
|
663
|
+
formatPrimary = cubism_comparisonPrimaryFormat,
|
664
|
+
formatChange = cubism_comparisonChangeFormat,
|
665
|
+
colors = ["#9ecae1", "#225b84", "#a1d99b", "#22723a"],
|
666
|
+
strokeWidth = 1.5;
|
667
|
+
|
668
|
+
function comparison(selection) {
|
669
|
+
|
670
|
+
selection
|
671
|
+
.on("mousemove.comparison", function() { context.focus(d3.mouse(this)[0]); })
|
672
|
+
.on("mouseout.comparison", function() { context.focus(null); });
|
673
|
+
|
674
|
+
selection.append("canvas")
|
675
|
+
.attr("width", width)
|
676
|
+
.attr("height", height);
|
677
|
+
|
678
|
+
selection.append("span")
|
679
|
+
.attr("class", "title")
|
680
|
+
.text(title);
|
681
|
+
|
682
|
+
selection.append("span")
|
683
|
+
.attr("class", "value primary");
|
684
|
+
|
685
|
+
selection.append("span")
|
686
|
+
.attr("class", "value change");
|
687
|
+
|
688
|
+
selection.each(function(d, i) {
|
689
|
+
var that = this,
|
690
|
+
id = ++cubism_id,
|
691
|
+
primary_ = typeof primary === "function" ? primary.call(that, d, i) : primary,
|
692
|
+
secondary_ = typeof secondary === "function" ? secondary.call(that, d, i) : secondary,
|
693
|
+
extent_ = typeof extent === "function" ? extent.call(that, d, i) : extent,
|
694
|
+
div = d3.select(that),
|
695
|
+
canvas = div.select("canvas"),
|
696
|
+
spanPrimary = div.select(".value.primary"),
|
697
|
+
spanChange = div.select(".value.change"),
|
698
|
+
ready;
|
699
|
+
|
700
|
+
canvas.datum({id: id, primary: primary_, secondary: secondary_});
|
701
|
+
canvas = canvas.node().getContext("2d");
|
702
|
+
|
703
|
+
function change(start, stop) {
|
704
|
+
canvas.save();
|
705
|
+
canvas.clearRect(0, 0, width, height);
|
706
|
+
|
707
|
+
// update the scale
|
708
|
+
var primaryExtent = primary_.extent(),
|
709
|
+
secondaryExtent = secondary_.extent(),
|
710
|
+
extent = extent_ == null ? primaryExtent : extent_;
|
711
|
+
scale.domain(extent).range([height, 0]);
|
712
|
+
ready = primaryExtent.concat(secondaryExtent).every(isFinite);
|
713
|
+
|
714
|
+
// consistent overplotting
|
715
|
+
var round = start / context.step() & 1
|
716
|
+
? cubism_comparisonRoundOdd
|
717
|
+
: cubism_comparisonRoundEven;
|
718
|
+
|
719
|
+
// positive changes
|
720
|
+
canvas.fillStyle = colors[2];
|
721
|
+
for (var i = 0, n = width; i < n; ++i) {
|
722
|
+
var y0 = scale(primary_.valueAt(i)),
|
723
|
+
y1 = scale(secondary_.valueAt(i));
|
724
|
+
if (y0 < y1) canvas.fillRect(round(i), y0, 1, y1 - y0);
|
725
|
+
}
|
726
|
+
|
727
|
+
// negative changes
|
728
|
+
canvas.fillStyle = colors[0];
|
729
|
+
for (i = 0; i < n; ++i) {
|
730
|
+
var y0 = scale(primary_.valueAt(i)),
|
731
|
+
y1 = scale(secondary_.valueAt(i));
|
732
|
+
if (y0 > y1) canvas.fillRect(round(i), y1, 1, y0 - y1);
|
733
|
+
}
|
734
|
+
|
735
|
+
// positive values
|
736
|
+
canvas.fillStyle = colors[3];
|
737
|
+
for (i = 0; i < n; ++i) {
|
738
|
+
var y0 = scale(primary_.valueAt(i)),
|
739
|
+
y1 = scale(secondary_.valueAt(i));
|
740
|
+
if (y0 <= y1) canvas.fillRect(round(i), y0, 1, strokeWidth);
|
741
|
+
}
|
742
|
+
|
743
|
+
// negative values
|
744
|
+
canvas.fillStyle = colors[1];
|
745
|
+
for (i = 0; i < n; ++i) {
|
746
|
+
var y0 = scale(primary_.valueAt(i)),
|
747
|
+
y1 = scale(secondary_.valueAt(i));
|
748
|
+
if (y0 > y1) canvas.fillRect(round(i), y0 - strokeWidth, 1, strokeWidth);
|
749
|
+
}
|
750
|
+
|
751
|
+
canvas.restore();
|
752
|
+
}
|
753
|
+
|
754
|
+
function focus(i) {
|
755
|
+
if (i == null) i = width - 1;
|
756
|
+
var valuePrimary = primary_.valueAt(i),
|
757
|
+
valueSecondary = secondary_.valueAt(i),
|
758
|
+
valueChange = (valuePrimary - valueSecondary) / valueSecondary;
|
759
|
+
|
760
|
+
spanPrimary
|
761
|
+
.datum(valuePrimary)
|
762
|
+
.text(isNaN(valuePrimary) ? null : formatPrimary);
|
763
|
+
|
764
|
+
spanChange
|
765
|
+
.datum(valueChange)
|
766
|
+
.text(isNaN(valueChange) ? null : formatChange)
|
767
|
+
.attr("class", "value change " + (valueChange > 0 ? "positive" : valueChange < 0 ? "negative" : ""));
|
768
|
+
}
|
769
|
+
|
770
|
+
// Display the first primary change immediately,
|
771
|
+
// but defer subsequent updates to the context change.
|
772
|
+
// Note that someone still needs to listen to the metric,
|
773
|
+
// so that it continues to update automatically.
|
774
|
+
primary_.on("change.comparison-" + id, firstChange);
|
775
|
+
secondary_.on("change.comparison-" + id, firstChange);
|
776
|
+
function firstChange(start, stop) {
|
777
|
+
change(start, stop), focus();
|
778
|
+
if (ready) {
|
779
|
+
primary_.on("change.comparison-" + id, cubism_identity);
|
780
|
+
secondary_.on("change.comparison-" + id, cubism_identity);
|
781
|
+
}
|
782
|
+
}
|
783
|
+
|
784
|
+
// Update the chart when the context changes.
|
785
|
+
context.on("change.comparison-" + id, change);
|
786
|
+
context.on("focus.comparison-" + id, focus);
|
787
|
+
});
|
788
|
+
}
|
789
|
+
|
790
|
+
comparison.remove = function(selection) {
|
791
|
+
|
792
|
+
selection
|
793
|
+
.on("mousemove.comparison", null)
|
794
|
+
.on("mouseout.comparison", null);
|
795
|
+
|
796
|
+
selection.selectAll("canvas")
|
797
|
+
.each(remove)
|
798
|
+
.remove();
|
799
|
+
|
800
|
+
selection.selectAll(".title,.value")
|
801
|
+
.remove();
|
802
|
+
|
803
|
+
function remove(d) {
|
804
|
+
d.primary.on("change.comparison-" + d.id, null);
|
805
|
+
d.secondary.on("change.comparison-" + d.id, null);
|
806
|
+
context.on("change.comparison-" + d.id, null);
|
807
|
+
context.on("focus.comparison-" + d.id, null);
|
808
|
+
}
|
809
|
+
};
|
810
|
+
|
811
|
+
comparison.height = function(_) {
|
812
|
+
if (!arguments.length) return height;
|
813
|
+
height = +_;
|
814
|
+
return comparison;
|
815
|
+
};
|
816
|
+
|
817
|
+
comparison.primary = function(_) {
|
818
|
+
if (!arguments.length) return primary;
|
819
|
+
primary = _;
|
820
|
+
return comparison;
|
821
|
+
};
|
822
|
+
|
823
|
+
comparison.secondary = function(_) {
|
824
|
+
if (!arguments.length) return secondary;
|
825
|
+
secondary = _;
|
826
|
+
return comparison;
|
827
|
+
};
|
828
|
+
|
829
|
+
comparison.scale = function(_) {
|
830
|
+
if (!arguments.length) return scale;
|
831
|
+
scale = _;
|
832
|
+
return comparison;
|
833
|
+
};
|
834
|
+
|
835
|
+
comparison.extent = function(_) {
|
836
|
+
if (!arguments.length) return extent;
|
837
|
+
extent = _;
|
838
|
+
return comparison;
|
839
|
+
};
|
840
|
+
|
841
|
+
comparison.title = function(_) {
|
842
|
+
if (!arguments.length) return title;
|
843
|
+
title = _;
|
844
|
+
return comparison;
|
845
|
+
};
|
846
|
+
|
847
|
+
comparison.formatPrimary = function(_) {
|
848
|
+
if (!arguments.length) return formatPrimary;
|
849
|
+
formatPrimary = _;
|
850
|
+
return comparison;
|
851
|
+
};
|
852
|
+
|
853
|
+
comparison.formatChange = function(_) {
|
854
|
+
if (!arguments.length) return formatChange;
|
855
|
+
formatChange = _;
|
856
|
+
return comparison;
|
857
|
+
};
|
858
|
+
|
859
|
+
comparison.colors = function(_) {
|
860
|
+
if (!arguments.length) return colors;
|
861
|
+
colors = _;
|
862
|
+
return comparison;
|
863
|
+
};
|
864
|
+
|
865
|
+
comparison.strokeWidth = function(_) {
|
866
|
+
if (!arguments.length) return strokeWidth;
|
867
|
+
strokeWidth = _;
|
868
|
+
return comparison;
|
869
|
+
};
|
870
|
+
|
871
|
+
return comparison;
|
872
|
+
};
|
873
|
+
|
874
|
+
var cubism_comparisonPrimaryFormat = d3.format(".2s"),
|
875
|
+
cubism_comparisonChangeFormat = d3.format("+.0%");
|
876
|
+
|
877
|
+
function cubism_comparisonRoundEven(i) {
|
878
|
+
return i & 0xfffffe;
|
879
|
+
}
|
880
|
+
|
881
|
+
function cubism_comparisonRoundOdd(i) {
|
882
|
+
return ((i + 1) & 0xfffffe) - 1;
|
883
|
+
}
|
884
|
+
cubism_contextPrototype.axis = function() {
|
885
|
+
var context = this,
|
886
|
+
scale = context.scale,
|
887
|
+
axis_ = d3.svg.axis().scale(scale),
|
888
|
+
format = context.step() < 6e4 ? cubism_axisFormatSeconds : cubism_axisFormatMinutes;
|
889
|
+
|
890
|
+
function axis(selection) {
|
891
|
+
var id = ++cubism_id,
|
892
|
+
tick;
|
893
|
+
|
894
|
+
var g = selection.append("svg")
|
895
|
+
.datum({id: id})
|
896
|
+
.attr("width", context.size())
|
897
|
+
.attr("height", Math.max(28, -axis.tickSize()))
|
898
|
+
.append("g")
|
899
|
+
.attr("transform", "translate(0," + (axis_.orient() === "top" ? 27 : 4) + ")")
|
900
|
+
.call(axis_);
|
901
|
+
|
902
|
+
context.on("change.axis-" + id, function() {
|
903
|
+
g.call(axis_);
|
904
|
+
if (!tick) tick = cloneTick();
|
905
|
+
});
|
906
|
+
|
907
|
+
context.on("focus.axis-" + id, function(i) {
|
908
|
+
if (tick) {
|
909
|
+
if (i == null) {
|
910
|
+
tick.style("display", "none");
|
911
|
+
g.selectAll("text").style("fill-opacity", null);
|
912
|
+
} else {
|
913
|
+
tick.style("display", null).attr("x", i).text(format(scale.invert(i)));
|
914
|
+
var dx = tick.node().getComputedTextLength() + 6;
|
915
|
+
g.selectAll("text").style("fill-opacity", function(d) { return Math.abs(scale(d) - i) < dx ? 0 : 1; });
|
916
|
+
}
|
917
|
+
}
|
918
|
+
});
|
919
|
+
|
920
|
+
function cloneTick() {
|
921
|
+
return g.select(function() { return this.appendChild(g.select("text").node().cloneNode(true)); })
|
922
|
+
.style("display", "none")
|
923
|
+
.text(null);
|
924
|
+
}
|
925
|
+
}
|
926
|
+
|
927
|
+
axis.remove = function(selection) {
|
928
|
+
|
929
|
+
selection.selectAll("svg")
|
930
|
+
.each(remove)
|
931
|
+
.remove();
|
932
|
+
|
933
|
+
function remove(d) {
|
934
|
+
context.on("change.axis-" + d.id, null);
|
935
|
+
context.on("focus.axis-" + d.id, null);
|
936
|
+
}
|
937
|
+
};
|
938
|
+
|
939
|
+
return d3.rebind(axis, axis_,
|
940
|
+
"orient",
|
941
|
+
"ticks",
|
942
|
+
"tickSubdivide",
|
943
|
+
"tickSize",
|
944
|
+
"tickPadding",
|
945
|
+
"tickFormat");
|
946
|
+
};
|
947
|
+
|
948
|
+
var cubism_axisFormatSeconds = d3.time.format("%I:%M:%S %p"),
|
949
|
+
cubism_axisFormatMinutes = d3.time.format("%I:%M %p");
|
950
|
+
cubism_contextPrototype.rule = function() {
|
951
|
+
var context = this;
|
952
|
+
|
953
|
+
function rule(selection) {
|
954
|
+
var id = ++cubism_id;
|
955
|
+
|
956
|
+
var line = selection.append("div")
|
957
|
+
.datum({id: id})
|
958
|
+
.attr("class", "line")
|
959
|
+
.style("position", "fixed")
|
960
|
+
.style("top", 0)
|
961
|
+
.style("right", 0)
|
962
|
+
.style("bottom", 0)
|
963
|
+
.style("width", "1px")
|
964
|
+
.style("pointer-events", "none");
|
965
|
+
|
966
|
+
context.on("focus.rule-" + id, function(i) {
|
967
|
+
line
|
968
|
+
.style("display", i == null ? "none" : null)
|
969
|
+
.style("left", function() { return this.parentNode.getBoundingClientRect().left + i + "px"; });
|
970
|
+
});
|
971
|
+
}
|
972
|
+
|
973
|
+
rule.remove = function(selection) {
|
974
|
+
|
975
|
+
selection.selectAll(".line")
|
976
|
+
.each(remove)
|
977
|
+
.remove();
|
978
|
+
|
979
|
+
function remove(d) {
|
980
|
+
context.on("focus.rule-" + d.id, null);
|
981
|
+
}
|
982
|
+
};
|
983
|
+
|
984
|
+
return rule;
|
985
|
+
};
|
986
|
+
})(this);
|