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 |
| 5 The complete set of authors may be found at http://polymer.github.io/AUTHORS |
| 6 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS |
| 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 |
| 9 --> |
| 10 |
| 11 <link rel="import" href="../paper-styles/paper-styles.html"> |
| 12 <link rel="import" href="../iron-flex-layout/iron-flex-layout.html"> |
| 13 <link rel="import" href="../iron-behaviors/iron-control-state.html"> |
| 14 <link rel="import" href="../paper-progress/paper-progress.html"> |
| 15 <link rel="import" href="../paper-input/paper-input.html"> |
| 16 |
| 17 <!-- |
| 18 `paper-slider` allows user to select a value from a range of values by |
| 19 moving the slider thumb. The interactive nature of the slider makes it a |
| 20 great choice for settings that reflect intensity levels, such as volume, |
| 21 brightness, or color saturation. |
| 22 |
| 23 Example: |
| 24 |
| 25 <paper-slider></paper-slider> |
| 26 |
| 27 Use `min` and `max` to specify the slider range. Default is 0 to 100. |
| 28 |
| 29 Example: |
| 30 |
| 31 <paper-slider min="10" max="200" value="110"></paper-slider> |
| 32 |
| 33 Styling slider: |
| 34 |
| 35 To change the slider progress bar color: |
| 36 |
| 37 paper-slider { |
| 38 --paper-slider-active-color: #0f9d58; |
| 39 } |
| 40 |
| 41 To change the slider knob color: |
| 42 |
| 43 paper-slider { |
| 44 --paper-slider-knob-color: #0f9d58; |
| 45 } |
| 46 |
| 47 To change the slider pin color: |
| 48 |
| 49 paper-slider { |
| 50 --paper-slider-pin-color: #0f9d58; |
| 51 } |
| 52 |
| 53 To change the slider pin's font color: |
| 54 |
| 55 paper-slider { |
| 56 --paper-slider-pin-font-color: #0f9d58; |
| 57 } |
| 58 |
| 59 To change the slider secondary progress bar color: |
| 60 |
| 61 paper-slider { |
| 62 --paper-slider-secondary-color: #0f9d58; |
| 63 } |
| 64 |
| 65 To change the slider disabled active color: |
| 66 |
| 67 paper-slider { |
| 68 --paper-slider-disabled-active-color: #ccc; |
| 69 } |
| 70 |
| 71 To change the slider disabled secondary progress bar color: |
| 72 |
| 73 paper-slider { |
| 74 --paper-slider-disabled-secondary-color: #ccc; |
| 75 } |
| 76 |
| 77 @group Paper Elements |
| 78 @element paper-slider |
| 79 @demo demo/index.html |
| 80 @hero hero.svg |
| 81 --> |
| 82 |
| 83 <dom-module id="paper-slider"> |
| 84 <link rel="import" type="css" href="paper-slider.css"> |
| 85 <template> |
| 86 <template is="dom-if" if="{{!disabled}}"> |
| 87 </template> |
| 88 |
| 89 <div id="sliderContainer" class$="[[_getClassNames(disabled, pin, snaps, imm
ediateValue, min, expand, dragging, transiting, editable)]]"> |
| 90 <div class="bar-container"> |
| 91 <paper-progress id="sliderBar" aria-hidden="true" min="[[min]]" max="[[m
ax]]" value="[[immediateValue]]" secondary-progress="[[secondaryProgress]]" |
| 92 on-down="_bardown" on-up="_resetKnob" on-track="_onTrack"></paper-prog
ress> |
| 93 </div> |
| 94 |
| 95 <template is="dom-if" if="[[snaps]]"> |
| 96 <div class="slider-markers horizontal layout"> |
| 97 <template is="dom-repeat" items="[[markers]]"> |
| 98 <div class="slider-marker flex"></div> |
| 99 </template> |
| 100 </div> |
| 101 </template> |
| 102 |
| 103 <div id="sliderKnob" on-down="_knobdown" on-up="_resetKnob" |
| 104 on-track="_onTrack" |
| 105 on-transitionend="_knobTransitionEnd" |
| 106 center-justified center horizontal layout> |
| 107 |
| 108 <div id="sliderKnobInner" value$="[[immediateValue]]"></div> |
| 109 </div> |
| 110 </div> |
| 111 |
| 112 <template is="dom-if" if="[[editable]]"> |
| 113 <paper-input id="input" class="slider-input" disabled$="[[disabled]]" on-c
hange="_inputChange"></paper-input> |
| 114 </template> |
| 115 |
| 116 </template> |
| 117 </dom-module> |
| 118 |
| 119 <script> |
| 120 /** |
| 121 * Fired when the slider's value changes. |
| 122 * |
| 123 * @event value-change |
| 124 */ |
| 125 |
| 126 /** |
| 127 * Fired when the slider's immediateValue changes. |
| 128 * |
| 129 * @event immediate-value-change |
| 130 */ |
| 131 |
| 132 /** |
| 133 * Fired when the slider's value changes due to user interaction. |
| 134 * |
| 135 * Changes to the slider's value due to changes in an underlying |
| 136 * bound variable will not trigger this event. |
| 137 * |
| 138 * @event change |
| 139 */ |
| 140 |
| 141 Polymer({ |
| 142 is: 'paper-slider', |
| 143 |
| 144 behaviors: [ |
| 145 Polymer.IronRangeBehavior, |
| 146 Polymer.IronControlState |
| 147 ], |
| 148 |
| 149 properties: { |
| 150 |
| 151 /** |
| 152 * If true, the slider thumb snaps to tick marks evenly spaced based |
| 153 * on the `step` property value. |
| 154 */ |
| 155 snaps: { |
| 156 type: Boolean, |
| 157 value: false, |
| 158 notify: true |
| 159 }, |
| 160 |
| 161 /** |
| 162 * If true, a pin with numeric value label is shown when the slider thumb |
| 163 * is pressed. Use for settings for which users need to know the exact |
| 164 * value of the setting. |
| 165 */ |
| 166 pin: { |
| 167 type: Boolean, |
| 168 value: false, |
| 169 notify: true |
| 170 }, |
| 171 |
| 172 /** |
| 173 * The number that represents the current secondary progress. |
| 174 */ |
| 175 secondaryProgress: { |
| 176 type: Number, |
| 177 value: 0, |
| 178 notify: true, |
| 179 observer: '_secondaryProgressChanged' |
| 180 }, |
| 181 |
| 182 /** |
| 183 * If true, an input is shown and user can use it to set the slider value. |
| 184 */ |
| 185 editable: { |
| 186 type: Boolean, |
| 187 value: false |
| 188 }, |
| 189 |
| 190 /** |
| 191 * The immediate value of the slider. This value is updated while the use
r |
| 192 * is dragging the slider. |
| 193 */ |
| 194 immediateValue: { |
| 195 type: Number, |
| 196 value: 0, |
| 197 readOnly: true |
| 198 }, |
| 199 |
| 200 /** |
| 201 * The maximum number of markers |
| 202 */ |
| 203 maxMarkers: { |
| 204 type: Number, |
| 205 value: 0, |
| 206 notify: true, |
| 207 observer: '_maxMarkersChanged' |
| 208 }, |
| 209 |
| 210 /** |
| 211 * If true, the knob is expanded |
| 212 */ |
| 213 expand: { |
| 214 type: Boolean, |
| 215 value: false, |
| 216 readOnly: true |
| 217 }, |
| 218 |
| 219 /** |
| 220 * True when the user is dragging the slider. |
| 221 */ |
| 222 dragging: { |
| 223 type: Boolean, |
| 224 value: false, |
| 225 readOnly: true |
| 226 }, |
| 227 |
| 228 transiting: { |
| 229 type: Boolean, |
| 230 value: false, |
| 231 readOnly: true |
| 232 }, |
| 233 |
| 234 markers: { |
| 235 readOnly: true, |
| 236 value: [] |
| 237 }, |
| 238 }, |
| 239 |
| 240 observers: [ |
| 241 '_updateKnob(value, min, max, snaps, step)', |
| 242 '_minChanged(min)', |
| 243 '_maxChanged(max)', |
| 244 '_valueChanged(value)', |
| 245 '_immediateValueChanged(immediateValue)' |
| 246 ], |
| 247 |
| 248 ready: function() { |
| 249 // issue polymer/polymer#1305 |
| 250 this.async(function() { |
| 251 this._updateKnob(this.value); |
| 252 this._updateInputValue(); |
| 253 }, 1); |
| 254 }, |
| 255 |
| 256 /** |
| 257 * Increases value by `step` but not above `max`. |
| 258 * @method increment |
| 259 */ |
| 260 increment: function() { |
| 261 this.value = this._clampValue(this.value + this.step); |
| 262 }, |
| 263 |
| 264 /** |
| 265 * Decreases value by `step` but not below `min`. |
| 266 * @method decrement |
| 267 */ |
| 268 decrement: function() { |
| 269 this.value = this._clampValue(this.value - this.step); |
| 270 }, |
| 271 |
| 272 _updateKnob: function(value) { |
| 273 this._positionKnob(this._calcRatio(value)); |
| 274 }, |
| 275 |
| 276 _minChanged: function() { |
| 277 this.setAttribute('aria-valuemin', this.min); |
| 278 }, |
| 279 |
| 280 _maxChanged: function() { |
| 281 this.setAttribute('aria-valuemax', this.max); |
| 282 }, |
| 283 |
| 284 _valueChanged: function() { |
| 285 this.setAttribute('aria-valuenow', this.value); |
| 286 this.fire('value-change'); |
| 287 }, |
| 288 |
| 289 _immediateValueChanged: function() { |
| 290 if (!this.dragging) { |
| 291 this.value = this.immediateValue; |
| 292 } |
| 293 this._updateInputValue(); |
| 294 this.fire('immediate-value-change'); |
| 295 }, |
| 296 |
| 297 _secondaryProgressChanged: function() { |
| 298 this.secondaryProgress = this._clampValue(this.secondaryProgress); |
| 299 }, |
| 300 |
| 301 _updateInputValue: function() { |
| 302 if (this.editable) { |
| 303 this.$$('#input').value = this.immediateValue; |
| 304 } |
| 305 }, |
| 306 |
| 307 _expandKnob: function() { |
| 308 this._setExpand(true); |
| 309 }, |
| 310 |
| 311 _resetKnob: function() { |
| 312 this._expandJob && this._expandJob.stop(); |
| 313 this._setExpand(false); |
| 314 }, |
| 315 |
| 316 _positionKnob: function(ratio) { |
| 317 this._setImmediateValue(this._calcStep(this._calcKnobPosition(ratio)) || 0
); |
| 318 this._setRatio(this.snaps ? this._calcRatio(this.immediateValue) : ratio); |
| 319 this.$.sliderKnob.style.left = this.ratio * 100 + '%'; |
| 320 }, |
| 321 |
| 322 _inputChange: function() { |
| 323 this.value = this.$$('#input').value; |
| 324 this.fire('change'); |
| 325 }, |
| 326 |
| 327 _calcKnobPosition: function(ratio) { |
| 328 return (this.max - this.min) * ratio + this.min; |
| 329 }, |
| 330 |
| 331 _onTrack: function(e) { |
| 332 switch (event.detail.state) { |
| 333 case 'end': |
| 334 this._trackEnd(event); |
| 335 break; |
| 336 case 'track': |
| 337 this._trackX(event); |
| 338 break; |
| 339 case 'start': |
| 340 this._trackStart(event); |
| 341 break; |
| 342 } |
| 343 }, |
| 344 |
| 345 _trackStart: function(e) { |
| 346 this._w = this.$.sliderBar.offsetWidth; |
| 347 this._x = this.ratio * this._w; |
| 348 this._startx = this._x || 0; |
| 349 this._minx = - this._startx; |
| 350 this._maxx = this._w - this._startx; |
| 351 this.$.sliderKnob.classList.add('dragging'); |
| 352 this._setDragging(true); |
| 353 e.preventDefault(); |
| 354 }, |
| 355 |
| 356 _trackX: function(e) { |
| 357 if (!this.dragging) { |
| 358 this._trackStart(e); |
| 359 } |
| 360 var x = Math.min(this._maxx, Math.max(this._minx, e.detail.dx)); |
| 361 this._x = this._startx + x; |
| 362 this._setImmediateValue(this._calcStep( |
| 363 this._calcKnobPosition(this._x / this._w)) || 0); |
| 364 var s = this.$.sliderKnob.style; |
| 365 s.transform = s.webkitTransform = 'translate3d(' + (this.snaps ? |
| 366 (this._calcRatio(this.immediateValue) * this._w) - this._startx : x) +
'px, 0, 0)'; |
| 367 }, |
| 368 |
| 369 _trackEnd: function() { |
| 370 var s = this.$.sliderKnob.style; |
| 371 s.transform = s.webkitTransform = ''; |
| 372 this.$.sliderKnob.classList.remove('dragging'); |
| 373 this._setDragging(false); |
| 374 this._resetKnob(); |
| 375 this.value = this.immediateValue; |
| 376 this.fire('change'); |
| 377 }, |
| 378 |
| 379 _knobdown: function(e) { |
| 380 e.preventDefault(); |
| 381 this._expandKnob(); |
| 382 }, |
| 383 |
| 384 _bardown: function(e) { |
| 385 e.preventDefault(); |
| 386 this._setTransiting(true); |
| 387 this._w = this.$.sliderBar.offsetWidth; |
| 388 var rect = this.$.sliderBar.getBoundingClientRect(); |
| 389 var ratio = (e.detail.x - rect.left) / this._w; |
| 390 this._positionKnob(ratio); |
| 391 this._expandJob = this.debounce(this._expandJob, this._expandKnob, 60); |
| 392 |
| 393 this.async(function() { |
| 394 this.fire('change'); |
| 395 }); |
| 396 }, |
| 397 |
| 398 _knobTransitionEnd: function(e) { |
| 399 if (e.target === this.$.sliderKnob) { |
| 400 this._setTransiting(false); |
| 401 } |
| 402 }, |
| 403 |
| 404 _maxMarkersChanged: function(maxMarkers) { |
| 405 var l = (this.max - this.min) / this.step; |
| 406 if (!this.snaps && l > maxMarkers) { |
| 407 this._setMarkers([]); |
| 408 } else { |
| 409 this._setMarkers(new Array(l)); |
| 410 } |
| 411 }, |
| 412 |
| 413 _getClassNames: function() { |
| 414 var classes = {}; |
| 415 |
| 416 classes['disabled'] = this.disabled; |
| 417 classes['pin'] = this.pin; |
| 418 classes['snaps'] = this.snaps; |
| 419 classes['ring'] = this.immediateValue <= this.min; |
| 420 classes['expand'] = this.expand; |
| 421 classes['dragging'] = this.dragging; |
| 422 classes['transiting'] = this.transiting; |
| 423 classes['editable'] = this.editable; |
| 424 |
| 425 return Object.keys(classes).filter( |
| 426 function(className) { |
| 427 return classes[className]; |
| 428 }).join(' '); |
| 429 }, |
| 430 |
| 431 _incrementKey: function(ev, keys) { |
| 432 if (keys.key === 'end') { |
| 433 this.value = this.max; |
| 434 } else { |
| 435 this.increment(); |
| 436 } |
| 437 this.fire('change'); |
| 438 }, |
| 439 |
| 440 _decrementKey: function(ev, keys) { |
| 441 if (keys.key === 'home') { |
| 442 this.value = this.min; |
| 443 } else { |
| 444 this.decrement(); |
| 445 } |
| 446 this.fire('change'); |
| 447 } |
| 448 }) |
| 449 </script> |
OLD | NEW |