/** * The slider is a way to allow the user to select a value from a given numerical range. * You might use it for choosing a percentage, combine two of them to get min and max values, * or use three of them to specify the hex values for a color. Each slider contains a single * 'thumb' that can be dragged along the slider's length to change the value. Sliders are equally * useful inside {@link Ext.form.Panel forms} and standalone. Here's how to quickly create a slider * in form, in this case enabling a user to choose a percentage: * * ```javascript * @example({ framework: 'extjs' }) * Ext.create('Ext.form.Panel', { * fullscreen: true, * items: [ * { * xtype: 'sliderfield', * label: 'Percentage', * value: 50, * minValue: 0, * maxValue: 100 * } * ] * }); * ``` * ```javascript * @example({framework: 'ext-react', packages:['ext-react']}) * import React, { Component } from 'react'; * import { ExtContainer, ExtFormPanel, ExtSliderField } from '@sencha/ext-react'; * export default class SliderFieldExample extends Component { * state = { * singleValue: 20, * multipleValue: [10, 70] * }; * * onSingleChange = (field, value) => { * this.setState({ singleValue: value }); * } * * onMultipleChange = (field, value) => { * this.setState({ multipleValue: value }); * } * * render() { * const { singleValue, multipleValue } = this.state; * * return ( * <ExtContainer layout="center"> * <ExtFormPanel shadow width="300"> * <ExtSliderField * onChange={this.onSingleChange} * label="Single Thumb" * value={singleValue} * /> * <div style={{marginBottom: '20px'}}>Value: {singleValue}</div> * <ExtSliderField * onChange={this.onMultipleChange} * label="Multiple Thumbs" * values={multipleValue} * /> * <div>Values: {multipleValue.join(', ')}</div> * </ExtFormPanel> * </ExtContainer> * ) * } * } * ``` * ```javascript * @example({framework: 'ext-angular', packages:['ext-angular']}) * import { Component } from '@angular/core' * declare var Ext: any; * * @Component({ * selector: 'app-root-1', * styles: [``], * template: ` * <ExtContainer [layout]="'center'"> * <ExtFormPanel [shadow]="true" [width]="400" [height]="300"> * <ExtSliderField * (change)="onSingleChange($event)" * label="Single Thumb" * [value]="singleValue" * > * </ExtSliderField> * <ExtContainer [style]="{marginBottom: 20}" * [html]="'Value: '+singleValue"> * </ExtContainer> * <ExtSliderField * (change)="onMultipleChange($event)" * label="Multiple Thumbs" * [value]="multipleValue" * > * </ExtSliderField> * <ExtContainer * [html]="'Values: '+multipleValue.join(', ')"> * </ExtContainer> * </ExtFormPanel> * </ExtContainer> * ` * }) * export class AppComponent { * singleValue:number = 20; * multipleValue:number[] = [10, 70]; * * onSingleChange = (params) => { * this.singleValue = params.newValue; * } * * onMultipleChange = (params) => { * this.multipleValue = params.newValue; * } * } * ``` * ```html * @example({framework: 'ext-web-components', packages:['ext-web-components'], tab: 1 }) * <ext-container layout="center"> * <ext-formpanel * shadow="true" * width="300" * > * <ext-sliderfield * onChange="sliderfield.onSingleChange" * label="Single Thumb" * value="20" * onready="sliderfield.readySingleChangeSliderField" * > * </ext-sliderfield> * <ext-container * style='{marginBottom: "20px"}' * onready="sliderfield.readySingleValueMessage" * > * </ext-container> * <ext-sliderfield * onChange="sliderfield.onMultipleChange" * label="Multiple Thumbs" * value="[10,70]" * onready="sliderfield.readyMultipleChangeSliderField" * > * </ext-sliderfield> * <ext-container * onready="sliderfield.readyMultipleValueMessage" * > * </ext-container> * </ext-formpanel> * </ext-container> * ``` * ```javascript * @example({framework: 'ext-web-components', packages:['ext-web-components'], tab: 2 }) * import '@sencha/ext-web-components/dist/ext-container.component'; * import '@sencha/ext-web-components/dist/ext-formpanel.component'; * import '@sencha/ext-web-components/dist/ext-sliderfield.component'; * * export default class SliderFieldComponent { * * constructor() { * this.singleValue = 20; * this.multipleValue = [10, 70]; * } * * onSingleChange = (event) => { * this.singleValueMessageView.setHTML(`Values: ${event.detail.newValue}`) * } * * readySingleChangeSliderField = (event) => { * this.singleValueSliderFieldView = event.detail.cmp; * } * * readyMultipleChangeSliderField = (event) => { * this.multipleValueSliderFieldView = event.detail.cmp; * } * * onMultipleChange = (event) => { * this.multipleValueMessageView.setHTML(`Values: ${event.detail.newValue.join(',')}`) * } * * readyMultipleValueMessage = (event) => { * this.multipleValueMessageView = event.detail.cmp; * this.multipleValueMessageView.setHtml(`Values: ${this.multipleValue}`) * } * * readySingleValueMessage = (event) => { * this.singleValueMessageView = event.detail.cmp; * this.singleValueMessageView.setHtml(`Value: ${this.singleValue}`); * } * } * * window.sliderfield = new SliderFieldComponent(); * ``` * * In this case we set a starting value of 50%, and defined the min and max values to be 0 and * 100 respectively, giving us a percentage slider. Because this is such a common use case, the * defaults for {@link #minValue} and {@link #maxValue} are already set to 0 and 100 so in the * example above they could be removed. * * It's often useful to render sliders outside the context of a form panel too. In this example * we create a slider that allows a user to choose the waist measurement of a pair of jeans. * Let's say the online store we're making this for sells jeans with waist sizes from 24 inches * to 60 inches in 2 inch increments - here's how we might achieve that: * * @example * Ext.create('Ext.form.Panel', { * fullscreen: true, * items: [ * { * xtype: 'sliderfield', * label: 'Waist Measurement', * minValue: 24, * maxValue: 60, * increment: 2, * value: 32 * } * ] * }); * * Now that we've got our slider, we can ask it what value it currently has and listen * to events that it fires. For example, if we wanted our app to show different images * for different sizes, we can listen to the {@link #change} event to be informed whenever * the slider is moved: * * slider.on('change', function(field, newValue) { * if (newValue[0] > 40) { * imgComponent.setSrc('large.png'); * } else { * imgComponent.setSrc('small.png'); * } * }, this); * * Here we listened to the {@link #change} event on the slider and updated the background * image of an {@link Ext.Img image component} based on what size the user selected. Of * course, you can use any logic inside your event listener. */Ext.define('Ext.field.Slider', { extend: 'Ext.field.Field', xtype: 'sliderfield', requires: ['Ext.slider.Slider'], alternateClassName: 'Ext.form.Slider', mixins: [ 'Ext.mixin.ConfigProxy', 'Ext.field.BoxLabelable' ], /** * @event change * Fires when the value changes. * @param {Ext.field.Slider} me * @param {Number[]} newValue The new value. * @param {Number[]} oldValue The old value. */ /** * @event dragchange * Fires when a thumb value changes via drag. * @param {Ext.field.Slider} me * @param {Ext.slider.Slider} sl Slider Component. * @param {Ext.slider.Thumb} thumb * @param {Number[]} newValue The new value of this thumb. * @param {Number[]} oldValue The old value of this thumb. */ /** * @event dragstart * Fires when the slider thumb starts a drag operation. * @param {Ext.field.Slider} this * @param {Ext.slider.Slider} sl Slider Component. * @param {Ext.slider.Thumb} thumb The thumb being dragged. * @param {Array} value The start value. * @param {Ext.event.Event} e */ /** * @event drag * Fires when the slider thumb starts a drag operation. * @param {Ext.field.Slider} this * @param {Ext.slider.Slider} sl Slider Component. * @param {Ext.slider.Thumb} thumb The thumb being dragged. * @param {Ext.event.Event} e */ /** * @event dragend * Fires when the slider thumb ends a drag operation. * @param {Ext.field.Slider} this * @param {Ext.slider.Slider} sl Slider Component. * @param {Ext.slider.Thumb} thumb The thumb being dragged. * @param {Array} value The end value. * @param {Ext.event.Event} e */ config: { /** * @private */ slider: { xtype: 'slider', inheritUi: true }, /** * @cfg {Boolean} liveUpdate * `true` to fire change events while the slider is dragging. `false` will * only fire a change once the drag is complete. */ liveUpdate: false, /** * @cfg tabIndex * @inheritdoc */ tabIndex: -1, /** * @cfg readOnly * Will make this field read only, meaning it cannot be changed with used interaction. * @accessor */ readOnly: false, /** * @cfg value * @inheritdoc Ext.slider.Slider#cfg-value * @accessor */ value: 0 }, /** * @property classCls * @inheritdoc */ classCls: Ext.baseCSSPrefix + 'sliderfield', proxyConfig: { slider: [ /** * @cfg increment * @inheritdoc Ext.slider.Slider#increment */ 'increment', /** * @cfg minValue * @inheritdoc Ext.slider.Slider#minValue */ 'minValue', /** * @cfg maxValue * @inheritdoc Ext.slider.Slider#maxValue */ 'maxValue' ] }, /** * @cfg bodyAlign * @inheritdoc */ bodyAlign: 'stretch', /** * @property defaultBindProperty * @inheritdoc */ defaultBindProperty: 'value', /** * @cfg twoWayBindable * @inheritdoc */ twoWayBindable: { values: 1, value: 1 }, /** * @cfg values * @inheritdoc Ext.slider.Slider#cfg-values */ constructor: function(config) { config = config || {}; if (config.hasOwnProperty('values')) { config.value = config.values; } this.callParent([config]); this.updateMultipleState(); }, /** * @private */ initialize: function() { this.callParent(); this.getSlider().on({ scope: this, change: 'onSliderChange', dragstart: 'onSliderDragStart', drag: 'onSliderDrag', dragend: 'onSliderDragEnd' }); }, getBodyTemplate: function() { return this.mixins.boxLabelable.getBodyTemplate.call(this); }, applySlider: function(slider) { if (slider && !slider.isInstance) { slider = this.mergeProxiedConfigs('slider', slider); slider.$initParent = this; slider = Ext.create(slider); delete slider.$initParent; } this.boxElement.appendChild(slider.el); slider.ownerCmp = this; return slider; }, updateSlider: function(slider) { slider.doInheritUi(); }, getValue: function() { return this._value; }, applyValue: function(value, oldValue) { value = this.callParent([value, oldValue]) || 0; // If we are currently dragging, don't allow the binding // to push a value over the top of what the user is doing. if (this.dragging && this.isSyncing('value')) { value = undefined; } else if (Ext.isArray(value)) { value = value.slice(0); if (oldValue && Ext.Array.equals(value, oldValue)) { value = undefined; } } else { value = [value]; } return value; }, updateValue: function(value, oldValue) { if (!this.dragging) { value = this.setSliderValue(value); } this.callParent([value, oldValue]); }, setSliderValue: function(value) { // Get the value back out after setting return this.getSlider().setValue(value).getValue(); }, onSliderChange: function(slider, thumb, newValue, oldValue) { this.setValue(slider.getValue()); this.fireEvent('dragchange', this, slider, thumb, newValue, oldValue); }, onSliderDragStart: function(slider, thumb, startValue, e) { this.dragging = true; this.fireEvent('dragstart', this, slider, thumb, startValue, e); }, onSliderDrag: function(slider, thumb, value, e) { var me = this; if (me.getLiveUpdate()) { me.setValue(slider.getValue()); } me.fireEvent('drag', me, slider, thumb, value, e); }, onSliderDragEnd: function(slider, thumb, startValue, e) { this.dragging = false; this.fireEvent('dragend', this, slider, thumb, startValue, e); }, /** * Convenience method. Calls {@link #setValue}. * @param {Object} value */ setValues: function(value) { this.setValue(value); this.updateMultipleState(); }, /** * Convenience method. Calls {@link #getValue} * @return {Object} */ getValues: function() { return this.getValue(); }, reset: function() { var config = this.config, initialValue = (this.config.hasOwnProperty('values')) ? config.values : config.value; this.setValue(initialValue); }, updateReadOnly: function(newValue) { this.getSlider().setReadOnly(newValue); }, updateMultipleState: function() { var value = this.getValue(); if (value && value.length > 1) { this.addCls(Ext.baseCSSPrefix + 'slider-multiple'); } }, updateDisabled: function(disabled, oldDisabled) { this.callParent([disabled, oldDisabled]); this.getSlider().setDisabled(disabled); }, doDestroy: function() { this.getSlider().destroy(); this.callParent(); }, getRefItems: function(deep) { var refItems = [], slider = this.getSlider(); if (slider) { refItems.push(slider); if (deep && slider.getRefItems) { refItems.push.apply(refItems, slider.getRefItems(deep)); } } return refItems; }, rawToValue: Ext.emptyFn});