Skip to content
This repository has been archived by the owner on Aug 29, 2023. It is now read-only.

Commit

Permalink
update(slider): discrete sliders now support live dragging between di…
Browse files Browse the repository at this point in the history
…screte values and snap-to animate to closest discrete value.
  • Loading branch information
ThomasBurleson committed Sep 27, 2014
1 parent fd7697d commit 8848e8e
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 18 deletions.
56 changes: 50 additions & 6 deletions src/components/slider/slider.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ function SliderDirective() {
'$element',
'$attrs',
'$$rAF',
'$timeout',
'$window',
'$materialEffects',
'$aria',
Expand Down Expand Up @@ -99,7 +98,7 @@ function SliderDirective() {
* We use a controller for all the logic so that we can expose a few
* things to unit tests
*/
function SliderController(scope, element, attr, $$rAF, $timeout, $window, $materialEffects, $aria) {
function SliderController(scope, element, attr, $$rAF, $window, $materialEffects, $aria) {

this.init = function init(ngModelCtrl) {
var thumb = angular.element(element[0].querySelector('.slider-thumb'));
Expand Down Expand Up @@ -136,6 +135,7 @@ function SliderController(scope, element, attr, $$rAF, $timeout, $window, $mater
hammertime.on('hammer.input', onInput);
hammertime.on('panstart', onPanStart);
hammertime.on('pan', onPan);
hammertime.on('panend', onPanEnd);

// On resize, recalculate the slider's dimensions and re-render
var updateAll = $$rAF.debounce(function() {
Expand Down Expand Up @@ -282,18 +282,28 @@ function SliderController(scope, element, attr, $$rAF, $timeout, $window, $mater
* Slide listeners
*/
var isSliding = false;
var isDiscrete = false;

function onInput(ev) {
if (!isSliding && ev.eventType === Hammer.INPUT_START &&
!element[0].hasAttribute('disabled')) {

isSliding = true;
isDiscrete = angular.isDefined(attr.discrete);

element.addClass('active');
element[0].focus();
refreshSliderDimensions();
doSlide(ev.center.x);

onPan(ev);

} else if (isSliding && ev.eventType === Hammer.INPUT_END) {

if ( isDiscrete ) onPanEnd(ev);

isSliding = false;
isDiscrete = false;

element.removeClass('panning active');
}
}
Expand All @@ -303,8 +313,26 @@ function SliderController(scope, element, attr, $$rAF, $timeout, $window, $mater
}
function onPan(ev) {
if (!isSliding) return;
doSlide(ev.center.x);

// While panning discrete, update only the
// visual positioning but not the model value.

if ( isDiscrete ) doPan( ev.center.x );
else doSlide( ev.center.x );

ev.preventDefault();
ev.srcEvent.stopPropagation();
}

function onPanEnd(ev) {
if ( isDiscrete ) {
// Updating the model and slide position
// and perform an animated snap-to operation
doSlide( ev.center.x );
ngModelRender();

ev.srcEvent.stopPropagation();
}
}

/**
Expand All @@ -314,9 +342,25 @@ function SliderController(scope, element, attr, $$rAF, $timeout, $window, $mater
this._onPanStart = onPanStart;
this._onPan = onPan;

function doSlide(x) {
/**
* Slide the UI by changing the model value
* @param x
*/
function doSlide( x ) {
var percent = (x - sliderDimensions.left) / (sliderDimensions.width);

scope.$evalAsync( function() {
setModelValue(min + percent * (max - min));
});
}

/**
* Slide the UI without changing the model (while dragging/panning)
* @param x
*/
function doPan( x ) {
var percent = (x - sliderDimensions.left) / (sliderDimensions.width);
scope.$evalAsync(function() { setModelValue(min + percent * (max - min)); });
setSliderPercent( percent );
}

};
Expand Down
26 changes: 14 additions & 12 deletions src/components/slider/slider.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@

describe('material-slider', function() {

function simulateEventAt( centerX, eventType ) {
return {
eventType: eventType,
center: { x: centerX },
preventDefault: angular.noop,
srcEvent : {
stopPropagation : angular.noop
}
};
}

beforeEach(module('material.components.slider','material.decorators'));

it('should set model on press', inject(function($compile, $rootScope, $timeout) {
Expand All @@ -14,25 +25,16 @@ describe('material-slider', function() {
right: 0
});

sliderCtrl._onInput({
eventType: Hammer.INPUT_START,
center: { x: 30 }
});
sliderCtrl._onInput( simulateEventAt( 30, Hammer.INPUT_START ));
$timeout.flush();
expect($rootScope.value).toBe(30);

//When going past max, it should clamp to max
sliderCtrl._onPan({
center: { x: 500 },
preventDefault: angular.noop
});
sliderCtrl._onPan( simulateEventAt( 500 ));
$timeout.flush();
expect($rootScope.value).toBe(100);

sliderCtrl._onPan({
center: { x: 50 },
preventDefault: angular.noop
});
sliderCtrl._onPan( simulateEventAt( 50 ));
$timeout.flush();
expect($rootScope.value).toBe(50);
}));
Expand Down

0 comments on commit 8848e8e

Please sign in to comment.