redis_analytics 0.1.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +12 -0
- data/CONTRIBUTING.md +33 -0
- data/Guardfile +10 -0
- data/README.md +105 -23
- data/Rakefile +3 -11
- data/TODO.md +12 -0
- data/bin/redis_analytics_dashboard +1 -1
- data/config.ru +13 -0
- data/lib/redis_analytics.rb +5 -1
- data/lib/redis_analytics/analytics.rb +17 -203
- data/lib/redis_analytics/api.rb +60 -0
- data/lib/redis_analytics/configuration.rb +47 -16
- data/lib/redis_analytics/dashboard.rb +28 -89
- data/lib/redis_analytics/dashboard/public/{favicon.ico → img/favicon.ico} +0 -0
- data/lib/redis_analytics/dashboard/public/javascripts/{bootstrap.min.js → vendor/bootstrap/bootstrap.min.js} +0 -0
- data/lib/redis_analytics/dashboard/public/javascripts/{jquery-1.9.1.min.js → vendor/jquery-1.9.1.min.js} +0 -0
- data/lib/redis_analytics/dashboard/public/javascripts/{jquery-jvectormap-1.2.2.min.js → vendor/jquery-jvectormap-1.2.2.min.js} +0 -0
- data/lib/redis_analytics/dashboard/public/javascripts/{jquery-jvectormap-world-mill-en.js → vendor/jquery-jvectormap-world-mill-en.js} +0 -0
- data/lib/redis_analytics/dashboard/public/javascripts/{morris.min.js → vendor/morris.min.js} +0 -0
- data/lib/redis_analytics/dashboard/public/javascripts/{raphael-min.js → vendor/raphael-min.js} +0 -0
- data/lib/redis_analytics/dashboard/views/activity.erb +7 -0
- data/lib/redis_analytics/dashboard/views/dialogs/unique_visits.erb +41 -0
- data/lib/redis_analytics/dashboard/views/dialogs/visits.erb +40 -0
- data/lib/redis_analytics/dashboard/views/footer.erb +1 -3
- data/lib/redis_analytics/dashboard/views/header.erb +17 -42
- data/lib/redis_analytics/dashboard/views/layout.erb +5 -22
- data/lib/redis_analytics/dashboard/views/visits.erb +38 -143
- data/lib/redis_analytics/dashboard/views/visits_js.erb +110 -247
- data/lib/redis_analytics/dashboard/views/widgets/bounce_rate.erb +3 -0
- data/lib/redis_analytics/dashboard/views/widgets/browsers_donut.erb +8 -0
- data/lib/redis_analytics/dashboard/views/widgets/first_visits.erb +3 -0
- data/lib/redis_analytics/dashboard/views/widgets/page_depth.erb +3 -0
- data/lib/redis_analytics/dashboard/views/widgets/referers_donut.erb +8 -0
- data/lib/redis_analytics/dashboard/views/widgets/total_page_views.erb +3 -0
- data/lib/redis_analytics/dashboard/views/widgets/total_visits.erb +3 -0
- data/lib/redis_analytics/dashboard/views/widgets/unique_visits_line.erb +26 -0
- data/lib/redis_analytics/dashboard/views/widgets/visit_duration.erb +3 -0
- data/lib/redis_analytics/dashboard/views/widgets/visit_spark.erb +23 -0
- data/lib/redis_analytics/dashboard/views/widgets/visitor_recency_slices.erb +39 -0
- data/lib/redis_analytics/dashboard/views/widgets/visits_area.erb +30 -0
- data/lib/redis_analytics/dashboard/views/widgets/visits_donut.erb +8 -0
- data/lib/redis_analytics/dashboard/views/widgets/world_map.erb +50 -0
- data/lib/redis_analytics/filter.rb +33 -0
- data/lib/redis_analytics/helpers.rb +36 -30
- data/lib/redis_analytics/metrics.rb +96 -0
- data/lib/redis_analytics/time_ext.rb +72 -2
- data/lib/redis_analytics/tracker.rb +13 -5
- data/lib/redis_analytics/version.rb +1 -1
- data/lib/redis_analytics/visit.rb +122 -0
- data/redis_analytics.gemspec +19 -14
- data/spec/lib/redis_analytics/analytics_spec.rb +59 -0
- data/spec/lib/redis_analytics/configuration_spec.rb +158 -0
- data/spec/lib/redis_analytics/dashboard_spec.rb +32 -0
- data/spec/lib/redis_analytics/filter_spec.rb +34 -0
- data/spec/lib/redis_analytics/tracker_spec.rb +20 -0
- data/spec/spec_helper.rb +13 -6
- data/spec/support/fakeredis.rb +1 -0
- data/wsd.png +0 -0
- metadata +268 -126
- data/lib/redis_analytics/config.ru +0 -10
- data/spec/redis_analytics_spec.rb +0 -57
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
module RedisAnalytics
|
6
|
+
|
7
|
+
class Api < Sinatra::Base
|
8
|
+
helpers Rack::RedisAnalytics::Helpers
|
9
|
+
|
10
|
+
get '/data/?' do
|
11
|
+
|
12
|
+
begin
|
13
|
+
to_date_time = Date.parse(params[:to_date_time]).to_time rescue Time.now
|
14
|
+
unit = params[:unit] || 'day'
|
15
|
+
aggregate = (params[:aggregate] == 'yes')
|
16
|
+
units = (params[:unit_count] || 1).to_i
|
17
|
+
p = params[:p].split(',')
|
18
|
+
from_date_time = to_date_time - units.send(unit)
|
19
|
+
results = []
|
20
|
+
|
21
|
+
p.each_with_index do |q, j|
|
22
|
+
result = self.send("#{unit}ly_#{q}", from_date_time, :to_date => to_date_time, :aggregate => aggregate)
|
23
|
+
if result.is_a?(Array) # time range data (non-aggregate)
|
24
|
+
result.each_with_index do |r, i|
|
25
|
+
results[i] ||= {}
|
26
|
+
date_value = r[0][0..2]
|
27
|
+
time_value = r[0][3..-1]
|
28
|
+
date_time_value = []
|
29
|
+
date_time_value << date_value.join('-')
|
30
|
+
date_time_value << time_value.join(':') if time_value
|
31
|
+
# results[i]['raw'] = date_time_value.join(' ').strip
|
32
|
+
results[i]['unix'] = Time.mktime(*r[0].map(&:to_i)).to_i
|
33
|
+
strf = case unit
|
34
|
+
when 'minute'
|
35
|
+
'%H%Mhrs'
|
36
|
+
when 'hour'
|
37
|
+
'%a %H00hrs'
|
38
|
+
when 'day'
|
39
|
+
'%a'
|
40
|
+
when 'month'
|
41
|
+
'%b'
|
42
|
+
when 'year'
|
43
|
+
'%Y'
|
44
|
+
end
|
45
|
+
results[i]['raw'] = Time.at(results[i]['unix']).strftime(strf)
|
46
|
+
results[i][q] = r[1]
|
47
|
+
end
|
48
|
+
elsif result.is_a?(Hash) or result.is_a?(Fixnum) # aggregate data
|
49
|
+
results[j] = {q => result}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
content_type :json
|
53
|
+
results.to_json
|
54
|
+
rescue Exception => e
|
55
|
+
halt 500, [500, [e.message, e.backtrace]].to_json
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -3,23 +3,30 @@ module Rack
|
|
3
3
|
module Configuration
|
4
4
|
# Redis connection instance
|
5
5
|
attr_accessor :redis_connection
|
6
|
-
|
6
|
+
|
7
7
|
# Redis namespace for keys
|
8
8
|
attr_writer :redis_namespace
|
9
9
|
|
10
|
-
# Name of the cookie which tracks
|
11
|
-
attr_writer :
|
10
|
+
# Name of the cookie which tracks first visitors
|
11
|
+
attr_writer :first_visit_cookie_name
|
12
12
|
|
13
|
-
# Name of the cookie which tracks visits
|
14
|
-
attr_writer :
|
13
|
+
# Name of the cookie which tracks current visits
|
14
|
+
attr_writer :current_visit_cookie_name
|
15
15
|
|
16
16
|
# Minutes the visit should timeout after (if no hit is received)
|
17
17
|
attr_writer :visit_timeout
|
18
18
|
|
19
19
|
# Endpoint for dashboard
|
20
|
-
|
20
|
+
attr_writer :dashboard_endpoint
|
21
21
|
|
22
|
-
#
|
22
|
+
# Endpoint for api
|
23
|
+
attr_writer :api_endpoint
|
24
|
+
|
25
|
+
attr_writer :path_filters
|
26
|
+
|
27
|
+
attr_writer :filters
|
28
|
+
|
29
|
+
# Path to the Geo IP Database file
|
23
30
|
attr_writer :geo_ip_data_path
|
24
31
|
|
25
32
|
# Redis namespace for keys
|
@@ -32,16 +39,32 @@ module Rack
|
|
32
39
|
@visit_timeout ||= 1 # minutes
|
33
40
|
end
|
34
41
|
|
35
|
-
# Name of the cookie which tracks
|
36
|
-
def
|
37
|
-
@
|
42
|
+
# Name of the cookie which tracks first visitors (unknown visitors)
|
43
|
+
def first_visit_cookie_name
|
44
|
+
@first_visit_cookie_name ||= '_rucn'
|
38
45
|
end
|
39
46
|
|
40
47
|
# Name of the cookie which tracks visits
|
41
|
-
def
|
42
|
-
@
|
48
|
+
def current_visit_cookie_name
|
49
|
+
@current_visit_cookie_name ||= '_vcn'
|
43
50
|
end
|
44
|
-
|
51
|
+
|
52
|
+
def filters
|
53
|
+
@filters ||= []
|
54
|
+
end
|
55
|
+
|
56
|
+
def path_filters
|
57
|
+
@path_filters ||= []
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_filter(&proc)
|
61
|
+
filters << RedisAnalytics::Filter.new(proc)
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_path_filter(path)
|
65
|
+
path_filters << RedisAnalytics::PathFilter.new(path)
|
66
|
+
end
|
67
|
+
|
45
68
|
def geo_ip_data_path
|
46
69
|
@geo_ip_data_path = ::File.expand_path(::File.join(::File.dirname(__FILE__),'..','..')) + "/bin/GeoIP.dat"
|
47
70
|
end
|
@@ -55,17 +78,25 @@ module Rack
|
|
55
78
|
end
|
56
79
|
|
57
80
|
def redis_key_timestamps # [format, expire in seconds or nil]
|
58
|
-
['%Y', '%Y_%m', '%Y_%m_%d', '%Y_%m_%d_%H',
|
81
|
+
['%Y', '%Y_%m', '%Y_%m_%d', '%Y_%m_%d_%H', '%Y_%m_%d_%H_%M']
|
59
82
|
end
|
60
83
|
|
61
84
|
def time_range_formats
|
62
85
|
[[:year, :month, "%b"], [:week, :day, "%a"], [:day, :hour, "%l%P"]]
|
63
86
|
end
|
64
|
-
|
87
|
+
|
65
88
|
def configure
|
66
89
|
yield self
|
67
90
|
end
|
68
|
-
|
91
|
+
|
92
|
+
def api_endpoint
|
93
|
+
@api_endpoint || dashboard_endpoint + '/api'
|
94
|
+
end
|
95
|
+
|
96
|
+
def dashboard_endpoint
|
97
|
+
@dashboard_endpoint || '/redis_analytics'
|
98
|
+
end
|
99
|
+
|
69
100
|
end
|
70
101
|
end
|
71
102
|
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
require 'sinatra/base'
|
2
|
-
require '
|
3
|
-
require 'active_support/core_ext'
|
4
|
-
require 'redis_analytics'
|
2
|
+
require 'sinatra/assetpack'
|
5
3
|
|
6
4
|
if defined? Encoding
|
7
5
|
Encoding.default_external = Encoding::UTF_8
|
@@ -9,106 +7,47 @@ end
|
|
9
7
|
|
10
8
|
module Rack
|
11
9
|
module RedisAnalytics
|
12
|
-
class Dashboard < Sinatra::Base
|
13
|
-
|
14
|
-
dir = ::File.expand_path(::File.dirname(__FILE__))
|
15
|
-
|
16
|
-
set :views, "#{dir}/dashboard/views"
|
17
|
-
|
18
|
-
if respond_to? :public_folder
|
19
|
-
set :public_folder, "#{dir}/dashboard/public"
|
20
|
-
else
|
21
|
-
set :public, "#{dir}/dashboard/public"
|
22
|
-
end
|
23
|
-
|
24
|
-
helpers do
|
25
|
-
include Rack::RedisAnalytics::Helpers
|
26
10
|
|
27
|
-
|
28
|
-
|
29
|
-
n + r + rand(r)
|
30
|
-
end
|
31
|
-
|
32
|
-
def parse_float(float)
|
33
|
-
float.nan? ? '0.0' : float
|
34
|
-
end
|
35
|
-
|
36
|
-
def with_benchmarking
|
37
|
-
@t0 = Time.now
|
38
|
-
yield
|
39
|
-
@t1 = Time.now
|
40
|
-
@t = @t1 - @t0
|
41
|
-
puts "Time Taken: #{@t} seconds"
|
42
|
-
end
|
11
|
+
class Dashboard < Sinatra::Base
|
12
|
+
register Sinatra::AssetPack
|
43
13
|
|
44
|
-
|
45
|
-
|
14
|
+
set :root, ::File.expand_path(::File.dirname(__FILE__))
|
15
|
+
set :views, "#{settings.root}/dashboard/views"
|
46
16
|
set :static, true
|
47
17
|
|
48
|
-
|
49
|
-
|
50
|
-
|
18
|
+
helpers Rack::RedisAnalytics::Helpers
|
19
|
+
|
20
|
+
assets do
|
21
|
+
serve '/css', from: "dashboard/public/css"
|
22
|
+
serve '/javascripts', from: "dashboard/public/javascripts"
|
23
|
+
serve '/img', from: "dashboard/public/img"
|
24
|
+
js :app, [
|
25
|
+
'/javascripts/vendor/*.js',
|
26
|
+
'/javascripts/*.js'
|
27
|
+
]
|
28
|
+
js :bootstrap, [
|
29
|
+
'/javascripts/vendor/bootstrap/*.js'
|
30
|
+
]
|
31
|
+
css :application, [
|
32
|
+
'/css/*.css'
|
33
|
+
]
|
34
|
+
js_compression :jsmin # :jsmin | :yui | :closure | :uglify
|
35
|
+
css_compression :simple # :simple | :sass | :yui | :sqwish
|
51
36
|
end
|
52
37
|
|
53
38
|
get '/' do
|
54
|
-
|
55
|
-
[status, headers, body]
|
39
|
+
redirect url('visits')
|
56
40
|
end
|
57
41
|
|
58
|
-
get '/activity' do
|
59
|
-
with_benchmarking do
|
60
|
-
# code
|
61
|
-
end
|
42
|
+
get '/activity/?' do
|
62
43
|
erb :activity
|
63
44
|
end
|
64
45
|
|
65
|
-
get '/visits' do
|
66
|
-
|
67
|
-
@range = (request.cookies["_rarng"] || RedisAnalytics.default_range).to_sym # should first try to fetch from cookie what the default range is
|
68
|
-
@data = {}
|
69
|
-
|
70
|
-
RedisAnalytics.time_range_formats.each do |range, unit, time_format|
|
71
|
-
multiple = (1.send(range)/1.send(unit)).round
|
72
|
-
time_range = @t0 - 1.send(range) + 1.send(unit)
|
73
|
-
@data[range] ||= {}
|
74
|
-
@data[range][:visits] = self.send("#{unit}ly_visits".to_sym, time_range)
|
75
|
-
@data[range][:total_visits] = @data[range][:visits].inject(0){|s, x| s += x[1].to_i; s}
|
76
|
-
@data[range][:new_visits] = self.send("#{unit}ly_new_visits", time_range)
|
77
|
-
@data[range][:total_new_visits] = @data[range][:new_visits].inject(0){|s, x| s += x[1].to_i; s}
|
78
|
-
@data[range][:page_views] = self.send("#{unit}ly_page_views", time_range)
|
79
|
-
|
80
|
-
@data[range][:total_page_views] = @data[range][:page_views].inject(0){|s, x| s += x[1].to_i; s}
|
81
|
-
@data[range][:visit_time] = self.send("#{unit}ly_visit_time", time_range)
|
82
|
-
@data[range][:avg_visit_time] = Hash[@data[range][:visit_time]].values.sum.to_f/@data[range][:visit_time].length.to_f
|
83
|
-
|
84
|
-
@data[range][:visits_new_visits_plot] = @data[range][:new_visits].inject(Hash[@data[range][:visits]]){|a, i| a[i[0]] = [i[1], a[i[0]]];a}.map{|k,v| {'date'=> k.strftime(time_format), 'new_visits' => v[0].to_i, 'returning_visits' => v[1].to_i - v[0].to_i}}
|
85
|
-
@data[range][:visits_new_visits_donut] = [{'label' => 'Returning Visitors', 'value' => @data[range][:total_visits] - @data[range][:total_new_visits]}, {'label' => 'New Visitors', 'value' => @data[range][:total_new_visits]}]
|
86
|
-
|
87
|
-
@data[range][:browsers_donut] = self.send("#{unit}ly_ratio_browsers", time_range, :aggregate => true).map{|x| {'label' => x[0], 'value' => x[1].to_i}}
|
88
|
-
@data[range][:platforms_donut] = self.send("#{unit}ly_ratio_platforms", time_range, :aggregate => true).map{|x| {'label' => x[0], 'value' => x[1].to_i}}
|
89
|
-
@data[range][:devices_donut] = self.send("#{unit}ly_ratio_platforms", time_range, :aggregate => true).map{|x| {'label' => x[0], 'value' => x[1].to_i}}
|
90
|
-
@data[range][:referrers_donut] = self.send("#{unit}ly_ratio_referrers", time_range, :aggregate => true).map{|x| {'label' => x[0], 'value' => x[1].to_i}}
|
91
|
-
|
92
|
-
unique_visits = self.send("#{unit}ly_unique_visits", time_range - 1.send(range)).map{|x,y| [x.strftime(time_format), y]}
|
93
|
-
|
94
|
-
# puts unique_visits[0..(multiple-1)].inject(Hash[unique_visits[multiple..(multiple*2-1)]]){|a, i| a[i[0]] = [i[1], a[i[0]]];a}.inspect
|
95
|
-
@data[range][:unique_visits] = unique_visits[0..(multiple-1)].inject(Hash[unique_visits[multiple..(multiple*2-1)]]){|a, i| a[i[0]] = [i[1], a[i[0]]];a}.map{|k,v| {'unit'=> k, 'unique_visits_last' => v[0].to_i, 'unique_visits_this' => v[1].to_i}}
|
96
|
-
second_page_views = self.send("#{unit}ly_second_page_views", time_range)
|
97
|
-
@data[range][:total_second_page_views] = second_page_views.inject(0){|s, x| s += x[1].to_i; s}
|
98
|
-
|
99
|
-
visitor_recency = self.send("#{unit}ly_ratio_recency", time_range, :aggregate => true)
|
100
|
-
@data[range][:visitor_recency_slices] = [0, RedisAnalytics.visitor_recency_slices, '*'].flatten.each_cons(2).inject([]) do |h, (x, y)|
|
101
|
-
h << [[x, y], visitor_recency.select{|a, b| a.to_i >= x and (a.to_i < y or y == '*') }.map{|p, q| q}.sum]
|
102
|
-
end
|
103
|
-
@data[range][:country_map] = Hash[self.send("#{unit}ly_ratio_country", time_range, :aggregate => true)]
|
104
|
-
end
|
105
|
-
@range = @data.keys[0] unless @data[@range]
|
106
|
-
end
|
107
|
-
@data[:all_visits] = daily_visits(Time.now - 1.year).map{|x,y| [x.to_i * 1000, realistic(y)]}
|
108
|
-
@data[:all_unique_visits] = daily_unique_visits(Time.now - 1.year).map{|x,y| [x.to_i * 1000, realistic(y)]}
|
46
|
+
get '/visits/?' do
|
47
|
+
@range = time_range
|
109
48
|
erb :visits
|
110
49
|
end
|
111
|
-
|
50
|
+
|
112
51
|
end
|
113
52
|
end
|
114
53
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/lib/redis_analytics/dashboard/public/javascripts/{morris.min.js → vendor/morris.min.js}
RENAMED
File without changes
|
data/lib/redis_analytics/dashboard/public/javascripts/{raphael-min.js → vendor/raphael-min.js}
RENAMED
File without changes
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<!-- Unique Visits Modal -->
|
2
|
+
<div id="unique_visits_modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
3
|
+
<div class="modal-header">
|
4
|
+
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
5
|
+
<h3 id="myModalLabel">Daily Unique Visits</h3>
|
6
|
+
</div>
|
7
|
+
<div class="modal-body">
|
8
|
+
<div id="unique_visits_detail" style="width:900px;height:400px;"></div>
|
9
|
+
</div>
|
10
|
+
<div class="modal-footer">
|
11
|
+
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
12
|
+
<!-- <button class="btn btn-primary">Save changes</button> -->
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
|
16
|
+
<script type="text/javascript">
|
17
|
+
$('#unique_visits_modal').on('show', function () {
|
18
|
+
colors = Highcharts.getOptions().colors;
|
19
|
+
// create the chart when all data is loaded
|
20
|
+
$(function(){
|
21
|
+
$('#unique_visits_detail').highcharts('StockChart', {
|
22
|
+
chart: {
|
23
|
+
},
|
24
|
+
// tooltip: {
|
25
|
+
// pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.change}%)<br/>',
|
26
|
+
// valueDecimals: 2
|
27
|
+
// },
|
28
|
+
yAxis: {
|
29
|
+
allowDecimals: false
|
30
|
+
},
|
31
|
+
xAxis: {
|
32
|
+
allowDecimals: false
|
33
|
+
},
|
34
|
+
series: [{
|
35
|
+
name: 'Unique Visits',
|
36
|
+
data: <%=@data[:all_unique_visits].to_json%>
|
37
|
+
}]
|
38
|
+
});
|
39
|
+
});
|
40
|
+
});
|
41
|
+
</script>
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<!-- Visits Modal -->
|
2
|
+
<div id="visits_modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
3
|
+
<div class="modal-header">
|
4
|
+
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
5
|
+
<h3 id="myModalLabel">Daily Visits</h3>
|
6
|
+
</div>
|
7
|
+
<div class="modal-body">
|
8
|
+
<div id="visits_detail" style="width:900px;height:400px;"></div>
|
9
|
+
</div>
|
10
|
+
<div class="modal-footer">
|
11
|
+
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
12
|
+
<!-- <button class="btn btn-primary">Save changes</button> -->
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
|
16
|
+
<script type="text/javascript">
|
17
|
+
$('#visits_modal').on('show', function () {
|
18
|
+
colors = Highcharts.getOptions().colors;
|
19
|
+
// create the chart when all data is loaded
|
20
|
+
$(function(){
|
21
|
+
$('#visits_detail').highcharts('StockChart', {
|
22
|
+
chart: {},
|
23
|
+
// tooltip: {
|
24
|
+
// pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.change}%)<br/>',
|
25
|
+
// valueDecimals: 2
|
26
|
+
// },
|
27
|
+
yAxis: {
|
28
|
+
allowDecimals: false
|
29
|
+
},
|
30
|
+
xAxis: {
|
31
|
+
allowDecimals: false
|
32
|
+
},
|
33
|
+
series: [{
|
34
|
+
name: 'Visits',
|
35
|
+
data: <%=@data[:all_visits].to_json%>
|
36
|
+
}]
|
37
|
+
});
|
38
|
+
});
|
39
|
+
});
|
40
|
+
</script>
|
@@ -1,44 +1,19 @@
|
|
1
1
|
<!-- start header -->
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
<li><a href="?template=united">United</a></li>
|
18
|
-
<li class="divider"></li>
|
19
|
-
<li><a href="?">Default</a></li>
|
20
|
-
</ul>
|
21
|
-
</li>
|
22
|
-
<li><a href="#">Preferences</a></li>
|
23
|
-
<li class="divider"></li>
|
24
|
-
<li><a href="#">About</a></li>
|
25
|
-
</ul>
|
26
|
-
</div>
|
27
|
-
|
28
|
-
<div class="btn-group" data-toggle="buttons-radio">
|
29
|
-
<!-- <a href="/visits" class="btn btn-small<%#' active' if request.path == '/visits'%>">Visits</a> -->
|
30
|
-
<!-- <a href="/activity" class="btn btn-small<%=' active' if request.path == '/activity'%>">Activity</a> -->
|
31
|
-
|
32
|
-
<!-- <button type="button" class="btn btn-small" onclick='javascript:visits_area.grid=true'>Transactions</button> -->
|
33
|
-
</div>
|
34
|
-
<div class="btn-group" data-toggle="buttons-radio">
|
35
|
-
<% Rack::RedisAnalytics.time_range_formats.map{|x| x[0]}.each do |range| %>
|
36
|
-
<button type="button" class="btn btn-small <%="active" if @range == range%>" onclick='changeTimeFrame("<%=range.to_s%>")'><%=range.to_s%></button>
|
37
|
-
<% end %>
|
38
|
-
</div>
|
39
|
-
|
40
|
-
</li>
|
41
|
-
</ul>
|
42
|
-
</div>
|
2
|
+
<div class="navbar">
|
3
|
+
<div class="navbar-inner">
|
4
|
+
<a class="brand" href="http://www.github.com/saturnine/redis_analytics">Redis Analytics</a>
|
5
|
+
<ul class="nav nav-pills pull-right">
|
6
|
+
<li>
|
7
|
+
<div class="btn-group" data-toggle="buttons-radio">
|
8
|
+
<a href="visits" class="btn btn-small <%=' active' if request.path.end_with?('/visits') %>">Visits</a>
|
9
|
+
</div>
|
10
|
+
<div class="btn-group" data-toggle="buttons-radio" id="timeRange">
|
11
|
+
<% Rack::RedisAnalytics.time_range_formats.map{|x| x[0]}.each do |range| %>
|
12
|
+
<button type="button" class="btn btn-small <%="active" if @range == range%>" onclick='changeTimeFrame("<%=range.to_s%>")'><%=range.to_s%></button>
|
13
|
+
<% end %>
|
14
|
+
</div>
|
15
|
+
</li>
|
16
|
+
</ul>
|
43
17
|
</div>
|
44
|
-
|
18
|
+
</div>
|
19
|
+
<!-- end header -->
|