Skip to content

Commit 94cbc3b

Browse files
authored
Merge pull request #1857 from plotly/fix-slider-marks
Fix slider marks and steps bugs
2 parents 6cfb787 + c947600 commit 94cbc3b

File tree

5 files changed

+114
-10
lines changed

5 files changed

+114
-10
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ This project adheres to [Semantic Versioning](https://semver.org/).
160160
```
161161

162162
### Fixed
163-
164163
- [#1858](https://github.com/plotly/dash/pull/1858) Support `mini-css-extract-plugin` Webpack plugin with `@plotly/webpack-dash-dynamic-import` node package - used by components to support dash async chunks. Updated dependencies of other `@plotly` node packages.
165164

166165
- [#1836](https://github.com/plotly/dash/pull/1836) Fix `__all__` in dcc and table for extras: dcc download helpers and table format helpers. This also restores this functionality to the obsolete top-level packages `dash_core_components` and `dash_table`.
@@ -185,6 +184,9 @@ This project adheres to [Semantic Versioning](https://semver.org/).
185184
- [#1707](https://github.com/plotly/dash/pull/1707) Change the default value of the `compress` argument to the `dash.Dash` constructor to `False`. This change reduces CPU usage, and was made in recognition of the fact that many deployment platforms (e.g. Dash Enterprise) already apply their own compression. If deploying to an environment that does not already provide compression, the Dash 1 behavior may be restored by adding `compress=True` to the `dash.Dash` constructor.
186185
- [#1734](https://github.com/plotly/dash/pull/1734) Added `npm run build` script to simplify build process involving `dash-renderer` and subcomponent libraries within `dash`.
187186

187+
### Fixed
188+
- [#1857](https://github.com/plotly/dash/pull/1857) Fixed a regression with `dcc.Slider` and `dcc.RangeSlider` where steps were not being set to marks if None was passed as the prop argument. Added a check to set the min and max based on the range of marks if they are not explicitly defined (for more info, see [#1843](https://github.com/plotly/dash/issues/1843) and [#1851](https://github.com/plotly/dash/issues/1843)).
189+
188190

189191
## Dash Core Components
190192
### Added

components/dash-core-components/src/fragments/RangeSlider.react.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, {Component} from 'react';
2-
import {assoc, omit} from 'ramda';
2+
import {assoc, omit, isNil} from 'ramda';
33
import {Range, createSliderWithTooltip} from 'rc-slider';
44
import computeSliderStyle from '../utils/computeSliderStyle';
55

@@ -8,6 +8,7 @@ import {
88
calcValue,
99
sanitizeMarks,
1010
calcStep,
11+
setUndefined,
1112
} from '../utils/computeSliderMarkers';
1213
import {propTypes, defaultProps} from '../components/RangeSlider.react';
1314

@@ -104,7 +105,13 @@ export default class RangeSlider extends Component {
104105
style={{position: 'relative'}}
105106
value={value ? value : calcValue(min, max, value)}
106107
marks={sanitizeMarks({min, max, marks, step})}
107-
step={calcStep(min, max, step)}
108+
max={setUndefined(min, max, marks).max_mark}
109+
min={setUndefined(min, max, marks).min_mark}
110+
step={
111+
step === null && !isNil(marks)
112+
? null
113+
: calcStep(min, max, step)
114+
}
108115
{...omit(
109116
[
110117
'className',

components/dash-core-components/src/fragments/Slider.react.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import React, {Component} from 'react';
22
import ReactSlider, {createSliderWithTooltip} from 'rc-slider';
3-
import {assoc, omit} from 'ramda';
3+
import {assoc, isNil, omit} from 'ramda';
44
import computeSliderStyle from '../utils/computeSliderStyle';
55

66
import 'rc-slider/assets/index.css';
77

8-
import {sanitizeMarks, calcStep} from '../utils/computeSliderMarkers';
8+
import {
9+
sanitizeMarks,
10+
calcStep,
11+
setUndefined,
12+
} from '../utils/computeSliderMarkers';
913
import {propTypes, defaultProps} from '../components/Slider.react';
1014

1115
/**
@@ -104,7 +108,13 @@ export default class Slider extends Component {
104108
style={{position: 'relative'}}
105109
value={value}
106110
marks={sanitizeMarks({min, max, marks, step})}
107-
step={calcStep(min, max, step)}
111+
max={setUndefined(min, max, marks).max_mark}
112+
min={setUndefined(min, max, marks).min_mark}
113+
step={
114+
step === null && !isNil(marks)
115+
? null
116+
: calcStep(min, max, step)
117+
}
108118
{...omit(
109119
[
110120
'className',

components/dash-core-components/src/utils/computeSliderMarkers.js

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {pickBy, isEmpty} from 'ramda';
1+
import {pickBy, isEmpty, isNil} from 'ramda';
22
import {formatPrefix} from 'd3-format';
33

44
/**
@@ -85,6 +85,29 @@ export const calcStep = (min, max, step) => {
8585
].sort((a, b) => Math.abs(a - v) - Math.abs(b - v))[0];
8686
};
8787

88+
/**
89+
* Set min and max if they are undefined and marks are defined
90+
*/
91+
export const setUndefined = (min, max, marks) => {
92+
const definedMarks = {min_mark: min, max_mark: max};
93+
94+
if (isNil(marks)) {
95+
return definedMarks;
96+
}
97+
98+
const marksObject = Object.keys(marks).map(Number);
99+
100+
if (isNil(min)) {
101+
definedMarks.min_mark = Math.min(...marksObject);
102+
}
103+
104+
if (isNil(max)) {
105+
definedMarks.max_mark = Math.max(...marksObject);
106+
}
107+
108+
return definedMarks;
109+
};
110+
88111
export const applyD3Format = (mark, min, max) => {
89112
const mu_ten_factor = -3;
90113
const k_ten_factor = 3;
@@ -124,7 +147,6 @@ export const autoGenerateMarks = (min, max, step) => {
124147
marks.pop();
125148
}
126149
}
127-
128150
const marksObject = {};
129151
marks.forEach(mark => {
130152
marksObject[mark] = applyD3Format(mark, min, max);
@@ -144,15 +166,18 @@ export const sanitizeMarks = ({min, max, marks, step}) => {
144166
return undefined;
145167
}
146168

169+
const {min_mark, max_mark} = setUndefined(min, max, marks);
170+
147171
const truncated_marks =
148172
marks && isEmpty(marks) === false
149-
? truncateMarks(min, max, marks)
173+
? truncateMarks(min_mark, max_mark, marks)
150174
: marks;
151175

152176
if (truncated_marks && isEmpty(truncated_marks) === false) {
153177
return truncated_marks;
154178
}
155-
return autoGenerateMarks(min, max, step);
179+
180+
return autoGenerateMarks(min_mark, max_mark, step);
156181
};
157182

158183
/**

components/dash-core-components/tests/integration/sliders/test_sliders.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,3 +523,63 @@ def test_slsl014_vertical_range_slider(dash_dcc):
523523
'#vertical-range-slider div.rc-slider-handle-2[role="slider"]'
524524
).click()
525525
assert dash_dcc.get_logs() == []
526+
527+
528+
def test_slsl015_range_slider_step_none(dash_dcc):
529+
app = Dash(__name__)
530+
app.layout = html.Div(
531+
[
532+
html.Label("Steps = Marks Slider"),
533+
dcc.Slider(
534+
id="none-step-slider",
535+
min=0,
536+
max=6,
537+
marks={
538+
i: "Label {}".format(i) if i == 1 else str(i) for i in range(1, 6)
539+
},
540+
step=None,
541+
value=4.6,
542+
vertical=False,
543+
),
544+
],
545+
style={"height": "500px"},
546+
)
547+
548+
dash_dcc.start_server(app)
549+
dash_dcc.wait_for_element("#none-step-slider")
550+
dash_dcc.percy_snapshot("none step slider")
551+
552+
dash_dcc.wait_for_element(
553+
'#none-step-slider div.rc-slider-handle[aria-valuenow="5"]'
554+
)
555+
556+
assert dash_dcc.get_logs() == []
557+
558+
559+
def test_slsl015_range_slider_no_min_max(dash_dcc):
560+
app = Dash(__name__)
561+
app.layout = html.Div(
562+
[
563+
html.Label("No Min or Max Slider"),
564+
dcc.Slider(
565+
id="no-min-max-step-slider",
566+
marks={
567+
i: "Label {}".format(i) if i == 1 else str(i) for i in range(1, 6)
568+
},
569+
step=None,
570+
value=5,
571+
vertical=False,
572+
),
573+
],
574+
style={"height": "500px"},
575+
)
576+
577+
dash_dcc.start_server(app)
578+
dash_dcc.wait_for_element("#no-min-max-step-slider")
579+
dash_dcc.percy_snapshot("no-min-max step slider")
580+
581+
dash_dcc.wait_for_element(
582+
'#no-min-max-step-slider div.rc-slider-handle[aria-valuemax="5"]'
583+
)
584+
585+
assert dash_dcc.get_logs() == []

0 commit comments

Comments
 (0)