Skip to content

Commit

Permalink
update area chart fill prop (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
severinlandolt authored Jun 19, 2024
1 parent 3e1f3a6 commit fc5b74a
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 132 deletions.
304 changes: 173 additions & 131 deletions src/components/AreaChart/AreaChart.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Tremor Raw AreaChart [v0.1.0]
// Tremor Raw AreaChart [v0.2.0]

"use client"

Expand Down Expand Up @@ -509,6 +509,7 @@ interface AreaChartProps extends React.HTMLAttributes<HTMLDivElement> {
yAxisLabel?: string
type?: "default" | "stacked" | "percent"
legendPosition?: "left" | "center" | "right"
fill?: "gradient" | "solid" | "none"
}

const AreaChart = React.forwardRef<HTMLDivElement, AreaChartProps>(
Expand Down Expand Up @@ -540,6 +541,7 @@ const AreaChart = React.forwardRef<HTMLDivElement, AreaChartProps>(
yAxisLabel,
type = "default",
legendPosition = "right",
fill = "gradient",
...other
} = props
const paddingValue = !showXAxis && !showYAxis ? 0 : 20
Expand All @@ -555,6 +557,42 @@ const AreaChart = React.forwardRef<HTMLDivElement, AreaChartProps>(
const yAxisDomain = getYAxisDomain(autoMinValue, minValue, maxValue)
const hasOnValueChange = !!onValueChange
const stacked = type === "stacked" || type === "percent"
const areaId = React.useId()

const getFillContent = ({
fillType,
activeDot,
activeLegend,
category,
}: {
fillType: AreaChartProps["fill"]
activeDot: ActiveDot | undefined
activeLegend: string | undefined
category: string
}) => {
const stopOpacity =
activeDot || (activeLegend && activeLegend !== category) ? 0.15 : 0.4

switch (fillType) {
case "none":
return <stop stopColor="currentColor" stopOpacity={0} />
case "gradient":
return (
<>
<stop
offset="5%"
stopColor="currentColor"
stopOpacity={stopOpacity}
/>
<stop offset="95%" stopColor="currentColor" stopOpacity={0} />
</>
)
case "solid":
default:
return <stop stopColor="currentColor" stopOpacity={stopOpacity} />
}
}

function valueToPercent(value: number) {
return `${(value * 100).toFixed(0)}%`
}
Expand Down Expand Up @@ -746,142 +784,146 @@ const AreaChart = React.forwardRef<HTMLDivElement, AreaChartProps>(
}
/>
) : null}
{categories.map((category) => (
<defs key={category}>
<linearGradient
className={cx(
getColorClassName(
categoryColors.get(category) as AvailableChartColorsKeys,
"text",
),
)}
id={categoryColors.get(category)}
x1="0"
y1="0"
x2="0"
y2="1"
>
<stop
offset="5%"
stopColor="currentColor"
stopOpacity={
activeDot || (activeLegend && activeLegend !== category)
? 0.15
: 0.4
}
/>
<stop offset="95%" stopColor="currentColor" stopOpacity={0} />
</linearGradient>
</defs>
))}
{categories.map((category) => (
<Area
className={cx(
getColorClassName(
categoryColors.get(category) as AvailableChartColorsKeys,
"stroke",
),
)}
strokeOpacity={
activeDot || (activeLegend && activeLegend !== category)
? 0.3
: 1
}
activeDot={(props: any) => {
const {
cx: cxCoord,
cy: cyCoord,
stroke,
strokeLinecap,
strokeLinejoin,
strokeWidth,
dataKey,
} = props
return (
<Dot
{categories.map((category) => {
const categoryId = `${areaId}-${category}`
return (
<React.Fragment key={category}>
<defs key={category}>
<linearGradient
key={category}
className={cx(
"stroke-white dark:stroke-gray-950",
onValueChange ? "cursor-pointer" : "",
getColorClassName(
categoryColors.get(
dataKey,
category,
) as AvailableChartColorsKeys,
"fill",
"text",
),
)}
cx={cxCoord}
cy={cyCoord}
r={5}
fill=""
stroke={stroke}
strokeLinecap={strokeLinecap}
strokeLinejoin={strokeLinejoin}
strokeWidth={strokeWidth}
onClick={(_, event) => onDotClick(props, event)}
/>
)
}}
dot={(props: any) => {
const {
stroke,
strokeLinecap,
strokeLinejoin,
strokeWidth,
cx: cxCoord,
cy: cyCoord,
dataKey,
index,
} = props

if (
(hasOnlyOneValueForKey(data, category) &&
!(
activeDot ||
(activeLegend && activeLegend !== category)
)) ||
(activeDot?.index === index &&
activeDot?.dataKey === category)
) {
return (
<Dot
key={index}
cx={cxCoord}
cy={cyCoord}
r={5}
stroke={stroke}
fill=""
strokeLinecap={strokeLinecap}
strokeLinejoin={strokeLinejoin}
strokeWidth={strokeWidth}
className={cx(
"stroke-white dark:stroke-gray-950",
onValueChange ? "cursor-pointer" : "",
getColorClassName(
categoryColors.get(
dataKey,
) as AvailableChartColorsKeys,
"fill",
),
)}
/>
)
}
return <React.Fragment key={index}></React.Fragment>
}}
key={category}
name={category}
type="linear"
dataKey={category}
stroke=""
strokeWidth={2}
strokeLinejoin="round"
strokeLinecap="round"
isAnimationActive={false}
connectNulls={connectNulls}
stackId={stacked ? "stack" : undefined}
fill={`url(#${categoryColors.get(category) as AvailableChartColorsKeys})`}
/>
))}
id={categoryId}
x1="0"
y1="0"
x2="0"
y2="1"
>
{getFillContent({
fillType: fill,
activeDot: activeDot,
activeLegend: activeLegend,
category: category,
})}
</linearGradient>
</defs>
<Area
className={cx(
getColorClassName(
categoryColors.get(
category,
) as AvailableChartColorsKeys,
"stroke",
),
)}
strokeOpacity={
activeDot || (activeLegend && activeLegend !== category)
? 0.3
: 1
}
activeDot={(props: any) => {
const {
cx: cxCoord,
cy: cyCoord,
stroke,
strokeLinecap,
strokeLinejoin,
strokeWidth,
dataKey,
} = props
return (
<Dot
className={cx(
"stroke-white dark:stroke-gray-950",
onValueChange ? "cursor-pointer" : "",
getColorClassName(
categoryColors.get(
dataKey,
) as AvailableChartColorsKeys,
"fill",
),
)}
cx={cxCoord}
cy={cyCoord}
r={5}
fill=""
stroke={stroke}
strokeLinecap={strokeLinecap}
strokeLinejoin={strokeLinejoin}
strokeWidth={strokeWidth}
onClick={(_, event) => onDotClick(props, event)}
/>
)
}}
dot={(props: any) => {
const {
stroke,
strokeLinecap,
strokeLinejoin,
strokeWidth,
cx: cxCoord,
cy: cyCoord,
dataKey,
index,
} = props

if (
(hasOnlyOneValueForKey(data, category) &&
!(
activeDot ||
(activeLegend && activeLegend !== category)
)) ||
(activeDot?.index === index &&
activeDot?.dataKey === category)
) {
return (
<Dot
key={index}
cx={cxCoord}
cy={cyCoord}
r={5}
stroke={stroke}
fill=""
strokeLinecap={strokeLinecap}
strokeLinejoin={strokeLinejoin}
strokeWidth={strokeWidth}
className={cx(
"stroke-white dark:stroke-gray-950",
onValueChange ? "cursor-pointer" : "",
getColorClassName(
categoryColors.get(
dataKey,
) as AvailableChartColorsKeys,
"fill",
),
)}
/>
)
}
return <React.Fragment key={index}></React.Fragment>
}}
key={category}
name={category}
type="linear"
dataKey={category}
stroke=""
strokeWidth={2}
strokeLinejoin="round"
strokeLinecap="round"
isAnimationActive={false}
connectNulls={connectNulls}
stackId={stacked ? "stack" : undefined}
fill={`url(#${categoryId})`}
/>
</React.Fragment>
)
})}
{/* hidden lines to increase clickable target area */}
{onValueChange
? categories.map((category) => (
Expand Down
12 changes: 12 additions & 0 deletions src/components/AreaChart/areachart.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -330,3 +330,15 @@ export const OneDataValue: Story = {
onValueChange: (v) => console.log(v),
},
}

export const WithFillSolid: Story = {
args: {
fill: "solid",
},
}

export const WithFillNone: Story = {
args: {
fill: "none",
},
}
8 changes: 7 additions & 1 deletion src/components/AreaChart/changelog.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
# Tremor Raw AreaChart Changelog

## 0.2.0

### Changes

- Feat: Add fill prop

## 0.1.0

### Changes

Feat: Add legendPosition prop
- Feat: Add legendPosition prop

0 comments on commit fc5b74a

Please sign in to comment.