3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
4 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7 Code distributed by Google as part of the polymer project is also
8 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
11 <link rel=
"import" href=
"../polymer/polymer.html">
12 <link rel=
"import" href=
"../paper-styles/paper-styles.html">
13 <link rel=
"import" href=
"../paper-progress/paper-progress.html">
14 <link rel=
"import" href=
"../paper-input/paper-input.html">
15 <link rel=
"import" href=
"../paper-behaviors/paper-inky-focus-behavior.html">
16 <link rel=
"import" href=
"../paper-ripple/paper-ripple.html">
17 <link rel=
"import" href=
"../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
18 <link rel=
"import" href=
"../iron-range-behavior/iron-range-behavior.html">
19 <link rel=
"import" href=
"../iron-form-element-behavior/iron-form-element-behavior.html">
22 `paper-slider` allows user to select a value from a range of values by
23 moving the slider thumb. The interactive nature of the slider makes it a
24 great choice for settings that reflect intensity levels, such as volume,
25 brightness, or color saturation.
29 <paper-slider></paper-slider>
31 Use `min` and `max` to specify the slider range. Default is 0 to 100.
35 <paper-slider min="10" max="200" value="110"></paper-slider>
39 The following custom properties and mixins are available for styling:
41 Custom property | Description | Default
42 ----------------|-------------|----------
43 `--paper-slider-bar-color` | The background color of the slider | `transparent`
44 `--paper-slider-active-color` | The progress bar color | `--google-blue-700`
45 `--paper-slider-secondary-color` | The secondary progress bar color | `--google-blue-300`
46 `--paper-slider-knob-color` | The knob color | `--google-blue-700`
47 `--paper-slider-disabled-knob-color` | The disabled knob color | `--google-grey-500`
48 `--paper-slider-pin-color` | The pin color | `--google-blue-700`
49 `--paper-slider-font-color` | The pin's text color | `#fff`
50 `--paper-slider-disabled-active-color` | The disabled progress bar color | `--google-grey-500`
51 `--paper-slider-disabled-secondary-color` | The disabled secondary progress bar color | `--google-grey-300`
59 <dom-module id=
"paper-slider">
61 <link rel=
"import" type=
"css" href=
"paper-slider.css">
64 <div id=
"sliderContainer"
65 class$=
"[[_getClassNames(disabled, pin, snaps, immediateValue, min, expand, dragging, transiting, editable)]]">
67 <div class=
"bar-container">
74 value=
"[[immediateValue]]"
75 secondary-progress=
"[[secondaryProgress]]"
82 <template is=
"dom-if" if=
"[[snaps]]">
83 <div class=
"slider-markers horizontal layout">
84 <template is=
"dom-repeat" items=
"[[markers]]">
85 <div class=
"slider-marker flex"></div>
91 class=
"center-justified center horizontal layout"
95 on-transitionend=
"_knobTransitionEnd">
96 <paper-ripple id=
"ink" class=
"circle" center hidden$=
"[[!receivedFocusFromKeyboard]]"></paper-ripple>
97 <div id=
"sliderKnobInner" value$=
"[[immediateValue]]"></div>
101 <template is=
"dom-if" if=
"[[editable]]">
105 disabled$=
"[[disabled]]"
106 on-change=
"_inputChange">
119 Polymer
.IronA11yKeysBehavior
,
120 Polymer
.PaperInkyFocusBehavior
,
121 Polymer
.IronFormElementBehavior
,
122 Polymer
.IronRangeBehavior
128 * If true, the slider thumb snaps to tick marks evenly spaced based
129 * on the `step` property value.
138 * If true, a pin with numeric value label is shown when the slider thumb
139 * is pressed. Use for settings for which users need to know the exact
140 * value of the setting.
149 * The number that represents the current secondary progress.
155 observer
: '_secondaryProgressChanged'
159 * If true, an input is shown and user can use it to set the slider value.
167 * The immediate value of the slider. This value is updated while the user
168 * is dragging the slider.
177 * The maximum number of markers
183 observer
: '_maxMarkersChanged'
187 * If true, the knob is expanded
196 * True when the user is dragging the slider.
218 '_updateKnob(value, min, max, snaps, step)',
221 '_valueChanged(value)',
222 '_immediateValueChanged(immediateValue)'
231 'left down pagedown home': '_decrementKey',
232 'right up pageup end': '_incrementKey'
236 // issue polymer/polymer#1305
237 this.async(function() {
238 this._updateKnob(this.value
);
239 this._updateInputValue();
244 * Increases value by `step` but not above `max`.
247 increment: function() {
248 this.value
= this._clampValue(this.value
+ this.step
);
252 * Decreases value by `step` but not below `min`.
255 decrement: function() {
256 this.value
= this._clampValue(this.value
- this.step
);
259 _updateKnob: function(value
) {
260 this._positionKnob(this._calcRatio(value
));
263 _minChanged: function() {
264 this.setAttribute('aria-valuemin', this.min
);
267 _maxChanged: function() {
268 this.setAttribute('aria-valuemax', this.max
);
271 _valueChanged: function() {
272 this.setAttribute('aria-valuenow', this.value
);
273 this.fire('value-change');
276 _immediateValueChanged: function() {
278 this.fire('immediate-value-change');
280 this.value
= this.immediateValue
;
282 this._updateInputValue();
285 _secondaryProgressChanged: function() {
286 this.secondaryProgress
= this._clampValue(this.secondaryProgress
);
289 _updateInputValue: function() {
291 this.$$('#input').value
= this.immediateValue
.toString();
295 _expandKnob: function() {
296 this._setExpand(true);
299 _resetKnob: function() {
300 this.cancelDebouncer('expandKnob');
301 this._setExpand(false);
304 _positionKnob: function(ratio
) {
305 this._setImmediateValue(this._calcStep(this._calcKnobPosition(ratio
)));
306 this._setRatio(this._calcRatio(this.immediateValue
));
308 this.$.sliderKnob
.style
.left
= (this.ratio
* 100) + '%';
311 _inputChange: function() {
312 this.value
= this.$$('#input').value
;
316 _calcKnobPosition: function(ratio
) {
317 return (this.max
- this.min
) * ratio
+ this.min
;
320 _onTrack: function(event
) {
321 switch (event
.detail
.state
) {
323 this._trackStart(event
);
334 _trackStart: function(event
) {
335 this._w
= this.$.sliderBar
.offsetWidth
;
336 this._x
= this.ratio
* this._w
;
337 this._startx
= this._x
|| 0;
338 this._minx
= - this._startx
;
339 this._maxx
= this._w
- this._startx
;
340 this.$.sliderKnob
.classList
.add('dragging');
342 this._setDragging(true);
345 _trackX: function(e
) {
346 if (!this.dragging
) {
350 var dx
= Math
.min(this._maxx
, Math
.max(this._minx
, e
.detail
.dx
));
351 this._x
= this._startx
+ dx
;
353 var immediateValue
= this._calcStep(this._calcKnobPosition(this._x
/ this._w
));
354 this._setImmediateValue(immediateValue
);
356 // update knob's position
357 var translateX
= ((this._calcRatio(immediateValue
) * this._w
) - this._startx
);
358 this.translate3d(translateX
+ 'px', 0, 0, this.$.sliderKnob
);
361 _trackEnd: function() {
362 var s
= this.$.sliderKnob
.style
;
364 this.$.sliderKnob
.classList
.remove('dragging');
365 this._setDragging(false);
367 this.value
= this.immediateValue
;
369 s
.transform
= s
.webkitTransform
= '';
374 _knobdown: function(event
) {
378 event
.detail
.sourceEvent
.preventDefault();
380 // set the focus manually because we will called prevent default
384 _bardown: function(event
) {
385 this._w
= this.$.sliderBar
.offsetWidth
;
386 var rect
= this.$.sliderBar
.getBoundingClientRect();
387 var ratio
= (event
.detail
.x
- rect
.left
) / this._w
;
388 var prevRatio
= this.ratio
;
390 this._setTransiting(true);
392 this._positionKnob(ratio
);
394 this.debounce('expandKnob', this._expandKnob
, 60);
396 // if the ratio doesn't change, sliderKnob's animation won't start
397 // and `_knobTransitionEnd` won't be called
398 // Therefore, we need to manually update the `transiting` state
400 if (prevRatio
=== this.ratio
) {
401 this._setTransiting(false);
404 this.async(function() {
409 event
.detail
.sourceEvent
.preventDefault();
412 _knobTransitionEnd: function(event
) {
413 if (event
.target
=== this.$.sliderKnob
) {
414 this._setTransiting(false);
418 _maxMarkersChanged: function(maxMarkers
) {
419 var l
= (this.max
- this.min
) / this.step
;
420 if (!this.snaps
&& l
> maxMarkers
) {
421 this._setMarkers([]);
423 this._setMarkers(new Array(l
));
427 _getClassNames: function() {
430 classes
.disabled
= this.disabled
;
431 classes
.pin
= this.pin
;
432 classes
.snaps
= this.snaps
;
433 classes
.ring
= this.immediateValue
<= this.min
;
434 classes
.expand
= this.expand
;
435 classes
.dragging
= this.dragging
;
436 classes
.transiting
= this.transiting
;
437 classes
.editable
= this.editable
;
439 return Object
.keys(classes
).filter(
440 function(className
) {
441 return classes
[className
];
445 _incrementKey: function(event
) {
446 if (event
.detail
.key
=== 'end') {
447 this.value
= this.max
;
454 _decrementKey: function(event
) {
455 if (event
.detail
.key
=== 'home') {
456 this.value
= this.min
;
465 * Fired when the slider's value changes.
467 * @event value-change
471 * Fired when the slider's immediateValue changes.
473 * @event immediate-value-change
477 * Fired when the slider's value changes due to user interaction.
479 * Changes to the slider's value due to changes in an underlying
480 * bound variable will not trigger this event.