Skip to content

Commit 35d817b

Browse files
authored
Merge pull request #3365 from plotly/slider-500
Warn if slider has more than 500 marks and use default instead
2 parents c2efe9b + 877ee41 commit 35d817b

File tree

2 files changed

+73
-4
lines changed

2 files changed

+73
-4
lines changed

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

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import {
1717
} from '../utils/formatSliderTooltip';
1818
import LoadingElement from '../utils/LoadingElement';
1919

20+
const MAX_MARKS = 500;
21+
2022
const sliderProps = [
2123
'min',
2224
'max',
@@ -76,6 +78,21 @@ export default class Slider extends Component {
7678
} = this.props;
7779
const value = this.state.value;
7880

81+
// Check if marks exceed 500 limit for performance
82+
let processedMarks = marks;
83+
if (marks && typeof marks === 'object' && marks !== null) {
84+
const marksCount = Object.keys(marks).length;
85+
if (marksCount > MAX_MARKS) {
86+
/* eslint-disable no-console */
87+
console.error(
88+
`dcc.Slider: Too many marks (${marksCount}) provided. ` +
89+
`For performance reasons, marks are limited to 500. ` +
90+
`Using auto-generated marks instead.`
91+
);
92+
processedMarks = undefined;
93+
}
94+
}
95+
7996
let tipProps, tipFormatter;
8097
if (tooltip) {
8198
/**
@@ -136,11 +153,16 @@ export default class Slider extends Component {
136153
tipFormatter={tipFormatter}
137154
style={{position: 'relative'}}
138155
value={value}
139-
marks={sanitizeMarks({min, max, marks, step})}
140-
max={setUndefined(min, max, marks).max_mark}
141-
min={setUndefined(min, max, marks).min_mark}
156+
marks={sanitizeMarks({
157+
min,
158+
max,
159+
marks: processedMarks,
160+
step,
161+
})}
162+
max={setUndefined(min, max, processedMarks).max_mark}
163+
min={setUndefined(min, max, processedMarks).min_mark}
142164
step={
143-
step === null && !isNil(marks)
165+
step === null && !isNil(processedMarks)
144166
? null
145167
: calcStep(min, max, step)
146168
}

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

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,3 +616,50 @@ def test_sls016_sliders_format_tooltips(dash_dcc):
616616
dash_dcc.percy_snapshot("sliders-format-tooltips")
617617

618618
assert dash_dcc.get_logs() == []
619+
620+
621+
def test_slsl017_marks_limit_500(dash_dcc):
622+
"""Test that slider works with exactly 500 marks"""
623+
app = Dash(__name__)
624+
marks_500 = {str(i): f"Mark {i}" for i in range(500)}
625+
app.layout = html.Div(
626+
[
627+
dcc.Slider(id="slider", min=0, max=499, marks=marks_500, value=250),
628+
html.Div(id="output"),
629+
]
630+
)
631+
632+
@app.callback(Output("output", "children"), [Input("slider", "value")])
633+
def update_output(value):
634+
return f"Selected: {value}"
635+
636+
dash_dcc.start_server(app)
637+
dash_dcc.wait_for_text_to_equal("#output", "Selected: 250")
638+
639+
# No warnings should be logged for 500 marks
640+
assert dash_dcc.get_logs() == []
641+
642+
643+
def test_slsl018_marks_limit_exceeded(dash_dcc):
644+
"""Test behavior when marks exceed 500 limit"""
645+
app = Dash(__name__)
646+
marks_501 = {str(i): f"Mark {i}" for i in range(501)}
647+
app.layout = html.Div(
648+
[
649+
dcc.Slider(id="slider", min=0, max=500, marks=marks_501, value=250),
650+
html.Div(id="output"),
651+
]
652+
)
653+
654+
@app.callback(Output("output", "children"), [Input("slider", "value")])
655+
def update_output(value):
656+
return f"Selected: {value}"
657+
658+
dash_dcc.start_server(app)
659+
dash_dcc.wait_for_text_to_equal("#output", "Selected: 250")
660+
661+
# Check that warning is logged
662+
logs = dash_dcc.get_logs()
663+
assert len(logs) > 0
664+
warning_found = any("Too many marks" in log["message"] for log in logs)
665+
assert warning_found, "Expected warning about too many marks not found in logs"

0 commit comments

Comments
 (0)