Skip to content

Commit

Permalink
Merge pull request #793 from QuentinRoy/multitouch
Browse files Browse the repository at this point in the history
Multitouch Support
  • Loading branch information
QuentinRoy authored Jul 28, 2017
2 parents 73159de + dec3a6c commit 1ae2b56
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 23 deletions.
31 changes: 31 additions & 0 deletions documentation/slider-options.php
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,34 @@
</div>

</section>


<?php sect('multitouch'); ?>

<h2>Multitouch</h2>

<section>
<div class="view">
<p>Set the multitouch option to <code>true</code> to allow simultaneous interaction with a slider and other content on the page (e.g. another slider). It is even possible to simultaneously control several handles of the same slider.</p>

<div class="example" style="margin: 0;">
<div class="sliders" id="slider-multitouch-1" style="margin-bottom: 20px"></div>
<div class="sliders" id="slider-multitouch-2" style="margin-bottom: 20px"></div>
<div class="sliders" id="slider-multitouch-3"></div>
<?php run('multitouch'); ?>
</div>

<div class="options">
<strong>Default</strong>
<div><code>false</code></div>

<strong>Accepted values</strong>
<div><code>true</code>, <code>false</code></div>
</div>

</div>

<div class="side">
<?php code('multitouch'); ?>
</div>
</section>
11 changes: 11 additions & 0 deletions documentation/slider-options/multitouch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[1, 2, 3].forEach(function (i) {
slider = document.getElementById('slider-multitouch-' + i);
noUiSlider.create(slider, {
start: [20, 80],
multitouch: true,
range: {
min: 0,
max: 100
}
});
});
10 changes: 10 additions & 0 deletions src/js/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,14 @@
};
}

function testMultitouch ( parsed, entry ) {
parsed.multitouch = entry;

if ( typeof entry !== 'boolean' ){
throw new Error("noUiSlider (" + VERSION + "): 'multitouch' option must be a boolean.");
}
}

function testTooltips ( parsed, entry ) {

if ( entry === false ) {
Expand Down Expand Up @@ -371,6 +379,7 @@
'limit': { r: false, t: testLimit },
'padding': { r: false, t: testPadding },
'behaviour': { r: true, t: testBehaviour },
'multitouch': { r: true, t: testMultitouch },
'ariaFormat': { r: false, t: testAriaFormat },
'format': { r: false, t: testFormat },
'tooltips': { r: false, t: testTooltips },
Expand All @@ -383,6 +392,7 @@
'connect': false,
'direction': 'ltr',
'behaviour': 'tap',
'multitouch': false,
'orientation': 'horizontal',
'cssPrefix' : 'noUi-',
'cssClasses': {
Expand Down
56 changes: 38 additions & 18 deletions src/js/scope_events.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,27 @@
function eventEnd ( event, data ) {

// The handle is no longer active, so remove the class.
if ( scope_ActiveHandle ) {
removeClass(scope_ActiveHandle, options.cssClasses.active);
scope_ActiveHandle = false;
}

// Remove cursor styles and text-selection events bound to the body.
if ( event.cursor ) {
scope_Body.style.cursor = '';
scope_Body.removeEventListener('selectstart', preventDefault);
if ( data.handle ) {
removeClass(data.handle, options.cssClasses.active);
scope_ActiveHandlesCount -= 1;
}

// Unbind the move and end events, which are added on 'start'.
scope_Listeners.forEach(function( c ) {
data.listeners.forEach(function( c ) {
scope_DocumentElement.removeEventListener(c[0], c[1]);
});

// Remove dragging class.
removeClass(scope_Target, options.cssClasses.drag);
if ( scope_ActiveHandlesCount === 0 ) {
// Remove dragging class.
removeClass(scope_Target, options.cssClasses.drag);
setZindex();

setZindex();
// Remove cursor styles and text-selection events bound to the body.
if ( event.cursor ) {
scope_Body.style.cursor = '';
scope_Body.removeEventListener('selectstart', preventDefault);
}
}

data.handleNumbers.forEach(function(handleNumber){
fireEvent('change', handleNumber);
Expand All @@ -62,25 +63,36 @@
// Bind move events on document.
function eventStart ( event, data ) {

var handle;
if ( data.handleNumbers.length === 1 ) {

var handle = scope_Handles[data.handleNumbers[0]];
var handleOrigin = scope_Handles[data.handleNumbers[0]];

// Ignore 'disabled' handles
if ( handle.hasAttribute('disabled') ) {
if ( handleOrigin.hasAttribute('disabled') ) {
return false;
}

handle = handleOrigin.children[0];
scope_ActiveHandlesCount += 1;

// Mark the handle as 'active' so it can be styled.
scope_ActiveHandle = handle.children[0];
addClass(scope_ActiveHandle, options.cssClasses.active);
addClass(handle, options.cssClasses.active);
}

// A drag should never propagate up to the 'tap' event.
event.stopPropagation();

// Record the event listeners.
var listeners = [];

// Attach the move and end events.
var moveEvent = attachEvent(actions.move, scope_DocumentElement, eventMove, {
// The event target has changed so we need to propagate the original one so that we keep
// relying on it to extract target touches.
target: event.target,
handle: handle,
listeners: listeners,
startCalcPoint: event.calcPoint,
baseSize: baseSize(),
pageOffset: event.pageOffset,
Expand All @@ -90,14 +102,22 @@
});

var endEvent = attachEvent(actions.end, scope_DocumentElement, eventEnd, {
target: event.target,
handle: handle,
listeners: listeners,
handleNumbers: data.handleNumbers
});

var outEvent = attachEvent("mouseout", scope_DocumentElement, documentLeave, {
target: event.target,
handle: handle,
listeners: listeners,
handleNumbers: data.handleNumbers
});

scope_Listeners = moveEvent.concat(endEvent, outEvent);
// We want to make sure we pushed the listeners in the listener list rather than creating
// a new one as it has already been passed to the event handlers.
listeners.push.apply(listeners, moveEvent.concat(endEvent, outEvent));

// Text selection isn't an issue on touch devices,
// so adding cursor styles can be skipped.
Expand Down
33 changes: 30 additions & 3 deletions src/js/scope_helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
return false;
}

e = fixEvent(e, data.pageOffset);
e = fixEvent(e, data.pageOffset, data.target || element);

// Handle reject of multitouch
if ( !e ) {
Expand Down Expand Up @@ -66,7 +66,7 @@
}

// Provide a clean event with standardized offset values.
function fixEvent ( e, pageOffset ) {
function fixEvent ( e, pageOffset, target ) {

// Filter the event to register the type, which can be
// touch, mouse or pointer. Offset changes need to be
Expand All @@ -83,8 +83,35 @@
pointer = true;
}

if ( touch ) {

// In the event that multitouch is activated, the only thing one handle should be concerned
// about is the touches that originated on top of it.
if ( touch && options.multitouch ) {
// Returns true if a touch originated on the target.
var isTouchOnTarget = function (touch) {
return touch.target === target || target.contains(touch.target);
};
// In the case of touchstart events, we need to make sure there is still no more than one
// touch on the target so we look amongst all touches.
if (e.type === 'touchstart') {
var targetTouches = Array.prototype.filter.call(e.touches, isTouchOnTarget);
// Do not support more than one touch per handle.
if ( targetTouches.length > 1 ) {
return false;
}
x = targetTouches[0].pageX;
y = targetTouches[0].pageY;
} else {
// In the other cases, find on changedTouches is enough.
var targetTouch = Array.prototype.find.call(e.changedTouches, isTouchOnTarget);
// Cancel if the target touch has not moved.
if ( !targetTouch ) {
return false;
}
x = targetTouch.pageX;
y = targetTouch.pageY;
}
} else if ( touch ) {
// Fix bug when user touches with two or more fingers on mobile devices.
// It's useful when you have two or more sliders on one page,
// that can be touched simultaneously.
Expand Down
3 changes: 1 addition & 2 deletions src/js/scope_start.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,13 @@ function closure ( target, options, originalOptions ){
var scope_Base;
var scope_Handles;
var scope_HandleNumbers = [];
var scope_ActiveHandle = false;
var scope_ActiveHandlesCount = 0;
var scope_Connects;
var scope_Spectrum = options.spectrum;
var scope_Values = [];
var scope_Events = {};
var scope_Self;
var scope_Pips;
var scope_Listeners = null;
var scope_Document = target.ownerDocument;
var scope_DocumentElement = scope_Document.documentElement;
var scope_Body = scope_Document.body;

0 comments on commit 1ae2b56

Please sign in to comment.