hawk-eye 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +1 -0
  3. data/README.md +2 -0
  4. data/Rakefile +26 -0
  5. data/app/assets/javascripts/hawk-eye.js.coffee +2 -0
  6. data/app/assets/javascripts/hawk-eye/base.js.coffee +17 -0
  7. data/app/assets/javascripts/hawk-eye/date-bin-variable.js.coffee +256 -0
  8. data/app/assets/javascripts/hawk-eye/test.js.coffee +256 -0
  9. data/app/assets/stylesheets/hawk-eye/graphs/_variable_bin.sass +18 -0
  10. data/app/assets/stylesheets/hawk-eye/hawk-eye.sass +2 -0
  11. data/app/assets/stylesheets/hawk-eye/test.sass +40 -0
  12. data/app/assets/stylesheets/hawk_eye/application.css +15 -0
  13. data/app/controllers/hawk_eye/application_controller.rb +14 -0
  14. data/app/helpers/hawk_eye/application_helper.rb +4 -0
  15. data/app/services/hawk_eye/graph/date_bin_helpers.rb +7 -0
  16. data/app/services/hawk_eye/graph/date_bin_variable.rb +89 -0
  17. data/app/views/hawk_eye/application/home.html.slim +15 -0
  18. data/app/views/layouts/hawk_eye/application.html.erb +14 -0
  19. data/config/routes.rb +3 -0
  20. data/lib/hawk-eye.rb +1 -0
  21. data/lib/hawk_eye.rb +7 -0
  22. data/lib/hawk_eye/engine.rb +5 -0
  23. data/lib/hawk_eye/version.rb +3 -0
  24. data/lib/tasks/hawk_eye_tasks.rake +4 -0
  25. data/spec/dummy/README.rdoc +28 -0
  26. data/spec/dummy/Rakefile +6 -0
  27. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  28. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  29. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  30. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  31. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  32. data/spec/dummy/bin/bundle +3 -0
  33. data/spec/dummy/bin/rails +4 -0
  34. data/spec/dummy/bin/rake +4 -0
  35. data/spec/dummy/bin/setup +29 -0
  36. data/spec/dummy/config.ru +4 -0
  37. data/spec/dummy/config/application.rb +32 -0
  38. data/spec/dummy/config/boot.rb +5 -0
  39. data/spec/dummy/config/database.yml +25 -0
  40. data/spec/dummy/config/environment.rb +5 -0
  41. data/spec/dummy/config/environments/development.rb +41 -0
  42. data/spec/dummy/config/environments/production.rb +79 -0
  43. data/spec/dummy/config/environments/test.rb +42 -0
  44. data/spec/dummy/config/initializers/assets.rb +11 -0
  45. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  46. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  47. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  48. data/spec/dummy/config/initializers/inflections.rb +16 -0
  49. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  50. data/spec/dummy/config/initializers/session_store.rb +3 -0
  51. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  52. data/spec/dummy/config/locales/en.yml +23 -0
  53. data/spec/dummy/config/routes.rb +4 -0
  54. data/spec/dummy/config/secrets.yml +22 -0
  55. data/spec/dummy/public/404.html +67 -0
  56. data/spec/dummy/public/422.html +67 -0
  57. data/spec/dummy/public/500.html +66 -0
  58. data/spec/dummy/public/favicon.ico +0 -0
  59. metadata +247 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 21679c4d16ca79235bea0cbffd1234c722788621
4
+ data.tar.gz: d3ffe869b2b75ffc64177a6057178dedb25dcb92
5
+ SHA512:
6
+ metadata.gz: e6f4abe501fc7bd1fc742a9f2443b742e37e749cbe44a6e62aa03dd20edb5bac3466974405957cf309e2d87ae8f84a1075a2c04379dabb64e9b25f24cc3eb7cd
7
+ data.tar.gz: b8eba4492c36cee2054e9ab1576767775d8478c395eb147a3910b497ca4bf39c0a9cd31037a1a1b580c377460b8d871f3bc67f44fa1dca7eddd69d6f2f460a99
data/LICENSE ADDED
@@ -0,0 +1 @@
1
+ Copyright 2016 Companytools
@@ -0,0 +1,2 @@
1
+ HawkEye
2
+ ========================================
@@ -0,0 +1,26 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'HawkEye'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ Bundler::GemHelper.install_tasks
26
+
@@ -0,0 +1,2 @@
1
+ #= require ./hawk-eye/base
2
+ #= require_directory ./hawk-eye
@@ -0,0 +1,17 @@
1
+ class HawkEye
2
+ constructor: ->
3
+ @setup_callbacks = {}
4
+
5
+ setup: (target = $(document))->
6
+ for setup_label, callbacks_of_label of @setup_callbacks
7
+ callbacks_of_label.forEach (callback)=>
8
+ callback.call(@, target)
9
+
10
+ register_setup: (label_or_callback, labelled_callback)->
11
+ unless labelled_callback?
12
+ labelled_callback = label_or_callback
13
+ label_or_callback = 'anonymous'
14
+ (@setup_callbacks[label_or_callback] ||= []).push labelled_callback
15
+
16
+ @HawkEye = new HawkEye()
17
+ Dunlop.register_setup 'hawk-eye', (target) => @HawkEye.setup(target)
@@ -0,0 +1,256 @@
1
+ class DateBinVariable
2
+ constructor: ->
3
+ @config = {}
4
+ configure: (config)->
5
+ @config = config
6
+ @setup()
7
+ setup: (data)->
8
+ @data = data if data
9
+ return unless @data
10
+ #window.data = data
11
+ @has_no_date = !!data.payload['no_date']
12
+ @container = $(data.target).html('')
13
+ @min_date = moment(@data.min_date)
14
+ @max_date = moment(@data.max_date)
15
+ @bin_type = data.bin_type
16
+ @date_key_format = "YYYY-MM-DD"
17
+ @active_facets = []
18
+
19
+ @generate_bar_chart()
20
+ @generate_facet_charts()
21
+
22
+
23
+ generate_bar_chart: ->
24
+ @bar_chart_container = $('<div></div>').addClass('bar-chart').appendTo(@container)
25
+ @set_bar_chart_keys()
26
+ columns = []
27
+ for variable in @data.variables
28
+ columns.push @get_variable_column(variable)
29
+ columns.unshift @bar_chart_ticks()
30
+
31
+ # Activating focus date helpers
32
+ number_of_ticks = columns[0].length - 1
33
+ number_of_variables = @data.variables.length
34
+
35
+ @bar_chart = c3.generate
36
+ bindto: @bar_chart_container.get(0)
37
+ data:
38
+ x: 'x'
39
+ columns: columns
40
+ type: 'bar'
41
+ #onmouseover: (d) => @recalculate_facets(date: d.x, variable: d.id)
42
+ #onmouseout: => @recalculate_facets()
43
+ onclick: (d, path)=>
44
+ return if @active_facets.length
45
+ `var graph=this`
46
+ color_def = {}
47
+ date_key = @bar_chart_keys[d.index]
48
+
49
+ if @focus_date is date_key
50
+ @focus_date = null
51
+ graph.data.colors @original_bar_chart_colors
52
+ else
53
+ #color_def[d.id] = "#aaaaaa"
54
+ for var_name in Object.keys(graph.data.colors())
55
+ color_def[var_name] = "#aaaaaa"
56
+
57
+ graph.data.colors(color_def)
58
+ # ugly solution to manually color the svg paths another color after render
59
+ delay 500, ->
60
+ bar_paths = $(graph.element).find('path.c3-bar')
61
+ for ivar in [0...number_of_variables]
62
+ bar_paths.get(d.x + ivar*number_of_ticks).style.fill = "rgb(200,100,100)"
63
+ @focus_date = date_key
64
+ @recalculate_facets(date: @focus_date)
65
+ axis:
66
+ x:
67
+ type: 'category'
68
+ @original_bar_chart_colors = $.extend({}, @bar_chart.data.colors())
69
+
70
+ reload_bar_chart: ->
71
+ columns = []
72
+ for variable in @data.variables
73
+ columns.push @get_variable_column(variable)
74
+ #columns.unshift @bar_chart_ticks()
75
+ @bar_chart.load
76
+ columns: columns
77
+
78
+ recalculate_facets: (options = {})->
79
+ for variable in @data.variables
80
+ #continue if options.variable and (options.variable is variable.name or options.variable is variable.label)
81
+ for facet, facet_index in @data.facets
82
+ facet_columns = []
83
+ for facet_value in facet.values
84
+ facet_total = @get_facet_total(variable.name, facet_index, facet_value, options)
85
+ facet_columns.push [facet_value, facet_total]
86
+ @facets[variable.name][facet.name].chart.load(columns: facet_columns)
87
+ @set_facet_legend_rows @facets[variable.name][facet.name].container.find('tbody'), facet_columns
88
+
89
+ generate_facet_charts: ->
90
+ @facets = {}
91
+ for variable in @data.variables
92
+ @facets[variable.name] = {}
93
+ for facet, facet_index in @data.facets
94
+ facet_container = $('<div></div>').addClass('facet-container').addClass(facet.name).data('variable', variable.name).data('facet', facet.name).appendTo(@container)
95
+ facet_graph_container = $('<div></div>').addClass('facet-graph').addClass(facet.name).appendTo(facet_container)
96
+ facet_legend = $("<div><table><thead><tr><th colspan='99'>#{facet.label}</th></tr></thead><tbody></tbody></table></div>").addClass('facet-legend').addClass(facet.name).addClass(variable.name).appendTo(facet_container)
97
+ facet_legend_body = facet_legend.find('tbody')
98
+ facet_container.append()
99
+ @facets[variable.name][facet.name] = {container: facet_container, index: facet_index}
100
+ facet_columns = []
101
+ for facet_value in facet.values
102
+ facet_columns.push [facet_value, @get_facet_total(variable.name, facet_index, facet_value)]
103
+ @set_facet_legend_rows(facet_legend_body, facet_columns)
104
+ do (variable, facet, facet_index) => # lock iteration closure
105
+ graph_settings =
106
+ bindto: facet_graph_container.get(0)
107
+ data:
108
+ columns: facet_columns
109
+ type: 'pie'
110
+ onclick: (d)=>
111
+ return if @focus_date
112
+ @set_active_facet variable, facet, d.id
113
+ true
114
+ pie:
115
+ label:
116
+ format: (value, ratio, id) -> value
117
+ legend:
118
+ item:
119
+ onclick: (facet_value)=>
120
+ @set_active_facet(variable, facet, facet_value)
121
+ true
122
+ #format: (value, ratio, id) -> "#{value} #{d3.format('%')(ratio)}"
123
+ if colors = @config.facet?.colors?[facet.name]
124
+ graph_settings.data.colors = colors
125
+ @facets[variable.name][facet.name].chart = c3.generate graph_settings
126
+
127
+ set_active_facet: (variable, facet, facet_value) ->
128
+ facet_css_class = facet.name
129
+ $(".facet-container.#{facet_css_class} .facet-legend tr").removeClass('facet-active')
130
+ $(".facet-container.#{facet_css_class} .c3-chart-arc").removeClass("facet-active").removeClass("facet-inactive")
131
+ facet_already_active = false
132
+ for active_facet in @active_facets
133
+ if active_facet.name is facet.name
134
+ facet_already_active = true
135
+ if active_facet.values[0] is facet_value # second click on same face value removes the facet lock
136
+ @active_facets = @active_facets.filter( (active_facet) -> active_facet.name isnt facet.name )
137
+ else # other facet value is chosen
138
+ active_facet.values = [facet_value]
139
+ $(".facet-container.#{facet_css_class} .facet-legend tr.legend-var-#{facet_value.dasherize()}").addClass('facet-active')
140
+ $(".facet-container.#{facet_css_class} .c3-chart-arc").addClass('facet-inactive')
141
+ $(".facet-container.#{facet_css_class} .c3-chart-arc.c3-target-#{facet_value.dasherize()}").removeClass("facet-inactive").addClass('facet-active')
142
+ else
143
+ # limit other facets
144
+ unless facet_already_active
145
+ @active_facets.push
146
+ name: facet.name
147
+ label: facet.label
148
+ values: [facet_value]
149
+ variable: variable.name
150
+ index: @facets[variable.name][facet.name].index
151
+ $(".facet-container.#{facet_css_class} .c3-chart-arc").addClass('facet-inactive')
152
+ $(".facet-container.#{facet_css_class} .c3-chart-arc.c3-target-#{facet_value.dasherize()}").removeClass("facet-inactive").addClass('facet-active')
153
+ $(".facet-container.#{facet_css_class} .facet-legend tr.legend-var-#{facet_value.dasherize()}").addClass('facet-active')
154
+ @reload_bar_chart()
155
+
156
+ set_facet_legend_rows: (tbody, rows)->
157
+ total = rows.reduce( ((t, r)-> t + r[1]), 0)
158
+ tbody.html('')
159
+ for row in rows
160
+ html_row = $('<tr></tr>').addClass("legend-var-#{String(row[0]).dasherize()}")
161
+ html_row.append $('<td></td>').text row[0]
162
+ html_row.append $('<td></td>').text row[1]
163
+ html_row.append $('<td></td>').text d3.format('%')(row[1]/total)
164
+ tbody.append html_row
165
+ tbody
166
+
167
+ get_facet_total: (variable, facet_index, facet_value, options = {})->
168
+ return @get_facet_total_for_date(options.date, variable, facet_index, facet_value) if options.date
169
+ total = 0
170
+ for date, results of @data.payload
171
+ total += @get_facet_total_for_date(date, variable, facet_index, facet_value, results)
172
+ total
173
+
174
+ get_facet_total_for_date: (date, variable, facet_index, facet_value, results)->
175
+ results ||= @data.payload[date]
176
+ results ||= []
177
+ total = 0
178
+ for result in results
179
+ total += result[variable] if result[variable] and result.facets[facet_index] is facet_value
180
+ total
181
+
182
+ get_variable_column: (variable)->
183
+ ary = [variable.label]
184
+ for bar_chart_key in @bar_chart_keys
185
+ ary.push @get_variable_total(variable.name, bar_chart_key)
186
+ ary
187
+
188
+ set_bar_chart_keys: ->
189
+ @bar_chart_keys = []
190
+ if @has_no_date
191
+ @bar_chart_keys.push 'no_date'
192
+ date_key = @min_date.format(@date_key_format)
193
+ @bar_chart_keys.push date_key
194
+ next_date = moment(@min_date).add(1, @bin_type)
195
+ while next_date <= @max_date
196
+ date_key = next_date.format(@date_key_format)
197
+ @bar_chart_keys.push date_key
198
+ next_date.add 1, @bin_type
199
+ @bar_chart_keys
200
+
201
+ get_variable_total: (variable, num)->
202
+ return 0 unless result_parts = @data.payload[num]
203
+ if @active_facets.length
204
+ total = 0
205
+ for result_part in result_parts
206
+ # do not add the value to the total if the facet value is not present in the result part
207
+ should_be_added_to_total = true
208
+ for active_facet in @active_facets
209
+ should_be_added_to_total = false unless active_facet.values.indexOf(result_part.facets[active_facet.index]) > -1
210
+ total += result_part[variable] if should_be_added_to_total
211
+ return total
212
+ else
213
+ return result_parts.map((part)->part[variable]).reduce (t, v) -> t + v
214
+
215
+ bar_chart_ticks: ->
216
+ x_row = ['x'] # tick below the bar
217
+ start_index = 0
218
+ if @has_no_date
219
+ x_row.push 'x'
220
+ start_index += 1 # first key will be 'no_date'
221
+ for key in @bar_chart_keys.slice(start_index)
222
+ x_row.push @format_bar_tick(key)
223
+ #x_row = x_row.concat ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
224
+ x_row
225
+
226
+ format_bar_tick: (key)->
227
+ date = moment(key)
228
+ format = "YYYY-MM-DD"
229
+ switch @bin_type
230
+ when "quarter" then return "#{date.quarter()}/#{date.year()}"
231
+ when "month"
232
+ format = "MMM"
233
+ format += " YY" if @min_date.year() isnt @max_date.year()
234
+ when "week"
235
+ result = "#{date.week()}"
236
+ result += "/#{date.year()}" if @min_date.year() isnt @max_date.year()
237
+ return result
238
+
239
+ date.format format
240
+ HawkEye.DateBinVariable = new DateBinVariable()
241
+ HawkEye.DateBinVariable.configure
242
+ facet:
243
+ colors:
244
+ state:
245
+ uncategorized: "#eee"
246
+ unplanned: "#aaa"
247
+ planned: "#aaa"
248
+ active: "#55f"
249
+ overdue: "#ffa500"
250
+ any_rejected: "#e44"
251
+ all_completed: "#5b5"
252
+ # workflow_step - duplicates
253
+ pending: "#eee"
254
+ processing: "#55f"
255
+ rejected: "#e44"
256
+ completed: "#5b5"
@@ -0,0 +1,256 @@
1
+ @dashboard = (id, fData) ->
2
+ barColor = 'steelblue'
3
+ # compute total for each state.
4
+
5
+ segColor = (c) ->
6
+ {
7
+ stateO: '#807dba'
8
+ stateP: '#e08214'
9
+ stateT: '#41ab5d'
10
+ }[c]
11
+
12
+ # function to handle histogram.
13
+
14
+ histoGram = (fD) ->
15
+ hG = {}
16
+ hGDim =
17
+ t: 60
18
+ r: 0
19
+ b: 30
20
+ l: 0
21
+
22
+ mouseover = (d) ->
23
+ # utility function to be called on mouseover.
24
+ # filter for selected state.
25
+ st = fData.filter((s) ->
26
+ s.State == d[0]
27
+ )[0]
28
+ nD = d3.keys(st.freq).map((s) ->
29
+ {
30
+ type: s
31
+ freq: st.freq[s]
32
+ }
33
+ )
34
+ # call update functions of pie-chart and legend.
35
+ pC.update nD
36
+ leg.update nD
37
+ return
38
+
39
+ mouseout = (d) ->
40
+ # utility function to be called on mouseout.
41
+ # reset the pie-chart and legend
42
+ pC.update tF
43
+ leg.update tF
44
+ return
45
+
46
+ hGDim.w = 500 - (hGDim.l) - (hGDim.r)
47
+ hGDim.h = 300 - (hGDim.t) - (hGDim.b)
48
+ #create svg for histogram.
49
+ hGsvg = d3.select(id).append('svg').attr('width', hGDim.w + hGDim.l + hGDim.r).attr('height', hGDim.h + hGDim.t + hGDim.b + 100).append('g').attr('transform', 'translate(' + hGDim.l + ',' + hGDim.t + ')')
50
+ # create function for x-axis mapping.
51
+ x = d3.scale.ordinal().rangeRoundBands([
52
+ 0
53
+ hGDim.w
54
+ ], 0.1).domain(fD.map((d) ->
55
+ d[0]
56
+ ))
57
+ # Add x-axis to the histogram svg.
58
+ hGsvg.append('g').attr('class', 'x axis').attr('transform', 'translate(0,' + hGDim.h + ')')
59
+ .call(d3.svg.axis().scale(x).orient('bottom'))
60
+ .selectAll('text')
61
+ .style("text-anchor", "end")
62
+ .attr("dx", "-.8em")
63
+ .attr("dy", ".15em")
64
+ .attr("transform", "rotate(-65)" )
65
+ # Create function for y-axis map.
66
+ y = d3.scale.linear().range([
67
+ hGDim.h
68
+ 0
69
+ ]).domain([
70
+ 0
71
+ d3.max(fD, (d) ->
72
+ d[1]
73
+ )
74
+ ])
75
+ # Create bars for histogram to contain rectangles and freq labels.
76
+ bars = hGsvg.selectAll('.bar').data(fD).enter().append('g').attr('class', 'bar')
77
+ #create the rectangles.
78
+ bars.append('rect').attr('x', (d) ->
79
+ x d[0]
80
+ ).attr('y', (d) ->
81
+ y d[1]
82
+ ).attr('width', x.rangeBand()).attr('height', (d) ->
83
+ hGDim.h - y(d[1])
84
+ ).attr('fill', barColor).on('mouseover', mouseover).on 'mouseout', mouseout
85
+ # mouseout is defined below.
86
+ #Create the frequency labels above the rectangles.
87
+ bars.append('text').text((d) ->
88
+ d3.format(',') d[1]
89
+ ).attr('x', (d) ->
90
+ x(d[0]) + x.rangeBand() / 2
91
+ ).attr('y', (d) ->
92
+ y(d[1]) - 5
93
+ ).attr 'text-anchor', 'middle'
94
+ # create function to update the bars. This will be used by pie-chart.
95
+
96
+ hG.update = (nD, color) ->
97
+ # update the domain of the y-axis map to reflect change in frequencies.
98
+ y.domain [
99
+ 0
100
+ d3.max(nD, (d) ->
101
+ `var bars`
102
+ d[1]
103
+ )
104
+ ]
105
+ # Attach the new data to the bars.
106
+ bars = hGsvg.selectAll('.bar').data(nD)
107
+ # transition the height and color of rectangles.
108
+ bars.select('rect').transition().duration(500).attr('y', (d) ->
109
+ y d[1]
110
+ ).attr('height', (d) ->
111
+ hGDim.h - y(d[1])
112
+ ).attr 'fill', color
113
+ # transition the frequency labels location and change value.
114
+ bars.select('text').transition().duration(500).text((d) ->
115
+ d3.format(',') d[1]
116
+ ).attr 'y', (d) ->
117
+ y(d[1]) - 5
118
+ return
119
+
120
+ hG
121
+
122
+ # function to handle pieChart.
123
+
124
+ pieChart = (pD) ->
125
+ pC = {}
126
+ pieDim =
127
+ w: 250
128
+ h: 250
129
+ # Utility function to be called on mouseover a pie slice.
130
+
131
+ mouseover = (d) ->
132
+ # call the update function of histogram with new data.
133
+ hG.update fData.map((v) ->
134
+ [
135
+ v.State
136
+ v.freq[d.data.type]
137
+ ]
138
+ ), segColor(d.data.type)
139
+ return
140
+
141
+ #Utility function to be called on mouseout a pie slice.
142
+
143
+ mouseout = (d) ->
144
+ # call the update function of histogram with all data.
145
+ hG.update fData.map((v) ->
146
+ [
147
+ v.State
148
+ v.total
149
+ ]
150
+ ), barColor
151
+ return
152
+
153
+ # Animating the pie-slice requiring a custom function which specifies
154
+ # how the intermediate paths should be drawn.
155
+
156
+ arcTween = (a) ->
157
+ i = d3.interpolate(@_current, a)
158
+ @_current = i(0)
159
+ (t) ->
160
+ arc i(t)
161
+
162
+ pieDim.r = Math.min(pieDim.w, pieDim.h) / 2
163
+ # create svg for pie chart.
164
+ piesvg = d3.select(id).append('svg').attr('width', pieDim.w).attr('height', pieDim.h).append('g').attr('transform', 'translate(' + pieDim.w / 2 + ',' + pieDim.h / 2 + ')')
165
+ # create function to draw the arcs of the pie slices.
166
+ arc = d3.svg.arc().outerRadius(pieDim.r - 10).innerRadius(0)
167
+ # create a function to compute the pie slice angles.
168
+ pie = d3.layout.pie().sort(null).value((d) ->
169
+ d.freq
170
+ )
171
+ # Draw the pie slices.
172
+ piesvg.selectAll('path').data(pie(pD)).enter().append('path').attr('d', arc).each((d) ->
173
+ @_current = d
174
+ return
175
+ ).style('fill', (d) ->
176
+ segColor d.data.type
177
+ ).on('mouseover', mouseover).on 'mouseout', mouseout
178
+ # create function to update pie-chart. This will be used by histogram.
179
+
180
+ pC.update = (nD) ->
181
+ piesvg.selectAll('path').data(pie(nD)).transition().duration(500).attrTween 'd', arcTween
182
+ return
183
+
184
+ pC
185
+
186
+ # function to handle legend.
187
+
188
+ legend = (lD) ->
189
+ `var legend`
190
+ leg = {}
191
+ # create table for legend.
192
+ legend = d3.select(id).append('table').attr('class', 'legend')
193
+ # create one row per segment.
194
+ tr = legend.append('tbody').selectAll('tr').data(lD).enter().append('tr')
195
+ # create the first column for each segment.
196
+
197
+ getLegend = (d, aD) ->
198
+ # Utility function to compute percentage.
199
+ d3.format('%') d.freq / d3.sum(aD.map((v) ->
200
+ v.freq
201
+ ))
202
+
203
+ tr.append('td').append('svg').attr('width', '16').attr('height', '16').append('rect').attr('width', '16').attr('height', '16').attr 'fill', (d) ->
204
+ segColor d.type
205
+ # create the second column for each segment.
206
+ tr.append('td').text (d) ->
207
+ d.type
208
+ # create the third column for each segment.
209
+ tr.append('td').attr('class', 'legendFreq').text (d) ->
210
+ d3.format(',') d.freq
211
+ # create the fourth column for each segment.
212
+ tr.append('td').attr('class', 'legendPerc').text (d) ->
213
+ getLegend d, lD
214
+ # Utility function to be used to update the legend.
215
+
216
+ leg.update = (nD) ->
217
+ # update the data attached to the row elements.
218
+ l = legend.select('tbody').selectAll('tr').data(nD)
219
+ # update the frequencies.
220
+ l.select('.legendFreq').text (d) ->
221
+ d3.format(',') d.freq
222
+ # update the percentage column.
223
+ l.select('.legendPerc').text (d) ->
224
+ getLegend d, nD
225
+ return
226
+
227
+ leg
228
+
229
+ fData.forEach (d) ->
230
+ d.total = d.freq.stateO + d.freq.stateP + d.freq.stateT
231
+ return
232
+ # calculate total frequency by segment for all state.
233
+ tF = [
234
+ 'stateO'
235
+ 'stateP'
236
+ 'stateT'
237
+ ].map((d) ->
238
+ {
239
+ type: d
240
+ freq: d3.sum(fData.map((t) ->
241
+ t.freq[d]
242
+ ))
243
+ }
244
+ )
245
+ # calculate total frequency by state for all segment.
246
+ sF = fData.map((d) ->
247
+ [
248
+ d.State
249
+ d.total
250
+ ]
251
+ )
252
+ hG = histoGram(sF)
253
+ pC = pieChart(tF)
254
+ leg = legend(tF)
255
+ # create the legend.
256
+ return