diff --git a/packages/desktop-client/src/components/reports/graphs/DonutGraph.tsx b/packages/desktop-client/src/components/reports/graphs/DonutGraph.tsx index f377a48e92b4b738dbd1fd40f5bb95af88d4b910..5599fb5c73388ba4d8da442e09a8f66712b83ff4 100644 --- a/packages/desktop-client/src/components/reports/graphs/DonutGraph.tsx +++ b/packages/desktop-client/src/components/reports/graphs/DonutGraph.tsx @@ -1,67 +1,87 @@ -import React from 'react'; +import React, { useState } from 'react'; -import { css } from 'glamor'; -import { PieChart, Pie, Cell, Tooltip, ResponsiveContainer } from 'recharts'; +import { PieChart, Pie, Cell, Sector, ResponsiveContainer } from 'recharts'; -import { amountToCurrency } from 'loot-core/src/shared/util'; - -import { theme } from '../../../style'; import { type CSSProperties } from '../../../style'; -import Text from '../../common/Text'; -import PrivacyFilter from '../../PrivacyFilter'; import Container from '../Container'; import { type DataEntity } from '../entities'; -import numberFormatterTooltip from '../numberFormatter'; - -type PayloadItem = { - name: string; - value: string; - color: string; - payload: { - date: string; - assets: number | string; - debt: number | string; - networth: number | string; - change: number | string; - fill: string; - }; -}; -type CustomTooltipProps = { - active?: boolean; - payload?: PayloadItem[]; - label?: string; -}; +const RADIAN = Math.PI / 180; +const ActiveShape = props => { + const { + cx, + cy, + midAngle, + innerRadius, + outerRadius, + startAngle, + endAngle, + fill, + payload, + percent, + value, + } = props; + const yAxis = payload.name ?? payload.date; + const sin = Math.sin(-RADIAN * midAngle); + const cos = Math.cos(-RADIAN * midAngle); + const sx = cx + (innerRadius - 10) * cos; + const sy = cy + (innerRadius - 10) * sin; + const mx = cx + (innerRadius - 30) * cos; + const my = cy + (innerRadius - 30) * sin; + const ex = cx + (cos >= 0 ? 1 : -1) * yAxis.length * 4; + const ey = cy + 8; + const textAnchor = cos <= 0 ? 'start' : 'end'; -const CustomTooltip = ({ active, payload, label }: CustomTooltipProps) => { - if (active && payload && payload.length) { - return ( - <div - className={`${css({ - zIndex: 1000, - pointerEvents: 'none', - borderRadius: 2, - boxShadow: '0 1px 6px rgba(0, 0, 0, .20)', - backgroundColor: theme.menuBackground, - color: theme.menuItemText, - padding: 10, - })}`} + return ( + <g> + <Sector + cx={cx} + cy={cy} + innerRadius={innerRadius} + outerRadius={outerRadius} + startAngle={startAngle} + endAngle={endAngle} + fill={fill} + /> + <Sector + cx={cx} + cy={cy} + startAngle={startAngle} + endAngle={endAngle} + innerRadius={outerRadius + 6} + outerRadius={outerRadius + 10} + fill={fill} + /> + <path + d={`M${sx},${sy}L${mx},${my}L${ex},${ey}`} + stroke={fill} + fill="none" + /> + <circle cx={ex} cy={ey} r={3} fill={fill} stroke="none" /> + <text + x={ex + (cos <= 0 ? 1 : -1) * 16} + y={ey} + textAnchor={textAnchor} + fill={fill} + >{`${yAxis}`}</text> + <text + x={ex + (cos <= 0 ? 1 : -1) * 16} + y={ey} + dy={18} + textAnchor={textAnchor} + fill={fill} + >{`${value.toFixed(2)}`}</text> + <text + x={ex + (cos <= 0 ? 1 : -1) * 16} + y={ey} + dy={36} + textAnchor={textAnchor} + fill="#999" > - <div> - <div style={{ marginBottom: 10 }}> - <strong>{payload[0].name}</strong> - </div> - <div style={{ lineHeight: 1.5 }}> - <PrivacyFilter> - <Text style={{ color: payload[0].payload.fill }}> - {amountToCurrency(payload[0].value)} - </Text> - </PrivacyFilter> - </div> - </div> - </div> - ); - } + {`(${(percent * 100).toFixed(2)}%)`} + </text> + </g> + ); }; type DonutGraphProps = { @@ -90,6 +110,12 @@ function DonutGraph({ } }; + const [activeIndex, setActiveIndex] = useState(0); + + const onPieEnter = (_, index) => { + setActiveIndex(index); + }; + return ( <Container style={{ @@ -103,18 +129,17 @@ function DonutGraph({ <div> {!compact && <div style={{ marginTop: '15px' }} />} <PieChart width={width} height={height}> - <Tooltip - content={<CustomTooltip />} - formatter={numberFormatterTooltip} - isAnimationActive={false} - /> <Pie + activeIndex={activeIndex} + activeShape={ActiveShape} dataKey={val => getVal(val)} nameKey={yAxis} isAnimationActive={false} data={data[splitData]} innerRadius={Math.min(width, height) * 0.2} fill="#8884d8" + labelLine={false} + onMouseEnter={onPieEnter} > {data.legend.map((entry, index) => ( <Cell key={`cell-${index}`} fill={entry.color} /> diff --git a/upcoming-release-notes/2098.md b/upcoming-release-notes/2098.md new file mode 100644 index 0000000000000000000000000000000000000000..fcfa29d54d61bd04aeeb4f6349a1f74b59f815db --- /dev/null +++ b/upcoming-release-notes/2098.md @@ -0,0 +1,6 @@ +--- +category: Enhancements +authors: [carkom] +--- + +Changing the view and functions for donut graph in custom reports.