@@ -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,37 @@ 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
+ } ) ;
90
+ }
91
+ initialize ( attributes , options ) {
92
+ super . initialize ( attributes , options ) ;
93
+ this . on ( 'change:readout_format' , this . update_readout_format , this ) ;
94
+ this . update_readout_format ( ) ;
95
+ }
96
+
97
+ update_readout_format ( ) {
98
+ this . readout_formatter = format ( this . get ( 'readout_format' ) ) ;
99
+ }
100
+
101
+ readout_formatter : any ;
102
+ }
103
+
72
104
export
73
105
class FloatRangeSliderModel extends FloatSliderModel { }
74
106
@@ -85,6 +117,112 @@ class FloatSliderView extends IntSliderView {
85
117
_parse_value = parseFloat ;
86
118
}
87
119
120
+
121
+ export
122
+ class FloatLogSliderView extends BaseIntSliderView {
123
+
124
+ update ( options ?) {
125
+ super . update ( options ) ;
126
+ let min = this . model . get ( 'min' ) ;
127
+ let max = this . model . get ( 'max' ) ;
128
+ let value = this . model . get ( 'value' ) ;
129
+ let base = this . model . get ( 'base' ) ;
130
+
131
+ let log_value = Math . log ( value ) / Math . log ( base ) ;
132
+
133
+ if ( log_value > max ) {
134
+ log_value = max ;
135
+ } else if ( log_value < min ) {
136
+ log_value = min ;
137
+ }
138
+ this . $slider . slider ( 'option' , 'value' , log_value ) ;
139
+ this . readout . textContent = this . valueToString ( value ) ;
140
+ if ( this . model . get ( 'value' ) !== value ) {
141
+ this . model . set ( 'value' , value , { updated_view : this } ) ;
142
+ this . touch ( ) ;
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Write value to a string
148
+ */
149
+ valueToString ( value : number ) : string {
150
+ let format = this . model . readout_formatter ;
151
+ return format ( value ) ;
152
+ }
153
+
154
+ /**
155
+ * Parse value from a string
156
+ */
157
+ stringToValue ( text : string ) : number {
158
+ return this . _parse_value ( text ) ;
159
+ }
160
+
161
+ /**
162
+ * this handles the entry of text into the contentEditable label first, the
163
+ * value is checked if it contains a parseable value then it is clamped
164
+ * within the min-max range of the slider finally, the model is updated if
165
+ * the value is to be changed
166
+ *
167
+ * if any of these conditions are not met, the text is reset
168
+ */
169
+ handleTextChange ( ) {
170
+ let value = this . stringToValue ( this . readout . textContent ) ;
171
+ let vmin = this . model . get ( 'min' ) ;
172
+ let vmax = this . model . get ( 'max' ) ;
173
+ let base = this . model . get ( 'base' ) ;
174
+
175
+ if ( isNaN ( value ) ) {
176
+ this . readout . textContent = this . valueToString ( this . model . get ( 'value' ) ) ;
177
+ } else {
178
+ value = Math . max ( Math . min ( value , Math . pow ( base , vmax ) ) , Math . pow ( base , vmin ) ) ;
179
+
180
+ if ( value !== this . model . get ( 'value' ) ) {
181
+ this . readout . textContent = this . valueToString ( value ) ;
182
+ this . model . set ( 'value' , value , { updated_view : this } ) ;
183
+ this . touch ( ) ;
184
+ } else {
185
+ this . readout . textContent = this . valueToString ( this . model . get ( 'value' ) ) ;
186
+ }
187
+ }
188
+ }
189
+ /**
190
+ * Called when the slider value is changing.
191
+ */
192
+ handleSliderChange ( e , ui ) {
193
+ let base = this . model . get ( 'base' ) ;
194
+ let actual_value = Math . pow ( base , this . _validate_slide_value ( ui . value ) ) ;
195
+ this . readout . textContent = this . valueToString ( actual_value ) ;
196
+
197
+ // Only persist the value while sliding if the continuous_update
198
+ // trait is set to true.
199
+ if ( this . model . get ( 'continuous_update' ) ) {
200
+ this . handleSliderChanged ( e , ui ) ;
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Called when the slider value has changed.
206
+ *
207
+ * Calling model.set will trigger all of the other views of the
208
+ * model to update.
209
+ */
210
+ handleSliderChanged ( e , ui ) {
211
+ let base = this . model . get ( 'base' ) ;
212
+ let actual_value = Math . pow ( base , this . _validate_slide_value ( ui . value ) ) ;
213
+ this . model . set ( 'value' , actual_value , { updated_view : this } ) ;
214
+ this . touch ( ) ;
215
+ }
216
+
217
+ _validate_slide_value ( x ) {
218
+ return x ;
219
+ }
220
+
221
+ _parse_value = parseFloat ;
222
+
223
+ }
224
+
225
+
88
226
export
89
227
class FloatRangeSliderView extends IntRangeSliderView {
90
228
/**
0 commit comments