zoom in and zoom out of price chart

This commit is contained in:
Yinyin Liu 2026-06-12 12:38:38 +02:00
parent 4afeceea5d
commit c0fa353a17
5 changed files with 43 additions and 5 deletions

View File

@ -1,9 +1,10 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Box, Typography } from '@mui/material'; import { Box, Button, Typography } from '@mui/material';
import CircularProgress from '@mui/material/CircularProgress'; import CircularProgress from '@mui/material/CircularProgress';
import RestartAltIcon from '@mui/icons-material/RestartAlt';
import { FormattedMessage, useIntl } from 'react-intl'; import { FormattedMessage, useIntl } from 'react-intl';
import ReactApexChart from 'react-apexcharts'; import ReactApexChart from 'react-apexcharts';
import { ApexOptions } from 'apexcharts'; import ApexCharts, { ApexOptions } from 'apexcharts';
import { I_S3Credentials } from 'src/interfaces/S3Types'; import { I_S3Credentials } from 'src/interfaces/S3Types';
import { UnixTime, TimeSpan } from 'src/dataCache/time'; import { UnixTime, TimeSpan } from 'src/dataCache/time';
import { import {
@ -17,6 +18,7 @@ interface CurrentPriceChartProps {
} }
const HISTORY_DAYS = 7; const HISTORY_DAYS = 7;
const CHART_ID = 'current-price-history';
function CurrentPriceChart(props: CurrentPriceChartProps) { function CurrentPriceChart(props: CurrentPriceChartProps) {
const intl = useIntl(); const intl = useIntl();
@ -49,6 +51,14 @@ function CurrentPriceChart(props: CurrentPriceChartProps) {
}; };
}, [props.id]); }, [props.id]);
// Snap the x-axis back to the full history window after the user drag-zooms.
const handleResetZoom = () => {
if (!series || series.data.length === 0) return;
const minX = series.data[0][0];
const maxX = series.data[series.data.length - 1][0];
ApexCharts.exec(CHART_ID, 'zoomX', minX, maxX);
};
const title = ( const title = (
<Typography variant="subtitle1" sx={{ fontWeight: 600, mb: 1 }}> <Typography variant="subtitle1" sx={{ fontWeight: 600, mb: 1 }}>
<FormattedMessage <FormattedMessage
@ -92,11 +102,13 @@ function CurrentPriceChart(props: CurrentPriceChartProps) {
const options: ApexOptions = { const options: ApexOptions = {
chart: { chart: {
id: 'current-price-history', id: CHART_ID,
type: 'line', type: 'line',
height: 300, height: 300,
// Toolbar hidden — its zoom glyphs are easy to miss; we expose an explicit
// "Reset zoom" button instead. Drag-to-zoom still works via zoom.enabled.
toolbar: { show: false }, toolbar: { show: false },
zoom: { autoScaleYaxis: true } zoom: { enabled: true, type: 'x', autoScaleYaxis: true }
}, },
dataLabels: { enabled: false }, dataLabels: { enabled: false },
// Spot price is constant within each pricing interval -> stepped line // Spot price is constant within each pricing interval -> stepped line
@ -138,7 +150,29 @@ function CurrentPriceChart(props: CurrentPriceChartProps) {
return ( return (
<Box sx={{ mb: 2 }}> <Box sx={{ mb: 2 }}>
{title} <Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
mb: 1
}}
>
<Typography variant="subtitle1" sx={{ fontWeight: 600 }}>
<FormattedMessage
id="currentPriceHistory"
defaultMessage="Current Price (last 7 days)"
/>
</Typography>
<Button
size="small"
variant="outlined"
startIcon={<RestartAltIcon />}
onClick={handleResetZoom}
>
<FormattedMessage id="resetZoom" defaultMessage="Reset zoom" />
</Button>
</Box>
<ReactApexChart <ReactApexChart
options={options} options={options}
series={chartSeries} series={chartSeries}

View File

@ -592,6 +592,7 @@
"currentPrice": "Aktueller Preis", "currentPrice": "Aktueller Preis",
"currentPriceHistory": "Aktueller Preis (letzte 7 Tage)", "currentPriceHistory": "Aktueller Preis (letzte 7 Tage)",
"currentPriceNoData": "Keine Preishistorie für die letzten 7 Tage verfügbar.", "currentPriceNoData": "Keine Preishistorie für die letzten 7 Tage verfügbar.",
"resetZoom": "Zoom zurücksetzen",
"priceToSell": "Verkaufspreis", "priceToSell": "Verkaufspreis",
"priceToBuy": "Kaufpreis", "priceToBuy": "Kaufpreis",
"timeToSell": "Verkaufszeit", "timeToSell": "Verkaufszeit",

View File

@ -340,6 +340,7 @@
"currentPrice": "Current Price", "currentPrice": "Current Price",
"currentPriceHistory": "Current Price (last 7 days)", "currentPriceHistory": "Current Price (last 7 days)",
"currentPriceNoData": "No price history available for the last 7 days.", "currentPriceNoData": "No price history available for the last 7 days.",
"resetZoom": "Reset zoom",
"priceToSell": "Price to Sell", "priceToSell": "Price to Sell",
"priceToBuy": "Price to Buy", "priceToBuy": "Price to Buy",
"timeToSell": "Time to Sell", "timeToSell": "Time to Sell",

View File

@ -592,6 +592,7 @@
"currentPrice": "Prix actuel", "currentPrice": "Prix actuel",
"currentPriceHistory": "Prix actuel (7 derniers jours)", "currentPriceHistory": "Prix actuel (7 derniers jours)",
"currentPriceNoData": "Aucun historique de prix disponible pour les 7 derniers jours.", "currentPriceNoData": "Aucun historique de prix disponible pour les 7 derniers jours.",
"resetZoom": "Réinitialiser le zoom",
"priceToSell": "Prix de vente", "priceToSell": "Prix de vente",
"priceToBuy": "Prix d'achat", "priceToBuy": "Prix d'achat",
"timeToSell": "Heure de vente", "timeToSell": "Heure de vente",

View File

@ -592,6 +592,7 @@
"currentPrice": "Prezzo attuale", "currentPrice": "Prezzo attuale",
"currentPriceHistory": "Prezzo attuale (ultimi 7 giorni)", "currentPriceHistory": "Prezzo attuale (ultimi 7 giorni)",
"currentPriceNoData": "Nessuno storico prezzi disponibile per gli ultimi 7 giorni.", "currentPriceNoData": "Nessuno storico prezzi disponibile per gli ultimi 7 giorni.",
"resetZoom": "Reimposta zoom",
"priceToSell": "Prezzo di vendita", "priceToSell": "Prezzo di vendita",
"priceToBuy": "Prezzo di acquisto", "priceToBuy": "Prezzo di acquisto",
"timeToSell": "Orario di vendita", "timeToSell": "Orario di vendita",