UNPKG

4.75 kBJavaScriptView Raw
1const _ETA = require('./eta');
2const _Terminal = require('./terminal');
3const _formatter = require('./formatter');
4const _EventEmitter = require('events');
5
6// Progress-Bar constructor
7module.exports = class GenericBar extends _EventEmitter{
8
9 constructor(options){
10 super();
11
12 // store options
13 this.options = options;
14
15 // store terminal instance
16 this.terminal = (this.options.terminal) ? this.options.terminal : new _Terminal(this.options.stream);
17
18 // the current bar value
19 this.value = 0;
20
21 // the end value of the bar
22 this.total = 100;
23
24 // last drawn string - only render on change!
25 this.lastDrawnString = null;
26
27 // start time (used for eta calculation)
28 this.startTime = null;
29
30 // last update time
31 this.lastRedraw = Date.now();
32
33 // default eta calulator (will be re-create on start)
34 this.eta = new _ETA(this.options.etaBufferLength, 0, 0);
35
36 // payload data
37 this.payload = {};
38
39 // progress bar active ?
40 this.isActive = false;
41
42 // use default formatter or custom one ?
43 this.formatter = (typeof this.options.format === 'function') ? this.options.format : _formatter;
44 }
45
46 // internal render function
47 render(){
48 // calculate the normalized current progress
49 let progress = (this.value/this.total);
50
51 // handle NaN Errors caused by total=0. Set to complete in this case
52 if (isNaN(progress)){
53 progress = (this.options && this.options.emptyOnZero) ? 0.0 : 1.0;
54 }
55
56 // limiter
57 progress = Math.min(Math.max(progress, 0.0), 1.0);
58
59 // formatter params
60 const params = {
61 progress: progress,
62 eta: this.eta.getTime(),
63 startTime: this.startTime,
64 total: this.total,
65 value: this.value,
66 maxWidth: this.terminal.getWidth()
67 };
68
69 // format string
70 const s = this.formatter(this.options, params, this.payload);
71
72 const forceRedraw = this.options.forceRedraw
73 // force redraw in notty-mode!
74 || (this.options.noTTYOutput && !this.terminal.isTTY());
75
76 // string changed ? only trigger redraw on change!
77 if (forceRedraw || this.lastDrawnString != s){
78 // trigger event
79 this.emit('redraw-pre');
80
81 // set cursor to start of line
82 this.terminal.cursorTo(0, null);
83
84 // write output
85 this.terminal.write(s);
86
87 // clear to the right from cursor
88 this.terminal.clearRight();
89
90 // store string
91 this.lastDrawnString = s;
92
93 // set last redraw time
94 this.lastRedraw = Date.now();
95
96 // trigger event
97 this.emit('redraw-post');
98 }
99 }
100
101 // start the progress bar
102 start(total, startValue, payload){
103 // set initial values
104 this.value = startValue || 0;
105 this.total = (typeof total !== 'undefined' && total >= 0) ? total : 100;
106 this.payload = payload || {};
107
108 this.startTime = Date.now();
109 this.lastDrawnString = '';
110
111 // initialize eta buffer
112 this.eta = new _ETA(this.options.etaBufferLength, this.startTime, this.value);
113
114 // set flag
115 this.isActive = true;
116
117 // start event
118 this.emit('start', total, startValue);
119 }
120
121 // stop the bar
122 stop(){
123 // set flag
124 this.isActive = false;
125
126 // stop event
127 this.emit('stop', this.total, this.value);
128 }
129
130 // update the bar value
131 update(current, payload){
132 if (typeof current !== 'undefined' && current !== null) {
133 // update value
134 this.value = current;
135
136 // add new value; recalculate eta
137 this.eta.update(Date.now(), current, this.total);
138 }
139
140 // update event (before stop() is called)
141 this.emit('update', this.total, this.value);
142
143 // merge payload
144 const payloadData = payload || {};
145 for (const key in payloadData){
146 this.payload[key] = payloadData[key];
147 }
148
149 // limit reached ? autostop set ?
150 if (this.value >= this.getTotal() && this.options.stopOnComplete) {
151 this.stop();
152 }
153 }
154
155 // update the bar value
156 increment(step, payload){
157 step = step || 1;
158 this.update(this.value + step, payload);
159 }
160
161 // get the total (limit) value
162 getTotal(){
163 return this.total;
164 }
165
166 // set the total (limit) value
167 setTotal(total){
168 if (typeof total !== 'undefined' && total >= 0){
169 this.total = total;
170 }
171 }
172}