From 7c50b750994782ff5f159686c17436456fddeac8 Mon Sep 17 00:00:00 2001 From: Arno Kaimbacher Date: Fri, 8 Jan 2021 16:35:26 +0100 Subject: [PATCH] - touchable RengeSlider.js and RangeSlider.css - addition utility methods - domEvent.js: add multiple handler with one initialization --- src/js/controls/SliderControl.js | 4 +- src/js/core/RangeSlider.css | 3 +- src/js/core/RangeSlider.js | 162 ++++++++++++++++++++----------- src/js/core/domEvent.js | 129 ++++++++---------------- src/js/core/utilities.js | 19 +++- 5 files changed, 168 insertions(+), 149 deletions(-) diff --git a/src/js/controls/SliderControl.js b/src/js/controls/SliderControl.js index 4634443..1d98aca 100644 --- a/src/js/controls/SliderControl.js +++ b/src/js/controls/SliderControl.js @@ -1,7 +1,6 @@ import { Control } from "./Control"; import * as dom from '../core/domUtil'; import * as util from '../core/utilities'; -import * as domEvent from '../core/domEvent'; import { RangeSlider } from '../core/RangeSlider'; import './SliderControl.css'; @@ -79,13 +78,14 @@ export class SliderControl extends Control { // this.slider.setAttribute("step", this.options.step); // this.slider.setAttribute("value", this.options.value); - this.slider = new RangeSlider(this._sliderContainer, { + this.slider = new RangeSlider({ orientation: "vertical", value: 1, max: 5, min: 1, inverse: true, id: "z-slider" }); + this.slider.addTo(this._sliderContainer); //if (this.options.syncSlider) { // L.DomEvent.on(this.slider, "input", function (e) { diff --git a/src/js/core/RangeSlider.css b/src/js/core/RangeSlider.css index 3096e16..c7e9a0d 100644 --- a/src/js/core/RangeSlider.css +++ b/src/js/core/RangeSlider.css @@ -7,7 +7,8 @@ .slider.slider-vertical { height: 160px; - width: 30px; + width: 35px; + z-index: 9; } .slider.slider-vertical .range-slider-track { diff --git a/src/js/core/RangeSlider.js b/src/js/core/RangeSlider.js index b87cb30..abe9b80 100644 --- a/src/js/core/RangeSlider.js +++ b/src/js/core/RangeSlider.js @@ -1,7 +1,8 @@ import { EventEmitter } from './EventEmitter'; -import * as dom from '../core/domUtil'; -import * as util from '../core/utilities'; -import * as domEvent from '../core/domEvent'; +import * as dom from './domUtil'; +import * as util from './utilities'; +import * as domEvent from './domEvent'; +import * as browser from './browser'; import './RangeSlider.css'; @@ -9,6 +10,7 @@ class RangeSlider extends EventEmitter { over = false; inDrag = false; + touchCapable = false; options = { value: 0, // set default value on initiation from `0` to `100` (percentage based) @@ -22,16 +24,21 @@ class RangeSlider extends EventEmitter { stepSize: 1 }; - constructor(elem, options) { + constructor(options) { super(); util.setOptions(this, options); this.value = this.options.value; - this.element = elem; + if (browser.touch && browser.mobile) { + this.touchCapable = true; + } + } + addTo(parentDiv) { //this._initLayout(); - this.picker = dom.createDom("div", { + this.element = parentDiv; + this.template = dom.createDom("div", { "class": 'slider', innerHTML: '
' + '
' + @@ -41,24 +48,23 @@ class RangeSlider extends EventEmitter { '
' + '
' - }, this.element); + }, parentDiv); - this.id = this.options.id; - // var tooltip = this.options.tooltip; - this.tooltip = this.picker.getElementsByClassName('tooltip')[0]; + this.id = this.options.id; + this.tooltip = this.template.getElementsByClassName('tooltip')[0]; this.tooltipInner = this.tooltip.getElementsByClassName('tooltip-inner')[0]; - this.sliderTrack = this.picker.getElementsByClassName('range-slider-track')[0]; - this.sliderTicks = this.picker.getElementsByClassName('slider-ticks')[0]; + this.sliderTrack = this.template.getElementsByClassName('range-slider-track')[0]; + this.sliderTicks = this.template.getElementsByClassName('slider-ticks')[0]; this.orientation = this.options.orientation; if (this.orientation === "horizontal") { - dom.addClass(this.picker, "slider-horizontal"); - //.addClass('slider-horizontal') + dom.addClass(this.template, "slider-horizontal"); + //.css('width', this.element.outerWidth()); - //$(this.picker).css('width', $(this.element).outerWidth()); - //this.picker.style.width = this.element['offsetWidth'] + 'px'; + //$(this.template).css('width', $(this.element).outerWidth()); + //this.template.style.width = this.element['offsetWidth'] + 'px'; this.orientation = 'horizontal'; this.stylePos = 'left'; this.mousePos = 'pageX'; @@ -67,11 +73,10 @@ class RangeSlider extends EventEmitter { dom.addClass(this.tooltip, "top"); this.tooltip.style.top = -this.tooltip['offsetHeight'] - 14 + 'px'; } else { - dom.addClass(this.picker, "slider-vertical"); + dom.addClass(this.template, "slider-vertical"); this.stylePos = 'top'; this.mousePos = 'pageY'; - this.sizePos = 'offsetHeight'; - // this.tooltip.addClass('right')[0].style.left = '100%'; + this.sizePos = 'offsetHeight'; dom.addClass(this.tooltip, "right"); this.tooltip.style.left = "100%"; } @@ -84,7 +89,7 @@ class RangeSlider extends EventEmitter { // this.range = true; //} - let positionStep = 160/4; + let positionStep = 160 / 4; let topPosition = 0; for (let i = this.min; i <= this.max; i = i + this.stepSize) { let sliderTick = dom.createDom("div", { @@ -95,16 +100,15 @@ class RangeSlider extends EventEmitter { } this.selection = this.options.selection; - this.selectionEl = this.picker.getElementsByClassName('slider-selection')[0]; + this.selectionEl = this.template.getElementsByClassName('slider-selection')[0]; if (this.selection === 'none') { - //this.selectionEl.addClass('hide'); dom.addClass(this.selectionEl, "hide"); } this.selectionElStyle = this.selectionEl.style; - this.handle1 = this.picker.getElementsByClassName('slider-handle')[0]; + this.handle1 = this.template.getElementsByClassName('slider-handle')[0]; this.handle1Stype = this.handle1.style; - this.handle2 = this.picker.getElementsByClassName('slider-handle')[1]; + this.handle2 = this.template.getElementsByClassName('slider-handle')[1]; this.handle2Stype = this.handle2.style; var handle = this.options.handle; @@ -141,17 +145,39 @@ class RangeSlider extends EventEmitter { this.stepSize * 100 / this.diff ]; - //this.offset = this.picker.offset(); - // this.offset = $(this.picker).offset(); - this.offset = this._getOffset(this.picker); - - this.size = this.picker[this.sizePos]; - + //this.offset = this.template.offset(); + // this.offset = $(this.template).offset(); + this.offset = this._getOffset(this.template); + this.size = this.template[this.sizePos]; //this.formater = options.formater; - this.layout(); - domEvent.on(this.picker, "mousedown", this.mousedown, this); + + // domEvent + // .on(this.template, 'mousedown touchstart', domEvent.stopPropagation) + // .on(this.template, 'click', domEvent.stopPropagation) + // .on(this.template, 'dblclick', domEvent.stopPropagation) + // .on(this.template, 'mousedown touchstart', domEvent.preventDefault) + // .on(this.template, 'mousedown touchstart', this.mousedown, this); + + if (this.touchCapable) { + // Touch: Bind touch events: + domEvent.on(this.template, 'touchstart', domEvent.stopPropagation) + domEvent.on(this.template, 'touchstart', domEvent.preventDefault); + domEvent.on(this.template, 'touchstart', this.mousedown, this); + } else { + domEvent.on(this.template, 'mousedown', domEvent.stopPropagation); + domEvent.on(this.template, 'click', domEvent.stopPropagation); + domEvent.on(this.template, 'dblclick', domEvent.stopPropagation); + domEvent.on(this.template, 'mousedown', domEvent.preventDefault); + domEvent.on(this.template, 'mousedown', this.mousedown, this); + } + + + + // domEvent.on(this.template, "mousedown touchstart", this.mousedown, this); + + dom.addClass(this.tooltip, "hide"); } @@ -197,17 +223,16 @@ class RangeSlider extends EventEmitter { } mousedown(ev) { - // Touch: Get the original event: - if (this.touchCapable && ev.type === 'touchstart') { - ev = ev.originalEvent; - } + // if (this.touchCapable && ev.type === 'touchstart') { + // ev = ev.originalEvent; + // } - //this.offset = this.picker.offset(); - // this.offset = $(this.picker).offset(); - this.offset = this._getOffset(this.picker); + //this.offset = this.template.offset(); + // this.offset = $(this.template).offset(); + this.offset = this._getOffset(this.template); - this.size = this.picker[this.sizePos]; + this.size = this.template[this.sizePos]; let percentage = this.getPercentage(ev); @@ -223,12 +248,19 @@ class RangeSlider extends EventEmitter { // this.percentage[this.dragged] = percentage; // this.layout(); - domEvent.on(this.picker, "mousemove", this.mousemove, this); - domEvent.on(this.picker, 'mouseup', this.mouseup, this); - domEvent.on(this.picker, 'mouseleave', this.onMouseLeave, this); + if (this.touchCapable) { + // Touch: Bind touch events: + domEvent.on(this.template, 'touchmove', this.mousemove, this); + domEvent.on(this.template, 'touchend', this.mouseup, this); + // domEvent.on(this.template, 'touchcancel', this.onMouseLeave, this); + } else { + domEvent.on(this.template, 'mousemove', this.mousemove, this); + domEvent.on(this.template, 'mouseup', this.mouseup, this); + domEvent.on(this.template, 'mouseleave', this.onMouseLeave, this); + } this.inDrag = true; - let value = this.calculateValue(); + // let value = this.calculateValue(); //if (this.options.inverse === true) { // val = val * -1; //} @@ -250,9 +282,9 @@ class RangeSlider extends EventEmitter { this.sliderTrack.style.cursor = "grab"; // Touch: Get the original event: - if (this.touchCapable && ev.type === 'touchmove') { - ev = ev.originalEvent; - } + // if (this.touchCapable && ev.type === 'touchmove') { + // ev = ev.originalEvent; + // } let percentage = this.getPercentage(ev); // if (this.range) { @@ -286,9 +318,18 @@ class RangeSlider extends EventEmitter { this.handle1.style.cursor = "pointer"; this.sliderTrack.style.cursor = "pointer"; - domEvent.off(this.picker, "mousemove", this.mousemove, this); - domEvent.off(this.picker, 'mouseup', this.mouseup, this); - domEvent.off(this.picker, 'mouseleave', this.onMouseLeave, this); + + + if (this.touchCapable) { + // Touch: Bind touch events: + domEvent.off(this.template, "touchmove", this.mousemove, this); + domEvent.off(this.template, 'touchend', this.mouseup, this); + // domEvent.off(this.template, 'touchcancel', this.onMouseLeave, this); + } else { + domEvent.off(this.template, "mousemove", this.mousemove, this); + domEvent.off(this.template, 'mouseup', this.mouseup, this); + domEvent.off(this.template, 'mouseleave', this.onMouseLeave, this); + } this.inDrag = false; //if (this.over == false) { @@ -304,9 +345,17 @@ class RangeSlider extends EventEmitter { this.handle1.style.cursor = "pointer"; this.sliderTrack.style.cursor = "pointer"; - domEvent.off(this.picker, "mousemove", this.mousemove, this); - domEvent.off(this.picker, 'mouseup', this.mouseup, this); - domEvent.off(this.picker, 'mouseleave', this.onMouseLeave, this); + + if (this.touchCapable) { + // Touch: Bind touch events: + domEvent.off(this.template, "touchmove", this.mousemove, this); + domEvent.off(this.template, 'touchend', this.mouseup, this); + // domEvent.off(this.template, 'touchcancel', this.onMouseLeave, this); + } else { + domEvent.off(this.template, "mousemove", this.mousemove, this); + domEvent.off(this.template, 'mouseup', this.mouseup, this); + domEvent.off(this.template, 'mouseleave', this.onMouseLeave, this); + } this.inDrag = false; @@ -324,15 +373,16 @@ class RangeSlider extends EventEmitter { ]; this.value = val; } else { - val = (this.min + Math.round((this.diff * this.percentage[0] / 100) / this.stepSize) * this.stepSize); + val = (this. + min + Math.round((this.diff * this.percentage[0] / 100) / this.stepSize) * this.stepSize); this.value = [val, this.value[1]]; } return val; } getPercentage(ev) { - if (this.touchCapable) { - ev = ev.touches[0]; + if (this.touchCapable && ev.touches) { + ev = ev.touches[0]; } let percentage = (ev[this.mousePos] - this.offset[this.stylePos]) * 100 / this.size; percentage = Math.round(percentage / this.percentage[2]) * this.percentage[2]; diff --git a/src/js/core/domEvent.js b/src/js/core/domEvent.js index e196958..f8bb8e3 100644 --- a/src/js/core/domEvent.js +++ b/src/js/core/domEvent.js @@ -1,19 +1,32 @@ import * as browser from '../core/browser'; import * as util from '../core/utilities'; - //static function - var stampForFn = (function () { - var lastId = 0, - key = '_id'; - return function (obj) { - obj[key] = obj[key] || ++lastId; - return obj[key]; - }; -}()); -export function addListener(obj, type, fn, context) { // (HTMLElement, String, Function[, Object]) +var mouseSubst = { + mouseenter: 'mouseover', + mouseleave: 'mouseout', + wheel: !('onwheel' in window) && 'mousewheel' +}; - var id = stampForFn(fn); +export function addListener(obj, types, fn, context) { + if (typeof types === 'object') { + for (let type in types) { + addaddOneListenerne(obj, type, types[type], fn); + } + } else { + types = util.splitWords(types); + + for (let i = 0, len = types.length; i < len; i++) { + addOneListener(obj, types[i], fn, context); + } + } + + return this; +} + +export function addOneListener(obj, type, fn, context) { // (HTMLElement, String, Function[, Object]) + + var id = util.stamp(fn); var key = '_gba_' + type + id; var handler, originalHandler, newType; @@ -23,19 +36,15 @@ export function addListener(obj, type, fn, context) { // (HTMLElement, String, F return fn.call(context || obj, e || domEvent._getEvent()); }; - //if (L.Browser.pointer && type.indexOf('touch') === 0) { - // return this.addPointerListener(obj, type, handler, id); - //} - //if (L.Browser.touch && (type === 'dblclick') && this.addDoubleTapListener) { - // this.addDoubleTapListener(obj, handler, id); - //} - if ('addEventListener' in obj) { - if (type === 'mousewheel') { - obj.addEventListener('DOMMouseScroll', handler, false); - obj.addEventListener(type, handler, false); + // if (type === 'mousewheel') { + // obj.addEventListener('DOMMouseScroll', handler, false); + // obj.addEventListener(type, handler, false); + // } + if (type === 'touchstart' || type === 'touchmove' || type === 'wheel' || type === 'mousewheel') { + obj.addEventListener(mouseSubst[type] || type, handler, false); } else if ((type === 'mouseenter') || (type === 'mouseleave')) { @@ -49,25 +58,15 @@ export function addListener(obj, type, fn, context) { // (HTMLElement, String, F obj.addEventListener(newType, handler, false); - } - //else if (type === 'click' && L.Browser.android) { - // originalHandler = handler; - // handler = function (e) { - // return L.DomEvent._filterClick(e, originalHandler); - // }; - - // obj.addEventListener(type, handler, false); - //} - else { + } else { obj.addEventListener(type, handler, false); } - } - - else if ('attachEvent' in obj) { + } else if ('attachEvent' in obj) { obj.attachEvent('on' + type, handler); } + obj[key] = obj[key] || {}; obj[key] = handler; return this; @@ -77,62 +76,14 @@ export function addListener(obj, type, fn, context) { // (HTMLElement, String, F // Alias to [`L.DomEvent.on`](#domevent-on) export { addListener as on }; - -function addOne(obj, type, fn, context) { - - - var id = type + util.stamp(fn) + (context ? '_' + util.stamp(context) : ''); - var eventsKey = '_gba_' + type + id; - - if (obj[eventsKey] && obj[eventsKey][id]) { return this; } - - var handler = function (e) { - return fn.call(context || obj, e || window.event); - }; - - var originalHandler = handler; - - if (browser.pointer && type.indexOf('touch') === 0) { - // Needs DomEvent.Pointer.js - addPointerListener(obj, type, handler, id); - - } else if (browser.touch && (type === 'dblclick') && !browserFiresNativeDblClick()) { - addDoubleTapListener(obj, handler, id); - - } else if ('addEventListener' in obj) { - - if (type === 'touchstart' || type === 'touchmove' || type === 'wheel' || type === 'mousewheel') { - obj.addEventListener(mouseSubst[type] || type, handler, Browser.passiveEvents ? {passive: false} : false); - - } else if (type === 'mouseenter' || type === 'mouseleave') { - handler = function (e) { - e = e || window.event; - if (isExternalTarget(obj, e)) { - originalHandler(e); - } - }; - obj.addEventListener(mouseSubst[type], handler, false); - - } else { - obj.addEventListener(type, originalHandler, false); - } - - } else if ('attachEvent' in obj) { - obj.attachEvent('on' + type, handler); - } - - obj[eventsKey] = obj[eventsKey] || {}; - obj[eventsKey][id] = handler; -} - export function removeListener(obj, type, fn) { // (HTMLElement, String, Function) - var id = stampForFn(fn); + var id = util.stamp(fn); var key = '_gba_' + type + id; var handler = obj[key]; if (!handler) { return this; } - + if ('removeEventListener' in obj) { if (type === 'mousewheel') { obj.removeEventListener('DOMMouseScroll', handler, false); @@ -187,9 +138,9 @@ export function stopPropagation(e) { // Adds `stopPropagation` to the element's `'click'`, `'doubleclick'`, // `'mousedown'` and `'touchstart'` events (plus browser variants). export function disableClickPropagation(el) { - addListener(el, 'mousedown touchstart dblclick', stopPropagation); - addOne(el, 'click', fakeStop); - return this; + addListener(el, 'mousedown touchstart dblclick', stopPropagation); + addOneListener(el, 'click', fakeStop); + return this; } export function preventDefault(e) { @@ -205,8 +156,8 @@ export function preventDefault(e) { var skipEvents = {}; export function fakeStop(e) { - // fakes stopPropagation by setting a special event flag, checked/reset with skipped(e) - skipEvents[e.type] = true; + // fakes stopPropagation by setting a special event flag, checked/reset with skipped(e) + skipEvents[e.type] = true; } export function skipped(e) { var skipped = skipEvents[e.type]; diff --git a/src/js/core/utilities.js b/src/js/core/utilities.js index e948a7d..fb18f09 100644 --- a/src/js/core/utilities.js +++ b/src/js/core/utilities.js @@ -147,7 +147,7 @@ export function setOptions(obj, options) { // Last unique ID used by [`stamp()`](#util-stamp) export var lastId = 0; -// @function stamp(obj: Object): Number +// @function stampForFn(obj: Object): Number // Returns the unique ID of an object, assigning it one if it doesn't have it. export function stamp(obj) { let key = '_gba_id'; @@ -156,6 +156,17 @@ export function stamp(obj) { } +// //static function +// var stamp = (function () { +// //var lastId = 0, +// let key = '_gba_id'; +// return function (obj) { +// obj[key] = obj[key] || ++lastId; +// return obj[key]; +// }; +// }()); +// export { stamp }; + export function hasTouch() { let phantomjs = navigator.userAgent.toLowerCase().indexOf('phantom') !== -1; @@ -171,4 +182,10 @@ export function hasTouch() { // Compatibility polyfill for [String.prototype.trim](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim) export function trim(str) { return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, ''); +} + +// @function splitWords(str: String): String[] +// Trims and splits the string on whitespace and returns the array of parts. +export function splitWords(str) { + return trim(str).split(/\s+/); } \ No newline at end of file