@@ -12,13 +12,14 @@ import {
12
12
import * as _ from 'underscore' ;
13
13
14
14
import {
15
- IntSliderView , IntRangeSliderView , IntTextView
15
+ IntSliderView , IntRangeSliderView , IntTextView , BaseIntSliderView
16
16
} from './widget_int' ;
17
17
18
18
import {
19
19
format
20
20
} from 'd3-format' ;
21
21
22
+
22
23
export
23
24
class FloatModel extends CoreDescriptionModel {
24
25
defaults ( ) {
@@ -69,6 +70,39 @@ class FloatSliderModel extends BoundedFloatModel {
69
70
readout_formatter : any ;
70
71
}
71
72
73
+ export
74
+ class FloatLogSliderModel extends BoundedFloatModel {
75
+ defaults ( ) {
76
+ return _ . extend ( super . defaults ( ) , {
77
+ _model_name : 'FloatLogSliderModel' ,
78
+ _view_name : 'FloatLogSliderView' ,
79
+ step : 0.1 ,
80
+ orientation : 'horizontal' ,
81
+ _range : false ,
82
+ readout : true ,
83
+ readout_format : '.2f' ,
84
+ slider_color : null ,
85
+ continuous_update : true ,
86
+ disabled : false ,
87
+ base : 10. ,
88
+ value : 1.0 ,
89
+ min : 0 ,
90
+ max : 4
91
+ } ) ;
92
+ }
93
+ initialize ( attributes , options ) {
94
+ super . initialize ( attributes , options ) ;
95
+ this . on ( 'change:readout_format' , this . update_readout_format , this ) ;
96
+ this . update_readout_format ( ) ;
97
+ }
98
+
99
+ update_readout_format ( ) {
100
+ this . readout_formatter = format ( this . get ( 'readout_format' ) ) ;
101
+ }
102
+
103
+ readout_formatter : any ;
104
+ }
105
+
72
106
export
73
107
class FloatRangeSliderModel extends FloatSliderModel { }
74
108
@@ -85,6 +119,112 @@ class FloatSliderView extends IntSliderView {
85
119
_parse_value = parseFloat ;
86
120
}
87
121
122
+
123
+ export
124
+ class FloatLogSliderView extends BaseIntSliderView {
125
+
126
+ update ( options ?) {
127
+ super . update ( options ) ;
128
+ let min = this . model . get ( 'min' ) ;
129
+ let max = this . model . get ( 'max' ) ;
130
+ let value = this . model . get ( 'value' ) ;
131
+ let base = this . model . get ( 'base' ) ;
132
+
133
+ let log_value = Math . log ( value ) / Math . log ( base ) ;
134
+
135
+ if ( log_value > max ) {
136
+ log_value = max ;
137
+ } else if ( log_value < min ) {
138
+ log_value = min ;
139
+ }
140
+ this . $slider . slider ( 'option' , 'value' , log_value ) ;
141
+ this . readout . textContent = this . valueToString ( value ) ;
142
+ if ( this . model . get ( 'value' ) !== value ) {
143
+ this . model . set ( 'value' , value , { updated_view : this } ) ;
144
+ this . touch ( ) ;
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Write value to a string
150
+ */
151
+ valueToString ( value : number ) : string {
152
+ let format = this . model . readout_formatter ;
153
+ return format ( value ) ;
154
+ }
155
+
156
+ /**
157
+ * Parse value from a string
158
+ */
159
+ stringToValue ( text : string ) : number {
160
+ return this . _parse_value ( text ) ;
161
+ }
162
+
163
+ /**
164
+ * this handles the entry of text into the contentEditable label first, the
165
+ * value is checked if it contains a parseable value then it is clamped
166
+ * within the min-max range of the slider finally, the model is updated if
167
+ * the value is to be changed
168
+ *
169
+ * if any of these conditions are not met, the text is reset
170
+ */
171
+ handleTextChange ( ) {
172
+ let value = this . stringToValue ( this . readout . textContent ) ;
173
+ let vmin = this . model . get ( 'min' ) ;
174
+ let vmax = this . model . get ( 'max' ) ;
175
+ let base = this . model . get ( 'base' ) ;
176
+
177
+ if ( isNaN ( value ) ) {
178
+ this . readout . textContent = this . valueToString ( this . model . get ( 'value' ) ) ;
179
+ } else {
180
+ value = Math . max ( Math . min ( value , Math . pow ( base , vmax ) ) , Math . pow ( base , vmin ) ) ;
181
+
182
+ if ( value !== this . model . get ( 'value' ) ) {
183
+ this . readout . textContent = this . valueToString ( value ) ;
184
+ this . model . set ( 'value' , value , { updated_view : this } ) ;
185
+ this . touch ( ) ;
186
+ } else {
187
+ this . readout . textContent = this . valueToString ( this . model . get ( 'value' ) ) ;
188
+ }
189
+ }
190
+ }
191
+ /**
192
+ * Called when the slider value is changing.
193
+ */
194
+ handleSliderChange ( e , ui ) {
195
+ let base = this . model . get ( 'base' ) ;
196
+ let actual_value = Math . pow ( base , this . _validate_slide_value ( ui . value ) ) ;
197
+ this . readout . textContent = this . valueToString ( actual_value ) ;
198
+
199
+ // Only persist the value while sliding if the continuous_update
200
+ // trait is set to true.
201
+ if ( this . model . get ( 'continuous_update' ) ) {
202
+ this . handleSliderChanged ( e , ui ) ;
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Called when the slider value has changed.
208
+ *
209
+ * Calling model.set will trigger all of the other views of the
210
+ * model to update.
211
+ */
212
+ handleSliderChanged ( e , ui ) {
213
+ let base = this . model . get ( 'base' ) ;
214
+ let actual_value = Math . pow ( base , this . _validate_slide_value ( ui . value ) ) ;
215
+ this . model . set ( 'value' , actual_value , { updated_view : this } ) ;
216
+ this . touch ( ) ;
217
+ }
218
+
219
+ _validate_slide_value ( x ) {
220
+ return x ;
221
+ }
222
+
223
+ _parse_value = parseFloat ;
224
+
225
+ }
226
+
227
+
88
228
export
89
229
class FloatRangeSliderView extends IntRangeSliderView {
90
230
/**
0 commit comments