UNPKG

8.84 kBJavaScriptView Raw
1var util = require('vis-util');
2
3/**
4 * An html slider control with start/stop/prev/next buttons
5 *
6 * @constructor Slider
7 * @param {Element} container The element where the slider will be created
8 * @param {Object} options Available options:
9 * {boolean} visible If true (default) the
10 * slider is visible.
11 */
12function Slider(container, options) {
13 if (container === undefined) {
14 throw new Error('No container element defined');
15 }
16 this.container = container;
17 this.visible = (options && options.visible != undefined) ? options.visible : true;
18
19 if (this.visible) {
20 this.frame = document.createElement('DIV');
21 //this.frame.style.backgroundColor = '#E5E5E5';
22 this.frame.style.width = '100%';
23 this.frame.style.position = 'relative';
24 this.container.appendChild(this.frame);
25
26 this.frame.prev = document.createElement('INPUT');
27 this.frame.prev.type = 'BUTTON';
28 this.frame.prev.value = 'Prev';
29 this.frame.appendChild(this.frame.prev);
30
31 this.frame.play = document.createElement('INPUT');
32 this.frame.play.type = 'BUTTON';
33 this.frame.play.value = 'Play';
34 this.frame.appendChild(this.frame.play);
35
36 this.frame.next = document.createElement('INPUT');
37 this.frame.next.type = 'BUTTON';
38 this.frame.next.value = 'Next';
39 this.frame.appendChild(this.frame.next);
40
41 this.frame.bar = document.createElement('INPUT');
42 this.frame.bar.type = 'BUTTON';
43 this.frame.bar.style.position = 'absolute';
44 this.frame.bar.style.border = '1px solid red';
45 this.frame.bar.style.width = '100px';
46 this.frame.bar.style.height = '6px';
47 this.frame.bar.style.borderRadius = '2px';
48 this.frame.bar.style.MozBorderRadius = '2px';
49 this.frame.bar.style.border = '1px solid #7F7F7F';
50 this.frame.bar.style.backgroundColor = '#E5E5E5';
51 this.frame.appendChild(this.frame.bar);
52
53 this.frame.slide = document.createElement('INPUT');
54 this.frame.slide.type = 'BUTTON';
55 this.frame.slide.style.margin = '0px';
56 this.frame.slide.value = ' ';
57 this.frame.slide.style.position = 'relative';
58 this.frame.slide.style.left = '-100px';
59 this.frame.appendChild(this.frame.slide);
60
61 // create events
62 var me = this;
63 this.frame.slide.onmousedown = function (event) {me._onMouseDown(event);};
64 this.frame.prev.onclick = function (event) {me.prev(event);};
65 this.frame.play.onclick = function (event) {me.togglePlay(event);};
66 this.frame.next.onclick = function (event) {me.next(event);};
67 }
68
69 this.onChangeCallback = undefined;
70
71 this.values = [];
72 this.index = undefined;
73
74 this.playTimeout = undefined;
75 this.playInterval = 1000; // milliseconds
76 this.playLoop = true;
77}
78
79/**
80 * Select the previous index
81 */
82Slider.prototype.prev = function() {
83 var index = this.getIndex();
84 if (index > 0) {
85 index--;
86 this.setIndex(index);
87 }
88};
89
90/**
91 * Select the next index
92 */
93Slider.prototype.next = function() {
94 var index = this.getIndex();
95 if (index < this.values.length - 1) {
96 index++;
97 this.setIndex(index);
98 }
99};
100
101/**
102 * Select the next index
103 */
104Slider.prototype.playNext = function() {
105 var start = new Date();
106
107 var index = this.getIndex();
108 if (index < this.values.length - 1) {
109 index++;
110 this.setIndex(index);
111 }
112 else if (this.playLoop) {
113 // jump to the start
114 index = 0;
115 this.setIndex(index);
116 }
117
118 var end = new Date();
119 var diff = (end - start);
120
121 // calculate how much time it to to set the index and to execute the callback
122 // function.
123 var interval = Math.max(this.playInterval - diff, 0);
124 // document.title = diff // TODO: cleanup
125
126 var me = this;
127 this.playTimeout = setTimeout(function() {me.playNext();}, interval);
128};
129
130/**
131 * Toggle start or stop playing
132 */
133Slider.prototype.togglePlay = function() {
134 if (this.playTimeout === undefined) {
135 this.play();
136 } else {
137 this.stop();
138 }
139};
140
141/**
142 * Start playing
143 */
144Slider.prototype.play = function() {
145 // Test whether already playing
146 if (this.playTimeout) return;
147
148 this.playNext();
149
150 if (this.frame) {
151 this.frame.play.value = 'Stop';
152 }
153};
154
155/**
156 * Stop playing
157 */
158Slider.prototype.stop = function() {
159 clearInterval(this.playTimeout);
160 this.playTimeout = undefined;
161
162 if (this.frame) {
163 this.frame.play.value = 'Play';
164 }
165};
166
167/**
168 * Set a callback function which will be triggered when the value of the
169 * slider bar has changed.
170 *
171 * @param {function} callback
172 */
173Slider.prototype.setOnChangeCallback = function(callback) {
174 this.onChangeCallback = callback;
175};
176
177/**
178 * Set the interval for playing the list
179 * @param {number} interval The interval in milliseconds
180 */
181Slider.prototype.setPlayInterval = function(interval) {
182 this.playInterval = interval;
183};
184
185/**
186 * Retrieve the current play interval
187 * @return {number} interval The interval in milliseconds
188 */
189Slider.prototype.getPlayInterval = function() {
190 return this.playInterval;
191};
192
193/**
194 * Set looping on or off
195 * @param {boolean} doLoop If true, the slider will jump to the start when
196 * the end is passed, and will jump to the end
197 * when the start is passed.
198 *
199 */
200Slider.prototype.setPlayLoop = function(doLoop) {
201 this.playLoop = doLoop;
202};
203
204
205/**
206 * Execute the onchange callback function
207 */
208Slider.prototype.onChange = function() {
209 if (this.onChangeCallback !== undefined) {
210 this.onChangeCallback();
211 }
212};
213
214/**
215 * redraw the slider on the correct place
216 */
217Slider.prototype.redraw = function() {
218 if (this.frame) {
219 // resize the bar
220 this.frame.bar.style.top = (this.frame.clientHeight/2 -
221 this.frame.bar.offsetHeight/2) + 'px';
222 this.frame.bar.style.width = (this.frame.clientWidth -
223 this.frame.prev.clientWidth -
224 this.frame.play.clientWidth -
225 this.frame.next.clientWidth - 30) + 'px';
226
227 // position the slider button
228 var left = this.indexToLeft(this.index);
229 this.frame.slide.style.left = (left) + 'px';
230 }
231};
232
233
234/**
235 * Set the list with values for the slider
236 * @param {Array} values A javascript array with values (any type)
237 */
238Slider.prototype.setValues = function(values) {
239 this.values = values;
240
241 if (this.values.length > 0)
242 this.setIndex(0);
243 else
244 this.index = undefined;
245};
246
247/**
248 * Select a value by its index
249 * @param {number} index
250 */
251Slider.prototype.setIndex = function(index) {
252 if (index < this.values.length) {
253 this.index = index;
254
255 this.redraw();
256 this.onChange();
257 }
258 else {
259 throw new Error('Index out of range');
260 }
261};
262
263/**
264 * retrieve the index of the currently selected vaue
265 * @return {number} index
266 */
267Slider.prototype.getIndex = function() {
268 return this.index;
269};
270
271
272/**
273 * retrieve the currently selected value
274 * @return {*} value
275 */
276Slider.prototype.get = function() {
277 return this.values[this.index];
278};
279
280
281Slider.prototype._onMouseDown = function(event) {
282 // only react on left mouse button down
283 var leftButtonDown = event.which ? (event.which === 1) : (event.button === 1);
284 if (!leftButtonDown) return;
285
286 this.startClientX = event.clientX;
287 this.startSlideX = parseFloat(this.frame.slide.style.left);
288
289 this.frame.style.cursor = 'move';
290
291 // add event listeners to handle moving the contents
292 // we store the function onmousemove and onmouseup in the graph, so we can
293 // remove the eventlisteners lateron in the function mouseUp()
294 var me = this;
295 this.onmousemove = function (event) {me._onMouseMove(event);};
296 this.onmouseup = function (event) {me._onMouseUp(event);};
297 util.addEventListener(document, 'mousemove', this.onmousemove);
298 util.addEventListener(document, 'mouseup', this.onmouseup);
299 util.preventDefault(event);
300};
301
302
303Slider.prototype.leftToIndex = function (left) {
304 var width = parseFloat(this.frame.bar.style.width) -
305 this.frame.slide.clientWidth - 10;
306 var x = left - 3;
307
308 var index = Math.round(x / width * (this.values.length-1));
309 if (index < 0) index = 0;
310 if (index > this.values.length-1) index = this.values.length-1;
311
312 return index;
313};
314
315Slider.prototype.indexToLeft = function (index) {
316 var width = parseFloat(this.frame.bar.style.width) -
317 this.frame.slide.clientWidth - 10;
318
319 var x = index / (this.values.length-1) * width;
320 var left = x + 3;
321
322 return left;
323};
324
325
326
327Slider.prototype._onMouseMove = function (event) {
328 var diff = event.clientX - this.startClientX;
329 var x = this.startSlideX + diff;
330
331 var index = this.leftToIndex(x);
332
333 this.setIndex(index);
334
335 util.preventDefault();
336};
337
338
339Slider.prototype._onMouseUp = function (event) { // eslint-disable-line no-unused-vars
340 this.frame.style.cursor = 'auto';
341
342 // remove event listeners
343 util.removeEventListener(document, 'mousemove', this.onmousemove);
344 util.removeEventListener(document, 'mouseup', this.onmouseup);
345
346 util.preventDefault();
347};
348
349module.exports = Slider;