forked from SAP/ui5-webcomponents
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSlider.js
226 lines (200 loc) · 6.13 KB
/
Slider.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
import Float from "@ui5/webcomponents-base/dist/types/Float.js";
import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js";
import SliderBase from "./SliderBase.js";
// Template
import SliderTemplate from "./generated/templates/SliderTemplate.lit.js";
/**
* @public
*/
const metadata = {
tag: "ui5-slider",
languageAware: true,
managedSlots: true,
properties: /** @lends sap.ui.webcomponents.main.Slider.prototype */ {
/**
* Current value of the slider
*
* @type {Float}
* @defaultvalue 0
* @public
*/
value: {
type: Float,
defaultValue: 0,
},
},
};
/**
* @class
*
* <h3 class="comment-api-title">Overview</h3>
* The Slider component represents a numerical range and a handle (grip).
* The purpose of the component is to enable visual selection of a value in
* a continuous numerical range by moving an adjustable handle.
*
* <h3>Structure</h3>
* The most important properties of the Slider are:
* <ul>
* <li>min - The minimum value of the slider range</li>
* <li>max - The maximum value of the slider range</li>
* <li>value - The current value of the slider</li>
* <li>step - Determines the increments in which the slider will move</li>
* <li>showTooltip - Determines if a tooltip should be displayed above the handle</li>
* <li>showTickmarks - Displays a visual divider between the step values</li>
* <li>labelInterval - Labels some or all of the tickmarks with their values.</li>
* </ul>
*
* <h3>Usage</h3>
* The most common usecase is to select values on a continuous numerical scale (e.g. temperature, volume, etc. ).
*
* <h3>Responsive Behavior</h3>
* The <code>ui5-slider</code> component adjusts to the size of its parent container by recalculating and
* resizing the width of the control. You can move the slider handle in several different ways:
* <ul>
* <li>Drag and drop to the desired value</li>
* <li>Click/tap on the range bar to move the handle to that location</li>
* </ul>
*
* <h3>ES6 Module Import</h3>
*
* <code>import "@ui5/webcomponents/dist/Slider";</code>
*
* @constructor
* @author SAP SE
* @alias sap.ui.webcomponents.main.Slider
* @extends sap.ui.webcomponents.base.UI5Element
* @tagname ui5-slider
* @since 1.0.0-rc.11
* @appenddocs SliderBase
* @public
*/
class Slider extends SliderBase {
static get metadata() {
return metadata;
}
static get template() {
return SliderTemplate;
}
constructor() {
super();
this._stateStorage.value = null;
this.i18nBundle = getI18nBundle("@ui5/webcomponents");
}
/**
*
* Check if the previously saved state is outdated. That would mean
* either it is the initial rendering or that a property has been changed
* programatically - because the previous state is always updated in
* the interaction handlers.
*
* Normalize current properties, update the previously stored state.
* Update the visual UI representation of the Slider
*
*/
onBeforeRendering() {
if (!this.isCurrentStateOutdated()) {
return;
}
this.notResized = true;
this.syncUIAndState("value");
this._updateHandleAndProgress(this.value);
}
/**
* Called when the user starts interacting with the slider
*
* @private
*/
_onmousedown(event) {
// If step is 0 no interaction is available because there is no constant
// (equal for all user environments) quantitative representation of the value
if (this.disabled || this.step === 0) {
return;
}
const newValue = this.handleDownBase(event, this._effectiveMin, this._effectiveMax);
// Do not yet update the Slider if press is over a handle. It will be updated if the user drags the mouse.
if (!this._isHandlePressed(this.constructor.getPageXValueFromEvent(event))) {
this._updateHandleAndProgress(newValue);
this.updateValue("value", newValue);
}
}
/**
* Called when the user moves the slider
*
* @private
*/
_handleMove(event) {
event.preventDefault();
// If step is 0 no interaction is available because there is no constant
// (equal for all user environments) quantitative representation of the value
if (this.disabled || this._effectiveStep === 0) {
return;
}
const newValue = this.constructor.getValueFromInteraction(event, this._effectiveStep, this._effectiveMin, this._effectiveMax, this.getBoundingClientRect(), this.directionStart);
this._updateHandleAndProgress(newValue);
this.updateValue("value", newValue);
}
/** Called when the user finish interacting with the slider
*
* @private
*/
_handleUp(event) {
this.handleUpBase();
}
/** Determines if the press is over the handle
*
* @private
*/
_isHandlePressed(clientX) {
const sliderHandle = this.shadowRoot.querySelector(".ui5-slider-handle");
const sliderHandleDomRect = sliderHandle.getBoundingClientRect();
return clientX >= sliderHandleDomRect.left && clientX <= sliderHandleDomRect.right;
}
/** Updates the UI representation of the progress bar and handle position
*
* @private
*/
_updateHandleAndProgress(newValue) {
const max = this._effectiveMax;
const min = this._effectiveMin;
// The progress (completed) percentage of the slider.
this._progressPercentage = (newValue - min) / (max - min);
// How many pixels from the left end of the slider will be the placed the affected by the user action handle
this._handlePositionFromStart = this._progressPercentage * 100;
}
get styles() {
return {
progress: {
"transform": `scaleX(${this._progressPercentage})`,
"transform-origin": `${this.directionStart} top`,
},
handle: {
[this.directionStart]: `${this._handlePositionFromStart}%`,
},
tickmarks: {
"background": `${this._tickmarks}`,
},
label: {
"width": `${this._labelWidth}%`,
},
labelContainer: {
"width": `100%`,
[this.directionStart]: `-${this._labelWidth / 2}%`,
},
tooltip: {
"visibility": `${this._tooltipVisibility}`,
},
};
}
get labelItems() {
return this._labelItems;
}
get tooltipValue() {
const stepPrecision = this.constructor._getDecimalPrecisionOfNumber(this._effectiveStep);
return this.value.toFixed(stepPrecision);
}
static async onDefine() {
await fetchI18nBundle("@ui5/webcomponents");
}
}
Slider.define();
export default Slider;