mirror of
https://github.com/umami-software/umami.git
synced 2026-02-07 22:27:16 +01:00
Updated menus, chart tooltips, styles.
This commit is contained in:
parent
0a16ab38e4
commit
92b283486e
23 changed files with 179 additions and 208 deletions
|
|
@ -1,9 +1,24 @@
|
|||
import { useMemo, useState } from 'react';
|
||||
import { useTheme } from '@umami/react-zen';
|
||||
import { BarChartTooltip } from '@/components/charts/BarChartTooltip';
|
||||
import { ChartTooltip } from '@/components/charts/ChartTooltip';
|
||||
import { Chart, ChartProps } from '@/components/charts/Chart';
|
||||
import { useLocale } from '@/components/hooks';
|
||||
import { renderNumberLabels } from '@/lib/charts';
|
||||
import { getThemeColors } from '@/lib/colors';
|
||||
import { formatDate } from '@/lib/date';
|
||||
import { formatLongCurrency, formatLongNumber } from '@/lib/format';
|
||||
|
||||
const dateFormats = {
|
||||
millisecond: 'T',
|
||||
second: 'pp',
|
||||
minute: 'p',
|
||||
hour: 'p - PP',
|
||||
day: 'PPPP',
|
||||
week: 'PPPP',
|
||||
month: 'LLLL yyyy',
|
||||
quarter: 'qqq',
|
||||
year: 'yyyy',
|
||||
};
|
||||
|
||||
export interface BarChartProps extends ChartProps {
|
||||
unit: string;
|
||||
|
|
@ -18,22 +33,23 @@ export interface BarChartProps extends ChartProps {
|
|||
isAllTime?: boolean;
|
||||
}
|
||||
|
||||
export function BarChart(props: BarChartProps) {
|
||||
export function BarChart({
|
||||
renderXLabel,
|
||||
renderYLabel,
|
||||
unit,
|
||||
XAxisType = 'time',
|
||||
YAxisType = 'linear',
|
||||
stacked = false,
|
||||
minDate,
|
||||
maxDate,
|
||||
currency,
|
||||
isAllTime,
|
||||
...props
|
||||
}: BarChartProps) {
|
||||
const [tooltip, setTooltip] = useState(null);
|
||||
const { theme } = useTheme();
|
||||
const { locale } = useLocale();
|
||||
const { colors } = getThemeColors(theme);
|
||||
const {
|
||||
renderXLabel,
|
||||
renderYLabel,
|
||||
unit,
|
||||
XAxisType = 'time',
|
||||
YAxisType = 'linear',
|
||||
stacked = false,
|
||||
minDate,
|
||||
maxDate,
|
||||
currency,
|
||||
isAllTime,
|
||||
} = props;
|
||||
|
||||
const options: any = useMemo(() => {
|
||||
return {
|
||||
|
|
@ -80,9 +96,23 @@ export function BarChart(props: BarChartProps) {
|
|||
}, [colors, unit, stacked, renderXLabel, renderYLabel]);
|
||||
|
||||
const handleTooltip = ({ tooltip }: { tooltip: any }) => {
|
||||
const { opacity } = tooltip;
|
||||
const { opacity, labelColors, dataPoints } = tooltip;
|
||||
|
||||
setTooltip(opacity ? tooltip : null);
|
||||
if (opacity) {
|
||||
setTooltip({
|
||||
title: formatDate(
|
||||
new Date(dataPoints[0].raw?.d || dataPoints[0].raw?.x || dataPoints[0].raw),
|
||||
dateFormats[unit],
|
||||
locale,
|
||||
),
|
||||
color: labelColors?.[0]?.backgroundColor,
|
||||
value: currency
|
||||
? formatLongCurrency(dataPoints[0].raw.y, currency)
|
||||
: `${formatLongNumber(dataPoints[0].raw.y)} ${dataPoints[0].dataset.label}`,
|
||||
});
|
||||
} else {
|
||||
setTooltip(null);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
@ -92,9 +122,9 @@ export function BarChart(props: BarChartProps) {
|
|||
type="bar"
|
||||
chartOptions={options}
|
||||
onTooltip={handleTooltip}
|
||||
style={{ height: 400 }}
|
||||
height="400px"
|
||||
/>
|
||||
{tooltip && <BarChartTooltip tooltip={tooltip} unit={unit} currency={currency} />}
|
||||
{tooltip && <ChartTooltip {...tooltip} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
import { useLocale } from '@/components/hooks';
|
||||
import { formatDate } from '@/lib/date';
|
||||
import { formatLongCurrency, formatLongNumber } from '@/lib/format';
|
||||
import { Column, Row, StatusLight, FloatingTooltip } from '@umami/react-zen';
|
||||
|
||||
const formats = {
|
||||
millisecond: 'T',
|
||||
second: 'pp',
|
||||
minute: 'p',
|
||||
hour: 'p - PP',
|
||||
day: 'PPPP',
|
||||
week: 'PPPP',
|
||||
month: 'LLLL yyyy',
|
||||
quarter: 'qqq',
|
||||
year: 'yyyy',
|
||||
};
|
||||
|
||||
export function BarChartTooltip({ tooltip, unit, currency }) {
|
||||
const { locale } = useLocale();
|
||||
const { labelColors, dataPoints } = tooltip;
|
||||
|
||||
return (
|
||||
<FloatingTooltip>
|
||||
<Column gap="3" fontSize="1">
|
||||
<Row alignItems="center">
|
||||
{formatDate(new Date(dataPoints[0].raw.d || dataPoints[0].raw.x), formats[unit], locale)}
|
||||
</Row>
|
||||
<Row alignItems="center">
|
||||
<StatusLight color={labelColors?.[0]?.backgroundColor}>
|
||||
{currency
|
||||
? formatLongCurrency(dataPoints[0].raw.y, currency)
|
||||
: `${formatLongNumber(dataPoints[0].raw.y)} ${dataPoints[0].dataset.label}`}
|
||||
</StatusLight>
|
||||
</Row>
|
||||
</Column>
|
||||
</FloatingTooltip>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,27 +1,31 @@
|
|||
import { Chart, ChartProps } from '@/components/charts/Chart';
|
||||
import { useState } from 'react';
|
||||
import { StatusLight } from '@umami/react-zen';
|
||||
import { formatLongNumber } from '@/lib/format';
|
||||
import { ChartTooltip } from '@/components/charts/ChartTooltip';
|
||||
|
||||
export interface BubbleChartProps extends ChartProps {
|
||||
type?: 'bubble';
|
||||
}
|
||||
|
||||
export function BubbleChart(props: BubbleChartProps) {
|
||||
export function BubbleChart({ type = 'bubble', ...props }: BubbleChartProps) {
|
||||
const [tooltip, setTooltip] = useState(null);
|
||||
const { type = 'bubble' } = props;
|
||||
|
||||
const handleTooltip = ({ tooltip }) => {
|
||||
const { labelColors, dataPoints } = tooltip;
|
||||
const { opacity, labelColors, title, dataPoints } = tooltip;
|
||||
|
||||
setTooltip(
|
||||
tooltip.opacity ? (
|
||||
<StatusLight color={labelColors?.[0]?.backgroundColor}>
|
||||
{formatLongNumber(dataPoints?.[0]?.raw)} {dataPoints?.[0]?.label}
|
||||
</StatusLight>
|
||||
) : null,
|
||||
opacity
|
||||
? {
|
||||
color: labelColors?.[0]?.backgroundColor,
|
||||
value: `${title}: ${dataPoints[0].raw}`,
|
||||
}
|
||||
: null,
|
||||
);
|
||||
};
|
||||
|
||||
return <Chart {...props} type={type} tooltip={tooltip} onTooltip={handleTooltip} />;
|
||||
return (
|
||||
<>
|
||||
<Chart {...props} type={type} onTooltip={handleTooltip} />
|
||||
{tooltip && <ChartTooltip {...tooltip} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import { useState, useRef, useEffect, useMemo, HTMLAttributes } from 'react';
|
||||
import { Loading } from '@umami/react-zen';
|
||||
import { useState, useRef, useEffect, useMemo } from 'react';
|
||||
import { Loading, Box, Column } from '@umami/react-zen';
|
||||
import ChartJS, { LegendItem, ChartOptions } from 'chart.js/auto';
|
||||
import { Legend } from '@/components/metrics/Legend';
|
||||
import { DEFAULT_ANIMATION_DURATION } from '@/lib/constants';
|
||||
import type { BoxProps } from '@umami/react-zen/Box';
|
||||
|
||||
export interface ChartProps extends HTMLAttributes<HTMLDivElement> {
|
||||
export interface ChartProps extends BoxProps {
|
||||
type?: 'bar' | 'bubble' | 'doughnut' | 'pie' | 'line' | 'polarArea' | 'radar' | 'scatter';
|
||||
data?: object;
|
||||
isLoading?: boolean;
|
||||
|
|
@ -138,12 +139,12 @@ export function Chart({
|
|||
}, [data, options]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div {...props}>
|
||||
<Column gap="6">
|
||||
<Box {...props}>
|
||||
{isLoading && <Loading position="page" icon="dots" />}
|
||||
<canvas ref={canvas} />
|
||||
</div>
|
||||
</Box>
|
||||
<Legend items={legendItems} onClick={handleLegendClick} />
|
||||
</>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
23
src/components/charts/ChartTooltip.tsx
Normal file
23
src/components/charts/ChartTooltip.tsx
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { ReactNode } from 'react';
|
||||
import { Column, Row, StatusLight, FloatingTooltip } from '@umami/react-zen';
|
||||
|
||||
export function ChartTooltip({
|
||||
title,
|
||||
color,
|
||||
value,
|
||||
}: {
|
||||
title?: string;
|
||||
color?: string;
|
||||
value?: ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<FloatingTooltip>
|
||||
<Column gap="3" fontSize="1">
|
||||
{title && <Row alignItems="center">{title}</Row>}
|
||||
<Row alignItems="center">
|
||||
<StatusLight color={color}>{value}</StatusLight>
|
||||
</Row>
|
||||
</Column>
|
||||
</FloatingTooltip>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,27 +1,31 @@
|
|||
import { Chart, ChartProps } from '@/components/charts/Chart';
|
||||
import { useState } from 'react';
|
||||
import { StatusLight } from '@umami/react-zen';
|
||||
import { formatLongNumber } from '@/lib/format';
|
||||
import { ChartTooltip } from '@/components/charts/ChartTooltip';
|
||||
|
||||
export interface PieChartProps extends ChartProps {
|
||||
type?: 'doughnut' | 'pie';
|
||||
}
|
||||
|
||||
export function PieChart(props: PieChartProps) {
|
||||
export function PieChart({ type = 'pie', ...props }: PieChartProps) {
|
||||
const [tooltip, setTooltip] = useState(null);
|
||||
const { type = 'pie' } = props;
|
||||
|
||||
const handleTooltip = ({ tooltip }) => {
|
||||
const { labelColors, dataPoints } = tooltip;
|
||||
const { opacity, labelColors, title, dataPoints } = tooltip;
|
||||
|
||||
setTooltip(
|
||||
tooltip.opacity ? (
|
||||
<StatusLight color={labelColors?.[0]?.backgroundColor}>
|
||||
{formatLongNumber(dataPoints?.[0]?.raw)} {dataPoints?.[0]?.label}
|
||||
</StatusLight>
|
||||
) : null,
|
||||
opacity
|
||||
? {
|
||||
color: labelColors?.[0]?.backgroundColor,
|
||||
value: `${title}: ${dataPoints[0].raw}`,
|
||||
}
|
||||
: null,
|
||||
);
|
||||
};
|
||||
|
||||
return <Chart {...props} type={type} tooltip={tooltip} onTooltip={handleTooltip} />;
|
||||
return (
|
||||
<>
|
||||
<Chart {...props} type={type} onTooltip={handleTooltip} />
|
||||
{tooltip && <ChartTooltip {...tooltip} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue