MUI Slider with restricted values but equal spacing

Viewed 393

I am using my own marks and displaying them on the slider using restricted values however the spacing is not ideal. How can I keep my own min/max/custom markers but have them be equally spaced on the slider?

Currently:

2-2.8-4-5.6---8---11----16

Desired:

2--2.8--4--5.6--8--11--16
<Box sx={{ width: 365 }}>
  <Slider
    aria-label="aperture"
    defaultValue={8}
    step={null}
    valueLabelDisplay="auto"
    marks={marksAperture[camera][0].settings} //2, 2.8, 4, 5.6, 8, 11, 16
    min={marksAperture[camera][0].minStop} //2
    max={marksAperture[camera][0].maxStop} //16
    onChange={this.handleApertureChange}
    sx={{
      "& .MuiSlider-markLabel": {
        fontSize: "10px",
      },
    }}
  />
</Box>
1 Answers

This is achievable by using a dictionary to map between the internal values of the Slider (1, 2, 3, 4, 5, 6, 7) to the scaled values (2, 2.8, 4, 5.6, 8, 11, 16).

You also need to add a scale callback to transform the value before it's displayed in the tooltip:

function calculateValue(value) {
  switch (value) {
    case 1:
      return 2;
    case 2:
      return 2.8;
    case 3:
      return 4;
    case 4:
      return 5.6;
    case 5:
      return 8;
    case 6:
      return 11;
    case 7:
      return 16;
    default:
      return 0;
  }
}

const marks = [1, 2, 3, 4, 5, 6, 7].map((value) => ({
  value,
  label: calculateValue(value)
}));

There is a small issue when using restricted values. If you drag the thumb a little bit but not enough to jump to the next or previous mark, the change handler still fires repeatedly. To prevent that, you can use controlled mode and update the state only if the value is changed:

const [value, setValue] = React.useState(null);

return (
  <Slider
    defaultValue={8}
    step={null}
    value={value}
    onChange={(_, newValue) => {
      if (newValue !== value) {
        console.log(calculateValue(newValue));
        setValue(newValue);
      }
    }}
    valueLabelDisplay="auto"
    marks={marks}
    scale={calculateValue}
    min={1} //2
    max={7} //16
  />
);

Codesandbox Demo

Related