UNPKG

4.41 kBJavaScriptView Raw
1'use strict';
2
3var INC = 'inc';
4var DEC = 'dec';
5
6/*
7conf: {
8 max: [number],
9 min: [number],
10 interval: [number], // update interval
11 step: [number], // update step e.g. is step = 2, it will inc/dec 2 every interval
12 type: [string], // inc: increment, dec: decrement
13 init: [number], // cannot be greater than max and smaller than min
14 lastUpdate: [*number] // an optional timestamp to conrtol last update state
15}
16*/
17function TimedNumber(conf) {
18 this.validate(conf);
19 this.conf = conf;
20 this.current = this.conf.init;
21 this.lastUpdate = this.conf.lastUpdate || Date.now();
22}
23
24// public
25TimedNumber.prototype.getValue = function () {
26 switch (this.conf.type) {
27 case INC:
28 return this.calculateCurrentValueForInc();
29 case DEC:
30 return this.calculateCurrentValueForDec();
31 }
32};
33
34// public
35TimedNumber.prototype.inc = function (value) {
36 if (!value || isNaN(value)) {
37 return false;
38 }
39 if (this.current + value > this.conf.max) {
40 return false;
41 }
42
43 if (this.current === this.conf.init) {
44 // initial mod
45 this.lastUpdate = Date.now();
46 }
47
48 // if type is inc, increasing means recovering
49 this.current += value;
50
51 this.lastUpdate = Date.now();
52
53 return true;
54};
55
56// public
57TimedNumber.prototype.dec = function (value) {
58 if (!value || isNaN(value)) {
59 return false;
60 }
61 if (this.current - value < this.conf.min) {
62 return false;
63 }
64
65 if (this.current === this.conf.init) {
66 // initial mod
67 this.lastUpdate = Date.now();
68 }
69
70 // if type is dec, decreasing means recovering
71 this.current -= value;
72
73 this.lastUpdate = Date.now();
74
75 return true;
76};
77
78// public
79TimedNumber.prototype.reset = function () {
80 this.current = this.conf.init;
81 this.lastUpdate = Date.now();
82};
83
84// public
85TimedNumber.prototype.getMaxValue = function () {
86 return this.conf.max;
87};
88
89// public
90TimedNumber.prototype.getMinValue = function () {
91 return this.conf.min;
92};
93
94// public
95TimedNumber.prototype.getInterval = function () {
96 return this.conf.interval;
97};
98
99// public
100TimedNumber.prototype.getStep = function () {
101 return this.conf.step;
102};
103
104// public
105TimedNumber.prototype.getLastUpdate = function () {
106 return this.lastUpdate;
107};
108
109// public
110TimedNumber.prototype.toObject = function () {
111 var obj = {};
112 obj.current = this.current;
113 obj.lastUpdate = this.lastUpdate;
114 for (var key in this.conf) {
115 obj[key] = this.conf[key];
116 }
117 return obj;
118};
119
120// private
121TimedNumber.prototype.validate = function (conf) {
122 if (!conf.hasOwnProperty('max') || isNaN(conf.max)) {
123 throw new Error('invalid max: ' + conf.max);
124 }
125 if (!conf.hasOwnProperty('min') || isNaN(conf.min) || conf.min >= conf.max) {
126 throw new Error('invalid min: ' + conf.min);
127 }
128 if (!conf.hasOwnProperty('interval') || isNaN(conf.interval) || conf.interval <= 0) {
129 throw new Error('invalid interval: ' + conf.interval);
130 }
131 if (!conf.hasOwnProperty('type') || (conf.type !== INC && conf.type !== DEC)) {
132 throw new Error('invalid type: ' + conf.type);
133 }
134 if (!conf.hasOwnProperty('init') || isNaN(conf.init) || conf.init <= 0) {
135 throw new Error('invalid init: ' + conf.init);
136 }
137 if (!conf.hasOwnProperty('step') || isNaN(conf.step) || conf.step <= 0) {
138 throw new Error('invalid step: ' + conf.step);
139 }
140 if (conf.type === INC && conf.step > conf.max) {
141 throw new Error('step must not be greater than max');
142 }
143 if (conf.type === DEC && conf.step < conf.min) {
144 throw new Error('step must not be smaller than min');
145 }
146};
147
148// private
149TimedNumber.prototype.calculateCurrentValueForInc = function () {
150 if (this.current === this.conf.max) {
151 return this.current;
152 }
153 var now = Date.now();
154 var timePast = now - this.lastUpdate;
155 var steps = Math.floor(timePast / this.conf.interval);
156 var incValue = this.conf.step * steps;
157 this.current = (this.current + incValue <= this.conf.max) ? this.current + incValue : this.conf.max;
158 if (incValue) {
159 this.lastUpdate = now;
160 }
161 return this.current;
162};
163
164// private
165TimedNumber.prototype.calculateCurrentValueForDec = function () {
166 if (this.current === this.conf.min) {
167 return this.current;
168 }
169 var now = Date.now();
170 var timePast = now - this.lastUpdate;
171 var steps = Math.floor(timePast / this.conf.interval);
172 var decValue = this.conf.step * steps;
173 this.current = (this.current - decValue >= this.conf.min) ? this.current - decValue : this.conf.min;
174 if (decValue) {
175 this.lastUpdate = now;
176 }
177 return this.current;
178};
179
180module.exports = TimedNumber;
181