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 |