| OLD | NEW |
| (Empty) |
| 1 <!-- | |
| 2 @license | |
| 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.g
ithub.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/CONTRI
BUTORS.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/PATEN
TS.txt | |
| 9 --> | |
| 10 | |
| 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-behavio
r.html"> | |
| 20 | |
| 21 <!-- | |
| 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. | |
| 26 | |
| 27 Example: | |
| 28 | |
| 29 <paper-slider></paper-slider> | |
| 30 | |
| 31 Use `min` and `max` to specify the slider range. Default is 0 to 100. | |
| 32 | |
| 33 Example: | |
| 34 | |
| 35 <paper-slider min="10" max="200" value="110"></paper-slider> | |
| 36 | |
| 37 ### Styling | |
| 38 | |
| 39 The following custom properties and mixins are available for styling: | |
| 40 | |
| 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 | `--go
ogle-grey-500` | |
| 51 `--paper-slider-disabled-secondary-color` | The disabled secondary progress bar
color | `--google-grey-300` | |
| 52 | |
| 53 @group Paper Elements | |
| 54 @element paper-slider | |
| 55 @demo demo/index.html | |
| 56 @hero hero.svg | |
| 57 --> | |
| 58 | |
| 59 <dom-module id="paper-slider"> | |
| 60 | |
| 61 <link rel="import" type="css" href="paper-slider.css"> | |
| 62 | |
| 63 <template> | |
| 64 <div id="sliderContainer" | |
| 65 class$="[[_getClassNames(disabled, pin, snaps, immediateValue, min, expand
, dragging, transiting, editable)]]"> | |
| 66 | |
| 67 <div class="bar-container"> | |
| 68 <paper-progress | |
| 69 id="sliderBar" | |
| 70 aria-hidden="true" | |
| 71 min="[[min]]" | |
| 72 max="[[max]]" | |
| 73 step="[[step]]" | |
| 74 value="[[immediateValue]]" | |
| 75 secondary-progress="[[secondaryProgress]]" | |
| 76 on-down="_bardown" | |
| 77 on-up="_resetKnob" | |
| 78 on-track="_onTrack"> | |
| 79 </paper-progress> | |
| 80 </div> | |
| 81 | |
| 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> | |
| 86 </template> | |
| 87 </div> | |
| 88 </template> | |
| 89 | |
| 90 <div id="sliderKnob" | |
| 91 class="center-justified center horizontal layout" | |
| 92 on-down="_knobdown" | |
| 93 on-up="_resetKnob" | |
| 94 on-track="_onTrack" | |
| 95 on-transitionend="_knobTransitionEnd"> | |
| 96 <paper-ripple id="ink" class="circle" center hidden$="[[!receivedFocus
FromKeyboard]]"></paper-ripple> | |
| 97 <div id="sliderKnobInner" value$="[[immediateValue]]"></div> | |
| 98 </div> | |
| 99 </div> | |
| 100 | |
| 101 <template is="dom-if" if="[[editable]]"> | |
| 102 <paper-input | |
| 103 id="input" | |
| 104 class="slider-input" | |
| 105 disabled$="[[disabled]]" | |
| 106 on-change="_inputChange"> | |
| 107 </paper-input> | |
| 108 </template> | |
| 109 </template> | |
| 110 | |
| 111 </dom-module> | |
| 112 | |
| 113 <script> | |
| 114 | |
| 115 Polymer({ | |
| 116 is: 'paper-slider', | |
| 117 | |
| 118 behaviors: [ | |
| 119 Polymer.IronA11yKeysBehavior, | |
| 120 Polymer.PaperInkyFocusBehavior, | |
| 121 Polymer.IronFormElementBehavior, | |
| 122 Polymer.IronRangeBehavior | |
| 123 ], | |
| 124 | |
| 125 properties: { | |
| 126 | |
| 127 /** | |
| 128 * If true, the slider thumb snaps to tick marks evenly spaced based | |
| 129 * on the `step` property value. | |
| 130 */ | |
| 131 snaps: { | |
| 132 type: Boolean, | |
| 133 value: false, | |
| 134 notify: true | |
| 135 }, | |
| 136 | |
| 137 /** | |
| 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. | |
| 141 */ | |
| 142 pin: { | |
| 143 type: Boolean, | |
| 144 value: false, | |
| 145 notify: true | |
| 146 }, | |
| 147 | |
| 148 /** | |
| 149 * The number that represents the current secondary progress. | |
| 150 */ | |
| 151 secondaryProgress: { | |
| 152 type: Number, | |
| 153 value: 0, | |
| 154 notify: true, | |
| 155 observer: '_secondaryProgressChanged' | |
| 156 }, | |
| 157 | |
| 158 /** | |
| 159 * If true, an input is shown and user can use it to set the slider value. | |
| 160 */ | |
| 161 editable: { | |
| 162 type: Boolean, | |
| 163 value: false | |
| 164 }, | |
| 165 | |
| 166 /** | |
| 167 * The immediate value of the slider. This value is updated while the use
r | |
| 168 * is dragging the slider. | |
| 169 */ | |
| 170 immediateValue: { | |
| 171 type: Number, | |
| 172 value: 0, | |
| 173 readOnly: true | |
| 174 }, | |
| 175 | |
| 176 /** | |
| 177 * The maximum number of markers | |
| 178 */ | |
| 179 maxMarkers: { | |
| 180 type: Number, | |
| 181 value: 0, | |
| 182 notify: true, | |
| 183 observer: '_maxMarkersChanged' | |
| 184 }, | |
| 185 | |
| 186 /** | |
| 187 * If true, the knob is expanded | |
| 188 */ | |
| 189 expand: { | |
| 190 type: Boolean, | |
| 191 value: false, | |
| 192 readOnly: true | |
| 193 }, | |
| 194 | |
| 195 /** | |
| 196 * True when the user is dragging the slider. | |
| 197 */ | |
| 198 dragging: { | |
| 199 type: Boolean, | |
| 200 value: false, | |
| 201 readOnly: true | |
| 202 }, | |
| 203 | |
| 204 transiting: { | |
| 205 type: Boolean, | |
| 206 value: false, | |
| 207 readOnly: true | |
| 208 }, | |
| 209 | |
| 210 markers: { | |
| 211 type: Array, | |
| 212 readOnly: true, | |
| 213 value: [] | |
| 214 }, | |
| 215 }, | |
| 216 | |
| 217 observers: [ | |
| 218 '_updateKnob(value, min, max, snaps, step)', | |
| 219 '_minChanged(min)', | |
| 220 '_maxChanged(max)', | |
| 221 '_valueChanged(value)', | |
| 222 '_immediateValueChanged(immediateValue)' | |
| 223 ], | |
| 224 | |
| 225 hostAttributes: { | |
| 226 role: 'slider', | |
| 227 tabindex: 0 | |
| 228 }, | |
| 229 | |
| 230 keyBindings: { | |
| 231 'left down pagedown home': '_decrementKey', | |
| 232 'right up pageup end': '_incrementKey' | |
| 233 }, | |
| 234 | |
| 235 ready: function() { | |
| 236 // issue polymer/polymer#1305 | |
| 237 this.async(function() { | |
| 238 this._updateKnob(this.value); | |
| 239 this._updateInputValue(); | |
| 240 }, 1); | |
| 241 }, | |
| 242 | |
| 243 /** | |
| 244 * Increases value by `step` but not above `max`. | |
| 245 * @method increment | |
| 246 */ | |
| 247 increment: function() { | |
| 248 this.value = this._clampValue(this.value + this.step); | |
| 249 }, | |
| 250 | |
| 251 /** | |
| 252 * Decreases value by `step` but not below `min`. | |
| 253 * @method decrement | |
| 254 */ | |
| 255 decrement: function() { | |
| 256 this.value = this._clampValue(this.value - this.step); | |
| 257 }, | |
| 258 | |
| 259 _updateKnob: function(value) { | |
| 260 this._positionKnob(this._calcRatio(value)); | |
| 261 }, | |
| 262 | |
| 263 _minChanged: function() { | |
| 264 this.setAttribute('aria-valuemin', this.min); | |
| 265 }, | |
| 266 | |
| 267 _maxChanged: function() { | |
| 268 this.setAttribute('aria-valuemax', this.max); | |
| 269 }, | |
| 270 | |
| 271 _valueChanged: function() { | |
| 272 this.setAttribute('aria-valuenow', this.value); | |
| 273 this.fire('value-change'); | |
| 274 }, | |
| 275 | |
| 276 _immediateValueChanged: function() { | |
| 277 if (this.dragging) { | |
| 278 this.fire('immediate-value-change'); | |
| 279 } else { | |
| 280 this.value = this.immediateValue; | |
| 281 } | |
| 282 this._updateInputValue(); | |
| 283 }, | |
| 284 | |
| 285 _secondaryProgressChanged: function() { | |
| 286 this.secondaryProgress = this._clampValue(this.secondaryProgress); | |
| 287 }, | |
| 288 | |
| 289 _updateInputValue: function() { | |
| 290 if (this.editable) { | |
| 291 this.$$('#input').value = this.immediateValue.toString(); | |
| 292 } | |
| 293 }, | |
| 294 | |
| 295 _expandKnob: function() { | |
| 296 this._setExpand(true); | |
| 297 }, | |
| 298 | |
| 299 _resetKnob: function() { | |
| 300 this.cancelDebouncer('expandKnob'); | |
| 301 this._setExpand(false); | |
| 302 }, | |
| 303 | |
| 304 _positionKnob: function(ratio) { | |
| 305 this._setImmediateValue(this._calcStep(this._calcKnobPosition(ratio))); | |
| 306 this._setRatio(this._calcRatio(this.immediateValue)); | |
| 307 | |
| 308 this.$.sliderKnob.style.left = (this.ratio * 100) + '%'; | |
| 309 }, | |
| 310 | |
| 311 _inputChange: function() { | |
| 312 this.value = this.$$('#input').value; | |
| 313 this.fire('change'); | |
| 314 }, | |
| 315 | |
| 316 _calcKnobPosition: function(ratio) { | |
| 317 return (this.max - this.min) * ratio + this.min; | |
| 318 }, | |
| 319 | |
| 320 _onTrack: function(event) { | |
| 321 switch (event.detail.state) { | |
| 322 case 'start': | |
| 323 this._trackStart(event); | |
| 324 break; | |
| 325 case 'track': | |
| 326 this._trackX(event); | |
| 327 break; | |
| 328 case 'end': | |
| 329 this._trackEnd(); | |
| 330 break; | |
| 331 } | |
| 332 }, | |
| 333 | |
| 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'); | |
| 341 | |
| 342 this._setDragging(true); | |
| 343 }, | |
| 344 | |
| 345 _trackX: function(e) { | |
| 346 if (!this.dragging) { | |
| 347 this._trackStart(e); | |
| 348 } | |
| 349 | |
| 350 var dx = Math.min(this._maxx, Math.max(this._minx, e.detail.dx)); | |
| 351 this._x = this._startx + dx; | |
| 352 | |
| 353 var immediateValue = this._calcStep(this._calcKnobPosition(this._x / this.
_w)); | |
| 354 this._setImmediateValue(immediateValue); | |
| 355 | |
| 356 // update knob's position | |
| 357 var translateX = ((this._calcRatio(immediateValue) * this._w) - this._star
tx); | |
| 358 this.translate3d(translateX + 'px', 0, 0, this.$.sliderKnob); | |
| 359 }, | |
| 360 | |
| 361 _trackEnd: function() { | |
| 362 var s = this.$.sliderKnob.style; | |
| 363 | |
| 364 this.$.sliderKnob.classList.remove('dragging'); | |
| 365 this._setDragging(false); | |
| 366 this._resetKnob(); | |
| 367 this.value = this.immediateValue; | |
| 368 | |
| 369 s.transform = s.webkitTransform = ''; | |
| 370 | |
| 371 this.fire('change'); | |
| 372 }, | |
| 373 | |
| 374 _knobdown: function(event) { | |
| 375 this._expandKnob(); | |
| 376 | |
| 377 // cancel selection | |
| 378 event.detail.sourceEvent.preventDefault(); | |
| 379 | |
| 380 // set the focus manually because we will called prevent default | |
| 381 this.focus(); | |
| 382 }, | |
| 383 | |
| 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; | |
| 389 | |
| 390 this._setTransiting(true); | |
| 391 | |
| 392 this._positionKnob(ratio); | |
| 393 | |
| 394 this.debounce('expandKnob', this._expandKnob, 60); | |
| 395 | |
| 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 | |
| 399 | |
| 400 if (prevRatio === this.ratio) { | |
| 401 this._setTransiting(false); | |
| 402 } | |
| 403 | |
| 404 this.async(function() { | |
| 405 this.fire('change'); | |
| 406 }); | |
| 407 | |
| 408 // cancel selection | |
| 409 event.detail.sourceEvent.preventDefault(); | |
| 410 }, | |
| 411 | |
| 412 _knobTransitionEnd: function(event) { | |
| 413 if (event.target === this.$.sliderKnob) { | |
| 414 this._setTransiting(false); | |
| 415 } | |
| 416 }, | |
| 417 | |
| 418 _maxMarkersChanged: function(maxMarkers) { | |
| 419 var l = (this.max - this.min) / this.step; | |
| 420 if (!this.snaps && l > maxMarkers) { | |
| 421 this._setMarkers([]); | |
| 422 } else { | |
| 423 this._setMarkers(new Array(l)); | |
| 424 } | |
| 425 }, | |
| 426 | |
| 427 _getClassNames: function() { | |
| 428 var classes = {}; | |
| 429 | |
| 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; | |
| 438 | |
| 439 return Object.keys(classes).filter( | |
| 440 function(className) { | |
| 441 return classes[className]; | |
| 442 }).join(' '); | |
| 443 }, | |
| 444 | |
| 445 _incrementKey: function(event) { | |
| 446 if (event.detail.key === 'end') { | |
| 447 this.value = this.max; | |
| 448 } else { | |
| 449 this.increment(); | |
| 450 } | |
| 451 this.fire('change'); | |
| 452 }, | |
| 453 | |
| 454 _decrementKey: function(event) { | |
| 455 if (event.detail.key === 'home') { | |
| 456 this.value = this.min; | |
| 457 } else { | |
| 458 this.decrement(); | |
| 459 } | |
| 460 this.fire('change'); | |
| 461 } | |
| 462 }); | |
| 463 | |
| 464 /** | |
| 465 * Fired when the slider's value changes. | |
| 466 * | |
| 467 * @event value-change | |
| 468 */ | |
| 469 | |
| 470 /** | |
| 471 * Fired when the slider's immediateValue changes. | |
| 472 * | |
| 473 * @event immediate-value-change | |
| 474 */ | |
| 475 | |
| 476 /** | |
| 477 * Fired when the slider's value changes due to user interaction. | |
| 478 * | |
| 479 * Changes to the slider's value due to changes in an underlying | |
| 480 * bound variable will not trigger this event. | |
| 481 * | |
| 482 * @event change | |
| 483 */ | |
| 484 | |
| 485 </script> | |
| OLD | NEW |