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

4
5
completeData = {}

Kjetil Thuen's avatar
Kjetil Thuen committed
6
7
chartWidth = (chartId) ->
  parseInt d3.select(chartId).style "width"
8

Kjetil Thuen's avatar
Kjetil Thuen committed
9
10
chartHeight = (chartId) ->
  700
11

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

Kjetil Thuen's avatar
Kjetil Thuen committed
16
17
margin = (chartId) ->
  chartWidth(chartId) / 50
18

19
speed = -> 500
Kjetil Thuen's avatar
Kjetil Thuen committed
20
21
barThickness = (chartId) ->
  Math.floor(chartHeight(chartId) / numBars(chartId)) - 2
22

Kjetil Thuen's avatar
Kjetil Thuen committed
23
x = (chartId) ->
24
25
26
  d3.scale.linear()
    .domain [
      0,
Kjetil Thuen's avatar
Kjetil Thuen committed
27
28
29
      d3.max(valuesFromFrame(chartId, 0), (d) ->
        Math.max(d.rvalue, d.lvalue)
      )
30
    ]
Kjetil Thuen's avatar
Kjetil Thuen committed
31
    .range [ 0, (chartWidth(chartId) / 2) - (margin(chartId) * 2) ]
32

Kjetil Thuen's avatar
Kjetil Thuen committed
33
y = (chartId, val) ->
34
  d3.scale.linear()
Kjetil Thuen's avatar
Kjetil Thuen committed
35
36
    .domain(d3.extent valuesFromFrame(chartId, 0), (d) -> d.age)
    .range [ 0, chartHeight(chartId) ]
37

38
39
40
41
42
x_axis = (chartId) ->
  d3.svg.axis()
    .scale x(chartId)
    .orient "bottom"
    .ticks 5
43
44
45
46
47

y_axis = d3.svg.axis()
  .orient "left"
  .ticks 5

Kjetil Thuen's avatar
Kjetil Thuen committed
48
addBar = (newBar, chartId) ->
49
50
51
  barGroup = newBar.append "g"
    .attr "class", "valuepoint"
    .attr "transform", (d, i) ->
Kjetil Thuen's avatar
Kjetil Thuen committed
52
      "translate(0, " + (y(chartId)(i) + 1) + ")"
53
54
55

  barGroup.append "rect"
    .attr "class", "right"
Kjetil Thuen's avatar
Kjetil Thuen committed
56
57
58
    .attr "x", chartWidth(chartId) / 2 + margin(chartId)
    .attr "width", (d) -> x(chartId)(d.rvalue)
    .attr "height", barThickness chartId
59
60
61

  barGroup.append "rect"
    .attr "class", "left"
Kjetil Thuen's avatar
Kjetil Thuen committed
62
63
64
65
66
67
68
69
70
71
72
73
    .attr "x", (d) -> (chartWidth(chartId) / 2) -
        x(chartId)(d.lvalue) - margin(chartId)
    .attr "width", (d) -> x(chartId)(d.lvalue)
    .attr "height", barThickness(chartId)

valuesFromFrame = (chartId, frameNum) ->
  frameIndexes = lodash.keys(completeData[chartId])
  completeData[chartId]['' + frameIndexes[frameNum] + '']

updateChart = (chartId, frameNum) ->
  data = valuesFromFrame chartId, frameNum
  chart = d3.select chartId + " svg.chart"
74
75
  xAxesGroup = chart.select "xAxesGroup"

76
  valuepoints = chart.selectAll "g.valuepoint"
77
    .data data, (d) -> d.birthyear
78
79
80

  valuepoints.transition()
    .attr "transform", (d, i) ->
Kjetil Thuen's avatar
Kjetil Thuen committed
81
      "translate(0, " + (y(chartId)(i) + 1) + ")"
82

83
84
  xAxesGroup.call x_axis(chartId)

Kjetil Thuen's avatar
Kjetil Thuen committed
85
  addBar valuepoints.enter(), chartId
86
87

  valuepoints.exit()
88
    .transition()
89
90
    .duration speed() / 2
    .attr "height", 0
91
    .remove()
92
  undefined
93

Kjetil Thuen's avatar
Kjetil Thuen committed
94
nextFrame = (chartId, frameNum) ->
95
96
  num = frameNum or 0
  num++
Kjetil Thuen's avatar
Kjetil Thuen committed
97
  if num >= lodash.keys(completeData[chartId]).length
98
    num = 0
Kjetil Thuen's avatar
Kjetil Thuen committed
99
  updateChart chartId, num
100
101
102
103
104
105
106
107
108
  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.
#
109
110
#The conteinarId is just a string identfying a div within wich the graph should
#be built. There can be several simultanious graphs
Kjetil Thuen's avatar
Kjetil Thuen committed
111
setupChart = (chartId, data) ->
112
  if data
Kjetil Thuen's avatar
Kjetil Thuen committed
113
    completeData[chartId] = data
114
115
116
117
118

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

119
    svg = d3.select id
120
121
      .insert "svg"
        .attr "class", "chart"
Kjetil Thuen's avatar
Kjetil Thuen committed
122
        .attr "shape-rendering", "geometricPrecision"
123
124
        .attr "width", chartWidth(id)
        .attr "height", chartHeight(id)
125

126
127
    nextFrame id, 0

128
129
130
131
132
    axisGroup = svg.append "g"
      .attr "class", "xAxesGroup"
      .attr "transform",
            "translate("+ chartWidth(id) / 2 + "," + margin(id) + ")"

133
  window.onresize = setupChart
134

135
136
137
exports.setupChart = setupChart
exports.speed = speed
exports.nextFrame = nextFrame