Merge pull request #674 from danvk/module
[dygraphs.git] / src / extras / rebase.js
1 /**
2 * @license
3 * Copyright 2015 Petr Shevtsov (petr.shevtsov@gmail.com)
4 * MIT-licensed (http://opensource.org/licenses/MIT)
5 *
6 * Rebase plugin
7 *
8 * On pan/zoom event, each series will rebase to a specified value (e.g. 100) at the
9 * start of the displayed period.
10 *
11 * See http://stats.oecd.org/glossary/detail.asp?ID=2249
12 *
13 * Options:
14 * Value to rebase. Must be either Number or 'percent' or null.
15 *
16 * See tests/straw-broom.html for demo.
17 */
18
19 /*global Dygraph:false */
20
21 (function() {
22
23 "use strict";
24
25 // Matches DefaultHandler.parseFloat
26 var parseFloat = function(val) {
27 if (val === null) return NaN;
28 return val;
29 };
30
31 Dygraph.DataHandlers.RebaseHandler = function(baseOpt) {
32 this.baseOpt = baseOpt;
33 };
34
35 var RebaseHandler = Dygraph.DataHandlers.RebaseHandler;
36 RebaseHandler.prototype = new Dygraph.DataHandlers.DefaultHandler();
37
38 RebaseHandler.rebase = function(value, initial, base) {
39 if (base === "percent") {
40 return (value / initial - 1) * 100;
41 }
42 return value * base / initial;
43 };
44
45 RebaseHandler.prototype.getExtremeYValues = function(series, dateWindow, options) {
46 var minY = null, maxY = null, y;
47 var firstIdx = 0, lastIdx = series.length - 1;
48 var initial = series[firstIdx][1];
49
50 for (var j = firstIdx; j <= lastIdx; j++) {
51 if (j === firstIdx) {
52 y = (this.baseOpt === "percent") ? 0 : this.baseOpt;
53 } else {
54 y = RebaseHandler.rebase(series[j][1], initial, this.baseOpt);
55 }
56 if (y === null || isNaN(y))
57 continue;
58 if (maxY === null || y > maxY) {
59 maxY = y;
60 }
61 if (minY === null || y < minY) {
62 minY = y;
63 }
64 }
65 return [ minY, maxY ];
66 };
67
68 RebaseHandler.prototype.seriesToPoints = function(series, setName, boundaryIdStart){
69 var points = [];
70 var firstIdx = 0;
71 var lastIdx = series.length - 1;
72 var initial = series[firstIdx][1]; // TODO: check for null
73 for (var i = 0; i <= lastIdx; ++i) {
74 var item = series[i];
75 var yraw = item[1];
76 var yval = yraw === null ? null : parseFloat(yraw);
77 if (yval !== null) {
78 if (i === firstIdx) {
79 yval = (this.baseOpt === "percent") ? 0 : this.baseOpt;
80 } else {
81 yval = RebaseHandler.rebase(yval, initial, this.baseOpt);
82 }
83 }
84 var point = {
85 x: NaN,
86 y: NaN,
87 xval: parseFloat(item[0]),
88 yval: yval,
89 name: setName,
90 idx: i + boundaryIdStart
91 };
92 points.push(point);
93 }
94 this.onPointsCreated_(series, points);
95 return points;
96 };
97
98 Dygraph.Plugins.Rebase = (function() {
99 var rebase = function(baseOpt) {
100 var isNum = function(v) {
101 return !isNaN(v) && (typeof v === 'number' || {}.toString.call(v) === '[object Number]');
102 };
103 if (baseOpt === "percent" || isNum(baseOpt)) {
104 this.baseOpt_ = baseOpt;
105 } else {
106 this.baseOpt_ = null;
107 }
108 };
109
110 rebase.prototype.toString = function() {
111 return "Rebase Plugin";
112 };
113
114 rebase.prototype.activate = function(g) {
115 if (this.baseOpt_ === null) {
116 return;
117 }
118 return {
119 predraw: this.predraw
120 };
121 };
122
123 rebase.prototype.predraw = function(e) {
124 var g = e.dygraph;
125
126 if (this.baseOpt_ === "percent") {
127 g.updateOptions({
128 axes: {
129 y: {
130 axisLabelFormatter: function(y) {
131 return y + '%';
132 },
133 valueFormatter: function(y) {
134 return Math.round(y * 100) / 100 + '%';
135 }
136 }
137 }
138 }, true);
139 }
140
141 g.dataHandler_ = new Dygraph.DataHandlers.RebaseHandler(this.baseOpt_);
142 };
143
144 return rebase;
145 })();
146 })();