Listing 6. Implementing a vertical zoom
// ... same ...
import Slider from 'rc-slider'; // Import the Slider component from rc-slider
import 'rc-slider/assets/index.css';
function App() {
// ... same ...
const [sliderValues, setSliderValues] = useState([0, 100]);
const [allowableRange, setAllowableRange] = useState([0, 100]);
const [yAxisDomain, setYAxisDomain] = useState([0, 100]);
// ... same ...
useEffect(() => {
if (cryptoData.prices && cryptoData.prices.length > 0) {
const minY = Math.min(...cryptoData.prices.map(entry => entry[1]));
const maxY = Math.max(...cryptoData.prices.map(entry => entry[1]));
setSliderValues([minY, maxY]);
setAllowableRange([minY, maxY]);
setYAxisDomain([minY, maxY]);
}
}, [cryptoData]);
// Update the yAxisDomain when the slider values change
useEffect(() => {
setYAxisDomain(sliderValues);
}, [sliderValues]);
// ... same ...
return (
// ... same ...
<label>Price Range: </label>
<Slider
range
value={sliderValues}
onChange={(newValues) => setSliderValues(newValues)}
min={allowableRange[0]}
max={allowableRange[1]}
/>
<LineChart width={800} height={400} data={cryptoData.prices}>
<CartesianGrid stroke="#f5f5f5" />
<XAxis dataKey="0" tickFormatter={(timestamp) => new Date(timestamp).toLocaleDateString()} />
<YAxis domain={([dataMin, dataMax]) => { return [yAxisDomain[0], yAxisDomain[1]]; }} />
<Tooltip labelFormatter={(value) => new Date(value).toLocaleDateString()} />
<Legend verticalAlign="top" height={36} />
<Line type="monotone" dataKey="1" stroke="#8884d8" dot={false} />
<Brush dataKey="0" height={30} stroke="#8884d8" />
</LineChart>
</div>
// ... same ...
</div>
</div>
);
}
export default App;
The clever part of Listing 6 is
<YAxis domain={([dataMin, dataMax]) => { return [yAxisDomain[0], yAxisDomain[1]]; }} />
The YAxis
component accepts a function (as well as hard-coded values), which takes two arguments: dataMin
and dataMax
. These two are built-in values that express the minimum and maximum values of the given data. In our case, we ignore them and use our own values: the yAxisDomain
array, which we calculate ourselves.
To set up the custom slider and use it to drive the vertical zoom, we need three state variables: sliderValues
, allowableRange
, and yAxisDomain
. These will be the slider’s output, the slider’s range values, and the variable used on the YAxis
domain, as we’ve described.
To set them up, we use an effect hook that watches the cryptoData
variable. When it changes, we find the minimum and maximum for the price data, set the slider’s allowable range, and default the current value to that range (note that the slider begins all the way zoomed out).
To keep the yAxisDomain
in sync with sliderValues
, we use another effect hook that watches sliderValues
.
Configuring the slider itself with these values is straightforward:
value={sliderValues} onChange={(newValues) => setSliderValues(newValues)} min={allowableRange[0]} max={allowableRange[1]}
The net result is that when the slider is moved, the chart updates its Y Axis range, giving us the zoom effect.
Conclusion
Recharts is a full-featured, reliable charting solution for JavaScript. Here, we’ve just covered some basics of what you can do with Recharts. I also showed you how to rig up a vertical zoom using the Y axis domain functional prop. In general, Recharts is a great option for charting in React, with a wide range of chart styles and options that you can play with.