From 6d569c7cdb9e6a434c766cfee209c201fc22c92a Mon Sep 17 00:00:00 2001 From: mariakax3 Date: Thu, 28 Nov 2024 17:19:21 +0100 Subject: [PATCH 1/4] made donut chart legend position adjustable --- .../charts/src/DonutChart/DonutChart.story.tsx | 2 +- .../charts/src/DonutChart/DonutChart.tsx | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/@mantine/charts/src/DonutChart/DonutChart.story.tsx b/packages/@mantine/charts/src/DonutChart/DonutChart.story.tsx index 38d61422467..b305ec9816e 100644 --- a/packages/@mantine/charts/src/DonutChart/DonutChart.story.tsx +++ b/packages/@mantine/charts/src/DonutChart/DonutChart.story.tsx @@ -12,7 +12,7 @@ const data = [ export function Usage() { return (
- +
); } diff --git a/packages/@mantine/charts/src/DonutChart/DonutChart.tsx b/packages/@mantine/charts/src/DonutChart/DonutChart.tsx index f0ec6a2316e..50c9c90033a 100644 --- a/packages/@mantine/charts/src/DonutChart/DonutChart.tsx +++ b/packages/@mantine/charts/src/DonutChart/DonutChart.tsx @@ -104,6 +104,7 @@ export interface DonutChartProps /** A function to format values inside the tooltip */ valueFormatter?: (value: number) => string; + legendOrientation?: 'top' | 'bottom' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'center-left' | 'center-right'; } export type DonutChartFactory = Factory<{ @@ -199,6 +200,7 @@ export const DonutChart = factory((_props, ref) => { valueFormatter, strokeColor, labelsType, + legendOrientation, ...others } = props; @@ -232,6 +234,19 @@ export const DonutChart = factory((_props, ref) => { /> )); + const legendPosition = { + 'top': { x: 0, y: -180 }, + 'bottom': { x: 0, y: 180 }, + 'top-left': { x: -180, y: -180 }, + 'top-right': { x: 180, y: -180 }, + 'bottom-left': { x: -180, y: 180 }, + 'bottom-right': { x: 180, y: 180 }, + 'center-left': { x: -230, y: 0 }, + 'center-right': { x: 230, y: 0 }, + }; + + const legendOffset = legendPosition[legendOrientation || 'center-right']; + return ( @@ -285,6 +300,7 @@ export const DonutChart = factory((_props, ref) => { valueFormatter={valueFormatter} /> )} + position={{ x: legendOffset.x, y: legendOffset.y }} {...tooltipProps} /> )} From c377db263cec6a4fc91f76df6092653fcd8cca71 Mon Sep 17 00:00:00 2001 From: mariakax3 Date: Tue, 3 Dec 2024 05:41:10 +0100 Subject: [PATCH 2/4] legend mode implemented --- .../src/DonutChart/DonutChart.story.tsx | 2 +- .../charts/src/DonutChart/DonutChart.tsx | 32 ++++++++++++++++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/packages/@mantine/charts/src/DonutChart/DonutChart.story.tsx b/packages/@mantine/charts/src/DonutChart/DonutChart.story.tsx index b305ec9816e..dddab22ad75 100644 --- a/packages/@mantine/charts/src/DonutChart/DonutChart.story.tsx +++ b/packages/@mantine/charts/src/DonutChart/DonutChart.story.tsx @@ -12,7 +12,7 @@ const data = [ export function Usage() { return (
- +
); } diff --git a/packages/@mantine/charts/src/DonutChart/DonutChart.tsx b/packages/@mantine/charts/src/DonutChart/DonutChart.tsx index 50c9c90033a..94c8785bc77 100644 --- a/packages/@mantine/charts/src/DonutChart/DonutChart.tsx +++ b/packages/@mantine/charts/src/DonutChart/DonutChart.tsx @@ -7,6 +7,7 @@ import { ResponsiveContainer, Tooltip, TooltipProps, + Legend, } from 'recharts'; import { Box, @@ -104,6 +105,7 @@ export interface DonutChartProps /** A function to format values inside the tooltip */ valueFormatter?: (value: number) => string; + legendMode?: 'hover' | 'side'; legendOrientation?: 'top' | 'bottom' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'center-left' | 'center-right'; } @@ -119,7 +121,8 @@ const defaultProps: Partial = { withLabelsLine: true, paddingAngle: 0, thickness: 20, - size: 160, + size: 240, + pieSize: 160, strokeWidth: 1, startAngle: 0, endAngle: 360, @@ -189,6 +192,7 @@ export const DonutChart = factory((_props, ref) => { withLabels, withLabelsLine, size, + pieSize, thickness, strokeWidth, startAngle, @@ -200,6 +204,7 @@ export const DonutChart = factory((_props, ref) => { valueFormatter, strokeColor, labelsType, + legendMode, legendOrientation, ...others } = props; @@ -245,7 +250,7 @@ export const DonutChart = factory((_props, ref) => { 'center-right': { x: 230, y: 0 }, }; - const legendOffset = legendPosition[legendOrientation || 'center-right']; + const legendOffset = { x: 260, y: legendPosition[legendOrientation || 'center-right'].y }; return ( @@ -253,8 +258,8 @@ export const DonutChart = factory((_props, ref) => { ((_props, ref) => { )} - {withTooltip && ( + {legendMode === 'hover' && withTooltip && ( ((_props, ref) => { /> )} + {legendMode === 'side' && ( + + )} + {children}
From dd207a5bfb246262a48363cd6d5d3169e2e8cd03 Mon Sep 17 00:00:00 2001 From: mariakax3 Date: Tue, 3 Dec 2024 05:47:51 +0100 Subject: [PATCH 3/4] chart highlight on side legend hover --- .../src/DonutChart/DonutChart.story.tsx | 2 +- .../charts/src/DonutChart/DonutChart.tsx | 34 +++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/packages/@mantine/charts/src/DonutChart/DonutChart.story.tsx b/packages/@mantine/charts/src/DonutChart/DonutChart.story.tsx index dddab22ad75..c636af207b7 100644 --- a/packages/@mantine/charts/src/DonutChart/DonutChart.story.tsx +++ b/packages/@mantine/charts/src/DonutChart/DonutChart.story.tsx @@ -12,7 +12,7 @@ const data = [ export function Usage() { return (
- +
); } diff --git a/packages/@mantine/charts/src/DonutChart/DonutChart.tsx b/packages/@mantine/charts/src/DonutChart/DonutChart.tsx index 94c8785bc77..8de848d6130 100644 --- a/packages/@mantine/charts/src/DonutChart/DonutChart.tsx +++ b/packages/@mantine/charts/src/DonutChart/DonutChart.tsx @@ -27,6 +27,7 @@ import { } from '@mantine/core'; import { ChartTooltip } from '../ChartTooltip/ChartTooltip'; import classes from './DonutChart.module.css'; +import React, { useState } from 'react'; export interface DonutChartCell { name: string; @@ -76,9 +77,12 @@ export interface DonutChartProps /** Controls thickness of the chart segments, `20` by default */ thickness?: number; - /** Controls chart width and height, height is increased by 40 if `withLabels` prop is set. Cannot be less than `thickness`. `80` by default */ + /** Controls chart area size along with side legend */ size?: number; + /** Controls chart width and height, height is increased by 40 if `withLabels` prop is set. Cannot be less than `thickness`. `80` by default */ + pieSize?: number; + /** Controls width of segments stroke, `1` by default */ strokeWidth?: number; @@ -105,8 +109,20 @@ export interface DonutChartProps /** A function to format values inside the tooltip */ valueFormatter?: (value: number) => string; + + /** Defines the behavior of the legend. Can be 'hover' (hover to highlight segments) or 'side' (static side legend). */ legendMode?: 'hover' | 'side'; - legendOrientation?: 'top' | 'bottom' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'center-left' | 'center-right'; + + /** Specifies the position of the legend on the chart. */ + legendOrientation?: + | 'top' + | 'bottom' + | 'top-left' + | 'top-right' + | 'bottom-left' + | 'bottom-right' + | 'center-left' + | 'center-right'; } export type DonutChartFactory = Factory<{ @@ -210,6 +226,7 @@ export const DonutChart = factory((_props, ref) => { } = props; const theme = useMantineTheme(); + const [hoveredSegment, setHoveredSegment] = useState(null); const getStyles = useStyles({ name: 'DonutChart', @@ -236,6 +253,13 @@ export const DonutChart = factory((_props, ref) => { fill={getThemeColor(item.color, theme)} stroke="var(--chart-stroke-color, var(--mantine-color-body))" strokeWidth={strokeWidth} + fillOpacity={ + legendMode === 'side' && hoveredSegment !== null + ? hoveredSegment === item.name + ? 1 + : 0.5 + : 1 + } /> )); @@ -301,7 +325,9 @@ export const DonutChart = factory((_props, ref) => { classNames={resolvedClassNames} styles={resolvedStyles} type="radial" - segmentId={tooltipDataSource === 'segment' ? payload?.[0]?.name : undefined} + segmentId={ + tooltipDataSource === 'segment' ? payload?.[0]?.name : undefined + } valueFormatter={valueFormatter} /> )} @@ -315,6 +341,8 @@ export const DonutChart = factory((_props, ref) => { layout="vertical" verticalAlign="middle" align="right" + onMouseEnter={(e: any) => setHoveredSegment(e?.value as string)} + onMouseLeave={() => setHoveredSegment(null)} wrapperStyle={{ position: 'absolute', left: `${legendOffset.x}px`, From 196a657b56009a5243c9825817c96191ccf0a937 Mon Sep 17 00:00:00 2001 From: mariakax3 Date: Tue, 3 Dec 2024 06:17:56 +0100 Subject: [PATCH 4/4] prettier run --- .../charts/src/DonutChart/DonutChart.story.tsx | 8 +++++++- .../@mantine/charts/src/DonutChart/DonutChart.tsx | 12 +++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/@mantine/charts/src/DonutChart/DonutChart.story.tsx b/packages/@mantine/charts/src/DonutChart/DonutChart.story.tsx index c636af207b7..5abfb0b9097 100644 --- a/packages/@mantine/charts/src/DonutChart/DonutChart.story.tsx +++ b/packages/@mantine/charts/src/DonutChart/DonutChart.story.tsx @@ -12,7 +12,13 @@ const data = [ export function Usage() { return (
- +
); } diff --git a/packages/@mantine/charts/src/DonutChart/DonutChart.tsx b/packages/@mantine/charts/src/DonutChart/DonutChart.tsx index 8de848d6130..7cc7e53e145 100644 --- a/packages/@mantine/charts/src/DonutChart/DonutChart.tsx +++ b/packages/@mantine/charts/src/DonutChart/DonutChart.tsx @@ -1,5 +1,7 @@ +import React, { useState } from 'react'; import { Cell, + Legend, Pie, PieLabel, PieProps, @@ -7,7 +9,6 @@ import { ResponsiveContainer, Tooltip, TooltipProps, - Legend, } from 'recharts'; import { Box, @@ -27,7 +28,6 @@ import { } from '@mantine/core'; import { ChartTooltip } from '../ChartTooltip/ChartTooltip'; import classes from './DonutChart.module.css'; -import React, { useState } from 'react'; export interface DonutChartCell { name: string; @@ -264,8 +264,8 @@ export const DonutChart = factory((_props, ref) => { )); const legendPosition = { - 'top': { x: 0, y: -180 }, - 'bottom': { x: 0, y: 180 }, + top: { x: 0, y: -180 }, + bottom: { x: 0, y: 180 }, 'top-left': { x: -180, y: -180 }, 'top-right': { x: 180, y: -180 }, 'bottom-left': { x: -180, y: 180 }, @@ -325,9 +325,7 @@ export const DonutChart = factory((_props, ref) => { classNames={resolvedClassNames} styles={resolvedStyles} type="radial" - segmentId={ - tooltipDataSource === 'segment' ? payload?.[0]?.name : undefined - } + segmentId={tooltipDataSource === 'segment' ? payload?.[0]?.name : undefined} valueFormatter={valueFormatter} /> )}