git-visualiser 0.0.1

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 (46) hide show
  1. checksums.yaml +15 -0
  2. data/bin/git_vis +19 -0
  3. data/lib/application/application.rb +82 -0
  4. data/lib/application/coffee_engine.rb +20 -0
  5. data/lib/application/images/ajax-loader.gif +0 -0
  6. data/lib/application/javascripts/branch_graph.coffee +424 -0
  7. data/lib/application/javascripts/commit_graph.coffee +442 -0
  8. data/lib/application/javascripts/common.coffee +50 -0
  9. data/lib/application/javascripts/d3.min.js +5 -0
  10. data/lib/application/javascripts/data_convert.coffee +56 -0
  11. data/lib/application/javascripts/jquery.min.js +6 -0
  12. data/lib/application/javascripts/moment.min.js +6 -0
  13. data/lib/application/javascripts/namespace.coffee +2 -0
  14. data/lib/application/sass_engine.rb +14 -0
  15. data/lib/application/stylesheets/scss/app.scss +172 -0
  16. data/lib/application/stylesheets/scss/flat_ui/_config.sass +16 -0
  17. data/lib/application/stylesheets/scss/flat_ui/_icon-font-24.sass +91 -0
  18. data/lib/application/stylesheets/scss/flat_ui/_icon-font.sass +91 -0
  19. data/lib/application/stylesheets/scss/flat_ui/_mixins.sass +96 -0
  20. data/lib/application/stylesheets/scss/flat_ui/_spaces.sass +129 -0
  21. data/lib/application/stylesheets/scss/flat_ui/flat-ui.sass +39 -0
  22. data/lib/application/stylesheets/scss/flat_ui/modules/_btn.sass +73 -0
  23. data/lib/application/stylesheets/scss/flat_ui/modules/_checkbox-and-radio.sass +86 -0
  24. data/lib/application/stylesheets/scss/flat_ui/modules/_demo.sass +228 -0
  25. data/lib/application/stylesheets/scss/flat_ui/modules/_footer.sass +57 -0
  26. data/lib/application/stylesheets/scss/flat_ui/modules/_input.sass +66 -0
  27. data/lib/application/stylesheets/scss/flat_ui/modules/_login.sass +95 -0
  28. data/lib/application/stylesheets/scss/flat_ui/modules/_navbar.sass +152 -0
  29. data/lib/application/stylesheets/scss/flat_ui/modules/_pager.sass +56 -0
  30. data/lib/application/stylesheets/scss/flat_ui/modules/_pagination.sass +75 -0
  31. data/lib/application/stylesheets/scss/flat_ui/modules/_palette.sass +88 -0
  32. data/lib/application/stylesheets/scss/flat_ui/modules/_progress.sass +29 -0
  33. data/lib/application/stylesheets/scss/flat_ui/modules/_select.sass +163 -0
  34. data/lib/application/stylesheets/scss/flat_ui/modules/_share.sass +34 -0
  35. data/lib/application/stylesheets/scss/flat_ui/modules/_tagsinput.sass +91 -0
  36. data/lib/application/stylesheets/scss/flat_ui/modules/_tile.sass +42 -0
  37. data/lib/application/stylesheets/scss/flat_ui/modules/_todo.sass +77 -0
  38. data/lib/application/stylesheets/scss/flat_ui/modules/_toggle.sass +85 -0
  39. data/lib/application/stylesheets/scss/flat_ui/modules/_tooltip.sass +45 -0
  40. data/lib/application/stylesheets/scss/flat_ui/modules/_type.sass +43 -0
  41. data/lib/application/stylesheets/scss/flat_ui/modules/_ui-slider.sass +44 -0
  42. data/lib/application/stylesheets/scss/flat_ui/modules/_video.sass +358 -0
  43. data/lib/application/views/authors_list.haml +11 -0
  44. data/lib/application/views/index.haml +48 -0
  45. data/lib/application/visualisation.rb +156 -0
  46. metadata +87 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NDBlYWUyNDk3NmY2MWM0Mzc1ZGEwYmJmNWFiYThhOGM5NjJjM2I4Yw==
5
+ data.tar.gz: !binary |-
6
+ YzEzZWFiZGMzYjUwODJlNWI4Nzc2NWRiMjRlNmUxOTEzM2MxM2I5MQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ MzY1MTFhNjhlZmUxOGI5YjA1ZmI1NmNjNGE4MDBlZGQ0MGNlNjM4ZGZhOTg2
10
+ NmMyMTUzMjIxODdlZjAyNzE5MDc5MTcxMWUxZGQxZmM2N2U3MWY0MjEwYjAx
11
+ ZTMwNjk3MDVjZDk5ZDk5NjJkNDg3NjY5MjdiZDg1NjYzMjI5ZTY=
12
+ data.tar.gz: !binary |-
13
+ M2YzOGZkZDA5MjJjNTI4ZjkyZDA3YTAyZTZiMDQ5NDBiNzIzYWQ1ZTE4MTlh
14
+ MWYwOWVjMTczYTViYzM5ZGFkODAwMDE1YjVlYzA0YzhmMjgwMTczZjIxZDFl
15
+ NmRkZjhkNmFlZDc1MWJkMTdkNjhjNGMwMzQyMTExZTYzOGFkNzA=
data/bin/git_vis ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+
4
+ begin
5
+ require 'rubygems'
6
+ require 'bundler'
7
+ require 'sinatra'
8
+ require 'haml'
9
+ require 'coffee-script'
10
+ require 'sass'
11
+ require 'json'
12
+
13
+ require 'application/sass_engine'
14
+ require 'application/coffee_engine'
15
+ require 'application/visualisation'
16
+
17
+ #start the application
18
+ require 'application/application'
19
+ end
@@ -0,0 +1,82 @@
1
+ class GitVisualiser < Sinatra::Base
2
+
3
+ use SassEngine
4
+ use CoffeeEngine
5
+
6
+ set :static, true
7
+ set :public_dir, File.expand_path('..', __FILE__)
8
+
9
+ set :views, File.expand_path('../views', __FILE__)
10
+ set :haml, { :format => :html5 }
11
+
12
+ get '/' do
13
+ haml :'/index'
14
+ end
15
+
16
+ get '/branches.json' do
17
+ branches = Visualisation.branches
18
+ content_type :json
19
+ branches.to_json
20
+ end
21
+
22
+ get '/merged_branches.json' do
23
+ merged_branches = Visualisation.repo_branches_merged
24
+ content_type :json
25
+ merged_branches.to_json
26
+ end
27
+
28
+ get '/filter_branch_commits.json' do
29
+ include_commit_sha = params[:include]
30
+ exclude_commit_sha = params[:exclude]
31
+
32
+ branches = branches_include = branches_exclude = []
33
+ branches_include = Visualisation.branches_containing_commit(include_commit_sha) if include_commit_sha != ''
34
+ branches_exclude = Visualisation.branches_excluding_commit(exclude_commit_sha) if exclude_commit_sha != ''
35
+
36
+ if !branches_include == {}
37
+ branches = Hash[branches_include.to_a - branches_exclude.to_a]
38
+ else
39
+ branches = branches_exclude
40
+ end
41
+
42
+ content_type :json
43
+ branches.to_json
44
+ end
45
+
46
+ get '/author_stats.json' do
47
+ ref = params[:ref]
48
+
49
+ @authors = Visualisation.branch_author_stats(ref)
50
+ @authors = @authors.slice(0, 3) #show a max of 3 authors
51
+
52
+ haml :'/authors_list' if @authors.length > 0
53
+ end
54
+
55
+ get '/commits.json' do
56
+ ref = params[:ref]
57
+ commits = Visualisation.commits_for_branch(ref)
58
+
59
+ content_type :json
60
+ commits.to_json
61
+ end
62
+
63
+ get '/commit_diff_stats.json' do
64
+ ref = params[:ref]
65
+ file_diff_stats = Visualisation.merge_base_file_stats(ref)
66
+
67
+ content_type :json
68
+ file_diff_stats.to_json
69
+ end
70
+
71
+ helpers do
72
+
73
+ def gravatar_image(email)
74
+ hash = Digest::MD5.hexdigest(email).to_s
75
+ "<img src=\"http://www.gravatar.com/avatar/#{hash}?s=48\" />"
76
+ end
77
+
78
+ end
79
+ end
80
+
81
+ puts "Running GitVisualiser"
82
+ GitVisualiser.run!
@@ -0,0 +1,20 @@
1
+ class CoffeeEngine < Sinatra::Base
2
+
3
+ set :views, File.dirname(__FILE__) + '/javascripts'
4
+ set :public_dir, File.expand_path('..', __FILE__)
5
+
6
+ get "/javascripts/d3.min.js" do
7
+ end
8
+
9
+ get "/javascripts/jquery.min.js" do
10
+ end
11
+
12
+ get "/javascripts/moment.min.js" do
13
+ end
14
+
15
+ get "/javascripts/*.js" do
16
+ filename = params[:splat].first
17
+ coffee filename.to_sym
18
+ end
19
+
20
+ end
@@ -0,0 +1,424 @@
1
+ class BranchGraph
2
+ constructor: ->
3
+ @initializeD3()
4
+ @getGraphData()
5
+ @initializeControls()
6
+ @commitGraph = new Visualisation.CommitGraph()
7
+ # @commitGraph.load("git-vis-2")
8
+
9
+ initializeD3: ->
10
+ # set up SVG for D3
11
+ @width = $("#branches-display").width();
12
+ @height = $("#branches-display").height();
13
+ @body = d3.select("body")
14
+ @svg = @body.select("#branches-display")
15
+ .append("svg")
16
+ .attr("width", @width)
17
+ .attr("height", @height)
18
+ @lastKeyDown = -1;
19
+
20
+ getGraphData: ->
21
+ # set up initial nodes and links
22
+ # - nodes are known by 'id', not by index in array.
23
+ # - links are always source < target; edge directions are set by 'left' and 'right'.
24
+ $.get "/branches.json", (data) ->
25
+ branch_data = data
26
+ $.get "/merged_branches.json", (merge_data) ->
27
+ Visualisation.branchGraph.initGraphData(branch_data, merge_data)
28
+
29
+ initializeControls: ->
30
+ $("#apply-filters-btn").click () =>
31
+ @apply_filters()
32
+ false
33
+
34
+ initGraphData: (branch_data, merge_data) =>
35
+ @branches = branch_data.branches;
36
+ @diff_lines = branch_data.diff;
37
+
38
+ @master = undefined
39
+ #remove the master branch from branches array
40
+ @branches = $.grep(@branches, (el, i) =>
41
+ if el.name is "master"
42
+ @master = el
43
+ return false
44
+ true
45
+ )
46
+
47
+ percent_diff = 0.0
48
+ total_diff = @diff_lines.add + @diff_lines.del
49
+ average_diff = total_diff / @branches.length
50
+
51
+ @nodes = []
52
+ @links = []
53
+ @branch_names = {}
54
+ @nodes.push
55
+ id: 0
56
+ branch: @master
57
+ size: 5.0
58
+ reflexive: false
59
+ fixed: true
60
+ x: @width / 2
61
+ y: @height / 2
62
+ @branch_names["master"] = 0
63
+ $.each @branches, (i, obj) =>
64
+ #calculate the percentage diff for this branch
65
+ percent_diff = (obj.diff.add + obj.diff.del) / average_diff
66
+ @nodes.push id: i + 1, branch: obj, size: percent_diff, reflexive: false, hidden: false
67
+ @branch_names[obj.name] = i + 1
68
+
69
+ #check for merges/edges for each branch/node
70
+ @linked_nodes = {}
71
+ $.each merge_data, (base_key, base) =>
72
+ $.each base, (branch_key, merged_branch) =>
73
+ if merged_branch.left || merged_branch.right
74
+ @linked_nodes[@branch_names[base_key] + ", " + @branch_names[branch_key]] = 1
75
+ @links.push
76
+ source: @branch_names[base_key]
77
+ target: @branch_names[branch_key]
78
+ left: merged_branch.left
79
+ right: merged_branch.right
80
+ hidden: false
81
+
82
+ #store original state
83
+ @all_nodes = @nodes
84
+ @all_links = @links
85
+ @all_branches = @branches
86
+ @all_branch_names = @branch_names
87
+
88
+ @initGraph(false)
89
+
90
+ initGraph: (redraw) ->
91
+ if redraw is true
92
+ d3.select("svg").remove()
93
+ @svg = @body.select("#vis-display")
94
+ .append("svg")
95
+ .attr("width", @width)
96
+ .attr("height", @height)
97
+ @recalculate_node_sizes()
98
+
99
+ lastNodeId = @nodes.length - 1
100
+
101
+ # init D3 force layout
102
+ @force = d3.layout.force()
103
+ .nodes(@nodes)
104
+ .links(@links)
105
+ .size([@width, @height])
106
+ .linkDistance(150)
107
+ .charge(-500)
108
+ .on("tick", @tick)
109
+
110
+ # define arrow markers for graph links
111
+ @svg.append('svg:defs').append('svg:marker')
112
+ .attr('id', 'end-arrow')
113
+ .attr('viewBox', '0 -5 10 10')
114
+ .attr('refX', 6)
115
+ .attr('markerWidth', 3)
116
+ .attr('markerHeight', 3)
117
+ .attr('orient', 'auto')
118
+ .append('svg:path')
119
+ .attr('d', 'M0,-5L10,0L0,5')
120
+ .attr('fill', '#999');
121
+
122
+ @svg.append('svg:defs').append('svg:marker')
123
+ .attr('id', 'start-arrow')
124
+ .attr('viewBox', '0 -5 10 10')
125
+ .attr('refX', 4)
126
+ .attr('markerWidth', 3)
127
+ .attr('markerHeight', 3)
128
+ .attr('orient', 'auto')
129
+ .append('svg:path')
130
+ .attr('d', 'M10,-5L0,0L10,5')
131
+ .attr('fill', '#999');
132
+
133
+ # handles to link and node element groups
134
+ @path = @svg.append('svg:g').selectAll('path')
135
+ @circle = @svg.append('svg:g').selectAll('g');
136
+
137
+ # mouse event vars
138
+ @selected_node = null
139
+ @selected_link = null
140
+ @mousedown_link = null
141
+ @mousedown_node = null
142
+ @mouseup_node = null
143
+
144
+ #remove the loading div here
145
+ $("#vis-loading").hide();
146
+ @restart()
147
+
148
+ resetMouseVars: ->
149
+ @mousedown_node = null
150
+ @mouseup_node = null
151
+ @mousedown_link = null
152
+
153
+ # update force layout (called automatically each iteration)
154
+ tick: ->
155
+ # draw directed edges with proper padding from node centers
156
+ Visualisation.branchGraph.path.attr "d", (d) ->
157
+ deltaX = d.target.x - d.source.x
158
+ deltaY = d.target.y - d.source.y
159
+ dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
160
+ normX = deltaX / dist
161
+ normY = deltaY / dist
162
+ sourcePadding = node_size(d.source) + 7
163
+ targetPadding = node_size(d.target) + 7
164
+ sourceX = d.source.x + (sourcePadding * normX)
165
+ sourceY = d.source.y + (sourcePadding * normY)
166
+ targetX = d.target.x - (targetPadding * normX)
167
+ targetY = d.target.y - (targetPadding * normY)
168
+ "M" + sourceX + "," + sourceY + "L" + targetX + "," + targetY
169
+
170
+ Visualisation.branchGraph.circle.attr "transform", (d) ->
171
+ "translate(" + d.x + "," + d.y + ")"
172
+
173
+ # update graph (called when needed)
174
+ restart: ->
175
+ # path (link) group
176
+ @path = @path.data(@links)
177
+
178
+ # update existing links
179
+ @path.classed("selected", (d) ->
180
+ d is @selected_link
181
+ ).style("marker-start", (d) ->
182
+ (if d.left then "url(#start-arrow)" else "")
183
+ ).style "marker-end", (d) ->
184
+ (if d.right then "url(#end-arrow)" else "")
185
+
186
+ # add new links
187
+ @path.enter().append("svg:path").attr("class", "link").classed("selected", (d) ->
188
+ d is @selected_link
189
+ ).style("marker-start", (d) ->
190
+ (if d.left then "url(#start-arrow)" else "")
191
+ ).style("marker-end", (d) ->
192
+ (if d.right then "url(#end-arrow)" else "")
193
+ )
194
+
195
+ # remove old links
196
+ @path.exit().remove()
197
+
198
+ # circle (node) group
199
+ # NB: the function arg is crucial here! nodes are known by id, not by index!
200
+ @circle = @circle.data(@nodes, (d) ->
201
+ d.id
202
+ )
203
+
204
+ #hide filtered nodes
205
+ @circle.selectAll("circle").select((d) ->
206
+ d.branch.hidden == false ? this : null
207
+ )
208
+
209
+ # update existing nodes (reflexive & selected visual states)
210
+ @circle.selectAll("circle").style("fill", (d) ->
211
+ (if (d is @selected_node) then d3.rgb(branch_color(d)).brighter().toString() else d3.rgb(branch_color(d)))
212
+ ).classed "reflexive", (d) ->
213
+ d.reflexive
214
+
215
+ @circle.selectAll("text")
216
+ .attr("x", (d) -> node_size(d)+5)
217
+ .attr("y", (d) -> node_size(d)/2)
218
+
219
+ # add new nodes
220
+ g = @circle.enter().append("svg:g")
221
+
222
+ # reposition drag line
223
+ vis = @
224
+ g.append("svg:circle").attr("class", "node")
225
+ .attr("branch", (d) -> d.branch.name)
226
+ .attr("r", (d) -> node_size(d))
227
+ .style("fill", (d) -> (d3.rgb(branch_color(d))))
228
+ .style("stroke", (d) -> d3.rgb(branch_color(d)).darker().toString())
229
+ .classed("reflexive", (d) -> d.reflexive)
230
+ .on("mouseover", (d) ->
231
+ d3.selectAll("circle").filter((d2) -> d != d2).transition().style "opacity", "0.25"
232
+ d3.selectAll("text").filter((d2) -> d != d2).transition().style "opacity", "0.10"
233
+ d3.selectAll("path.link").filter((d2) -> d != d2).transition().style "opacity", "0.10"
234
+ vis.getAuthorStats(d.branch.name))
235
+ .on("mouseout", (d) ->
236
+ d3.selectAll("circle").transition().style "opacity", "1"
237
+ d3.selectAll("text").transition().style "opacity", "1"
238
+ d3.selectAll("path").transition().style "opacity", "1"
239
+ vis.clearAuthorStats())
240
+ .on("mousedown", (d) ->
241
+ vis.mousedown_node = d
242
+ d3.selectAll("circle").filter((d2) ->
243
+ vis.neighbouring(vis.dom_node(d)[0].__data__.id, vis.dom_node(d2)[0].__data__.id)
244
+ ).transition().style "opacity", "1"
245
+ d3.selectAll("text").filter((d2) ->
246
+ vis.neighbouring(vis.dom_node(d)[0].__data__.id, vis.dom_node(d2)[0].__data__.id)
247
+ ).transition().style "opacity", "1"
248
+ d3.selectAll("path.link").filter((d2) ->
249
+ return false if d2 is undefined
250
+ return true if d2.source == vis.mousedown_node || d2.target == vis.mousedown_node
251
+ ).transition().style "opacity", "1")
252
+ .on("dblclick", (d) ->
253
+ vis.commitGraph.load(d.branch.name)
254
+ )
255
+ .call(@force.drag())
256
+
257
+ # show node IDs
258
+ g.append("svg:text")
259
+ .attr("x", (d) -> node_size(d)+5)
260
+ .attr("y", (d) -> node_size(d)/2)
261
+ .attr("class", "name").text (d) ->
262
+ d.branch.name + " " + d.branch.diff.add + " / " + d.branch.diff.del
263
+
264
+ # remove old nodes
265
+ @circle.exit().remove()
266
+
267
+ # set the graph in motion
268
+ @force.start()
269
+
270
+ clear_filters : () ->
271
+ @nodes = @all_nodes
272
+ @links = @all_links
273
+ @branches = @all_branches
274
+ @branch_names = @all_branch_names
275
+
276
+ apply_filters: () ->
277
+ @clear_filters()
278
+
279
+ #filter branches merged with master
280
+ if $("#filter_merged_checkbox").is(":checked")
281
+ @filter_merged_with_master()
282
+
283
+ #filter branches merged with master
284
+ if $("#filter_remotes_checkbox").is(":checked")
285
+ @filter_remotes()
286
+
287
+ #filter branches by name
288
+ filter_name_query = $("#filter_names_input").val()
289
+ @filter_branch_names(filter_name_query) if filter_name_query.length > 0
290
+
291
+ additional_requests = false
292
+ #filter branches containing commit
293
+ show_commit_sha = $("#show_commit_input").val()
294
+ exclude_commit_sha = $("#exclude_commit_input").val()
295
+
296
+ if show_commit_sha.length > 0 || exclude_commit_sha.length > 0
297
+ additional_requests = true
298
+ @filter_branch_commits(show_commit_sha, exclude_commit_sha)
299
+
300
+ # if we arent making any more requests for this data then
301
+ # restart, otherwise the additional requests callback will make restart call
302
+ if !additional_requests
303
+ @restart()
304
+
305
+ dom_node: (data) ->
306
+ return if !data.branch
307
+ $("circle[branch=" + "'#{data.branch.name}'" + "]")
308
+
309
+ filter_merged_with_master: () ->
310
+ @nodes = $.grep @nodes, (node, i) =>
311
+ if node.branch.merged_with_master is true
312
+ return true if node.branch.name == "master"
313
+ @links = $.grep @links, (link, i) ->
314
+ return false if link.source == node or link.target == node
315
+ true
316
+ @branches = $.grep @branches, (branch, i) ->
317
+ return false if branch == node.branch
318
+ true
319
+ @branch_names = $.grep @branch_names, (name, i) ->
320
+ return false if name == node.branch.name
321
+ true
322
+ return false
323
+ true
324
+
325
+ filter_remotes: () ->
326
+ @nodes = $.grep @nodes, (node, i) =>
327
+ if node.branch.remote is true
328
+ return true if node.branch.name == "master"
329
+ @links = $.grep @links, (link, i) ->
330
+ return false if link.source == node or link.target == node
331
+ true
332
+ @branches = $.grep @branches, (branch, i) ->
333
+ return false if branch == node.branch
334
+ true
335
+ @branch_names = $.grep @branch_names, (name, i) ->
336
+ return false if name == node.branch.name
337
+ true
338
+ return false
339
+ true
340
+
341
+ filter_branch_names: (query) ->
342
+ @nodes = $.grep @nodes, (node, i) =>
343
+ if node.branch.name.indexOf(query) == -1
344
+ return true if node.branch.name == "master"
345
+ @links = $.grep @links, (link, i) ->
346
+ return false if link.source == node or link.target == node
347
+ true
348
+ @branches = $.grep @branches, (branch, i) ->
349
+ return false if branch == node.branch
350
+ true
351
+ @branch_names = $.grep @branch_names, (name, i) ->
352
+ return false if name == node.branch.name
353
+ true
354
+ return false
355
+ true
356
+
357
+ filter_branch_commits: (include_commit_sha, exclude_commit_sha) ->
358
+ json_data = {include: include_commit_sha, exclude: exclude_commit_sha}
359
+ $.get "/filter_branch_commits.json", json_data, (data) =>
360
+ branch_names = data
361
+ @nodes = $.grep @nodes, (node, i) =>
362
+ if $.inArray(node.branch.name, branch_names) is -1
363
+ return true if node.branch.name == "master"
364
+ @links = $.grep @links, (link, i) ->
365
+ return false if link.source == node or link.target == node
366
+ true
367
+ @branches = $.grep @branches, (branch, i) ->
368
+ return false if branch == node.branch
369
+ true
370
+ @branch_names = $.grep @branch_names, (name, i) ->
371
+ return false if name == node.branch.name
372
+ true
373
+ return false
374
+ true
375
+ @restart()
376
+
377
+ branch_color = (node) ->
378
+ return "#1f77b4" if node.branch.name is "master"
379
+ return "#9CDECD" if node.branch.merged_with_master
380
+ #color based on additions and deletions
381
+ branch_diff = node.branch.diff.add - node.branch.diff.del
382
+ if branch_diff > 100
383
+ "#6ACD72"
384
+ else if branch_diff > 0 && branch_diff <= 100
385
+ "#FFF48F"
386
+ else
387
+ "#C3554B"
388
+
389
+ node_size = (node_data) ->
390
+ rad = 5 * node_data.size
391
+
392
+ rad = 5 if rad < 5
393
+ rad = 20 if rad > 20
394
+ return rad
395
+
396
+ recalculate_node_sizes: () ->
397
+ percent_diff = 0.0
398
+ total_diff = 0.0
399
+ # recalculate total diff of all filtered branches
400
+ $.each @branches, (i, branch) ->
401
+ total_diff += branch.diff.add + branch.diff.del
402
+ average_diff = total_diff / @branches.length
403
+
404
+ # recalculate size for each node based on new average
405
+ $.each @nodes, (i, node) ->
406
+ if node.branch.name != "master"
407
+ node.size = (node.branch.diff.add + node.branch.diff.del) / average_diff
408
+
409
+ neighbouring: (node_id, other_id) ->
410
+ @linked_nodes[node_id + ", " + other_id] == 1 ||
411
+ @linked_nodes[other_id + ", " + node_id] == 1 ||
412
+ node_id == other_id
413
+
414
+ getAuthorStats: (branch_name) ->
415
+ $.get "/author_stats.json", {ref: branch_name}, (data) ->
416
+ $("#authors-list").html(data)
417
+
418
+ clearAuthorStats: ->
419
+ $("#authors-list").empty()
420
+
421
+
422
+
423
+ Visualisation.BranchGraph = BranchGraph
424
+ Visualisation.branchGraph = new BranchGraph()