graffable 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/CHANGES.md +14 -0
- data/Procfile +2 -0
- data/Rakefile +4 -0
- data/db/migrations/004_add_reports_txt.rb +12 -0
- data/graffable.gemspec +2 -0
- data/lib/graffable/app.rb +67 -12
- data/lib/graffable/public/javascript/jquery.flot.tooltip.min-0.6.6.js +12 -0
- data/lib/graffable/version.rb +1 -1
- data/lib/graffable/views/layout.haml +8 -5
- data/lib/graffable/views/report.haml +13 -4
- metadata +33 -4
- data/TODO.md +0 -9
- data/lib/graffable/public/javascript/jquery.flot.tooltip.min-0.6.5.js +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e2223326e8c8ba239381e37e462493512fc7b5f9
|
4
|
+
data.tar.gz: 3e469d9a364e2e146204ad14cc2edefec26f61c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 607a1e4529864ba28870a84ec4c4e8f984544829a57aa336c53c2593e3316ef4def2eac44d2331e89599522ece482ad7f50eaf92d16c2909e68748c97c8ad6db
|
7
|
+
data.tar.gz: 32cca37a38e3c92137b2fed6e49aa4160a2f99c245ee828e961b0268909b46b6deb24a1a67511507481d9db66b07e129e4421a286ac8a670ba1c60e12bc95674
|
data/.gitignore
CHANGED
data/CHANGES.md
CHANGED
@@ -2,6 +2,20 @@
|
|
2
2
|
Graffable Changes
|
3
3
|
=================
|
4
4
|
|
5
|
+
2014-03-12 Graffable v0.0.3
|
6
|
+
---------------------------
|
7
|
+
* Added hourly reports
|
8
|
+
* Reports now include label totals
|
9
|
+
* Reports now sort labels by total
|
10
|
+
* Reports have more descriptive `<title>` and `<h1>` tags
|
11
|
+
* Reports now ordered by description
|
12
|
+
* Reports no longer attempt to plot data when there is no data to plot
|
13
|
+
* Reports now have an optional `txt` column
|
14
|
+
* Update JQuery to v2.1.0
|
15
|
+
* Update jquery.flot.tooltip to v0.6.6
|
16
|
+
* Update Twitter Bootstrap to v3.1.1
|
17
|
+
|
18
|
+
|
5
19
|
2014-02-06 Graffable v0.0.2
|
6
20
|
---------------------------
|
7
21
|
* `Graffable::Database.connect()` now connects to `ENV['DATABASE_URL']` (was `ENV['GRAFFABLE_DATABASE_URL']`)
|
data/Procfile
ADDED
data/Rakefile
CHANGED
data/graffable.gemspec
CHANGED
@@ -25,6 +25,8 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.add_dependency 'sinatra-flash'
|
26
26
|
|
27
27
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
28
|
+
spec.add_development_dependency 'dotenv'
|
29
|
+
spec.add_development_dependency 'foreman'
|
28
30
|
spec.add_development_dependency 'rake'
|
29
31
|
spec.add_development_dependency 'sqlite3'
|
30
32
|
end
|
data/lib/graffable/app.rb
CHANGED
@@ -26,12 +26,36 @@ module Graffable
|
|
26
26
|
end
|
27
27
|
|
28
28
|
|
29
|
+
# /:group/:report/:year/:month/:day.json
|
30
|
+
get %r{/(.+)/(.+)/(\d{4})/(\d{2})/(\d{2}).(csv|json)} do |group_name, report_name, year, month, day, extension|
|
31
|
+
group = assert_group group_name
|
32
|
+
report = assert_report group, report_name
|
33
|
+
|
34
|
+
# TODO DRY!
|
35
|
+
query = "SELECT year,month,day,hour,label,#{ report[:aggregate].to_s.upcase }(value) AS value " +
|
36
|
+
"FROM numbers " +
|
37
|
+
"WHERE report_id=:report_id " +
|
38
|
+
"AND year=:year " +
|
39
|
+
"AND month=:month " +
|
40
|
+
"AND day=:day " +
|
41
|
+
"GROUP BY year,month,day,hour,label " +
|
42
|
+
"ORDER BY year,month,day,hour,label"
|
43
|
+
dataset = @db.fetch( query, day: day, month: month, report_id: report[:id], year: year )
|
44
|
+
|
45
|
+
case extension
|
46
|
+
when 'csv'
|
47
|
+
return_csv dataset
|
48
|
+
when 'json'
|
49
|
+
return_json dataset, date_formatter: lambda { |y,m,d,h| h }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
29
53
|
# /:group/:report/:year/:month.json
|
30
54
|
get %r{/(.+)/(.+)/(\d{4})/(\d{2}).(csv|json)} do |group_name, report_name, year, month, extension|
|
31
55
|
group = assert_group group_name
|
32
56
|
report = assert_report group, report_name
|
33
57
|
|
34
|
-
# TODO DRY
|
58
|
+
# TODO DRY!
|
35
59
|
query = "SELECT year,month,day,label,#{ report[:aggregate].to_s.upcase }(value) AS value " +
|
36
60
|
"FROM numbers " +
|
37
61
|
"WHERE report_id=:report_id " +
|
@@ -54,7 +78,7 @@ module Graffable
|
|
54
78
|
group = assert_group group_name
|
55
79
|
report = assert_report group, report_name
|
56
80
|
|
57
|
-
# TODO DRY
|
81
|
+
# TODO DRY!
|
58
82
|
query = "SELECT year,month,label,#{ report[:aggregate].to_s.upcase }(value) AS value " +
|
59
83
|
"FROM numbers " +
|
60
84
|
"WHERE report_id=:report_id " +
|
@@ -76,7 +100,7 @@ module Graffable
|
|
76
100
|
group = assert_group group_name
|
77
101
|
report = assert_report group, report_name
|
78
102
|
|
79
|
-
# TODO DRY
|
103
|
+
# TODO DRY!
|
80
104
|
query = "SELECT year,month,day,label,#{ report[:aggregate].to_s.upcase }(value) AS value " +
|
81
105
|
"FROM numbers " +
|
82
106
|
"WHERE report_id=:report_id " +
|
@@ -93,12 +117,35 @@ module Graffable
|
|
93
117
|
end
|
94
118
|
end
|
95
119
|
|
96
|
-
# TODO DRY
|
120
|
+
# TODO DRY!
|
121
|
+
get %r{/(.+)/(.+)/(\d{4})/(\d{2})/(\d{2})} do |group_name, report_name, year, month, day|
|
122
|
+
@group = @groups.detect { |g| group_name == g[:name] }
|
123
|
+
redirect_with_warning( '/', "Report group not found: #{group_name}" ) unless @group
|
124
|
+
|
125
|
+
@reports = @db[:reports].where( group_id: @group[:id] ).order(:description).all
|
126
|
+
@report = @reports.detect { |r| report_name == r[:name] }
|
127
|
+
redirect_with_warning( "/#{group_name}", "Report not found: #{report_name}" ) unless @report
|
128
|
+
|
129
|
+
@data_url = "/#{group_name}/#{report_name}/#{year}/#{month}/#{day}.json"
|
130
|
+
@interval = "#{year}-#{month}-#{day}"
|
131
|
+
|
132
|
+
date = Date.parse( "#{year}-#{month}-#{day}" )
|
133
|
+
prev_day = date - 1
|
134
|
+
next_day = date + 1
|
135
|
+
@previous = "/#{group_name}/#{report_name}/#{ prev_day.year }/#{ prev_day.strftime('%m') }/#{ prev_day.strftime('%d') }"
|
136
|
+
@next = "/#{group_name}/#{report_name}/#{ next_day.year }/#{ next_day.strftime('%m') }/#{ next_day.strftime('%d') }"
|
137
|
+
|
138
|
+
@title = "#{ @report[:description] } - #{ @interval }"
|
139
|
+
|
140
|
+
haml :report
|
141
|
+
end
|
142
|
+
|
143
|
+
# TODO DRY!
|
97
144
|
get %r{/(.+)/(.+)/(\d{4})/(\d{2})} do |group_name, report_name, year, month|
|
98
145
|
@group = @groups.detect { |g| group_name == g[:name] }
|
99
146
|
redirect_with_warning( '/', "Report group not found: #{group_name}" ) unless @group
|
100
147
|
|
101
|
-
@reports = @db[:reports].where( group_id: @group[:id] ).all
|
148
|
+
@reports = @db[:reports].where( group_id: @group[:id] ).order(:description).all
|
102
149
|
@report = @reports.detect { |r| report_name == r[:name] }
|
103
150
|
redirect_with_warning( "/#{group_name}", "Report not found: #{report_name}" ) unless @report
|
104
151
|
|
@@ -109,15 +156,17 @@ module Graffable
|
|
109
156
|
@previous = "/#{group_name}/#{report_name}/#{ date.prev_month.year }/#{ date.prev_month.strftime('%m') }"
|
110
157
|
@next = "/#{group_name}/#{report_name}/#{ date.next_month.year }/#{ date.next_month.strftime('%m') }"
|
111
158
|
|
159
|
+
@title = "#{ @report[:description] } - #{ @interval }"
|
160
|
+
|
112
161
|
haml :report
|
113
162
|
end
|
114
163
|
|
115
|
-
# TODO DRY
|
164
|
+
# TODO DRY!
|
116
165
|
get %r{/(.+)/(.+)/(\d{4})} do |group_name, report_name, year|
|
117
166
|
@group = @groups.detect { |g| group_name == g[:name] }
|
118
167
|
redirect_with_warning( '/', "Report group not found: #{group_name}" ) unless @group
|
119
168
|
|
120
|
-
@reports = @db[:reports].where( group_id: @group[:id] ).all
|
169
|
+
@reports = @db[:reports].where( group_id: @group[:id] ).order(:description).all
|
121
170
|
@report = @reports.detect { |r| report_name == r[:name] }
|
122
171
|
redirect_with_warning( "/#{group_name}", "Report not found: #{report_name}" ) unless @report
|
123
172
|
|
@@ -128,21 +177,25 @@ module Graffable
|
|
128
177
|
@previous = "/#{group_name}/#{report_name}/#{ date.prev_year.year }"
|
129
178
|
@next = "/#{group_name}/#{report_name}/#{ date.next_year.year }"
|
130
179
|
|
180
|
+
@title = "#{ @report[:description] } - #{ @interval }"
|
181
|
+
|
131
182
|
haml :report
|
132
183
|
end
|
133
184
|
|
134
|
-
# TODO DRY
|
185
|
+
# TODO DRY!
|
135
186
|
get '/:group/:report' do
|
136
187
|
@group = @groups.detect { |g| params[:group] == g[:name] }
|
137
188
|
redirect_with_warning( '/', "Report group not found: #{ params[:group] }" ) unless @group
|
138
189
|
|
139
|
-
@reports = @db[:reports].where( group_id: @group[:id] ).all
|
190
|
+
@reports = @db[:reports].where( group_id: @group[:id] ).order(:description).all
|
140
191
|
@report = @reports.detect { |r| params[:report] == r[:name] }
|
141
192
|
redirect_with_warning( "/#{ params[:group] }", "Report not found: #{ params[:report] }" ) unless @report
|
142
193
|
|
143
194
|
@data_url = "/#{ params[:group] }/#{ params[:report] }.json"
|
144
195
|
@interval = 'Recent'
|
145
196
|
|
197
|
+
@title = "#{ @report[:description] } - #{ @interval }"
|
198
|
+
|
146
199
|
haml :report
|
147
200
|
end
|
148
201
|
|
@@ -150,7 +203,7 @@ module Graffable
|
|
150
203
|
@group = @groups.detect{ |g| params[:group] == g[:name] }
|
151
204
|
redirect_with_warning( '/', "Report group not found: #{ params[:group] }" ) unless @group
|
152
205
|
|
153
|
-
@reports = @db[:reports].where( group_id: @group[:id] ).all
|
206
|
+
@reports = @db[:reports].where( group_id: @group[:id] ).order(:description).all
|
154
207
|
haml :group
|
155
208
|
end
|
156
209
|
|
@@ -227,14 +280,16 @@ module Graffable
|
|
227
280
|
|
228
281
|
values = values.sort.reverse.slice( 0 .. opts[:max] - 1 ).reverse if opts[:max] > - 1
|
229
282
|
values.each do |tuple|
|
230
|
-
date
|
283
|
+
date = date_mapping[ tuple.first ]
|
231
284
|
pairs = tuple.last
|
232
285
|
pairs.each_pair do |label, value|
|
233
286
|
unless data.key?(label)
|
234
|
-
data[label] = { data: [] }
|
287
|
+
data[label] = { data: [], total: 0 }
|
235
288
|
data[label][:label] = label unless label.empty?
|
236
289
|
end
|
237
290
|
data[label][:data].push [ date, value ]
|
291
|
+
data[label][:total] = data[label][:total] + value
|
292
|
+
data[label][:label] = "#{label} (#{ data[label][:total] })" unless label.empty?
|
238
293
|
end
|
239
294
|
end
|
240
295
|
|
@@ -0,0 +1,12 @@
|
|
1
|
+
/*
|
2
|
+
* jquery.flot.tooltip
|
3
|
+
*
|
4
|
+
* description: easy-to-use tooltips for Flot charts
|
5
|
+
* version: 0.6.6
|
6
|
+
* author: Krzysztof Urbas @krzysu [myviews.pl]
|
7
|
+
* website: https://github.com/krzysu/flot.tooltip
|
8
|
+
*
|
9
|
+
* build on 2014-02-10
|
10
|
+
* released under MIT License, 2012
|
11
|
+
*/
|
12
|
+
!function(a){var b={tooltip:!1,tooltipOpts:{content:"%s | X: %x | Y: %y",xDateFormat:null,yDateFormat:null,monthNames:null,dayNames:null,shifts:{x:10,y:20},defaultTheme:!0,onHover:function(){}}},c=function(a){this.tipPosition={x:0,y:0},this.init(a)};c.prototype.init=function(b){function c(a){var b={};b.x=a.pageX,b.y=a.pageY,e.updateTooltipPosition(b)}function d(a,b,c){var d=e.getDomElement();if(c){var f;f=e.stringFormat(e.tooltipOptions.content,c),d.html(f),e.updateTooltipPosition({x:b.pageX,y:b.pageY}),d.css({left:e.tipPosition.x+e.tooltipOptions.shifts.x,top:e.tipPosition.y+e.tooltipOptions.shifts.y}).show(),"function"==typeof e.tooltipOptions.onHover&&e.tooltipOptions.onHover(c,d)}else d.hide().html("")}var e=this;b.hooks.bindEvents.push(function(b,f){if(e.plotOptions=b.getOptions(),e.plotOptions.tooltip!==!1&&"undefined"!=typeof e.plotOptions.tooltip){e.tooltipOptions=e.plotOptions.tooltipOpts;{e.getDomElement()}a(b.getPlaceholder()).bind("plothover",d),a(f).bind("mousemove",c)}}),b.hooks.shutdown.push(function(b,e){a(b.getPlaceholder()).unbind("plothover",d),a(e).unbind("mousemove",c)})},c.prototype.getDomElement=function(){var b;return a("#flotTip").length>0?b=a("#flotTip"):(b=a("<div />").attr("id","flotTip"),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.updateTooltipPosition=function(b){var c=a("#flotTip").outerWidth()+this.tooltipOptions.shifts.x,d=a("#flotTip").outerHeight()+this.tooltipOptions.shifts.y;b.x-a(window).scrollLeft()>a(window).innerWidth()-c&&(b.x-=c),b.y-a(window).scrollTop()>a(window).innerHeight()-d&&(b.y-=d),this.tipPosition.x=b.x,this.tipPosition.y=b.y},c.prototype.stringFormat=function(a,b){var c,d,e=/%p\.{0,1}(\d{0,})/,f=/%s/,g=/%x\.{0,1}(\d{0,})/,h=/%y\.{0,1}(\d{0,})/,i="%x",j="%y";if("undefined"!=typeof b.series.threshold?(c=b.datapoint[0],d=b.datapoint[1]):(c=b.series.data[b.dataIndex][0],d=b.series.data[b.dataIndex][1]),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)),"undefined"!=typeof b.series.percent&&(a=this.adjustValPrecision(e,a,b.series.percent)),a="undefined"!=typeof b.series.label?a.replace(f,b.series.label):a.replace(f,""),this.isTimeMode("xaxis",b)&&this.isXDateFormat(b)&&(a=a.replace(g,this.timestampToDate(c,this.tooltipOptions.xDateFormat))),this.isTimeMode("yaxis",b)&&this.isYDateFormat(b)&&(a=a.replace(h,this.timestampToDate(d,this.tooltipOptions.yDateFormat))),"number"==typeof c&&(a=this.adjustValPrecision(g,a,c)),"number"==typeof d&&(a=this.adjustValPrecision(h,a,d)),"undefined"!=typeof b.series.xaxis.ticks&&b.series.xaxis.ticks.length>b.dataIndex&&!this.isTimeMode("xaxis",b)&&(a=a.replace(g,b.series.xaxis.ticks[b.dataIndex].label)),"undefined"!=typeof b.series.yaxis.ticks)for(var k in b.series.yaxis.ticks)if(b.series.yaxis.ticks.hasOwnProperty(k)){var l=this.isCategoriesMode("yaxis",b)?b.series.yaxis.ticks[k].label:b.series.yaxis.ticks[k].v;l===d&&(a=a.replace(h,b.series.yaxis.ticks[k].label))}return"undefined"!=typeof b.series.xaxis.tickFormatter&&(a=a.replace(i,b.series.xaxis.tickFormatter(c,b.series.xaxis).replace(/\$/g,"$$"))),"undefined"!=typeof b.series.yaxis.tickFormatter&&(a=a.replace(j,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(){return"undefined"!=typeof this.tooltipOptions.xDateFormat&&null!==this.tooltipOptions.xDateFormat},c.prototype.isYDateFormat=function(){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){var d=new Date(1*b);return a.plot.formatDate(d,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};var d=function(a){new c(a)};a.plot.plugins.push({init:d,options:b,name:"tooltip",version:"0.6.6"})}(jQuery);
|
data/lib/graffable/version.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
%html
|
2
2
|
%head
|
3
3
|
%meta{ name: 'viewport', content: 'width=device-width, initial-scale=1.0' }
|
4
|
-
%link{ rel: 'stylesheet', type: 'text/css', href: '//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.
|
4
|
+
%link{ rel: 'stylesheet', type: 'text/css', href: '//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/css/bootstrap.min.css' }
|
5
5
|
%link{ rel: 'stylesheet', type: 'text/css', href: url('/stylesheets/graffable.css') }
|
6
|
-
%title= 'Metrics'
|
6
|
+
%title= @title ? "Metrics - #{ @title }" : 'Metrics'
|
7
7
|
%body
|
8
|
-
%script{ type: 'text/javascript', src: '//cdnjs.cloudflare.com/ajax/libs/jquery/2.0
|
9
|
-
%script{ type: 'text/javascript', src: '//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.
|
8
|
+
%script{ type: 'text/javascript', src: '//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js' }
|
9
|
+
%script{ type: 'text/javascript', src: '//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/js/bootstrap.min.js' }
|
10
10
|
%script{ type: 'text/javascript', src: '//cdnjs.cloudflare.com/ajax/libs/flot/0.8.2/jquery.flot.min.js' }
|
11
11
|
%script{ type: 'text/javascript', src: '//cdnjs.cloudflare.com/ajax/libs/flot/0.8.2/jquery.flot.categories.min.js' }
|
12
12
|
%script{ type: 'text/javascript', src: '//cdnjs.cloudflare.com/ajax/libs/flot/0.8.2/jquery.flot.stack.min.js' }
|
13
|
-
%script{ type: 'text/javascript', src: url('/javascript/jquery.flot.tooltip.min-0.6.
|
13
|
+
%script{ type: 'text/javascript', src: url('/javascript/jquery.flot.tooltip.min-0.6.6.js') }
|
14
14
|
|
15
15
|
%nav.navbar.navbar-default{ role: 'navigation' }
|
16
16
|
.navbar-header
|
@@ -50,12 +50,15 @@
|
|
50
50
|
- url = "/#{ @group[:name] }/#{ @report[:name] }"
|
51
51
|
- year = Time.now.year
|
52
52
|
- month = Time.now.strftime("%m")
|
53
|
+
- day = DateTime.now.strftime("%d")
|
53
54
|
%li
|
54
55
|
%a{ href: url(url) } Recent
|
55
56
|
%li
|
56
57
|
%a{ href: url("#{url}/#{year}") }= year
|
57
58
|
%li
|
58
59
|
%a{ href: url("#{url}/#{year}/#{month}") }= "#{year}-#{month}"
|
60
|
+
%li
|
61
|
+
%a{ href: url("#{url}/#{year}/#{month}/#{day}") }= "#{year}-#{month}-#{day}"
|
59
62
|
|
60
63
|
.container
|
61
64
|
.flash
|
@@ -3,14 +3,18 @@
|
|
3
3
|
- if @previous
|
4
4
|
%a{ href: url(@previous) }
|
5
5
|
%span.glyphicon.glyphicon-chevron-left
|
6
|
-
%h1{ style: 'display: inline; padding: 0em 1em;' }= @report[:description]
|
6
|
+
%h1{ style: 'display: inline; padding: 0em 1em;' }= @title || @report[:description]
|
7
7
|
- if @next
|
8
8
|
%a{ href: url(@next) }
|
9
9
|
%span.glyphicon.glyphicon-chevron-right
|
10
10
|
|
11
11
|
#content{ style: 'align: center; margin: auto; padding: 1em; width: 95%;' }
|
12
12
|
#placeholder{ style: 'align: center; height: 75%; margin: auto; padding: 1em; width: 95%;' }
|
13
|
-
#
|
13
|
+
#footer
|
14
|
+
%span#legend{ style: 'float: left; padding-bottom: 1em;' }
|
15
|
+
- if @report[:txt]
|
16
|
+
%span#accordion{ style: 'float: right; padding-bottom: 5em;' }
|
17
|
+
%span= @report[:txt]
|
14
18
|
|
15
19
|
:javascript
|
16
20
|
data_url = "#{ url(@data_url) }";
|
@@ -51,8 +55,13 @@
|
|
51
55
|
var data = [];
|
52
56
|
|
53
57
|
function onDataReceived(series) {
|
54
|
-
|
55
|
-
|
58
|
+
if ( 'undefined' == typeof series.data || ( series.data instanceof Array && 0 == series.data.length ) ) {
|
59
|
+
$('#placeholder').html("<p style='color: red' alignment='center'>No data available for this time period</p>");
|
60
|
+
}
|
61
|
+
else {
|
62
|
+
$.plot( "#placeholder", series.data.sort( function(a,b) { return b.total - a.total } ), options );
|
63
|
+
$( "#accordion" ).accordion( { active: false, collapsible: true } ); // XXX
|
64
|
+
}
|
56
65
|
}
|
57
66
|
|
58
67
|
$.ajax({
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graffable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- blair christensen.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: haml
|
@@ -94,6 +94,34 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '1.3'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: dotenv
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: foreman
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
97
125
|
- !ruby/object:Gem::Dependency
|
98
126
|
name: rake
|
99
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -133,13 +161,14 @@ files:
|
|
133
161
|
- CHANGES.md
|
134
162
|
- Gemfile
|
135
163
|
- LICENSE.txt
|
164
|
+
- Procfile
|
136
165
|
- README.md
|
137
166
|
- Rakefile
|
138
|
-
- TODO.md
|
139
167
|
- config.ru
|
140
168
|
- db/migrations/001_create_groups.rb
|
141
169
|
- db/migrations/002_create_reports.rb
|
142
170
|
- db/migrations/003_create_numbers.rb
|
171
|
+
- db/migrations/004_add_reports_txt.rb
|
143
172
|
- graffable.gemspec
|
144
173
|
- lib/graffable.rb
|
145
174
|
- lib/graffable/app.rb
|
@@ -147,7 +176,7 @@ files:
|
|
147
176
|
- lib/graffable/importer.rb
|
148
177
|
- lib/graffable/migration_task.rb
|
149
178
|
- lib/graffable/public/favicon.ico
|
150
|
-
- lib/graffable/public/javascript/jquery.flot.tooltip.min-0.6.
|
179
|
+
- lib/graffable/public/javascript/jquery.flot.tooltip.min-0.6.6.js
|
151
180
|
- lib/graffable/public/stylesheets/graffable.css
|
152
181
|
- lib/graffable/seed_task.rb
|
153
182
|
- lib/graffable/version.rb
|
data/TODO.md
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* jquery.flot.tooltip
|
3
|
-
*
|
4
|
-
* description: easy-to-use tooltips for Flot charts
|
5
|
-
* version: 0.6.5
|
6
|
-
* author: Krzysztof Urbas @krzysu [myviews.pl]
|
7
|
-
* website: https://github.com/krzysu/flot.tooltip
|
8
|
-
*
|
9
|
-
* build on 2014-01-23
|
10
|
-
* released under MIT License, 2012
|
11
|
-
*/
|
12
|
-
(function(t){var i={tooltip:!1,tooltipOpts:{content:"%s | X: %x | Y: %y",xDateFormat:null,yDateFormat:null,monthNames:null,dayNames:null,shifts:{x:10,y:20},defaultTheme:!0,onHover:function(){}}},o=function(t){this.tipPosition={x:0,y:0},this.init(t)};o.prototype.init=function(i){function o(t){var i={};i.x=t.pageX,i.y=t.pageY,s.updateTooltipPosition(i)}function e(t,i,o){var e=s.getDomElement();if(o){var n;n=s.stringFormat(s.tooltipOptions.content,o),e.html(n),s.updateTooltipPosition({x:i.pageX,y:i.pageY}),e.css({left:s.tipPosition.x+s.tooltipOptions.shifts.x,top:s.tipPosition.y+s.tooltipOptions.shifts.y}).show(),"function"==typeof s.tooltipOptions.onHover&&s.tooltipOptions.onHover(o,e)}else e.hide().html("")}var s=this;i.hooks.bindEvents.push(function(i,n){s.plotOptions=i.getOptions(),s.plotOptions.tooltip!==!1&&void 0!==s.plotOptions.tooltip&&(s.tooltipOptions=s.plotOptions.tooltipOpts,s.getDomElement(),t(i.getPlaceholder()).bind("plothover",e),t(n).bind("mousemove",o))}),i.hooks.shutdown.push(function(i,s){t(i.getPlaceholder()).unbind("plothover",e),t(s).unbind("mousemove",o)})},o.prototype.getDomElement=function(){var i;return t("#flotTip").length>0?i=t("#flotTip"):(i=t("<div />").attr("id","flotTip"),i.appendTo("body").hide().css({position:"absolute"}),this.tooltipOptions.defaultTheme&&i.css({background:"#fff","z-index":"100",padding:"0.4em 0.6em","border-radius":"0.5em","font-size":"0.8em",border:"1px solid #111",display:"none","white-space":"nowrap"})),i},o.prototype.updateTooltipPosition=function(i){var o=t("#flotTip").outerWidth()+this.tooltipOptions.shifts.x,e=t("#flotTip").outerHeight()+this.tooltipOptions.shifts.y;i.x-t(window).scrollLeft()>t(window).innerWidth()-o&&(i.x-=o),i.y-t(window).scrollTop()>t(window).innerHeight()-e&&(i.y-=e),this.tipPosition.x=i.x,this.tipPosition.y=i.y},o.prototype.stringFormat=function(t,i){var o,e,s=/%p\.{0,1}(\d{0,})/,n=/%s/,p=/%x\.{0,1}(\d{0,})/,a=/%y\.{0,1}(\d{0,})/,r="%x",l="%y";return i.series.threshold!==void 0?(o=i.datapoint[0],e=i.datapoint[1]):(o=i.series.data[i.dataIndex][0],e=i.series.data[i.dataIndex][1]),null===i.series.label&&i.series.originSeries&&(i.series.label=i.series.originSeries.label),"function"==typeof t&&(t=t(i.series.label,o,e,i)),i.series.percent!==void 0&&(t=this.adjustValPrecision(s,t,i.series.percent)),t=i.series.label!==void 0?t.replace(n,i.series.label):t.replace(n,""),this.isTimeMode("xaxis",i)&&this.isXDateFormat(i)&&(t=t.replace(p,this.timestampToDate(o,this.tooltipOptions.xDateFormat))),this.isTimeMode("yaxis",i)&&this.isYDateFormat(i)&&(t=t.replace(a,this.timestampToDate(e,this.tooltipOptions.yDateFormat))),"number"==typeof o&&(t=this.adjustValPrecision(p,t,o)),"number"==typeof e&&(t=this.adjustValPrecision(a,t,e)),i.series.xaxis.ticks!==void 0&&i.series.xaxis.ticks.length>i.dataIndex&&!this.isTimeMode("xaxis",i)&&(t=t.replace(p,i.series.xaxis.ticks[i.dataIndex].label)),i.series.xaxis.tickFormatter!==void 0&&(t=t.replace(r,i.series.xaxis.tickFormatter(o,i.series.xaxis).replace(/\$/g,"$$"))),i.series.yaxis.tickFormatter!==void 0&&(t=t.replace(l,i.series.yaxis.tickFormatter(e,i.series.yaxis).replace(/\$/g,"$$"))),t},o.prototype.isTimeMode=function(t,i){return i.series[t].options.mode!==void 0&&"time"===i.series[t].options.mode},o.prototype.isXDateFormat=function(){return this.tooltipOptions.xDateFormat!==void 0&&null!==this.tooltipOptions.xDateFormat},o.prototype.isYDateFormat=function(){return this.tooltipOptions.yDateFormat!==void 0&&null!==this.tooltipOptions.yDateFormat},o.prototype.timestampToDate=function(i,o){var e=new Date(1*i);return t.plot.formatDate(e,o,this.tooltipOptions.monthNames,this.tooltipOptions.dayNames)},o.prototype.adjustValPrecision=function(t,i,o){var e,s=i.match(t);return null!==s&&""!==RegExp.$1&&(e=RegExp.$1,o=o.toFixed(e),i=i.replace(t,o)),i};var e=function(t){new o(t)};t.plot.plugins.push({init:e,options:i,name:"tooltip",version:"0.6.1"})})(jQuery);
|