timebars.coffee 3.13 KB
Newer Older
Kjetil Thuen's avatar
Kjetil Thuen committed
1
2
d3 = require 'd3-browserify'
lodash = require 'lodash'
3

4
5
completeData = {}

6
7
chartWidth = (containerId) ->
  parseInt d3.select(containerId).style "width"
8

9
10
chartHeight = (containerId) ->
  500
11

12
13
14
numBars = (containerId) ->
  vals = lodash.first(lodash.values completeData[containerId])
  vals.length
Kjetil Thuen's avatar
Kjetil Thuen committed
15

16
17
margin = (containerId) ->
  chartWidth(containerId) / 50
18

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
speed = -> 500

barThickness = (containerId) ->
  chartHeight(containerId) / numBars(containerId)

x = (containerId) ->
  d3.scale.linear()
    .domain [
      0,
      d3.max(valuesFromFrame(containerId, 0), (d) -> Math.max(d.rvalue, d.lvalue))
    ]
    .range [ 0, chartWidth(containerId) / 2 ]

y = (containerId, val) ->
  d3.scale.linear()
    .domain(d3.extent valuesFromFrame(containerId, 0), (d) -> d.age)
    .rangeRound [ 0, chartHeight(containerId) ]

addBar = (newBar, containerId) ->
38
39
40
  barGroup = newBar.append "g"
    .attr "class", "valuepoint"
    .attr "transform", (d, i) ->
41
      "translate(0, " + (y(containerId)(i) + .5) + ")"
42
43
44

  barGroup.append "rect"
    .attr "class", "right"
45
46
47
    .attr "x", chartWidth(containerId) / 2 + margin(containerId)
    .attr "width", (d) -> x(containerId)(d.rvalue)
    .attr "height", barThickness containerId
48
49
50

  barGroup.append "rect"
    .attr "class", "left"
51
52
53
54
    .attr "x", (d) -> (chartWidth(containerId) / 2) -
        x(containerId)(d.lvalue) - margin(containerId)
    .attr "width", (d) -> x(containerId)(d.lvalue)
    .attr "height", barThickness(containerId)
55

56
57
58
59
60
61
valuesFromFrame = (containerId, frameNum) ->
  frameIndexes = lodash.keys(completeData[containerId])
  completeData[containerId]['' + frameIndexes[frameNum] + '']

updateChart = (containerId, frameNum) ->
  data = valuesFromFrame containerId, frameNum
62
63
  chart = d3.select containerId + " svg.chart"
  valuepoints = chart.selectAll "g.valuepoint"
64
    .data data, (d) -> d.birthyear
65
66
67
68
69

  valuepoints.transition()
    .ease "linear"
    .duration speed()
    .attr "transform", (d, i) ->
70
      "translate(0, " + (y(containerId)(i) + .5) + ")"
71

72
  addBar valuepoints.enter(), containerId
73
74

  valuepoints.exit()
75
    .transition()
76
77
    .duration speed() / 2
    .attr "height", 0
78
    .remove()
79
  undefined
80

81
82
83
nextFrame = (containerId, frameNum) ->
  num = frameNum or 0
  num++
84
  if num >= lodash.keys(completeData[containerId]).length
85
86
87
88
89
90
91
92
93
94
95
    num = 0
  updateChart containerId, num
  num

#Constructor.
#
#The data parameter should be an object with named years. Each year member
#should be an array with at least two members (male and female, further members
#are ignored), each element in these arrays should contain an object that has
#the value property.
#
96
97
#The conteinarId is just a string identfying a div within wich the graph should
#be built. There can be several simultanious graphs
98
setupChart = (containerId, data) ->
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  if data
    completeData[containerId] = data

  lodash.forEach (lodash.keys completeData), (id) ->
    d3.select id
      .html ""

    d3.select id
      .insert "svg"
        .attr "class", "chart"
        .attr "width", chartWidth(id)
        .attr "height", chartHeight(id)
    nextFrame id, 0

  window.onresize = setupChart
114

115
116
117
exports.setupChart = setupChart
exports.speed = speed
exports.nextFrame = nextFrame