recharts#TooltipProps TypeScript Examples
The following examples show how to use
recharts#TooltipProps.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: graphs.ts From backstage with Apache License 2.0 | 5 votes |
isInvalid = ({ label, payload }: TooltipProps) => {
// null labels are empty strings, which are valid
return label === undefined || !payload || !payload.length;
}
Example #2
Source File: CostOverviewBreakdownChart.tsx From backstage with Apache License 2.0 | 4 votes |
CostOverviewBreakdownChart = ({
costBreakdown,
}: CostOverviewBreakdownChartProps) => {
const theme = useTheme<CostInsightsTheme>();
const classes = useStyles(theme);
const lastCompleteBillingDate = useLastCompleteBillingDate();
const { duration } = useFilters(mapFiltersToProps);
const [isExpanded, setExpanded] = useState(false);
if (!costBreakdown) {
return null;
}
const flattenedAggregation = costBreakdown
.map(cost => cost.aggregation)
.flat();
const totalCost = aggregationSum(flattenedAggregation);
const previousPeriodTotal = getPreviousPeriodTotalCost(
flattenedAggregation,
duration,
lastCompleteBillingDate,
);
const currentPeriodTotal = totalCost - previousPeriodTotal;
const canExpand = costBreakdown.length >= 8;
const otherCategoryIds: string[] = [];
const breakdownsByDate = costBreakdown.reduce(
(breakdownByDate, breakdown) => {
const breakdownTotal = aggregationSum(breakdown.aggregation);
// Group breakdown items with less than 10% of the total cost into "Other" category if needed
const isOtherCategory =
canExpand && breakdownTotal < totalCost * LOW_COST_THRESHOLD;
const updatedBreakdownByDate = { ...breakdownByDate };
if (isOtherCategory) {
otherCategoryIds.push(breakdown.id);
}
breakdown.aggregation.forEach(curAggregation => {
const costsForDate = updatedBreakdownByDate[curAggregation.date] || {};
updatedBreakdownByDate[curAggregation.date] = {
...costsForDate,
[breakdown.id]:
(costsForDate[breakdown.id] || 0) + curAggregation.amount,
};
});
return updatedBreakdownByDate;
},
{} as Record<string, Record<string, number>>,
);
const chartData: Record<string, number>[] = Object.keys(breakdownsByDate).map(
date => {
const costsForDate = Object.keys(breakdownsByDate[date]).reduce(
(dateCosts, breakdown) => {
// Group costs for items that belong to 'Other' in the chart.
const cost = breakdownsByDate[date][breakdown];
const breakdownCost =
!isExpanded && otherCategoryIds.includes(breakdown)
? { Other: (dateCosts.Other || 0) + cost }
: { [breakdown]: cost };
return { ...dateCosts, ...breakdownCost };
},
{} as Record<string, number>,
);
return {
...costsForDate,
date: Date.parse(date),
};
},
);
const sortedBreakdowns = costBreakdown.sort(
(a, b) => aggregationSum(a.aggregation) - aggregationSum(b.aggregation),
);
const renderAreas = () => {
const separatedBreakdowns = sortedBreakdowns
// Check that the breakdown is a separate group and hasn't been added to 'Other'
.filter(
breakdown =>
breakdown.id !== 'Other' && !otherCategoryIds.includes(breakdown.id),
)
.map(breakdown => breakdown.id);
// Keep 'Other' category at the bottom of the stack
const breakdownsToDisplay = isExpanded
? sortedBreakdowns.map(breakdown => breakdown.id)
: ['Other', ...separatedBreakdowns];
return breakdownsToDisplay.map((breakdown, i) => {
// Logic to handle case where there are more items than data viz colors.
const color =
theme.palette.dataViz[
(breakdownsToDisplay.length - 1 - i) %
(theme.palette.dataViz.length - 1)
];
return (
<Area
key={breakdown}
dataKey={breakdown}
isAnimationActive={false}
stackId="1"
stroke={color}
fill={color}
onClick={() => setExpanded(true)}
style={{
cursor: breakdown === 'Other' && !isExpanded ? 'pointer' : null,
}}
/>
);
});
};
const tooltipRenderer: ContentRenderer<TooltipProps> = ({
label,
payload = [],
}) => {
if (isInvalid({ label, payload })) return null;
const date =
typeof label === 'number'
? DateTime.fromMillis(label)
: DateTime.fromISO(label!);
const dateTitle = date.toUTC().toFormat(DEFAULT_DATE_FORMAT);
const items = payload.map(p => ({
label: p.dataKey as string,
value: formatGraphValue(p.value as number),
fill: p.fill!,
}));
const expandText = (
<Box>
<Divider
style={{
backgroundColor: emphasize(theme.palette.divider, 1),
margin: '10px 0',
}}
/>
<Box display="flex" justifyContent="space-between" alignItems="center">
<FullScreenIcon />
<Typography>Click to expand</Typography>
</Box>
</Box>
);
return (
<Tooltip title={dateTitle}>
{items.reverse().map((item, index) => (
<TooltipItem key={`${item.label}-${index}`} item={item} />
))}
{canExpand && !isExpanded ? expandText : null}
</Tooltip>
);
};
const options: Partial<BarChartLegendOptions> = {
previousName: formatPeriod(duration, lastCompleteBillingDate, false),
currentName: formatPeriod(duration, lastCompleteBillingDate, true),
hideMarker: true,
};
return (
<Box display="flex" flexDirection="column">
<Box display="flex" flexDirection="row">
<BarChartLegend
costStart={previousPeriodTotal}
costEnd={currentPeriodTotal}
options={options}
/>
</Box>
<ResponsiveContainer
width={classes.container.width}
height={classes.container.height}
>
<AreaChart
data={chartData}
margin={{
top: 16,
right: 30,
bottom: 40,
}}
>
<CartesianGrid stroke={classes.cartesianGrid.stroke} />
<XAxis
dataKey="date"
domain={['dataMin', 'dataMax']}
tickFormatter={overviewGraphTickFormatter}
tickCount={6}
type="number"
stroke={classes.axis.fill}
/>
<YAxis
domain={[() => 0, 'dataMax']}
tick={{ fill: classes.axis.fill }}
tickFormatter={formatGraphValue}
width={classes.yAxis.width}
/>
{renderAreas()}
<RechartsTooltip content={tooltipRenderer} animationDuration={100} />
</AreaChart>
</ResponsiveContainer>
</Box>
);
}
Example #3
Source File: CostOverviewChart.tsx From backstage with Apache License 2.0 | 4 votes |
CostOverviewChart = ({
dailyCostData,
metric,
metricData,
responsive = true,
}: CostOverviewChartProps) => {
const theme = useTheme<CostInsightsTheme>();
const styles = useStyles(theme);
const data = {
dailyCost: {
dataKey: 'dailyCost',
name: `Daily Cost`,
format: 'currency',
data: dailyCostData,
},
metric: {
dataKey: metric?.kind ?? 'Unknown',
name: metric?.name ?? 'Unknown',
format: metricData?.format ?? 'number',
data: metricData,
},
};
const metricsByDate = data.metric.data
? data.metric.data.aggregation.reduce(groupByDate, {})
: {};
const chartData: ChartData[] = data.dailyCost.data.aggregation
.slice()
.sort(aggregationSort)
.map(entry => ({
date: Date.parse(entry.date),
trend: trendFrom(data.dailyCost.data.trendline!, Date.parse(entry.date)),
dailyCost: entry.amount,
...(metric && data.metric.data
? { [data.metric.dataKey]: metricsByDate[`${entry.date}`] }
: {}),
}));
const tooltipRenderer: ContentRenderer<TooltipProps> = ({
label,
payload = [],
}) => {
if (isInvalid({ label, payload })) return null;
const dataKeys = [data.dailyCost.dataKey, data.metric.dataKey];
const date =
typeof label === 'number'
? DateTime.fromMillis(label)
: DateTime.fromISO(label!);
const title = date.toUTC().toFormat(DEFAULT_DATE_FORMAT);
const items = payload
.filter(p => dataKeys.includes(p.dataKey as string))
.map(p => ({
label:
p.dataKey === data.dailyCost.dataKey
? data.dailyCost.name
: data.metric.name,
value:
p.dataKey === data.dailyCost.dataKey
? formatGraphValue(p.value as number, data.dailyCost.format)
: formatGraphValue(p.value as number, data.metric.format),
fill:
p.dataKey === data.dailyCost.dataKey
? theme.palette.blue
: theme.palette.magenta,
}));
return (
<Tooltip title={title}>
{items.map((item, index) => (
<TooltipItem key={`${item.label}-${index}`} item={item} />
))}
</Tooltip>
);
};
return (
<Box display="flex" flexDirection="column">
<CostOverviewLegend
dailyCostData={dailyCostData}
metric={metric}
metricData={metricData}
/>
<ResponsiveContainer
width={responsive ? '100%' : styles.container.width}
height={styles.container.height}
className="cost-overview-chart"
>
<ComposedChart margin={styles.chart.margin} data={chartData}>
<CartesianGrid stroke={styles.cartesianGrid.stroke} />
<XAxis
dataKey="date"
domain={['dataMin', 'dataMax']}
tickFormatter={overviewGraphTickFormatter}
tickCount={6}
type="number"
stroke={styles.axis.fill}
/>
<YAxis
domain={[() => 0, 'dataMax']}
tick={{ fill: styles.axis.fill }}
tickFormatter={formatGraphValue}
width={styles.yAxis.width}
yAxisId={data.dailyCost.dataKey}
/>
{metric && (
<YAxis
hide
domain={[() => 0, toDataMax(data.metric.dataKey, chartData)]}
width={styles.yAxis.width}
yAxisId={data.metric.dataKey}
/>
)}
<Area
dataKey={data.dailyCost.dataKey}
isAnimationActive={false}
fill={theme.palette.blue}
fillOpacity={0.4}
stroke="none"
yAxisId={data.dailyCost.dataKey}
/>
<Line
activeDot={false}
dataKey="trend"
dot={false}
isAnimationActive={false}
label={false}
strokeWidth={2}
stroke={theme.palette.blue}
yAxisId={data.dailyCost.dataKey}
/>
{metric && (
<Line
dataKey={data.metric.dataKey}
dot={false}
isAnimationActive={false}
label={false}
strokeWidth={2}
stroke={theme.palette.magenta}
yAxisId={data.metric.dataKey}
/>
)}
<RechartsTooltip content={tooltipRenderer} animationDuration={100} />
</ComposedChart>
</ResponsiveContainer>
</Box>
);
}