Skip to content
This repository was archived by the owner on Jun 3, 2024. It is now read-only.

Commit b098058

Browse files
author
Shammamah Hossain
authored
Omit marks that are outside of range specified by min and max. (#695)
* Omit marks that are outside of range specified by min and max. * Handle case in which marks prop is not defined. * Add test for out-of-range numbers. * Use pickBy. * Add mark at point below minimum value. * Also omit out-of-range marks for slider. * Add test for slider. * Add padding to Slider and RangeSlider containers. * Update test for persistence. With the new padding values, the '0' selection is no longer at the very edge of the container div. * Change test for always visible rangeslider. * Only add top padding if there are always-visible tooltips on the top. * Preserve whitespace in marks. * Add optional verticalHeight prop for vertical sliders. * Update slider stylesheet. * Update coordinates to reflect new padding. * Remove file. * Use fixed-width slider for rangeslider test. * Fix persistence test. * Memoize computation of style and move function to utils. * Simplify style code. * Fix eslint errors. * Modify style object directly. * Update CHANGELOG.
1 parent 5a9f3d3 commit b098058

File tree

7 files changed

+143
-15
lines changed

7 files changed

+143
-15
lines changed

CHANGELOG.md

+11
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22
All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning](http://semver.org/).
44

5+
## [Unreleased]
6+
7+
### Changed
8+
- [#695](https://github.com/plotly/dash-core-components/pull/695) Improvements to Slider and RangeSlider
9+
- Marks outside of the range specified by `min` and `max` are now omitted when the slider renders.
10+
- Padding is now dependent on the orientation (vertical or horizontal), and whether or not tooltips are always displayed.
11+
- The whitespace is now preserved for `marks` labels.
12+
13+
### Added
14+
- [#695](https://github.com/plotly/dash-core-components/pull/695) Added new property `verticalHeight` to Slider and RangeSlider, to allow the user to specify the height (in px) of vertical sliders. This defaults to `400`.
15+
516
## [1.5.1] - 2019-11-14
617
### Fixed
718
- [#696](https://github.com/plotly/dash-core-components/pull/696) Fix IE11 compatibility issues and ES5 compatibility and validation

src/components/RangeSlider.react.js

+27-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import React, {Component} from 'react';
22
import PropTypes from 'prop-types';
3-
import {assoc, omit} from 'ramda';
3+
import {assoc, omit, pickBy} from 'ramda';
44
import {Range, createSliderWithTooltip} from 'rc-slider';
5+
import computeSliderStyle from '../utils/computeSliderStyle';
56

67
/**
78
* A double slider with two handles.
@@ -14,6 +15,7 @@ export default class RangeSlider extends Component {
1415
this.DashSlider = props.tooltip
1516
? createSliderWithTooltip(Range)
1617
: Range;
18+
this._computeStyle = computeSliderStyle();
1719
}
1820

1921
propsToState(newProps) {
@@ -42,6 +44,7 @@ export default class RangeSlider extends Component {
4244
tooltip,
4345
updatemode,
4446
vertical,
47+
verticalHeight,
4548
} = this.props;
4649
const value = this.state.value;
4750

@@ -58,14 +61,21 @@ export default class RangeSlider extends Component {
5861
tipProps = tooltip;
5962
}
6063

64+
const truncatedMarks =
65+
this.props.marks &&
66+
pickBy(
67+
(k, mark) => mark >= this.props.min && mark <= this.props.max,
68+
this.props.marks
69+
);
70+
6171
return (
6272
<div
6373
id={id}
6474
data-dash-is-loading={
6575
(loading_state && loading_state.is_loading) || undefined
6676
}
6777
className={className}
68-
style={vertical ? {height: '100%'} : {}}
78+
style={this._computeStyle(vertical, verticalHeight, tooltip)}
6979
>
7080
<this.DashSlider
7181
onChange={value => {
@@ -82,8 +92,16 @@ export default class RangeSlider extends Component {
8292
}}
8393
tipProps={tipProps}
8494
value={value}
95+
marks={truncatedMarks}
8596
{...omit(
86-
['className', 'value', 'setProps', 'updatemode'],
97+
[
98+
'className',
99+
'value',
100+
'setProps',
101+
'marks',
102+
'updatemode',
103+
'verticalHeight',
104+
],
87105
this.props
88106
)}
89107
/>
@@ -213,6 +231,11 @@ RangeSlider.propTypes = {
213231
*/
214232
vertical: PropTypes.bool,
215233

234+
/**
235+
* The height, in px, of the slider if it is vertical.
236+
*/
237+
verticalHeight: PropTypes.number,
238+
216239
/**
217240
* Determines when the component should update
218241
* its value. If `mouseup`, then the slider
@@ -281,4 +304,5 @@ RangeSlider.defaultProps = {
281304
updatemode: 'mouseup',
282305
persisted_props: ['value'],
283306
persistence_type: 'local',
307+
verticalHeight: 400,
284308
};

src/components/Slider.react.js

+27-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import React, {Component} from 'react';
22
import ReactSlider, {createSliderWithTooltip} from 'rc-slider';
33
import PropTypes from 'prop-types';
4-
import {assoc, omit} from 'ramda';
4+
import {assoc, omit, pickBy} from 'ramda';
55
import './css/[email protected]';
6+
import computeSliderStyle from '../utils/computeSliderStyle';
67

78
/**
89
* A slider component with a single handle.
@@ -14,6 +15,7 @@ export default class Slider extends Component {
1415
this.DashSlider = props.tooltip
1516
? createSliderWithTooltip(ReactSlider)
1617
: ReactSlider;
18+
this._computeStyle = computeSliderStyle();
1719
}
1820

1921
propsToState(newProps) {
@@ -42,6 +44,7 @@ export default class Slider extends Component {
4244
tooltip,
4345
updatemode,
4446
vertical,
47+
verticalHeight,
4548
} = this.props;
4649
const value = this.state.value;
4750

@@ -58,14 +61,21 @@ export default class Slider extends Component {
5861
tipProps = tooltip;
5962
}
6063

64+
const truncatedMarks = this.props.marks
65+
? pickBy(
66+
(k, mark) => mark >= this.props.min && mark <= this.props.max,
67+
this.props.marks
68+
)
69+
: this.props.marks;
70+
6171
return (
6272
<div
6373
id={id}
6474
data-dash-is-loading={
6575
(loading_state && loading_state.is_loading) || undefined
6676
}
6777
className={className}
68-
style={vertical ? {height: '100%'} : {}}
78+
style={this._computeStyle(vertical, verticalHeight, tooltip)}
6979
>
7080
<this.DashSlider
7181
onChange={value => {
@@ -82,8 +92,16 @@ export default class Slider extends Component {
8292
}}
8393
tipProps={tipProps}
8494
value={value}
95+
marks={truncatedMarks}
8596
{...omit(
86-
['className', 'setProps', 'updatemode', 'value'],
97+
[
98+
'className',
99+
'setProps',
100+
'updatemode',
101+
'value',
102+
'marks',
103+
'verticalHeight',
104+
],
87105
this.props
88106
)}
89107
/>
@@ -194,6 +212,11 @@ Slider.propTypes = {
194212
*/
195213
vertical: PropTypes.bool,
196214

215+
/**
216+
* The height, in px, of the slider if it is vertical.
217+
*/
218+
verticalHeight: PropTypes.number,
219+
197220
/**
198221
* Determines when the component should update
199222
* its value. If `mouseup`, then the slider
@@ -262,4 +285,5 @@ Slider.defaultProps = {
262285
updatemode: 'mouseup',
263286
persisted_props: ['value'],
264287
persistence_type: 'local',
288+
verticalHeight: 400,
265289
};

src/components/css/[email protected]

+2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
text-align: center;
5757
cursor: pointer;
5858
color: #999;
59+
white-space: pre;
60+
width: fit-content;
5961
}
6062
.rc-slider-mark-text-active {
6163
color: #666;

src/utils/computeSliderStyle.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import {memoizeWith, identity, contains} from 'ramda';
2+
3+
export default () => {
4+
return memoizeWith(identity, (vertical, verticalHeight, tooltip) => {
5+
const style = {
6+
padding: '25px',
7+
};
8+
9+
if (vertical) {
10+
style.height = verticalHeight + 'px';
11+
12+
if (
13+
!tooltip ||
14+
!tooltip.always_visible ||
15+
!contains(tooltip.placement, [
16+
'left',
17+
'topRight',
18+
'bottomRight',
19+
])
20+
) {
21+
style.paddingLeft = '0px';
22+
}
23+
} else {
24+
if (
25+
!tooltip ||
26+
!tooltip.always_visible ||
27+
!contains(tooltip.placement, ['top', 'topLeft', 'topRight'])
28+
) {
29+
style.paddingTop = '0px';
30+
}
31+
}
32+
33+
return style;
34+
});
35+
};

tests/integration/misc/test_persistence.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,11 @@ def make_output(*args):
147147
dash_dcc.find_element("#radioitems label:first-child input").click() # red
148148

149149
range_slider = dash_dcc.find_element("#rangeslider")
150-
dash_dcc.click_at_coord_fractions(range_slider, 0.01, 0.5) # 0
151-
dash_dcc.click_at_coord_fractions(range_slider, 0.5, 0.5) # 5
150+
dash_dcc.click_at_coord_fractions(range_slider, 0.5, 0.25) # 5
151+
dash_dcc.click_at_coord_fractions(range_slider, 0.8, 0.25) # 8
152152

153153
slider = dash_dcc.find_element("#slider")
154-
dash_dcc.click_at_coord_fractions(slider, 0.2, 0.5) # 22
154+
dash_dcc.click_at_coord_fractions(slider, 0.2, 0.25) # 22
155155

156156
dash_dcc.find_element("#tabs .tab:last-child").click() # C
157157

@@ -166,7 +166,7 @@ def make_output(*args):
166166
[u"4️⃣", u"6️⃣"],
167167
"yes maybe",
168168
"r",
169-
[0, 5],
169+
[5, 8],
170170
22,
171171
"C",
172172
"knock knock\nwho's there?",

tests/integration/sliders/test_sliders.py

+37-5
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,15 @@ def update_output(value):
2626
dash_dcc.wait_for_text_to_equal("#out", "You have selected 5")
2727

2828
slider = dash_dcc.find_element("#slider")
29-
dash_dcc.click_at_coord_fractions(slider, 0.5, 0.5)
29+
dash_dcc.click_at_coord_fractions(slider, 0.5, 0.25)
3030
dash_dcc.wait_for_text_to_equal("#out", "You have selected 10")
31-
dash_dcc.click_at_coord_fractions(slider, 0.75, 0.5)
31+
dash_dcc.click_at_coord_fractions(slider, 0.75, 0.25)
3232
dash_dcc.wait_for_text_to_equal("#out", "You have selected 15")
3333

3434

3535
def test_slsl002_always_visible_rangeslider(dash_dcc):
3636
app = dash.Dash(__name__)
37-
app.layout = html.Div([
37+
app.layout = html.Div(style={'width': '400px'}, children=[
3838
dcc.RangeSlider(
3939
id="rangeslider",
4040
min=0,
@@ -54,7 +54,39 @@ def update_output(rng):
5454
dash_dcc.wait_for_text_to_equal("#out", "You have selected 5-15")
5555

5656
slider = dash_dcc.find_element("#rangeslider")
57-
dash_dcc.click_at_coord_fractions(slider, 0.1, 0.5)
57+
dash_dcc.click_at_coord_fractions(slider, 0.15, 0.25)
5858
dash_dcc.wait_for_text_to_equal("#out", "You have selected 2-15")
59-
dash_dcc.click_at_coord_fractions(slider, 0.5, 0.5)
59+
dash_dcc.click_at_coord_fractions(slider, 0.5, 0.25)
6060
dash_dcc.wait_for_text_to_equal("#out", "You have selected 2-10")
61+
62+
63+
def test_slsl003_out_of_range_marks_slider(dash_dcc):
64+
65+
app = dash.Dash(__name__)
66+
app.layout = html.Div([
67+
dcc.Slider(
68+
min=0,
69+
max=5,
70+
marks={i: 'Label {}'.format(i) for i in range(-1, 10)}
71+
)
72+
])
73+
74+
dash_dcc.start_server(app)
75+
76+
assert len(dash_dcc.find_elements('span.rc-slider-mark-text')) == 6
77+
78+
79+
def test_slsl004_out_of_range_marks_rangeslider(dash_dcc):
80+
81+
app = dash.Dash(__name__)
82+
app.layout = html.Div([
83+
dcc.RangeSlider(
84+
min=0,
85+
max=5,
86+
marks={i: 'Label {}'.format(i) for i in range(-1, 10)}
87+
)
88+
])
89+
90+
dash_dcc.start_server(app)
91+
92+
assert len(dash_dcc.find_elements('span.rc-slider-mark-text')) == 6

0 commit comments

Comments
 (0)