Skip to content

feat(range): Add a noSwitching value to prevent switching min/max #233

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 31, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 2.6.0 (not-released)
## Features
- Add a `noSwitching` option to prevent the user from switching the min and max handles (#233).

# 2.5.0 (2016-01-24)
## Features
- Add a `minRange` option to set a minimal range (#231).
Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ The default options are:
keyboardSupport: true,
scale: 1,
enforceRange: false,
noSwitching: false,
onlyBindHandles: false,
onStart: null,
onChange: null,
Expand All @@ -199,7 +200,7 @@ The default options are:

**precision** - _Number (defaults to 0)_: The precision to display values with. The `toFixed()` is used internally for this.

**minRange** - _Number (defaults to 0)_: The minimum range authorized on the slider.
**minRange** - _Number (defaults to 0)_: The minimum range authorized on the slider. *Applies to range slider only.*

**translate** - _Function(value, sliderId)_: Custom translate function. Use this if you want to translate values displayed on the slider. For example if you want to display dollar amounts instead of just numbers:
```html
Expand All @@ -226,9 +227,9 @@ $scope.slider = {

**stepsArray** - _Array_: If you want to display a slider with non linear/number steps. Just pass an array with each slider value and that's it; the floor, ceil and step settings of the slider will be computed automatically. The `rz-slider-model` value will be the index of the selected item in the stepsArray.

**draggableRange** - _Boolean (defaults to false)_: When set to true and using a range slider, the range can be dragged by the selection bar.
**draggableRange** - _Boolean (defaults to false)_: When set to true and using a range slider, the range can be dragged by the selection bar. *Applies to range slider only.*

**draggableRangeOnly** - _Boolean (defaults to false)_: Same as draggableRange but the slider range can't be changed.
**draggableRangeOnly** - _Boolean (defaults to false)_: Same as draggableRange but the slider range can't be changed. *Applies to range slider only.*

**showSelectionBar** - _Boolean (defaults to false)_: Set to true to always show the selection bar before the slider handle.

Expand Down Expand Up @@ -256,6 +257,8 @@ $scope.slider = {

**enforceRange** - _Boolean (defaults to false)_: Set to true to round the `rzSliderModel` and `rzSliderHigh` to the slider range even when modified from outside the slider. When set to false, if the model values are modified from outside the slider, they are not rounded but they are still rendered properly on the slider.

**noSwitching** - _Boolean (defaults to false)_: Set to true to prevent to user from switching the min and max handles. *Applies to range slider only.*

**onlyBindHandles** - _Boolean (defaults to false)_: Set to true to only bind events on slider handles.

**onStart** - _Function(sliderId, modelValue, highValue)_: Function to be called when a slider update is started. If an id was set in the options, then it's passed to this callback. This callback is called before any update on the model.
Expand Down
12 changes: 12 additions & 0 deletions demo/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ app.controller('MainCtrl', function($scope, $rootScope, $timeout, $modal) {
}
};

//Range slider with noSwitching config
$scope.noSwitchingSlider = {
minValue: 10,
maxValue: 90,
options: {
floor: 0,
ceil: 100,
step: 1,
noSwitching: true
}
};

//Slider with selection bar
$scope.slider_visible_bar = {
value: 10,
Expand Down
9 changes: 9 additions & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ <h2>Range slider with minimum range of 10</h2>
></rzslider>
</article>

<article>
<h2>Range slider with noSwitching=true</h2>
<rzslider
rz-slider-model="noSwitchingSlider.minValue"
rz-slider-high="noSwitchingSlider.maxValue"
rz-slider-options="noSwitchingSlider.options"
></rzslider>
</article>

<article>
<h2>Slider with visible selection bar</h2>
<rzslider
Expand Down
6 changes: 5 additions & 1 deletion dist/rzslider.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*! angularjs-slider - v2.5.0 -
(c) Rafal Zajac <[email protected]>, Valentin Hervieu <[email protected]>, Jussi Saarivirta <[email protected]>, Angelin Sirbu <[email protected]> -
https://github.com/angular-slider/angularjs-slider -
2016-01-24 */
2016-01-31 */
rzslider {
position: relative;
display: inline-block;
Expand Down Expand Up @@ -98,6 +98,10 @@ rzslider .rz-pointer:hover:after {
background-color: #ffffff;
}

rzslider .rz-pointer.rz-active {
z-index: 4;
}

rzslider .rz-pointer.rz-active:after {
background-color: #451aff;
}
Expand Down
115 changes: 51 additions & 64 deletions dist/rzslider.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
keyboardSupport: true,
scale: 1,
enforceRange: false,
noSwitching: false,
onlyBindHandles: false,
onStart: null,
onChange: null,
Expand Down Expand Up @@ -843,7 +844,7 @@
updateHandles: function(which, newOffset) {
if (which === 'rzSliderModel')
this.updateLowHandle(newOffset);
else if (which === 'rzSliderHigh')
else
this.updateHighHandle(newOffset);

this.updateSelectionBar();
Expand Down Expand Up @@ -883,7 +884,7 @@
},

/**
* Show / hide floor / ceiling label
* Show/hide floor/ceiling label
*
* @returns {undefined}
*/
Expand Down Expand Up @@ -1177,8 +1178,15 @@
if (!this.range) {
return this.minH;
}
var offset = this.getEventPosition(event);
return Math.abs(offset - this.minH.rzsp) < Math.abs(offset - this.maxH.rzsp) ? this.minH : this.maxH;
var offset = this.getEventPosition(event),
distanceMin = Math.abs(offset - this.minH.rzsp),
distanceMax = Math.abs(offset - this.maxH.rzsp);
if (distanceMin < distanceMax)
return this.minH;
else if (distanceMin > distanceMax)
return this.maxH;
else //if event is at the same distance from min/max then if it's at left of minH, we return minH else maxH
return offset < this.minH.rzsp ? this.minH : this.maxH;
},

/**
Expand Down Expand Up @@ -1322,21 +1330,14 @@
newValue;

if (newOffset <= 0) {
if (pointer.rzsp === 0)
return;
newValue = this.minValue;
newOffset = 0;
} else if (newOffset >= this.maxPos) {
if (pointer.rzsp === this.maxPos)
return;
newValue = this.maxValue;
newOffset = this.maxPos;
} else {
newValue = this.offsetToValue(newOffset);
newValue = this.roundStep(newValue);
newOffset = this.valueToOffset(newValue);
}
this.positionTrackingHandle(newValue, newOffset);
this.positionTrackingHandle(newValue);
},

/**
Expand Down Expand Up @@ -1402,36 +1403,28 @@
if (action == null || this.tracking === '') return;
event.preventDefault();

var newValue = this.roundStep(this.sanitizeValue(action)),
newOffset = this.valueToOffset(newValue);
var newValue = this.roundStep(this.sanitizeValue(action));
if (!this.options.draggableRangeOnly) {
this.positionTrackingHandle(newValue, newOffset);
this.positionTrackingHandle(newValue);
} else {
var difference = this.scope.rzSliderHigh - this.scope.rzSliderModel,
newMinOffset, newMaxOffset,
newMinValue, newMaxValue;
if (this.tracking === 'rzSliderModel') {
newMinValue = newValue;
newMinOffset = newOffset;
newMaxValue = newValue + difference;
if (newMaxValue > this.maxValue) {
newMaxValue = this.maxValue;
newMinValue = newMaxValue - difference;
newMinOffset = this.valueToOffset(newMinValue);
}
newMaxOffset = this.valueToOffset(newMaxValue);
} else {
newMaxValue = newValue;
newMaxOffset = newOffset;
newMinValue = newValue - difference;
if (newMinValue < this.minValue) {
newMinValue = this.minValue;
newMaxValue = newMinValue + difference;
newMaxOffset = this.valueToOffset(newMaxValue);
}
newMinOffset = this.valueToOffset(newMinValue);
}
this.positionTrackingBar(newMinValue, newMaxValue, newMinOffset, newMaxOffset);
this.positionTrackingBar(newMinValue, newMaxValue);
}
},

Expand Down Expand Up @@ -1469,100 +1462,94 @@
*/
onDragMove: function(pointer, event) {
var newOffset = this.getEventPosition(event),
newMinOffset, newMaxOffset,
newMinValue, newMaxValue;

if (newOffset <= this.dragging.lowLimit) {
if (this.minH.rzsp === 0)
return;
newMinValue = this.minValue;
newMinOffset = 0;
newMaxValue = this.minValue + this.dragging.difference;
newMaxOffset = this.valueToOffset(newMaxValue);
} else if (newOffset >= this.maxPos - this.dragging.highLimit) {
if (this.maxH.rzsp === this.maxPos)
return;
newMaxValue = this.maxValue;
newMaxOffset = this.maxPos;
newMinValue = this.maxValue - this.dragging.difference;
newMinOffset = this.valueToOffset(newMinValue);
} else {
newMinValue = this.offsetToValue(newOffset - this.dragging.lowLimit);
newMinValue = this.roundStep(newMinValue);
newMinOffset = this.valueToOffset(newMinValue);
newMaxValue = newMinValue + this.dragging.difference;
newMaxOffset = this.valueToOffset(newMaxValue);
}

this.positionTrackingBar(newMinValue, newMaxValue, newMinOffset, newMaxOffset);
this.positionTrackingBar(newMinValue, newMaxValue);
},

/**
* Set the new value and offset for the entire bar
*
* @param {number} newMinValue the new minimum value
* @param {number} newMaxValue the new maximum value
* @param {number} newMinOffset the new minimum offset
* @param {number} newMaxOffset the new maximum offset
*/
positionTrackingBar: function(newMinValue, newMaxValue, newMinOffset, newMaxOffset) {
positionTrackingBar: function(newMinValue, newMaxValue) {
this.scope.rzSliderModel = newMinValue;
this.scope.rzSliderHigh = newMaxValue;
this.updateHandles('rzSliderModel', newMinOffset);
this.updateHandles('rzSliderHigh', newMaxOffset);
this.updateHandles('rzSliderModel', this.valueToOffset(newMinValue));
this.updateHandles('rzSliderHigh', this.valueToOffset(newMaxValue));
this.applyModel();
},

/**
* Set the new value and offset to the current tracking handle
*
* @param {number} newValue new model value
* @param {number} newOffset new offset value
*/
positionTrackingHandle: function(newValue, newOffset) {
positionTrackingHandle: function(newValue) {
var valueChanged = false;
var switched = false;

if (this.range) {
newValue = this.applyMinRange(newValue);
newOffset = this.valueToOffset(newValue);
/* This is to check if we need to switch the min and max handles */
if (this.tracking === 'rzSliderModel' && newValue >= this.scope.rzSliderHigh) {
switched = true;
this.scope[this.tracking] = this.scope.rzSliderHigh;
this.updateHandles(this.tracking, this.maxH.rzsp);
this.updateAriaAttributes();
this.tracking = 'rzSliderHigh';
this.minH.removeClass('rz-active');
this.maxH.addClass('rz-active');
if (this.options.keyboardSupport)
this.focusElement(this.maxH);
if (this.tracking === 'rzSliderModel' && newValue > this.scope.rzSliderHigh) {
if (this.options.noSwitching && this.scope.rzSliderHigh !== this.minValue) {
newValue = this.applyMinRange(this.scope.rzSliderHigh);
}
else {
this.scope[this.tracking] = this.scope.rzSliderHigh;
this.updateHandles(this.tracking, this.maxH.rzsp);
this.updateAriaAttributes();
this.tracking = 'rzSliderHigh';
this.minH.removeClass('rz-active');
this.maxH.addClass('rz-active');
if (this.options.keyboardSupport)
this.focusElement(this.maxH);
}
valueChanged = true;
} else if (this.tracking === 'rzSliderHigh' && newValue <= this.scope.rzSliderModel) {
switched = true;
this.scope[this.tracking] = this.scope.rzSliderModel;
this.updateHandles(this.tracking, this.minH.rzsp);
this.updateAriaAttributes();
this.tracking = 'rzSliderModel';
this.maxH.removeClass('rz-active');
this.minH.addClass('rz-active');
if (this.options.keyboardSupport)
this.focusElement(this.minH);
} else if (this.tracking === 'rzSliderHigh' && newValue < this.scope.rzSliderModel) {
if (this.options.noSwitching && this.scope.rzSliderModel !== this.maxValue) {
newValue = this.applyMinRange(this.scope.rzSliderModel);
}
else {
this.scope[this.tracking] = this.scope.rzSliderModel;
this.updateHandles(this.tracking, this.minH.rzsp);
this.updateAriaAttributes();
this.tracking = 'rzSliderModel';
this.maxH.removeClass('rz-active');
this.minH.addClass('rz-active');
if (this.options.keyboardSupport)
this.focusElement(this.minH);
}
valueChanged = true;
}
}

if (this.scope[this.tracking] !== newValue) {
this.scope[this.tracking] = newValue;
this.updateHandles(this.tracking, newOffset);
this.updateHandles(this.tracking, this.valueToOffset(newValue));
this.updateAriaAttributes();
valueChanged = true;
}

if (valueChanged) {
if (valueChanged)
this.applyModel();
}
return switched;
},

applyMinRange: function(newValue) {
Expand Down
Loading