chart-candy 0.0.7

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.
Files changed (34) hide show
  1. data/Gemfile +4 -0
  2. data/LICENSE +7 -0
  3. data/README.md +109 -0
  4. data/Rakefile +11 -0
  5. data/app/assets/javascripts/chart_candy/base.coffee +16 -0
  6. data/app/assets/javascripts/chart_candy/counter.coffee +50 -0
  7. data/app/assets/javascripts/chart_candy/donut.coffee +162 -0
  8. data/app/assets/javascripts/chart_candy/index.js +4 -0
  9. data/app/assets/javascripts/chart_candy/line.coffee +338 -0
  10. data/app/assets/stylesheets/chart_candy/base.css.scss +66 -0
  11. data/app/assets/stylesheets/chart_candy/counter.css.scss +11 -0
  12. data/app/assets/stylesheets/chart_candy/donut.css.scss +34 -0
  13. data/app/assets/stylesheets/chart_candy/index.css +6 -0
  14. data/app/assets/stylesheets/chart_candy/line.css.scss +107 -0
  15. data/app/controllers/candy_charts_controller.rb +60 -0
  16. data/config/locales/fr.yml +36 -0
  17. data/config/routes.rb +3 -0
  18. data/lib/chart-candy.rb +23 -0
  19. data/lib/chart-candy/authentication.rb +45 -0
  20. data/lib/chart-candy/base_chart.rb +11 -0
  21. data/lib/chart-candy/builder.rb +46 -0
  22. data/lib/chart-candy/builder/base.rb +70 -0
  23. data/lib/chart-candy/builder/counter.rb +12 -0
  24. data/lib/chart-candy/builder/donut.rb +73 -0
  25. data/lib/chart-candy/builder/line.rb +114 -0
  26. data/lib/chart-candy/builder/xls_builder.rb +159 -0
  27. data/lib/chart-candy/engine.rb +5 -0
  28. data/lib/chart-candy/helpers.rb +169 -0
  29. data/lib/chart-candy/implants.rb +10 -0
  30. data/lib/chart-candy/implants/railtie.rb +17 -0
  31. data/spec/chart-candy_spec.rb +11 -0
  32. data/spec/spec_helper.rb +12 -0
  33. data/vendor/assets/javascripts/d3.js +4 -0
  34. metadata +118 -0
@@ -0,0 +1,66 @@
1
+ div.wrapper-chart{font-family:"Lucida Grande", Arial;float:left;margin:0px 0px 40px 0px;width:100%;
2
+ h2{clear:both;float:left;font-size:24px;margin:0px 0px 20px 0px;width:100%;}
3
+ h2 span.subtitle{clear:both;color:#777;display:block;font-size:16px;}
4
+
5
+ div.tools{border:1px solid #dadada;border-bottom:1px solid #ccc;border-top-left-radius:8px;border-top-right-radius:8px;clear:both;float:left;height:50px;margin:0px 0px -1px 0px;padding:0px;width:100%;
6
+ background: #ececec;
7
+ background: linear-gradient(top, #F2F2F2, #ececec);
8
+ background: -moz-linear-gradient(top, #F2F2F2, #ececec);
9
+ background: -webkit-linear-gradient(top, #F2F2F2, #ececec);
10
+
11
+ select{margin:5px 0px 0px 0px;}
12
+
13
+ div.tool{float:left;margin:10px 30px 0px 0px;}
14
+
15
+ div.holder-template{margin-left:30px;
16
+ ul.items{margin:0px;
17
+ li{padding:0px;}
18
+ li span.text{background-image:image-url("application/icon-charts.png");display:block;text-indent:-9999px;height:15px;margin:0px 15px;padding-left:0px;padding-right:0px;width:20px;}
19
+ li.table span.text{background-position:-100px 5px;}
20
+ li.selected.table span.text{background-position:-100px -45px;}
21
+ }
22
+ }
23
+
24
+ div.holder-export-xls{float:right;
25
+ a{background:#fafafa;border:1px solid #ddd;border-radius:4px;color:#555;display:block;font-size:11px;margin:0px 0px 0px 0px;padding:7px 15px;text-decoration:none;text-indent:0px;}
26
+ a:hover{background:#fff;color:#222;}
27
+ }
28
+ }
29
+
30
+ div.templates{width:100%;}
31
+
32
+ div.table{clear:both;display:none;float:left;margin:0px 0px 0px 0px;overflow:hidden;width:100%;
33
+ table{border-collapse:collapse;border-spacing:0;border:none;border-left:1px solid #ddd;border-right:1px solid #ddd;clear:both;float:left;margin:0px;padding:0px;width:100%;
34
+ thead{
35
+ tr{
36
+ th{border:none;border-left:1px solid #dddddd;border-bottom:1px solid #d1d1d1;border-top:1px solid #e1e1e1;box-shadow:inset 0 1px 0 0 #fff;color:#000;cursor:default;font-family:'Lucida Grande', Helvetica, Arial, sans-serif;font-weight:bold;font-size:13px;height:auto;padding:10px 20px 10px 20px;
37
+ background: #ececec;
38
+ background: linear-gradient(top, #F2F2F2, #ececec);
39
+ background: -moz-linear-gradient(top, #F2F2F2, #ececec);
40
+ background: -webkit-linear-gradient(top, #F2F2F2, #ececec);
41
+ }
42
+ th:first-child{border-left:none;padding-left:30px;}
43
+ th:last-child{padding-right:30px;}
44
+ }
45
+
46
+ }
47
+ tbody{
48
+ tr{
49
+ td{border-bottom:1px solid #ddd;border-left:none;border-right:none;color:#555;font-size:12px;margin:0px;padding:10px 20px 10px 20px;}
50
+ td.number{text-align:right;}
51
+ td:first-child{padding-left:30px;}
52
+ td:last-child{padding-right:30px;}
53
+ }
54
+ tr:hover td{background-color:#fafafa;}
55
+ }
56
+ tfoot{
57
+ tr{
58
+ td{background-color:#F6F6F6;border-bottom:1px solid #ddd;color:#000;font-size:13px;font-weight:bold;padding:10px 20px;}
59
+ td.number{text-align:right;}
60
+ td:first-child{padding-left:30px;}
61
+ td:last-child{padding-right:30px;}
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }
@@ -0,0 +1,11 @@
1
+ div.chart-counter{border:1px solid #ddd;border-radius:8px;padding:10px 0px;width:150px;
2
+ background: #fff;
3
+ background: linear-gradient(top, #fff, #f5f5f5);
4
+ background: -moz-linear-gradient(top, #fff, #f5f5f5);
5
+ background: -webkit-linear-gradient(top, #fff, #f5f5f5);
6
+
7
+ h2{display:none;}
8
+ span{display:block;text-align:center;width:100%;}
9
+ span.label.primary{color:#999;font-size:11px;margin:0px 0px 3px 0px;}
10
+ span.value.primary{color:#000;font-family:Arial;font-size:36px;font-weight:bold;}
11
+ }
@@ -0,0 +1,34 @@
1
+ div.chart-donut{clear:none;float:left;margin-left:30px;width:450px;
2
+ div.tools{background:none;border:none;margin:0px;
3
+ div.holder-template {margin-left:0px;
4
+ ul.items{
5
+ li.chart span.text{background-position:0px 5px;}
6
+ li.selected.chart span.text{background-position:0px -45px;}
7
+ }
8
+ }
9
+ div.holder-export-xls{margin-right:0px;}
10
+ }
11
+
12
+ div.templates{float:left;
13
+ div.chart{display:block;height:340px;padding:20px 80px 0px 80px;width:450px;
14
+ svg{
15
+ path.slice-1{fill:#10c7df;}
16
+ path.slice-2{fill:#ffcc00;}
17
+ path.slice-3{fill:#c1e443;}
18
+ path.slice-4{fill:#fd41cd;}
19
+ path.slice-5{fill:#11aec6;}
20
+ path.slice-6{fill:#e09200;}
21
+ path.slice-7{fill:#84d200;}
22
+ path.slice-8{fill:#f2a1e7;}
23
+
24
+ text{cursor:default;}
25
+ .hole{
26
+ .label{fill:#000;font-size:14px;font-weight:bold;}
27
+ .text0{fill:#999;font-size:12px;text-transform:uppercase;}
28
+ }
29
+ }
30
+
31
+ div.tooltip{background-color:#fff;border:1px solid #ddd;border-radius:8;box-shadow:0px 5px 6px -6px #333;color:#000;display:none;height:auto;padding:10px 20px;position:absolute;visibility:visible;width:auto;z-index:100;}
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,6 @@
1
+ /*
2
+ *= require ./base
3
+ *= require ./counter
4
+ *= require ./donut
5
+ *= require ./line
6
+ */
@@ -0,0 +1,107 @@
1
+ div.chart-line{clear:both;float:left;width:100%;
2
+
3
+ div.tools{margin-left:60px;width:979px;
4
+ div.holder-step{float:right;margin-right:30px;
5
+ div.select-field div.current span.text{width:120px;}
6
+ }
7
+
8
+ div.holder-template ul.items{
9
+ li.chart span.text{background-position:-50px 5px;}
10
+ li.selected.chart span.text{background-position:-50px -45px;}
11
+ }
12
+ }
13
+
14
+ div.templates{
15
+ div.table{margin-left:60px;width:981px;}
16
+
17
+ div.chart{clear:both;height:350px;margin-top:-5px;padding:0px 60px 40px 60px;width:1100px;
18
+ svg{overflow:visible;height:100%;width:100%;
19
+ rect.bg{ fill:#fff; }
20
+
21
+ g.tooltip{
22
+ rect{border-radius:1em;fill:#fff;stroke:#ccc;}
23
+ text{cursor:default;fill:#555;font-family:'Arial';
24
+ tspan.x{font-size:1em;fill:#777;}
25
+ tspan.y{font-size:1em;fill:#333;}
26
+ }
27
+ }
28
+
29
+ path{fill:none;}
30
+
31
+ g.axis {shape-rendering:crispEdges;
32
+ line {stroke:#f1f1f1;}
33
+ .minor {stroke-opacity:.3;}
34
+ path {stroke:#e1e1e1;}
35
+ }
36
+
37
+ g.pointer{opacity:0;
38
+ circle{fill:#fff;stroke-width:2;}
39
+ }
40
+ g.pointer-1 circle{stroke:#10c7df;}
41
+ g.pointer-2 circle{stroke:#ffcc00;}
42
+ g.pointer-3 circle{stroke:#c1e443;}
43
+ g.pointer-4 circle{stroke:#fd41cd;}
44
+ g.pointer-5 circle{stroke:#11aec6;}
45
+ g.pointer-6 circle{stroke:#e09200;}
46
+ g.pointer-7 circle{stroke:#84d200;}
47
+ g.pointer-8 circle{stroke:#f2a1e7;}
48
+ g.pointer.disabled{opacity:0;}
49
+
50
+
51
+ g.line{display:block;width:100%;height:100%;
52
+ path.stroke{stroke-opacity:1;stroke-width:2;}
53
+ path.area{fill:none;fill-opacity:.3;}
54
+ }
55
+
56
+ g.line-1{
57
+ path.stroke{stroke:#10c7df;}
58
+ path.area{fill:#c7ffff;}
59
+ }
60
+ g.line-2 path.stroke{stroke:#ffcc00;}
61
+ g.line-3 path.stroke{stroke:#c1e443;}
62
+ g.line-4 path.stroke{stroke:#fd41cd;}
63
+ g.line-5 path.stroke{stroke:#11aec6;}
64
+ g.line-6 path.stroke{stroke:#e09200;}
65
+ g.line-7 path.stroke{stroke:#84d200;}
66
+ g.line-8 path.stroke{stroke:#f2a1e7;}
67
+
68
+ g.line.selected{
69
+ path.stroke{stroke-width:3;}
70
+ path.area{fill-opacity:.5;}
71
+ }
72
+
73
+ g.line.hidden{
74
+ path.stroke{stroke:#f00;}
75
+ }
76
+
77
+
78
+ g.legend{
79
+ rect{fill:#fafafa;fill-opacity:.6;}
80
+
81
+ g.item{cursor:pointer;
82
+ text{fill:#555;}
83
+ line{stroke-width:3;}
84
+ }
85
+ g.item:hover{
86
+ text{fill:#000;}
87
+ line{stroke-width:4;}
88
+ }
89
+ g.item.item-1 line{stroke:#10c7df;}
90
+ g.item.item-2 line{stroke:#ffcc00;}
91
+ g.item.item-3 line{stroke:#c1e443;}
92
+ g.item.item-4 line{stroke:#fd41cd;}
93
+ g.item.item-5 line{stroke:#11aec6;}
94
+ g.item.item-6 line{stroke:#e09200;}
95
+ g.item.item-7 line{stroke:#84d200;}
96
+ g.item.item-8 line{stroke:#f2a1e7;}
97
+
98
+ g.item.disabled{
99
+ text{fill:#999;}
100
+ line{stroke-opacity:0.1;}
101
+ }
102
+ }
103
+ }
104
+ }
105
+ }
106
+
107
+ }
@@ -0,0 +1,60 @@
1
+ #*************************************************************************************
2
+ # TOCOMMENT
3
+ #*************************************************************************************
4
+ class CandyChartsController < ApplicationController
5
+ before_filter :authenticate
6
+
7
+ def show
8
+ if @granted
9
+ set_default_to if params[:from] and not params[:to]
10
+
11
+ name = (params[:id].gsub('-', '_').camelize + 'Chart')
12
+
13
+ begin
14
+ chart = name.constantize.new(params)
15
+ rescue
16
+ raise "Chart Candy: You must defined #{name}"
17
+ end
18
+
19
+ builder = "ChartCandy::Builder::#{params[:nature].camelize}".constantize.new(params[:id], params)
20
+
21
+ chart.build builder
22
+
23
+ respond_to do |format|
24
+ format.json { render json: builder.to_json }
25
+ format.xls { render_xls builder }
26
+ end
27
+ else
28
+ respond_to do |format|
29
+ format.json { render json: { 'state' => 'access_refused' } }
30
+ format.xls { render text: 'access_refused' }
31
+ end
32
+ end
33
+ end
34
+
35
+ def render_xls(builder)
36
+ spreadsheet = StringIO.new
37
+ builder.to_xls.write spreadsheet
38
+
39
+ send_data spreadsheet.string, filename: builder.filename, type: "application/vnd.ms-excel"
40
+ end
41
+
42
+ def authenticate
43
+ auth = ChartCandy::Authentication.new(request.url, params)
44
+
45
+ @granted = (auth.valid_token? and not auth.expired?)
46
+ end
47
+
48
+ def set_default_to
49
+ if params[:nature] == 'line'
50
+ params[:to] = case params[:step]
51
+ when 'day' then (Time.now.utc - 1.day).end_of_day.iso8601
52
+ when 'week' then (Time.now.utc - 1.week).end_of_week.iso8601
53
+ when 'month' then (Time.now.utc - 1.month).end_of_month.iso8601
54
+ else Time.now.utc.iso8601
55
+ end
56
+ else
57
+ params[:to] = Time.now.utc.iso8601
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,36 @@
1
+ fr:
2
+ date:
3
+ abbr_day_names: [lun, mar, mer, jeu, ven, sam, dim]
4
+ day_names: [dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi]
5
+ abbr_month_names: [~, jan, fév, mar, avr, mai, jun, jul, aoû, sep, oct, nov, déc]
6
+ month_names: [~, janvier, février, mars, avril, mai, juin, juillet, août, septembre, octobre, novembre, décembre]
7
+
8
+ chart_candy:
9
+ base:
10
+ steps:
11
+ day: Quotidien
12
+ week: Hebdomadaire
13
+ month: Mensuel
14
+
15
+ template:
16
+ table: Tableau
17
+ chart: Diagramme
18
+
19
+ xls_export: "Exporter en Excel"
20
+
21
+ date:
22
+ period:
23
+ label: Période du
24
+ label_month: Période de
25
+ to: au
26
+ to_month: à
27
+ week: "Semaine du"
28
+
29
+ time:
30
+ formats:
31
+ chart_candy_date_without_day: "%B %Y"
32
+ chart_candy_date_long: "%e %B %Y"
33
+ chart_candy_date_long_without_year: "%e %B"
34
+ chart_candy_day: "%e"
35
+ chart_candy_long: "%e %B %Y à %H:%M"
36
+ chart_candy_year: "%Y"
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ Rails.application.routes.draw do
2
+ resources :candy_charts, only: [:index, :show], controller: "candy_charts"
3
+ end
@@ -0,0 +1,23 @@
1
+ module ChartCandy
2
+ def self.localize(path, options={})
3
+ options.reverse_merge! format: :date_long
4
+
5
+ options[:format] = "chart_candy_#{options[:format]}".to_sym
6
+
7
+ return I18n.localize(path, options)
8
+ end
9
+
10
+ def self.translate(path, options={})
11
+ I18n.translate("chart_candy.#{path}", options)
12
+ end
13
+
14
+ def self.t(path, options={})
15
+ self.translate path, options
16
+ end
17
+ end
18
+
19
+ require "chart-candy/authentication"
20
+ require "chart-candy/base_chart"
21
+ require "chart-candy/builder"
22
+ require "chart-candy/engine"
23
+ require 'chart-candy/implants'
@@ -0,0 +1,45 @@
1
+ module ChartCandy
2
+ class Authentication
3
+ def self.compact_params(original_params)
4
+ compacted_params = ''
5
+
6
+ original_params.each { |k,v| compacted_params << (k.to_s + v.to_s) if not self.reserved_params.include?(k.to_s) }
7
+
8
+ return compacted_params
9
+ end
10
+
11
+ def self.reserved_params
12
+ ['action', 'class', 'controller', 'format', 'from', 'nature', 'step', 'to', 'token', 'tools', 'update_every', 'version']
13
+ end
14
+
15
+ def self.tokenize(str)
16
+ Digest::HMAC.hexdigest(str.chars.sort.join.gsub('/', ''), Rails.configuration.secret_token, Digest::SHA1)
17
+ #HMAC::SHA1.hexdigest(Rails.configuration.secret_token, str.chars.sort.join.gsub('/', ''))
18
+ end
19
+
20
+ def initialize(request_url, params={})
21
+ @request_url = request_url
22
+ @params = params
23
+ end
24
+
25
+ def expired?
26
+ @params[:timestamp] and Time.parse(@params[:timestamp]) + 12.hours < Time.now
27
+ end
28
+
29
+ def valid_token?
30
+ @params[:token] == tokenize(filter_url)
31
+ end
32
+
33
+ private
34
+
35
+ def filter_url
36
+ filtered_url = @request_url.split('?').first.rpartition('/').first
37
+
38
+ return filtered_url + ChartCandy::Authentication.compact_params(@params)
39
+ end
40
+
41
+ def tokenize(str)
42
+ ChartCandy::Authentication.tokenize(str)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,11 @@
1
+ module ChartCandy
2
+ class BaseChart
3
+ def initialize(params)
4
+ @params = params
5
+
6
+ @from = params[:from] ? Time.parse(params[:from]) : nil
7
+ @to = params[:to] ? Time.parse(params[:to]) : Time.now
8
+ @step = params[:step] || 'month'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,46 @@
1
+ module ChartCandy::Builder
2
+ def self.period(start_at, end_at, options={})
3
+ options.reverse_merge!(step: 'day')
4
+
5
+ start_at_format = case
6
+ when options[:step] == 'month' then :date_without_day
7
+ when options[:step] == 'year' then :year
8
+ when start_at.year != end_at.year then :date_long
9
+ when start_at.month != end_at.month then :date_long_without_year
10
+ else :day
11
+ end
12
+
13
+ end_at_format = case options[:step]
14
+ when 'month' then :date_without_day
15
+ when 'year' then :year
16
+ else :date_long
17
+ end
18
+
19
+ content = []
20
+ content << ChartCandy.localize(start_at, format: start_at_format)
21
+ content << (['month', 'year'].include?(options[:step]) ? ChartCandy.t('date.period.to_month') : ChartCandy.t('date.period.to'))
22
+ content << ChartCandy.localize(end_at, format: end_at_format)
23
+
24
+ content[0].capitalize!
25
+
26
+ return content.join(' ')
27
+ end
28
+
29
+ def self.get_step_from_interval(interval)
30
+ days = (interval / (3600 * 24)).to_i.abs
31
+
32
+ return case days
33
+ when 0..5 then 'day'
34
+ when 6..27 then 'week'
35
+ when 28..88 then 'month'
36
+ when 89..363 then 'quarter'
37
+ else 'year'
38
+ end
39
+ end
40
+ end
41
+
42
+ require 'chart-candy/builder/base.rb'
43
+ require 'chart-candy/builder/counter.rb'
44
+ require 'chart-candy/builder/donut.rb'
45
+ require 'chart-candy/builder/line.rb'
46
+ require 'chart-candy/builder/xls_builder.rb'