chartx 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/.gitignore +17 -0
  2. data/.gitmodules +3 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +145 -0
  6. data/Rakefile +1 -0
  7. data/chartx.gemspec +40 -0
  8. data/lib/chartx/engine.rb +11 -0
  9. data/lib/chartx/helper.rb +184 -0
  10. data/lib/chartx/version.rb +3 -0
  11. data/lib/chartx.rb +3 -0
  12. data/screenshots/barchart.png +0 -0
  13. data/screenshots/bulletchart.png +0 -0
  14. data/screenshots/horizontalbarchart.png +0 -0
  15. data/screenshots/linechart.png +0 -0
  16. data/screenshots/linewithfocuschart.png +0 -0
  17. data/screenshots/multibarchart2.png +0 -0
  18. data/screenshots/piechart.png +0 -0
  19. data/screenshots/scatterchart.png +0 -0
  20. data/screenshots/stackedareachart.png +0 -0
  21. data/screenshots/stackedareachart3.png +0 -0
  22. data/vendor/assets/javascripts/chartx-core.js +9 -0
  23. data/vendor/assets/javascripts/chartx-models.js +2 -0
  24. data/vendor/assets/javascripts/nvd3/.gitignore +27 -0
  25. data/vendor/assets/javascripts/nvd3/.jshintrc +3 -0
  26. data/vendor/assets/javascripts/nvd3/LICENSE.md +49 -0
  27. data/vendor/assets/javascripts/nvd3/README.md +1 -0
  28. data/vendor/assets/javascripts/nvd3/lib/cie.js +155 -0
  29. data/vendor/assets/javascripts/nvd3/lib/crossfilter.js +1180 -0
  30. data/vendor/assets/javascripts/nvd3/lib/crossfilter.min.js +1 -0
  31. data/vendor/assets/javascripts/nvd3/lib/d3.js +8798 -0
  32. data/vendor/assets/javascripts/nvd3/lib/d3.min.js +5 -0
  33. data/vendor/assets/javascripts/nvd3/lib/fisheye.js +86 -0
  34. data/vendor/assets/javascripts/nvd3/lib/hive.js +80 -0
  35. data/vendor/assets/javascripts/nvd3/lib/horizon.js +192 -0
  36. data/vendor/assets/javascripts/nvd3/lib/sankey.js +292 -0
  37. data/vendor/assets/javascripts/nvd3/nv.d3.js +13048 -0
  38. data/vendor/assets/javascripts/nvd3/nv.d3.min.js +6 -0
  39. data/vendor/assets/javascripts/nvd3/src/core.js +118 -0
  40. data/vendor/assets/javascripts/nvd3/src/intro.js +1 -0
  41. data/vendor/assets/javascripts/nvd3/src/models/axis.js +398 -0
  42. data/vendor/assets/javascripts/nvd3/src/models/boilerplate.js +102 -0
  43. data/vendor/assets/javascripts/nvd3/src/models/bullet.js +377 -0
  44. data/vendor/assets/javascripts/nvd3/src/models/bulletChart.js +341 -0
  45. data/vendor/assets/javascripts/nvd3/src/models/cumulativeLineChart.js +685 -0
  46. data/vendor/assets/javascripts/nvd3/src/models/discreteBar.js +327 -0
  47. data/vendor/assets/javascripts/nvd3/src/models/discreteBarChart.js +290 -0
  48. data/vendor/assets/javascripts/nvd3/src/models/distribution.js +146 -0
  49. data/vendor/assets/javascripts/nvd3/src/models/historicalBar.js +289 -0
  50. data/vendor/assets/javascripts/nvd3/src/models/historicalBarChart.js +421 -0
  51. data/vendor/assets/javascripts/nvd3/src/models/indentedTree.js +317 -0
  52. data/vendor/assets/javascripts/nvd3/src/models/legend.js +207 -0
  53. data/vendor/assets/javascripts/nvd3/src/models/line.js +284 -0
  54. data/vendor/assets/javascripts/nvd3/src/models/lineChart.js +421 -0
  55. data/vendor/assets/javascripts/nvd3/src/models/linePlusBarChart.js +455 -0
  56. data/vendor/assets/javascripts/nvd3/src/models/linePlusBarWithFocusChart.js +665 -0
  57. data/vendor/assets/javascripts/nvd3/src/models/lineWithFisheye.js +197 -0
  58. data/vendor/assets/javascripts/nvd3/src/models/lineWithFisheyeChart.js +319 -0
  59. data/vendor/assets/javascripts/nvd3/src/models/lineWithFocusChart.js +560 -0
  60. data/vendor/assets/javascripts/nvd3/src/models/multiBar.js +442 -0
  61. data/vendor/assets/javascripts/nvd3/src/models/multiBarChart.js +506 -0
  62. data/vendor/assets/javascripts/nvd3/src/models/multiBarHorizontal.js +420 -0
  63. data/vendor/assets/javascripts/nvd3/src/models/multiBarHorizontalChart.js +448 -0
  64. data/vendor/assets/javascripts/nvd3/src/models/multiBarTimeSeries.js +371 -0
  65. data/vendor/assets/javascripts/nvd3/src/models/multiBarTimeSeriesChart.js +403 -0
  66. data/vendor/assets/javascripts/nvd3/src/models/multiChart.js +444 -0
  67. data/vendor/assets/javascripts/nvd3/src/models/ohlcBar.js +365 -0
  68. data/vendor/assets/javascripts/nvd3/src/models/parallelCoordinates.js +238 -0
  69. data/vendor/assets/javascripts/nvd3/src/models/pie.js +386 -0
  70. data/vendor/assets/javascripts/nvd3/src/models/pieChart.js +302 -0
  71. data/vendor/assets/javascripts/nvd3/src/models/scatter.js +660 -0
  72. data/vendor/assets/javascripts/nvd3/src/models/scatterChart.js +614 -0
  73. data/vendor/assets/javascripts/nvd3/src/models/scatterPlusLineChart.js +610 -0
  74. data/vendor/assets/javascripts/nvd3/src/models/sparkline.js +179 -0
  75. data/vendor/assets/javascripts/nvd3/src/models/sparklinePlus.js +293 -0
  76. data/vendor/assets/javascripts/nvd3/src/models/stackedArea.js +336 -0
  77. data/vendor/assets/javascripts/nvd3/src/models/stackedAreaChart.js +490 -0
  78. data/vendor/assets/javascripts/nvd3/src/nv.d3.css +704 -0
  79. data/vendor/assets/javascripts/nvd3/src/outro.js +1 -0
  80. data/vendor/assets/javascripts/nvd3/src/tooltip.js +133 -0
  81. data/vendor/assets/javascripts/nvd3/src/utils.js +118 -0
  82. data/vendor/assets/javascripts/set-env.js.erb +1 -0
  83. data/vendor/assets/stylesheets/chartx.css +3 -0
  84. metadata +189 -0
@@ -0,0 +1,685 @@
1
+
2
+ nv.models.cumulativeLineChart = function() {
3
+
4
+ //============================================================
5
+ // Public Variables with Default Settings
6
+ //------------------------------------------------------------
7
+
8
+ var lines = nv.models.line()
9
+ , xAxis = nv.models.axis()
10
+ , yAxis = nv.models.axis()
11
+ , legend = nv.models.legend()
12
+ , controls = nv.models.legend()
13
+ ;
14
+
15
+ var margin = {top: 30, right: 30, bottom: 50, left: 60}
16
+ , color = nv.utils.defaultColor()
17
+ , width = null
18
+ , height = null
19
+ , showLegend = true
20
+ , tooltips = true
21
+ , showControls = true
22
+ , rescaleY = true
23
+ , tooltip = function(key, x, y, e, graph) {
24
+ return '<h3>' + key + '</h3>' +
25
+ '<p>' + y + ' at ' + x + '</p>'
26
+ }
27
+ , x //can be accessed via chart.xScale()
28
+ , y //can be accessed via chart.yScale()
29
+ , id = lines.id()
30
+ , state = { index: 0, rescaleY: rescaleY }
31
+ , defaultState = null
32
+ , noData = 'No Data Available.'
33
+ , average = function(d) { return d.average }
34
+ , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState')
35
+ ;
36
+
37
+ xAxis
38
+ .orient('bottom')
39
+ .tickPadding(7)
40
+ ;
41
+ yAxis
42
+ .orient('left')
43
+ ;
44
+
45
+ //============================================================
46
+
47
+
48
+ //============================================================
49
+ // Private Variables
50
+ //------------------------------------------------------------
51
+
52
+ var dx = d3.scale.linear()
53
+ , index = {i: 0, x: 0}
54
+ ;
55
+
56
+ var showTooltip = function(e, offsetElement) {
57
+ var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
58
+ top = e.pos[1] + ( offsetElement.offsetTop || 0),
59
+ x = xAxis.tickFormat()(lines.x()(e.point, e.pointIndex)),
60
+ y = yAxis.tickFormat()(lines.y()(e.point, e.pointIndex)),
61
+ content = tooltip(e.series.key, x, y, e, chart);
62
+
63
+ nv.tooltip.show([left, top], content, null, null, offsetElement);
64
+ };
65
+
66
+ /*
67
+ //Moved to see if we can get better behavior to fix issue #315
68
+ var indexDrag = d3.behavior.drag()
69
+ .on('dragstart', dragStart)
70
+ .on('drag', dragMove)
71
+ .on('dragend', dragEnd);
72
+
73
+ function dragStart(d,i) {
74
+ d3.select(chart.container)
75
+ .style('cursor', 'ew-resize');
76
+ }
77
+
78
+ function dragMove(d,i) {
79
+ d.x += d3.event.dx;
80
+ d.i = Math.round(dx.invert(d.x));
81
+
82
+ d3.select(this).attr('transform', 'translate(' + dx(d.i) + ',0)');
83
+ chart.update();
84
+ }
85
+
86
+ function dragEnd(d,i) {
87
+ d3.select(chart.container)
88
+ .style('cursor', 'auto');
89
+ chart.update();
90
+ }
91
+ */
92
+
93
+ //============================================================
94
+
95
+
96
+ function chart(selection) {
97
+ selection.each(function(data) {
98
+ var container = d3.select(this).classed('nv-chart-' + id, true),
99
+ that = this;
100
+
101
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
102
+ - margin.left - margin.right,
103
+ availableHeight = (height || parseInt(container.style('height')) || 400)
104
+ - margin.top - margin.bottom;
105
+
106
+
107
+ chart.update = function() { container.transition().call(chart) };
108
+ chart.container = this;
109
+
110
+ //set state.disabled
111
+ state.disabled = data.map(function(d) { return !!d.disabled });
112
+
113
+ if (!defaultState) {
114
+ var key;
115
+ defaultState = {};
116
+ for (key in state) {
117
+ if (state[key] instanceof Array)
118
+ defaultState[key] = state[key].slice(0);
119
+ else
120
+ defaultState[key] = state[key];
121
+ }
122
+ }
123
+
124
+ var indexDrag = d3.behavior.drag()
125
+ .on('dragstart', dragStart)
126
+ .on('drag', dragMove)
127
+ .on('dragend', dragEnd);
128
+
129
+
130
+ function dragStart(d,i) {
131
+ d3.select(chart.container)
132
+ .style('cursor', 'ew-resize');
133
+ }
134
+
135
+ function dragMove(d,i) {
136
+ index.x = d3.event.x;
137
+ index.i = Math.round(dx.invert(index.x));
138
+ updateZero();
139
+ }
140
+
141
+ function dragEnd(d,i) {
142
+ d3.select(chart.container)
143
+ .style('cursor', 'auto');
144
+
145
+ // update state and send stateChange with new index
146
+ state.index = index.i;
147
+ dispatch.stateChange(state);
148
+ }
149
+
150
+
151
+
152
+
153
+ //------------------------------------------------------------
154
+ // Display No Data message if there's nothing to show.
155
+
156
+ if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
157
+ var noDataText = container.selectAll('.nv-noData').data([noData]);
158
+
159
+ noDataText.enter().append('text')
160
+ .attr('class', 'nvd3 nv-noData')
161
+ .attr('dy', '-.7em')
162
+ .style('text-anchor', 'middle');
163
+
164
+ noDataText
165
+ .attr('x', margin.left + availableWidth / 2)
166
+ .attr('y', margin.top + availableHeight / 2)
167
+ .text(function(d) { return d });
168
+
169
+ return chart;
170
+ } else {
171
+ container.selectAll('.nv-noData').remove();
172
+ }
173
+
174
+ //------------------------------------------------------------
175
+
176
+
177
+ //------------------------------------------------------------
178
+ // Setup Scales
179
+
180
+ x = lines.xScale();
181
+ y = lines.yScale();
182
+
183
+
184
+ if (!rescaleY) {
185
+ var seriesDomains = data
186
+ .filter(function(series) { return !series.disabled })
187
+ .map(function(series,i) {
188
+ var initialDomain = d3.extent(series.values, lines.y());
189
+
190
+ //account for series being disabled when losing 95% or more
191
+ if (initialDomain[0] < -.95) initialDomain[0] = -.95;
192
+
193
+ return [
194
+ (initialDomain[0] - initialDomain[1]) / (1 + initialDomain[1]),
195
+ (initialDomain[1] - initialDomain[0]) / (1 + initialDomain[0])
196
+ ];
197
+ });
198
+
199
+ var completeDomain = [
200
+ d3.min(seriesDomains, function(d) { return d[0] }),
201
+ d3.max(seriesDomains, function(d) { return d[1] })
202
+ ]
203
+
204
+ lines.yDomain(completeDomain);
205
+ } else {
206
+ lines.yDomain(null);
207
+ }
208
+
209
+
210
+ dx .domain([0, data[0].values.length - 1]) //Assumes all series have same length
211
+ .range([0, availableWidth])
212
+ .clamp(true);
213
+
214
+ //------------------------------------------------------------
215
+
216
+
217
+ var data = indexify(index.i, data);
218
+
219
+
220
+ //------------------------------------------------------------
221
+ // Setup containers and skeleton of chart
222
+
223
+ var wrap = container.selectAll('g.nv-wrap.nv-cumulativeLine').data([data]);
224
+ var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-cumulativeLine').append('g');
225
+ var g = wrap.select('g');
226
+
227
+ gEnter.append('g').attr('class', 'nv-x nv-axis');
228
+ gEnter.append('g').attr('class', 'nv-y nv-axis');
229
+ gEnter.append('g').attr('class', 'nv-background');
230
+ gEnter.append('g').attr('class', 'nv-linesWrap');
231
+ gEnter.append('g').attr('class', 'nv-avgLinesWrap');
232
+ gEnter.append('g').attr('class', 'nv-legendWrap');
233
+ gEnter.append('g').attr('class', 'nv-controlsWrap');
234
+
235
+ //------------------------------------------------------------
236
+
237
+
238
+ //------------------------------------------------------------
239
+ // Legend
240
+
241
+ if (showLegend) {
242
+ legend.width(availableWidth);
243
+
244
+ g.select('.nv-legendWrap')
245
+ .datum(data)
246
+ .call(legend);
247
+
248
+ if ( margin.top != legend.height()) {
249
+ margin.top = legend.height();
250
+ availableHeight = (height || parseInt(container.style('height')) || 400)
251
+ - margin.top - margin.bottom;
252
+ }
253
+
254
+ g.select('.nv-legendWrap')
255
+ .attr('transform', 'translate(0,' + (-margin.top) +')')
256
+ }
257
+
258
+ //------------------------------------------------------------
259
+
260
+
261
+ //------------------------------------------------------------
262
+ // Controls
263
+
264
+ if (showControls) {
265
+ var controlsData = [
266
+ { key: 'Re-scale y-axis', disabled: !rescaleY }
267
+ ];
268
+
269
+ controls.width(140).color(['#444', '#444', '#444']);
270
+ g.select('.nv-controlsWrap')
271
+ .datum(controlsData)
272
+ .attr('transform', 'translate(0,' + (-margin.top) +')')
273
+ .call(controls);
274
+ }
275
+
276
+ //------------------------------------------------------------
277
+
278
+
279
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
280
+
281
+
282
+ // Show error if series goes below 100%
283
+ var tempDisabled = data.filter(function(d) { return d.tempDisabled });
284
+
285
+ wrap.select('.tempDisabled').remove(); //clean-up and prevent duplicates
286
+ if (tempDisabled.length) {
287
+ wrap.append('text').attr('class', 'tempDisabled')
288
+ .attr('x', availableWidth / 2)
289
+ .attr('y', '-.71em')
290
+ .style('text-anchor', 'end')
291
+ .text(tempDisabled.map(function(d) { return d.key }).join(', ') + ' values cannot be calculated for this time period.');
292
+ }
293
+
294
+ //------------------------------------------------------------
295
+ // Main Chart Component(s)
296
+
297
+ gEnter.select('.nv-background')
298
+ .append('rect');
299
+
300
+ g.select('.nv-background rect')
301
+ .attr('width', availableWidth)
302
+ .attr('height', availableHeight);
303
+
304
+ lines
305
+ //.x(function(d) { return d.x })
306
+ .y(function(d) { return d.display.y })
307
+ .width(availableWidth)
308
+ .height(availableHeight)
309
+ .color(data.map(function(d,i) {
310
+ return d.color || color(d, i);
311
+ }).filter(function(d,i) { return !data[i].disabled && !data[i].tempDisabled; }));
312
+
313
+
314
+
315
+ var linesWrap = g.select('.nv-linesWrap')
316
+ .datum(data.filter(function(d) { return !d.disabled && !d.tempDisabled }));
317
+
318
+ //d3.transition(linesWrap).call(lines);
319
+ linesWrap.call(lines);
320
+
321
+ /*Handle average lines [AN-612] ----------------------------*/
322
+
323
+ //Store a series index number in the data array.
324
+ data.forEach(function(d,i) {
325
+ d.seriesIndex = i;
326
+ });
327
+
328
+ var avgLineData = data.filter(function(d) {
329
+ return !d.disabled && !!average(d);
330
+ });
331
+
332
+ var avgLines = g.select(".nv-avgLinesWrap").selectAll("line")
333
+ .data(avgLineData, function(d) { return d.key; });
334
+
335
+ avgLines.enter()
336
+ .append('line')
337
+ .style('stroke-width',2)
338
+ .style('stroke-dasharray','10,10')
339
+ .style('stroke',function (d,i) {
340
+ return lines.color()(d,d.seriesIndex);
341
+ })
342
+ .attr('x1',0)
343
+ .attr('x2',availableWidth)
344
+ .attr('y1', function(d) { return y(average(d)); })
345
+ .attr('y2', function(d) { return y(average(d)); });
346
+
347
+ avgLines
348
+ .attr('x1',0)
349
+ .attr('x2',availableWidth)
350
+ .attr('y1', function(d) { return y(average(d)); })
351
+ .attr('y2', function(d) { return y(average(d)); });
352
+
353
+ avgLines.exit().remove();
354
+
355
+ //Create index line -----------------------------------------
356
+
357
+ var indexLine = linesWrap.selectAll('.nv-indexLine')
358
+ .data([index]);
359
+ indexLine.enter().append('rect').attr('class', 'nv-indexLine')
360
+ .attr('width', 3)
361
+ .attr('x', -2)
362
+ .attr('fill', 'red')
363
+ .attr('fill-opacity', .5)
364
+ .call(indexDrag)
365
+
366
+ indexLine
367
+ .attr('transform', function(d) { return 'translate(' + dx(d.i) + ',0)' })
368
+ .attr('height', availableHeight)
369
+
370
+ //------------------------------------------------------------
371
+
372
+
373
+ //------------------------------------------------------------
374
+ // Setup Axes
375
+
376
+ xAxis
377
+ .scale(x)
378
+ //Suggest how many ticks based on the chart width and D3 should listen (70 is the optimal number for MM/DD/YY dates)
379
+ .ticks( Math.min(data[0].values.length,availableWidth/70) )
380
+ .tickSize(-availableHeight, 0);
381
+
382
+ g.select('.nv-x.nv-axis')
383
+ .attr('transform', 'translate(0,' + y.range()[0] + ')');
384
+ d3.transition(g.select('.nv-x.nv-axis'))
385
+ .call(xAxis);
386
+
387
+
388
+ yAxis
389
+ .scale(y)
390
+ .ticks( availableHeight / 36 )
391
+ .tickSize( -availableWidth, 0);
392
+
393
+ d3.transition(g.select('.nv-y.nv-axis'))
394
+ .call(yAxis);
395
+
396
+ //------------------------------------------------------------
397
+
398
+
399
+ //============================================================
400
+ // Event Handling/Dispatching (in chart's scope)
401
+ //------------------------------------------------------------
402
+
403
+
404
+ function updateZero() {
405
+ indexLine
406
+ .data([index]);
407
+
408
+ container.call(chart);
409
+ }
410
+
411
+ g.select('.nv-background rect')
412
+ .on('click', function() {
413
+ index.x = d3.mouse(this)[0];
414
+ index.i = Math.round(dx.invert(index.x));
415
+
416
+ // update state and send stateChange with new index
417
+ state.index = index.i;
418
+ dispatch.stateChange(state);
419
+
420
+ updateZero();
421
+ });
422
+
423
+ lines.dispatch.on('elementClick', function(e) {
424
+ index.i = e.pointIndex;
425
+ index.x = dx(index.i);
426
+
427
+ // update state and send stateChange with new index
428
+ state.index = index.i;
429
+ dispatch.stateChange(state);
430
+
431
+ updateZero();
432
+ });
433
+
434
+ controls.dispatch.on('legendClick', function(d,i) {
435
+ d.disabled = !d.disabled;
436
+ rescaleY = !d.disabled;
437
+
438
+ state.rescaleY = rescaleY;
439
+ dispatch.stateChange(state);
440
+
441
+ //selection.transition().call(chart);
442
+ chart.update();
443
+ });
444
+
445
+
446
+ legend.dispatch.on('legendClick', function(d,i) {
447
+ d.disabled = !d.disabled;
448
+
449
+ if (!data.filter(function(d) { return !d.disabled }).length) {
450
+ data.map(function(d) {
451
+ d.disabled = false;
452
+ wrap.selectAll('.nv-series').classed('disabled', false);
453
+ return d;
454
+ });
455
+ }
456
+
457
+ state.disabled = data.map(function(d) { return !!d.disabled });
458
+ dispatch.stateChange(state);
459
+
460
+ //selection.transition().call(chart);
461
+ chart.update();
462
+ });
463
+
464
+ legend.dispatch.on('legendDblclick', function(d) {
465
+ //Double clicking should always enable current series, and disabled all others.
466
+ data.forEach(function(d) {
467
+ d.disabled = true;
468
+ });
469
+ d.disabled = false;
470
+
471
+ state.disabled = data.map(function(d) { return !!d.disabled });
472
+ dispatch.stateChange(state);
473
+ chart.update();
474
+ });
475
+
476
+
477
+ /*
478
+ //
479
+ legend.dispatch.on('legendMouseover', function(d, i) {
480
+ d.hover = true;
481
+ selection.transition().call(chart)
482
+ });
483
+
484
+ legend.dispatch.on('legendMouseout', function(d, i) {
485
+ d.hover = false;
486
+ selection.transition().call(chart)
487
+ });
488
+ */
489
+
490
+ dispatch.on('tooltipShow', function(e) {
491
+ if (tooltips) showTooltip(e, that.parentNode);
492
+ });
493
+
494
+
495
+ // Update chart from a state object passed to event handler
496
+ dispatch.on('changeState', function(e) {
497
+
498
+ if (typeof e.disabled !== 'undefined') {
499
+ data.forEach(function(series,i) {
500
+ series.disabled = e.disabled[i];
501
+ });
502
+
503
+ state.disabled = e.disabled;
504
+ }
505
+
506
+
507
+ if (typeof e.index !== 'undefined') {
508
+ index.i = e.index;
509
+ index.x = dx(index.i);
510
+
511
+ state.index = e.index;
512
+
513
+ indexLine
514
+ .data([index]);
515
+ }
516
+
517
+
518
+ if (typeof e.rescaleY !== 'undefined') {
519
+ rescaleY = e.rescaleY;
520
+ }
521
+
522
+ chart.update();
523
+ });
524
+
525
+ //============================================================
526
+
527
+ });
528
+
529
+ return chart;
530
+ }
531
+
532
+
533
+ //============================================================
534
+ // Event Handling/Dispatching (out of chart's scope)
535
+ //------------------------------------------------------------
536
+
537
+ lines.dispatch.on('elementMouseover.tooltip', function(e) {
538
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
539
+ dispatch.tooltipShow(e);
540
+ });
541
+
542
+ lines.dispatch.on('elementMouseout.tooltip', function(e) {
543
+ dispatch.tooltipHide(e);
544
+ });
545
+
546
+ dispatch.on('tooltipHide', function() {
547
+ if (tooltips) nv.tooltip.cleanup();
548
+ });
549
+
550
+ //============================================================
551
+
552
+
553
+ //============================================================
554
+ // Expose Public Variables
555
+ //------------------------------------------------------------
556
+
557
+ // expose chart's sub-components
558
+ chart.dispatch = dispatch;
559
+ chart.lines = lines;
560
+ chart.legend = legend;
561
+ chart.xAxis = xAxis;
562
+ chart.yAxis = yAxis;
563
+
564
+ d3.rebind(chart, lines, 'defined', 'isArea', 'x', 'y', 'size', 'xDomain', 'yDomain', 'forceX', 'forceY', 'interactive', 'clipEdge', 'clipVoronoi', 'id');
565
+
566
+ chart.margin = function(_) {
567
+ if (!arguments.length) return margin;
568
+ margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
569
+ margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
570
+ margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
571
+ margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
572
+ return chart;
573
+ };
574
+
575
+ chart.width = function(_) {
576
+ if (!arguments.length) return width;
577
+ width = _;
578
+ return chart;
579
+ };
580
+
581
+ chart.height = function(_) {
582
+ if (!arguments.length) return height;
583
+ height = _;
584
+ return chart;
585
+ };
586
+
587
+ chart.color = function(_) {
588
+ if (!arguments.length) return color;
589
+ color = nv.utils.getColor(_);
590
+ legend.color(color);
591
+ return chart;
592
+ };
593
+
594
+ chart.rescaleY = function(_) {
595
+ if (!arguments.length) return rescaleY;
596
+ rescaleY = _
597
+ return rescaleY;
598
+ };
599
+
600
+ chart.showControls = function(_) {
601
+ if (!arguments.length) return showControls;
602
+ showControls = _;
603
+ return chart;
604
+ };
605
+
606
+ chart.showLegend = function(_) {
607
+ if (!arguments.length) return showLegend;
608
+ showLegend = _;
609
+ return chart;
610
+ };
611
+
612
+ chart.tooltips = function(_) {
613
+ if (!arguments.length) return tooltips;
614
+ tooltips = _;
615
+ return chart;
616
+ };
617
+
618
+ chart.tooltipContent = function(_) {
619
+ if (!arguments.length) return tooltip;
620
+ tooltip = _;
621
+ return chart;
622
+ };
623
+
624
+ chart.state = function(_) {
625
+ if (!arguments.length) return state;
626
+ state = _;
627
+ return chart;
628
+ };
629
+
630
+ chart.defaultState = function(_) {
631
+ if (!arguments.length) return defaultState;
632
+ defaultState = _;
633
+ return chart;
634
+ };
635
+
636
+ chart.noData = function(_) {
637
+ if (!arguments.length) return noData;
638
+ noData = _;
639
+ return chart;
640
+ };
641
+
642
+ chart.average = function(_) {
643
+ if(!arguments.length) return average;
644
+ average = _;
645
+ return chart;
646
+ };
647
+
648
+ //============================================================
649
+
650
+
651
+ //============================================================
652
+ // Functions
653
+ //------------------------------------------------------------
654
+
655
+ /* Normalize the data according to an index point. */
656
+ function indexify(idx, data) {
657
+ return data.map(function(line, i) {
658
+ if (!line.values) {
659
+ return line;
660
+ }
661
+ var v = lines.y()(line.values[idx], idx);
662
+
663
+ //TODO: implement check below, and disable series if series loses 100% or more cause divide by 0 issue
664
+ if (v < -.95) {
665
+ //if a series loses more than 100%, calculations fail.. anything close can cause major distortion (but is mathematically correct till it hits 100)
666
+ line.tempDisabled = true;
667
+ return line;
668
+ }
669
+
670
+ line.tempDisabled = false;
671
+
672
+ line.values = line.values.map(function(point, pointIndex) {
673
+ point.display = {'y': (lines.y()(point, pointIndex) - v) / (1 + v) };
674
+ return point;
675
+ })
676
+
677
+ return line;
678
+ })
679
+ }
680
+
681
+ //============================================================
682
+
683
+
684
+ return chart;
685
+ }