Commit 8dabafd1 authored by Igor Stuev's avatar Igor Stuev Committed by GitHub

Merge pull request #569 from blockscout/chart-fixes

x axis format
parents 30f609ca cde125d6
......@@ -10,3 +10,5 @@ export const MINUTE = 60 * SECOND;
export const HOUR = 60 * MINUTE;
export const DAY = 24 * HOUR;
export const WEEK = 7 * DAY;
export const MONTH = 30 * DAY;
export const YEAR = 365 * DAY;
......@@ -130,7 +130,7 @@ const EthereumChart = () => {
type="left"
scale={ yScale }
ticks={ 5 }
tickFormat={ yTickFormat }
tickFormatGenerator={ yTickFormat }
disableAnimation
/>
<ChartOverlay ref={ overlayRef } width={ innerWidth } height={ innerHeight }>
......
......@@ -7,11 +7,11 @@ interface Props extends Omit<React.SVGProps<SVGGElement>, 'scale'> {
scale: d3.ScaleTime<number, number> | d3.ScaleLinear<number, number>;
disableAnimation?: boolean;
ticks: number;
tickFormat?: (domainValue: d3.AxisDomain, index: number) => string;
tickFormatGenerator?: (axis: d3.Axis<d3.NumberValue>) => (domainValue: d3.AxisDomain, index: number) => string;
anchorEl?: SVGRectElement | null;
}
const ChartAxis = ({ type, scale, ticks, tickFormat, disableAnimation, anchorEl, ...props }: Props) => {
const ChartAxis = ({ type, scale, ticks, tickFormatGenerator, disableAnimation, anchorEl, ...props }: Props) => {
const ref = React.useRef<SVGGElement>(null);
const textColorToken = useColorModeValue('blackAlpha.600', 'whiteAlpha.500');
......@@ -23,10 +23,14 @@ const ChartAxis = ({ type, scale, ticks, tickFormat, disableAnimation, anchorEl,
}
const axisGenerator = type === 'left' ? d3.axisLeft : d3.axisBottom;
const axis = tickFormat ?
axisGenerator(scale).ticks(ticks).tickFormat(tickFormat) :
axisGenerator(scale).ticks(ticks);
const axis = axisGenerator(scale).ticks(ticks);
if (tickFormatGenerator) {
axis.tickFormat(tickFormatGenerator(axis));
}
const axisGroup = d3.select(ref.current);
if (disableAnimation) {
axisGroup.call(axis);
} else {
......@@ -38,7 +42,7 @@ const ChartAxis = ({ type, scale, ticks, tickFormat, disableAnimation, anchorEl,
.attr('opacity', 1)
.attr('color', textColor)
.attr('font-size', '0.75rem');
}, [ scale, ticks, tickFormat, disableAnimation, type, textColor ]);
}, [ scale, ticks, tickFormatGenerator, disableAnimation, type, textColor ]);
React.useEffect(() => {
if (!anchorEl) {
......
......@@ -55,7 +55,7 @@ const ChartWidgetGraph = ({ isEnlarged, items, onZoom, isZoomResetInitial, title
}, [ isGroupedValues, rangedItems ]);
const chartData = [ { items: displayedData, name: 'Value', color } ];
const { yTickFormat, xScale, yScale } = useTimeChartController({
const { xTickFormat, yTickFormat, xScale, yScale } = useTimeChartController({
data: [ { items: displayedData, name: title, color } ],
width: innerWidth,
height: innerHeight,
......@@ -105,7 +105,7 @@ const ChartWidgetGraph = ({ isEnlarged, items, onZoom, isZoomResetInitial, title
type="left"
scale={ yScale }
ticks={ isEnlarged ? 6 : 3 }
tickFormat={ yTickFormat }
tickFormatGenerator={ yTickFormat }
disableAnimation
/>
......@@ -115,6 +115,7 @@ const ChartWidgetGraph = ({ isEnlarged, items, onZoom, isZoomResetInitial, title
transform={ `translate(0, ${ innerHeight })` }
ticks={ isMobile ? 1 : 4 }
anchorEl={ overlayRef.current }
tickFormatGenerator={ xTickFormat }
disableAnimation
/>
......
......@@ -3,6 +3,7 @@ import { useMemo } from 'react';
import type { TimeChartData } from 'ui/shared/chart/types';
import { WEEK, MONTH, YEAR } from 'lib/consts';
import formatNumberToMetricPrefix from 'lib/formatNumberToMetricPrefix';
interface Props {
......@@ -29,7 +30,8 @@ export default function useTimeChartController({ data, width, height }: Props) {
);
const yMin = useMemo(
() => d3.min(data, ({ items }) => d3.min(items, ({ value }) => value)) || 0,
// use -1 instead of 0 to correctly display the curve between two zero points.
() => d3.min(data, ({ items }) => d3.min(items, ({ value }) => value)) || -1,
[ data ],
);
......@@ -51,8 +53,27 @@ export default function useTimeChartController({ data, width, height }: Props) {
[ height, yMin, yMax ],
);
const xTickFormat = (d: d3.AxisDomain) => d.toLocaleString();
const yTickFormat = (d: d3.AxisDomain) => formatNumberToMetricPrefix(Number(d));
const xTickFormat = (axis: d3.Axis<d3.NumberValue>) => (d: d3.AxisDomain) => {
let format: (date: Date) => string;
const scale = axis.scale();
const extent = scale.domain();
const span = Number(extent[1]) - Number(extent[0]);
if (span > YEAR) {
format = d3.timeFormat('%Y');
} else if (span > 2 * MONTH) {
format = d3.timeFormat('%b');
} else if (span > WEEK) {
format = d3.timeFormat('%b %d');
} else {
format = d3.timeFormat('%a %d');
}
return format(d as Date);
};
const yTickFormat = () => (d: d3.AxisDomain) => formatNumberToMetricPrefix(Number(d));
return {
xTickFormat,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment