|
1 function streamgraph($selector, $slider) { |
|
2 |
|
3 /* Constants */ |
|
4 |
|
5 var VMARGIN = 3, |
|
6 YEARSHEIGHT = 20, |
|
7 STARTTIME = new Date(2007,6,1), |
|
8 ENDTIME = new Date(), |
|
9 CURVE = .3, |
|
10 COLORS = [ "#943a23", "#fbee97", "#cfbb95", "#da9761", "#ba5036" ], |
|
11 SELECTEDCOLOR = "#c51810"; |
|
12 |
|
13 /* Generating random data */ |
|
14 |
|
15 var data = [], |
|
16 clustercount = 12, |
|
17 slicecount = 20, |
|
18 maxdata = 10, |
|
19 randpart = 4, |
|
20 dampfactor = .333; |
|
21 for (var i = 0; i < clustercount; i++) { |
|
22 var line = [], |
|
23 peaktime = Math.floor(Math.random() * slicecount); |
|
24 for (var j = 0; j < slicecount; j++) { |
|
25 var point = Math.min(maxdata, Math.max(0, (Math.random() - .5) * randpart + Math.max(0, maxdata * (1 - dampfactor * Math.abs(j - peaktime))))); |
|
26 line.push(point); |
|
27 } |
|
28 data.push(line); |
|
29 } |
|
30 |
|
31 /* Calculating scales and positions */ |
|
32 |
|
33 var width = $selector.width(), |
|
34 height = $selector.height(), |
|
35 transp = _.zip.apply( _, data ), |
|
36 cumulative = _(transp).map(function(column) { |
|
37 var total = 0; |
|
38 return _(column).map(function(point) { |
|
39 return total += point; |
|
40 }); |
|
41 }), |
|
42 sums = _(cumulative).map(function(column) { |
|
43 return _(column).last(); |
|
44 }) |
|
45 maxcol = _(sums).max(), |
|
46 streamheight = height - YEARSHEIGHT, |
|
47 yscale = (streamheight - 2 * VMARGIN) / maxcol, |
|
48 centery = streamheight / 2, |
|
49 xscale = width / (transp.length - 1), |
|
50 txscale = width / (ENDTIME - STARTTIME), |
|
51 coords = _(data).map(function(line, lineindex) { |
|
52 return _(line).map(function(point, colindex) { |
|
53 var lowercumul = lineindex ? cumulative[colindex][lineindex - 1] : 0, |
|
54 uppercumul = cumulative[colindex][lineindex]; |
|
55 return { |
|
56 data: point, |
|
57 x: xscale * colindex, |
|
58 lowery: centery + yscale * ( ( sums[colindex] / 2 ) - lowercumul ), |
|
59 uppery: centery + yscale * ( ( sums[colindex] / 2 ) - uppercumul ), |
|
60 } |
|
61 }); |
|
62 }), |
|
63 paths = _(coords).map(function(line) { |
|
64 var lowerline = _(line).reduce(function(path, point, colindex) { |
|
65 var res = path; |
|
66 if (colindex) { |
|
67 res += "," + (point.x - CURVE * xscale) + "," + point.lowery + "," + point.x + "," + point.lowery; |
|
68 } else { |
|
69 res += "M" + point.x + "," + point.lowery; |
|
70 } |
|
71 if (colindex < line.length - 1) { |
|
72 res += "C" + (point.x + CURVE * xscale) + "," + point.lowery; |
|
73 } |
|
74 return res; |
|
75 }, ""); |
|
76 var upperline = _(line).reduceRight(function(path, point, colindex) { |
|
77 var res = path; |
|
78 if (colindex < line.length - 1) { |
|
79 res += "," + (point.x + CURVE * xscale) + "," + point.uppery + "," + point.x + "," + point.uppery; |
|
80 } else { |
|
81 res += "L" + point.x + "," + point.uppery; |
|
82 } |
|
83 if (colindex) { |
|
84 res += "C" + (point.x - CURVE * xscale) + "," + point.uppery; |
|
85 } |
|
86 return res; |
|
87 }, ""); |
|
88 return lowerline + upperline; |
|
89 }); |
|
90 |
|
91 /* Drawing streamgraph*/ |
|
92 |
|
93 var paper = new Raphael($selector[0]); |
|
94 |
|
95 _(paths).each(function(path, index) { |
|
96 var color = COLORS[index % COLORS.length], |
|
97 path = paper.path(path); |
|
98 path.attr({ |
|
99 stroke: "none", |
|
100 fill: color |
|
101 }).mouseover(function() { |
|
102 path.attr({ |
|
103 fill: SELECTEDCOLOR |
|
104 }); |
|
105 }).mouseout(function() { |
|
106 path.attr({ |
|
107 fill: color |
|
108 }) |
|
109 }); |
|
110 }); |
|
111 |
|
112 /* Drawing years */ |
|
113 |
|
114 paper.path("M0," + (height - YEARSHEIGHT) + "," + width + "," + (height - YEARSHEIGHT)) |
|
115 var lastyear = ENDTIME.getFullYear(); |
|
116 for (var i = STARTTIME.getFullYear(); i <= lastyear; i++) { |
|
117 var x = txscale * (new Date(i,0,1) - STARTTIME); |
|
118 paper.path("M" + x + ",0," + x + "," + height); |
|
119 var x = txscale * (new Date(i,6,1) - STARTTIME); |
|
120 paper.text(x, height - .5 * YEARSHEIGHT, i) |
|
121 .attr({ |
|
122 "text-anchor": "middle", |
|
123 "font-family": "Times New Roman, serif", |
|
124 "font-size": "14px" |
|
125 }); |
|
126 } |
|
127 |
|
128 } |
|
129 |
|
130 $(function() { |
|
131 streamgraph($(".streamgraph"), $("#slider-range")); |
|
132 }) |