I want to display a range on the slider from 1000 to 1M and add the following markers
const followersMarks = [
{
value: 1000,
label: '1k',
},
{
value: 5000,
label: '5k',
},
{
value: 10000,
label: '10k',
},
{
value: 25000,
label: '25k',
},
{
value: 50000,
label: '50k',
},
{
value: 100000,
label: '100k',
},
{
value: 250000,
label: '250k',
},
{
value: 500000,
label: '500k',
},
{
value: 1000000,
label: '1M',
},
];
Am adding it as follows
<Form.Group controlId="formGridState">
<Form.Label className="mb-15">Followers Range</Form.Label>
<Slider
value={followersRange}
onChange={handleChangeFollowersRange}
valueLabelDisplay="auto"
aria-labelledby="range-slider"
step="1000"
valueLabelDisplay="on"
marks={followersMarks}
min={1000}
max={1000000}
/>
</Form.Group>
This is the result:
What do I need?
Since at the start of the range I am displaying more markers the legibility and UX are bad. Is there a way to use scale
to show the range in such way that it takes 50-60% of the space to show the first 25% of the values and then space out the rest?
Below is a working example of one way to do this. The key thing to note is that the values for min
, max
, step
, and value
(including value
within marks
) are linear values. The scale
function then translates these to the non-linear values you want to display.
import React from "react";
import Typography from "@material-ui/core/Typography";
import Slider from "@material-ui/core/Slider";
const followersMarks = [
{
value: 0,
scaledValue: 1000,
label: "1k"
},
{
value: 25,
scaledValue: 5000,
label: "5k"
},
{
value: 50,
scaledValue: 10000,
label: "10k"
},
{
value: 75,
scaledValue: 25000,
label: "25k"
},
{
value: 100,
scaledValue: 50000,
label: "50k"
},
{
value: 125,
scaledValue: 100000,
label: "100k"
},
{
value: 150,
scaledValue: 250000,
label: "250k"
},
{
value: 175,
scaledValue: 500000,
label: "500k"
},
{
value: 200,
scaledValue: 1000000,
label: "1M"
}
];
const scale = value => {
const previousMarkIndex = Math.floor(value / 25);
const previousMark = followersMarks[previousMarkIndex];
const remainder = value % 25;
if (remainder === 0) {
return previousMark.scaledValue;
}
const nextMark = followersMarks[previousMarkIndex + 1];
const increment = (nextMark.scaledValue - previousMark.scaledValue) / 25;
return remainder * increment + previousMark.scaledValue;
};
function numFormatter(num) {
if (num > 999 && num < 1000000) {
return (num / 1000).toFixed(0) + "K"; // convert to K for number from > 1000 < 1 million
} else if (num >= 1000000) {
return (num / 1000000).toFixed(0) + "M"; // convert to M for number from > 1 million
} else if (num < 900) {
return num; // if value < 1000, nothing to do
}
}
export default function NonLinearSlider() {
const [value, setValue] = React.useState(1);
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<div>
<Typography id="non-linear-slider" gutterBottom>
Followers
</Typography>
<Slider
style={{ maxWidth: 500 }}
value={value}
min={0}
step={1}
max={200}
valueLabelFormat={numFormatter}
marks={followersMarks}
scale={scale}
onChange={handleChange}
valueLabelDisplay="auto"
aria-labelledby="non-linear-slider"
/>
<Typography>Value: {scale(value)}</Typography>
</div>
);
}
Here is a similar example, but modified for a range slider:
import React from "react";
import Typography from "@material-ui/core/Typography";
import Slider from "@material-ui/core/Slider";
const followersMarks = [
{
value: 0,
scaledValue: 1000,
label: "1k"
},
{
value: 25,
scaledValue: 5000,
label: "5k"
},
{
value: 50,
scaledValue: 10000,
label: "10k"
},
{
value: 75,
scaledValue: 25000,
label: "25k"
},
{
value: 100,
scaledValue: 50000,
label: "50k"
},
{
value: 125,
scaledValue: 100000,
label: "100k"
},
{
value: 150,
scaledValue: 250000,
label: "250k"
},
{
value: 175,
scaledValue: 500000,
label: "500k"
},
{
value: 200,
scaledValue: 1000000,
label: "1M"
}
];
const scaleValues = (valueArray) => {
return [scale(valueArray[0]), scale(valueArray[1])];
};
const scale = (value) => {
if (value === undefined) {
return undefined;
}
const previousMarkIndex = Math.floor(value / 25);
const previousMark = followersMarks[previousMarkIndex];
const remainder = value % 25;
if (remainder === 0) {
return previousMark.scaledValue;
}
const nextMark = followersMarks[previousMarkIndex + 1];
const increment = (nextMark.scaledValue - previousMark.scaledValue) / 25;
return remainder * increment + previousMark.scaledValue;
};
function numFormatter(num) {
if (num > 999 && num < 1000000) {
return (num / 1000).toFixed(0) + "K"; // convert to K for number from > 1000 < 1 million
} else if (num >= 1000000) {
return (num / 1000000).toFixed(0) + "M"; // convert to M for number from > 1 million
} else if (num < 900) {
return num; // if value < 1000, nothing to do
}
}
export default function NonLinearSlider() {
const [value, setValue] = React.useState([1, 25]);
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<div>
<Typography id="non-linear-slider" gutterBottom>
Followers
</Typography>
<Slider
style={{ maxWidth: 500 }}
value={value}
min={0}
step={1}
max={200}
valueLabelFormat={numFormatter}
marks={followersMarks}
scale={scaleValues}
onChange={handleChange}
valueLabelDisplay="auto"
aria-labelledby="non-linear-slider"
/>
<Typography>Values: {JSON.stringify(scaleValues(value))}</Typography>
</div>
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With