d3-charts 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGELOG.md +3 -0
  3. data/D3-LICENSE +26 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +92 -0
  6. data/LICENSE +25 -0
  7. data/README.md +72 -0
  8. data/Rakefile +2 -0
  9. data/app/assets/javascripts/d3.js +9263 -0
  10. data/app/assets/javascripts/d3.min.js +5 -0
  11. data/d3-charts.gemspec +21 -0
  12. data/lib/chart_generators/bar_chart_generator.rb +23 -0
  13. data/lib/chart_generators/base_generator.rb +76 -0
  14. data/lib/chart_generators/bubble_chart_generator.rb +11 -0
  15. data/lib/chart_generators/histogram_generator.rb +11 -0
  16. data/lib/chart_generators/line_chart_generator.rb +11 -0
  17. data/lib/chart_generators/pie_chart_generator.rb +11 -0
  18. data/lib/chart_generators/polar_area_diagram_generator.rb +11 -0
  19. data/lib/chart_generators/radar_chart_generator.rb +11 -0
  20. data/lib/chart_generators/streamgraph_generator.rb +11 -0
  21. data/lib/chart_generators/treemap_generator.rb +11 -0
  22. data/lib/chart_helpers/common/bar_chart.rb +16 -0
  23. data/lib/chart_helpers/common/histogram.rb +12 -0
  24. data/lib/chart_helpers/common/line_chart.rb +11 -0
  25. data/lib/chart_helpers/common/pie_chart.rb +11 -0
  26. data/lib/chart_helpers/common_plots/biplot.rb +0 -0
  27. data/lib/chart_helpers/common_plots/box_plot.rb +0 -0
  28. data/lib/chart_helpers/common_plots/dot_plot.rb +0 -0
  29. data/lib/chart_helpers/common_plots/probability_plot.rb +0 -0
  30. data/lib/chart_helpers/common_plots/scatterplot.rb +0 -0
  31. data/lib/chart_helpers/field_specific/candlestick_chart.rb +0 -0
  32. data/lib/chart_helpers/field_specific/kagi_chart.rb +0 -0
  33. data/lib/chart_helpers/field_specific/open_high_low_close_chart.rb +0 -0
  34. data/lib/chart_helpers/field_specific/sparkline.rb +0 -0
  35. data/lib/chart_helpers/less_common/bubble_chart.rb +8 -0
  36. data/lib/chart_helpers/less_common/polar_area_diagram.rb +8 -0
  37. data/lib/chart_helpers/less_common/radar_chart.rb +9 -0
  38. data/lib/chart_helpers/less_common/streamgraph.rb +9 -0
  39. data/lib/chart_helpers/less_common/treemap.rb +16 -0
  40. data/lib/chart_helpers/less_common/waterfall_chart.rb +0 -0
  41. data/lib/chart_helpers/other/control_chart.rb +0 -0
  42. data/lib/chart_helpers/other/greninger_chart.rb +0 -0
  43. data/lib/chart_helpers/other/heatmap.rb +0 -0
  44. data/lib/chart_helpers/other/natal_chart.rb +0 -0
  45. data/lib/chart_helpers/other/nomogram.rb +0 -0
  46. data/lib/chart_helpers/other/pareto_chart.rb +0 -0
  47. data/lib/chart_helpers/other/run_chart.rb +0 -0
  48. data/lib/chart_helpers/other/strip_chart.rb +0 -0
  49. data/lib/chart_helpers/other/structure_chart.rb +0 -0
  50. data/lib/chart_helpers/other/vowel_chart.rb +0 -0
  51. data/lib/chart_helpers/well_known_named/gantt_chart.rb +0 -0
  52. data/lib/chart_helpers/well_known_named/nolan_chart.rb +0 -0
  53. data/lib/chart_helpers/well_known_named/pert_chart.rb +0 -0
  54. data/lib/chart_helpers/well_known_named/smith_chart.rb +0 -0
  55. data/lib/chart_templates/css/bubble_chart.css.erb +3 -0
  56. data/lib/chart_templates/css/histogram.css.erb +19 -0
  57. data/lib/chart_templates/css/horizontal_bar_chart.css.erb +8 -0
  58. data/lib/chart_templates/css/line_chart.css.erb +35 -0
  59. data/lib/chart_templates/css/pie_chart.css.erb +8 -0
  60. data/lib/chart_templates/css/polar_area_diagram.css.erb +5 -0
  61. data/lib/chart_templates/css/radar_chart.css.erb +6 -0
  62. data/lib/chart_templates/css/streamgraph.css.erb +26 -0
  63. data/lib/chart_templates/css/treemap.css.erb +20 -0
  64. data/lib/chart_templates/css/vertical_bar_chart.css.erb +23 -0
  65. data/lib/chart_templates/js/bubble_chart.js.erb +49 -0
  66. data/lib/chart_templates/js/histogram.js.erb +55 -0
  67. data/lib/chart_templates/js/horizontal_bar_chart.js.erb +13 -0
  68. data/lib/chart_templates/js/line_chart.js.erb +60 -0
  69. data/lib/chart_templates/js/pie_chart.js.erb +44 -0
  70. data/lib/chart_templates/js/polar_area_diagram.js.erb +184 -0
  71. data/lib/chart_templates/js/radar_chart.js.erb +299 -0
  72. data/lib/chart_templates/js/streamgraph.js.erb +161 -0
  73. data/lib/chart_templates/js/treemap.js.erb +46 -0
  74. data/lib/chart_templates/js/vertical_bar_chart.js.erb +59 -0
  75. data/lib/d3-charts.rb +23 -0
  76. data/lib/d3/charts.rb +3 -0
  77. data/lib/d3/charts/engine.rb +6 -0
  78. data/lib/d3/charts/railtie.rb +19 -0
  79. data/lib/d3/charts/version.rb +5 -0
  80. metadata +156 -0
@@ -0,0 +1,299 @@
1
+ //Practically all this code comes from https://github.com/alangrafu/radar-chart-d3
2
+ //I only made some additions and aesthetic adjustments to make the chart look better
3
+ //(of course, that is only my point of view)
4
+ //Such as a better placement of the titles at each line end,
5
+ //adding numbers that reflect what each circular level stands for
6
+ //Not placing the last level and slight differences in color
7
+ //
8
+ //For a bit of extra information check the blog about it:
9
+ //http://nbremer.blogspot.nl/2013/09/making-d3-radar-chart-look-bit-better.html
10
+
11
+ var RadarChart = {
12
+ draw: function(id, d, options){
13
+ var cfg = {
14
+ radius: 5,
15
+ w: 600,
16
+ h: 600,
17
+ factor: 1,
18
+ factorLegend: .85,
19
+ levels: 3,
20
+ maxValue: 0,
21
+ radians: 2 * Math.PI,
22
+ opacityArea: 0.5,
23
+ ToRight: 5,
24
+ TranslateX: 80,
25
+ TranslateY: 30,
26
+ ExtraWidthX: 100,
27
+ ExtraWidthY: 100,
28
+ color: d3.scale.category10()
29
+ };
30
+
31
+ if('undefined' !== typeof options){
32
+ for(var i in options){
33
+ if('undefined' !== typeof options[i]){
34
+ cfg[i] = options[i];
35
+ }
36
+ }
37
+ }
38
+ cfg.maxValue = Math.max(cfg.maxValue, d3.max(d, function(i){return d3.max(i.map(function(o){return o.value;}))}));
39
+ var allAxis = (d[0].map(function(i, j){return i.axis}));
40
+ var total = allAxis.length;
41
+ var radius = cfg.factor*Math.min(cfg.w/2, cfg.h/2);
42
+ var Format = d3.format('%');
43
+ d3.select(id).select("svg").remove();
44
+
45
+ var g = d3.select(id)
46
+ .append("svg")
47
+ .attr("width", cfg.w+cfg.ExtraWidthX)
48
+ .attr("height", cfg.h+cfg.ExtraWidthY)
49
+ .append("g")
50
+ .attr("transform", "translate(" + cfg.TranslateX + "," + cfg.TranslateY + ")");
51
+ ;
52
+
53
+ var tooltip;
54
+
55
+ //Circular segments
56
+ for(var j=0; j<cfg.levels-1; j++){
57
+ var levelFactor = cfg.factor*radius*((j+1)/cfg.levels);
58
+ g.selectAll(".levels")
59
+ .data(allAxis)
60
+ .enter()
61
+ .append("svg:line")
62
+ .attr("x1", function(d, i){return levelFactor*(1-cfg.factor*Math.sin(i*cfg.radians/total));})
63
+ .attr("y1", function(d, i){return levelFactor*(1-cfg.factor*Math.cos(i*cfg.radians/total));})
64
+ .attr("x2", function(d, i){return levelFactor*(1-cfg.factor*Math.sin((i+1)*cfg.radians/total));})
65
+ .attr("y2", function(d, i){return levelFactor*(1-cfg.factor*Math.cos((i+1)*cfg.radians/total));})
66
+ .attr("class", "line")
67
+ .style("stroke", "grey")
68
+ .style("stroke-opacity", "0.75")
69
+ .style("stroke-width", "0.3px")
70
+ .attr("transform", "translate(" + (cfg.w/2-levelFactor) + ", " + (cfg.h/2-levelFactor) + ")");
71
+ }
72
+
73
+ //Text indicating at what % each level is
74
+ for(var j=0; j<cfg.levels; j++){
75
+ var levelFactor = cfg.factor*radius*((j+1)/cfg.levels);
76
+ g.selectAll(".levels")
77
+ .data([1]) //dummy data
78
+ .enter()
79
+ .append("svg:text")
80
+ .attr("x", function(d){return levelFactor*(1-cfg.factor*Math.sin(0));})
81
+ .attr("y", function(d){return levelFactor*(1-cfg.factor*Math.cos(0));})
82
+ .attr("class", "legend")
83
+ .style("font-family", "sans-serif")
84
+ .style("font-size", "10px")
85
+ .attr("transform", "translate(" + (cfg.w/2-levelFactor + cfg.ToRight) + ", " + (cfg.h/2-levelFactor) + ")")
86
+ .attr("fill", "#737373")
87
+ .text(Format((j+1)*cfg.maxValue/cfg.levels));
88
+ }
89
+
90
+ series = 0;
91
+
92
+ var axis = g.selectAll(".axis")
93
+ .data(allAxis)
94
+ .enter()
95
+ .append("g")
96
+ .attr("class", "axis");
97
+
98
+ axis.append("line")
99
+ .attr("x1", cfg.w/2)
100
+ .attr("y1", cfg.h/2)
101
+ .attr("x2", function(d, i){return cfg.w/2*(1-cfg.factor*Math.sin(i*cfg.radians/total));})
102
+ .attr("y2", function(d, i){return cfg.h/2*(1-cfg.factor*Math.cos(i*cfg.radians/total));})
103
+ .attr("class", "line")
104
+ .style("stroke", "grey")
105
+ .style("stroke-width", "1px");
106
+
107
+ axis.append("text")
108
+ .attr("class", "legend")
109
+ .text(function(d){return d})
110
+ .style("font-family", "sans-serif")
111
+ .style("font-size", "11px")
112
+ .attr("text-anchor", "middle")
113
+ .attr("dy", "1.5em")
114
+ .attr("transform", function(d, i){return "translate(0, -10)"})
115
+ .attr("x", function(d, i){return cfg.w/2*(1-cfg.factorLegend*Math.sin(i*cfg.radians/total))-60*Math.sin(i*cfg.radians/total);})
116
+ .attr("y", function(d, i){return cfg.h/2*(1-Math.cos(i*cfg.radians/total))-20*Math.cos(i*cfg.radians/total);});
117
+
118
+
119
+ d.forEach(function(y, x){
120
+ dataValues = [];
121
+ g.selectAll(".nodes")
122
+ .data(y, function(j, i){
123
+ dataValues.push([
124
+ cfg.w/2*(1-(parseFloat(Math.max(j.value, 0))/cfg.maxValue)*cfg.factor*Math.sin(i*cfg.radians/total)),
125
+ cfg.h/2*(1-(parseFloat(Math.max(j.value, 0))/cfg.maxValue)*cfg.factor*Math.cos(i*cfg.radians/total))
126
+ ]);
127
+ });
128
+ dataValues.push(dataValues[0]);
129
+ g.selectAll(".area")
130
+ .data([dataValues])
131
+ .enter()
132
+ .append("polygon")
133
+ .attr("class", "radar-chart-serie"+series)
134
+ .style("stroke-width", "2px")
135
+ .style("stroke", cfg.color(series))
136
+ .attr("points",function(d) {
137
+ var str="";
138
+ for(var pti=0;pti<d.length;pti++){
139
+ str=str+d[pti][0]+","+d[pti][1]+" ";
140
+ }
141
+ return str;
142
+ })
143
+ .style("fill", function(j, i){return cfg.color(series)})
144
+ .style("fill-opacity", cfg.opacityArea)
145
+ .on('mouseover', function (d){
146
+ z = "polygon."+d3.select(this).attr("class");
147
+ g.selectAll("polygon")
148
+ .transition(200)
149
+ .style("fill-opacity", 0.1);
150
+ g.selectAll(z)
151
+ .transition(200)
152
+ .style("fill-opacity", .7);
153
+ })
154
+ .on('mouseout', function(){
155
+ g.selectAll("polygon")
156
+ .transition(200)
157
+ .style("fill-opacity", cfg.opacityArea);
158
+ });
159
+ series++;
160
+ });
161
+ series=0;
162
+
163
+
164
+ d.forEach(function(y, x){
165
+ g.selectAll(".nodes")
166
+ .data(y).enter()
167
+ .append("svg:circle")
168
+ .attr("class", "radar-chart-serie"+series)
169
+ .attr('r', cfg.radius)
170
+ .attr("alt", function(j){return Math.max(j.value, 0)})
171
+ .attr("cx", function(j, i){
172
+ dataValues.push([
173
+ cfg.w/2*(1-(parseFloat(Math.max(j.value, 0))/cfg.maxValue)*cfg.factor*Math.sin(i*cfg.radians/total)),
174
+ cfg.h/2*(1-(parseFloat(Math.max(j.value, 0))/cfg.maxValue)*cfg.factor*Math.cos(i*cfg.radians/total))
175
+ ]);
176
+ return cfg.w/2*(1-(Math.max(j.value, 0)/cfg.maxValue)*cfg.factor*Math.sin(i*cfg.radians/total));
177
+ })
178
+ .attr("cy", function(j, i){
179
+ return cfg.h/2*(1-(Math.max(j.value, 0)/cfg.maxValue)*cfg.factor*Math.cos(i*cfg.radians/total));
180
+ })
181
+ .attr("data-id", function(j){return j.axis})
182
+ .style("fill", cfg.color(series)).style("fill-opacity", .9)
183
+ .on('mouseover', function (d){
184
+ newX = parseFloat(d3.select(this).attr('cx')) - 10;
185
+ newY = parseFloat(d3.select(this).attr('cy')) - 5;
186
+
187
+ tooltip
188
+ .attr('x', newX)
189
+ .attr('y', newY)
190
+ .text(Format(d.value))
191
+ .transition(200)
192
+ .style('opacity', 1);
193
+
194
+ z = "polygon."+d3.select(this).attr("class");
195
+ g.selectAll("polygon")
196
+ .transition(200)
197
+ .style("fill-opacity", 0.1);
198
+ g.selectAll(z)
199
+ .transition(200)
200
+ .style("fill-opacity", .7);
201
+ })
202
+ .on('mouseout', function(){
203
+ tooltip
204
+ .transition(200)
205
+ .style('opacity', 0);
206
+ g.selectAll("polygon")
207
+ .transition(200)
208
+ .style("fill-opacity", cfg.opacityArea);
209
+ })
210
+ .append("svg:title")
211
+ .text(function(j){return Math.max(j.value, 0)});
212
+
213
+ series++;
214
+ });
215
+ //Tooltip
216
+ tooltip = g.append('text')
217
+ .style('opacity', 0)
218
+ .style('font-family', 'sans-serif')
219
+ .style('font-size', '13px');
220
+ }
221
+ };
222
+
223
+ var w = 500,
224
+ h = 500;
225
+
226
+ var colorscale = d3.scale.category10();
227
+
228
+ //Legend titles
229
+ var LegendOptions = ['Smartphone','Tablet'];
230
+
231
+ //Data
232
+ d3.json("<%= data %>", function(error, d) {
233
+ //Options for the Radar chart, other than default
234
+ var mycfg = {
235
+ w: w,
236
+ h: h,
237
+ maxValue: 0.6,
238
+ levels: 6,
239
+ ExtraWidthX: 300
240
+ }
241
+
242
+ //Call function to draw the Radar chart
243
+ //Will expect that data is in %'s
244
+ RadarChart.draw("<%= element %>", d, mycfg);
245
+
246
+ ////////////////////////////////////////////
247
+ /////////// Initiate legend ////////////////
248
+ ////////////////////////////////////////////
249
+
250
+ var svg = d3.select('<%= element + "_body" %>')
251
+ .selectAll('svg')
252
+ .append('svg')
253
+ .attr("width", w+300)
254
+ .attr("height", h)
255
+
256
+ //Create the title for the legend
257
+ var text = svg.append("text")
258
+ .attr("class", "title")
259
+ .attr('transform', 'translate(90,0)')
260
+ .attr("x", w - 70)
261
+ .attr("y", 10)
262
+ .attr("font-size", "12px")
263
+ .attr("fill", "#404040")
264
+ .text("What % of owners use a specific service in a week");
265
+
266
+ //Initiate Legend
267
+ var legend = svg.append("g")
268
+ .attr("class", "legend")
269
+ .attr("height", 100)
270
+ .attr("width", 200)
271
+ .attr('transform', 'translate(90,20)')
272
+ ;
273
+ //Create colour squares
274
+ legend.selectAll('rect')
275
+ .data(LegendOptions)
276
+ .enter()
277
+ .append("rect")
278
+ .attr("x", w - 65)
279
+ .attr("y", function(d, i){ return i * 20;})
280
+ .attr("width", 10)
281
+ .attr("height", 10)
282
+ .style("fill", function(d, i){ return colorscale(i);})
283
+ ;
284
+ //Create text next to squares
285
+ legend.selectAll('text')
286
+ .data(LegendOptions)
287
+ .enter()
288
+ .append("text")
289
+ .attr("x", w - 52)
290
+ .attr("y", function(d, i){ return i * 20 + 9;})
291
+ .attr("font-size", "11px")
292
+ .attr("fill", "#737373")
293
+ .text(function(d) { return d; });
294
+ });
295
+
296
+
297
+
298
+
299
+
@@ -0,0 +1,161 @@
1
+
2
+ chart("<%= data %>");
3
+
4
+ function chart(csvpath) {
5
+
6
+ var datearray = [];
7
+ var colorrange = ["#045A8D", "#2B8CBE", "#74A9CF", "#A6BDDB", "#D0D1E6", "#F1EEF6"];
8
+ strokecolor = colorrange[0];
9
+
10
+ var format = d3.time.format("%m/%d/%y");
11
+
12
+ var margin = {top: 20, right: 40, bottom: 30, left: 30};
13
+ var width = parseInt(d3.select(".streamgraph_body").style("width")) - margin.left - margin.right;
14
+ var height = 400 - margin.top - margin.bottom;
15
+
16
+ var tooltip = d3.select("<%= element %>_body")
17
+ .append("div")
18
+ .attr("class", "remove")
19
+ .style("position", "relative")
20
+ .style("z-index", "20")
21
+ .style("visibility", "hidden")
22
+ .style("top", "-430px")
23
+ .style("left", "55px");
24
+
25
+ var x = d3.time.scale()
26
+ .range([0, width]);
27
+
28
+ var y = d3.scale.linear()
29
+ .range([height-10, 0]);
30
+
31
+ var z = d3.scale.ordinal()
32
+ .range(colorrange);
33
+
34
+ var xAxis = d3.svg.axis()
35
+ .scale(x)
36
+ .orient("bottom")
37
+ .ticks(d3.time.weeks);
38
+
39
+ var yAxis = d3.svg.axis()
40
+ .scale(y);
41
+
42
+ var yAxisr = d3.svg.axis()
43
+ .scale(y);
44
+
45
+ var stack = d3.layout.stack()
46
+ .offset("silhouette")
47
+ .values(function(d) { return d.values; })
48
+ .x(function(d) { return d.date; })
49
+ .y(function(d) { return d.value; });
50
+
51
+ var nest = d3.nest()
52
+ .key(function(d) { return d.key; });
53
+
54
+ var area = d3.svg.area()
55
+ .interpolate("cardinal")
56
+ .x(function(d) { return x(d.date); })
57
+ .y0(function(d) { return y(d.y0); })
58
+ .y1(function(d) { return y(d.y0 + d.y); });
59
+
60
+ var svg = d3.select("<%= element %>").append("svg")
61
+ .attr("width", width + margin.left + margin.right)
62
+ .attr("height", height + margin.top + margin.bottom)
63
+ .append("g")
64
+ .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
65
+
66
+ var graph = d3.csv(csvpath, function(data) {
67
+ data.forEach(function(d) {
68
+ d.date = format.parse(d.date);
69
+ d.value = +d.value;
70
+ });
71
+
72
+ var layers = stack(nest.entries(data));
73
+
74
+ x.domain(d3.extent(data, function(d) { return d.date; }));
75
+ y.domain([0, d3.max(data, function(d) { return d.y0 + d.y; })]);
76
+
77
+ svg.selectAll(".layer")
78
+ .data(layers)
79
+ .enter().append("path")
80
+ .attr("class", "layer")
81
+ .attr("d", function(d) { return area(d.values); })
82
+ .style("fill", function(d, i) { return z(i); });
83
+
84
+
85
+ svg.append("g")
86
+ .attr("class", "x axis")
87
+ .attr("transform", "translate(0," + height + ")")
88
+ .call(xAxis);
89
+
90
+ svg.append("g")
91
+ .attr("class", "y axis")
92
+ .attr("transform", "translate(" + width + ", 0)")
93
+ .call(yAxis.orient("right"));
94
+
95
+ svg.append("g")
96
+ .attr("class", "y axis")
97
+ .call(yAxis.orient("left"));
98
+
99
+ svg.selectAll(".layer")
100
+ .attr("opacity", 1)
101
+ .on("mouseover", function(d, i) {
102
+ svg.selectAll(".layer").transition()
103
+ .duration(250)
104
+ .attr("opacity", function(d, j) {
105
+ return j != i ? 0.6 : 1;
106
+ })})
107
+
108
+ .on("mousemove", function(d, i) {
109
+ mousex = d3.mouse(this);
110
+ mousex = mousex[0];
111
+ var invertedx = x.invert(mousex);
112
+ invertedx = invertedx.getMonth() + invertedx.getDate();
113
+ var selected = (d.values);
114
+ for (var k = 0; k < selected.length; k++) {
115
+ datearray[k] = selected[k].date
116
+ datearray[k] = datearray[k].getMonth() + datearray[k].getDate();
117
+ }
118
+
119
+ mousedate = datearray.indexOf(invertedx);
120
+ pro = d.values[mousedate].value;
121
+
122
+ d3.select(this)
123
+ .classed("hover", true)
124
+ .attr("stroke", strokecolor)
125
+ .attr("stroke-width", "0.5px"),
126
+ tooltip.html( "<p>" + d.key + "<br>" + pro + "</p>" ).style("visibility", "visible");
127
+
128
+ })
129
+ .on("mouseout", function(d, i) {
130
+ svg.selectAll(".layer")
131
+ .transition()
132
+ .duration(250)
133
+ .attr("opacity", "1");
134
+ d3.select(this)
135
+ .classed("hover", false)
136
+ .attr("stroke-width", "0px"), tooltip.html( "<p>" + d.key + "<br>" + pro + "</p>" ).style("visibility", "hidden");
137
+ })
138
+
139
+ var vertical = d3.select("<%= element %>")
140
+ .append("div")
141
+ .attr("class", "remove")
142
+ .style("position", "relative")
143
+ .style("z-index", "19")
144
+ .style("width", "1px")
145
+ .style("height", "380px")
146
+ .style("top", "-400px")
147
+ .style("bottom", "0px")
148
+ .style("left", "0px")
149
+ .style("background", "#fff");
150
+
151
+ d3.select("<%= element %>")
152
+ .on("mousemove", function(){
153
+ mousex = d3.mouse(this);
154
+ mousex = mousex[0] + 5;
155
+ vertical.style("left", mousex + "px" )})
156
+ .on("mouseover", function(){
157
+ mousex = d3.mouse(this);
158
+ mousex = mousex[0] + 5;
159
+ vertical.style("left", mousex + "px")});
160
+ });
161
+ }