From ccdb23bdb9b28d19a489bf989198310f174343ab Mon Sep 17 00:00:00 2001 From: Hallo89 Date: Sun, 11 Nov 2018 16:05:49 +0100 Subject: [PATCH] initial commit --- slider89.css | 55 +++++++++++++++ slider89.js | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 241 insertions(+) create mode 100644 slider89.css create mode 100644 slider89.js diff --git a/slider89.css b/slider89.css new file mode 100644 index 0000000..a757a2f --- /dev/null +++ b/slider89.css @@ -0,0 +1,55 @@ +.slider89 { + display: inline-block; +} +.slider89 .slider { + position: relative; + padding: 0; + background-color: hsl(0, 0%, 19%); + font-family: monospace; + font-size: 18px; + font-weight: bold; + height: 25px; +} +.slider89 .slider_knob { + position: absolute; + cursor: pointer; + left: 0; + height: 25px; + width: 14px; + background-color: hsl(0, 0%, 27%); + z-index: 1; +} +.slider89 .slider_tooltip { + position: absolute; + display: flex; + align-items: center; + padding: 1px 3px 0; + color: hsl(0, 0%, 45%); + height: 100%; + cursor: default; + opacity: 1; + transition: .2s ease-out; +} +.slider89 .slider_tooltip.left { + left: 0; +} +.slider89 .slider_tooltip.right { + right: 0; +} +.slider89 .slider_tooltip.hidden { + opacity: 0; +} + +.slider_header { + color: hsl(0, 0%, 70%); + font-family: 'Calibri', serif; + font-size: 20px; + display: block; +} + +.noselect { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} diff --git a/slider89.js b/slider89.js new file mode 100644 index 0000000..3f8cbc8 --- /dev/null +++ b/slider89.js @@ -0,0 +1,186 @@ +function Slider89(target, values = {}) { + //Define the attributes of the object instance + this.absWidth = values.absWidth != null ? values.absWidth : slider89.absWidth; + this.min = values.min != null ? values.min : slider89.min; + this.max = values.max != null ? values.max : slider89.max; + this.value = values.value != null ? values.value : slider89.value; + this.comma = values.comma != null ? values.comma : slider89.comma; + this.width = this.computeWidth(values) || this.computeWidth(slider89) + this.caption = values.caption || slider89.caption; + this.trimComma = values.trimComma != null ? values.trimComma : slider89.trimComma; + this.tipDuration = values.tipDuration != null ? values.tipDuration : slider89.tipDuration; + this.classList = values.classList || slider89.classList; + if (this.width == 'auto') { + this.width + } + if (values.task) { + this.setTask(this, values.task); + } else if (slider89.task) { + this.task = slider89.task; + } + + this.taskLock = false; + this.tipTimer; + + //Call buildElement parsing the target (element for the slider to be created in / to be replaced with) to build the slider + this.element = this.buildElement(target, values.replaceNode != null ? values.replaceNode : slider89.replaceNode); + + //Write 'this' into a carrier-variable and attach the needed event listeners + let obj = this + this.element.children[0].addEventListener('mousedown', function(e) { + document.body.classList.add('noselect'); + obj.executeSlider(e.x); + window.addEventListener('mousemove', obj.mouseMove); + }); + //On mouse up, removet the mouse move listener which was added on mouse down + window.addEventListener('mouseup', function() { + document.body.classList.remove('noselect'); + window.removeEventListener('mousemove', obj.mouseMove); + }); + //The function executed by the mousemove listener. Needs to be here in order to reach 'obj' + this.mouseMove = function(e) { + obj.executeSlider(e.x) + } +} + +Slider89.prototype.computeWidth = function(method) { + return method.width == 'auto' ? this.max - this.min + 14 : method.width + 14 * !this.absWidth; +} + +Slider89.prototype.setTask = function(target, task) { + if (typeof task == 'function') { + target.task = task; + } else if (typeof task != 'function') { + console.error('Slider89 error: specified task \'' + task + '\' is not a function.\nContinuing without a task.'); + } +} + +Slider89.prototype.newValues = function(newValues = {}) { + this.absWidth = newValues.absWidth != null ? newValues.absWidth : this.absWidth; + this.value = newValues.value ? newValues.value : ((newValues.max || this.max) - (newValues.min || this.min)) * this.value / (this.max - this.min) || this.value; + this.min = newValues.min || this.min; + this.max = newValues.max || this.max; + this.comma = newValues.comma || this.comma; + this.width = this.computeWidth(newValues) || this.width; + if (newValues.caption) { + this.caption = newValues.caption; + this.element.children[1].innerHTML = this.caption; + } + this.trimComma = newValues.trimComma != null ? newValues.trimComma : this.trimComma; + this.tipDuration = newValues.tipDuration != null ? newValues.tipDuration : this.tipDuration; + if (newValues.classList) { + this.classList = newValues.classList; + for (var i = 0; i < this.classList.length; i++) { + this.element.classList.add(this.classList[i]); + } + } + if (newValues.task) { + this.setTask(newValues.task); + } + + if (newValues.width && newValues.width != 'auto') { + this.element.children[0].style.width = this.width + 'px'; + } +} + +//Build the slider inside the specified target element and return it as element +Slider89.prototype.buildElement = function(target, replace) { + let node = document.createElement('div'); + node.classList.add('slider89'); + node.innerHTML = ` +
+ + +
+ ${this.caption} + `; + for (var i = 0; i < this.classList.length; i++) { + node.classList.add(this.classList[i]); + } + if (replace) { + target.parentNode.replaceChild(node, target); + } else { + target.appendChild(node); + } + return node; +} + +Slider89.prototype.executeSlider = function(clickedX) { + let node = this.element.children[0]; + let rect = node.getBoundingClientRect(); + let tip = node.children[1]; + let finalValue; + let distance = clickedX - rect.left - 7; + if (distance < 0) { + distance = 0; + } else if (distance > rect.width - 14) { + distance = rect.width - 14; + } + distance = Math.round(distance); + //set the value tooltip; if nothing has happened for the time the user has defined (default 250ms), hide it + clearTimeout(this.tipTimer); + tip.classList.remove('hidden'); + this.tipTimer = setTimeout(function() { + tip.classList.add('hidden'); + }, this.tipDuration); + //translate the slider knob + node.children[0].style.transform = 'translateX(' + distance + 'px)'; + //compute the final value + finalValue = (this.max - this.min) * distance / (rect.width - 14) + this.min; + //limit the amount of figures after comma accordingly to the value + if (this.trimComma) { + finalValue = Number(finalValue.toFixed(this.comma)); + tip.innerHTML = finalValue; + } else { + finalValue = finalValue.toFixed(this.comma); + tip.innerHTML = finalValue; + finalValue = Number(finalValue); + } + //If nothing has changed, stop + if (this.value == finalValue) { + if (!this.taskLock && this.task != null) { + (this.task)(); + this.taskLock = true; + } + return; + } + this.taskLock = false; + if (this.task != null) { + (this.task)(); + } + //Update value + this.value = finalValue; + //Change the positioning of the tooltip accordingly to the position of the slider knob + if (distance >= rect.width - tip.clientWidth - 14 && tip.classList.contains('right') || distance <= tip.clientWidth && tip.classList.contains('left')) { + tip.classList.toggle('right'); + tip.classList.toggle('left'); + } +} + +var slider89 = { + absWidth: false, + min: 0, + max: 100, + value: 0, + comma: 0, + width: 'auto', + caption: '', + trimComma: true, + tipDuration: 250, + classList: [], + replaceNode: false, + defaultValues: function(defValues) { + if (defValues.absWidth != null) this.absWidth = defValues.absWidth; + if (defValues.min != null) this.min = defValues.min; + if (defValues.max != null) this.max = defValues.max; + if (defValues.value != null) this.value = defValues.value; + if (defValues.comma != null) this.comma = defValues.comma; + if (defValues.width != null) this.width = defValues.width; + if (defValues.caption) this.caption = defValues.caption; + if (defValues.trimComma != null) this.trimComma = defValues.trimComma; + if (defValues.tipDuration != null) this.tipDuration = defValues.tipDuration; + if (defValues.classList) this.classList = defValues.classList; + if (defValues.replaceNode != null) this.replaceNode = defValues.replaceNode; + if (defValues.task) Slider89.prototype.setTask(this, defValues.task); + } +}