diff --git a/frontend/src/component/admin/network/NetworkTrafficUsage/BackendConnections.tsx b/frontend/src/component/admin/network/NetworkTrafficUsage/BackendConnections.tsx index e8f3083b2e..78bd042c88 100644 --- a/frontend/src/component/admin/network/NetworkTrafficUsage/BackendConnections.tsx +++ b/frontend/src/component/admin/network/NetworkTrafficUsage/BackendConnections.tsx @@ -11,7 +11,6 @@ import { } from '@mui/material'; import { PeriodSelector } from './PeriodSelector.tsx'; import { Bar } from 'react-chartjs-2'; -import { customHighlightPlugin } from 'component/common/Chart/customHighlightPlugin'; import { getChartLabel } from './chart-functions.ts'; import { useConsumptionStats } from './hooks/useStats.ts'; import { StyledBox, TopRow } from './SharedComponents.tsx'; @@ -27,6 +26,7 @@ import { import annotationPlugin from 'chartjs-plugin-annotation'; import { useChartDataSelection } from './hooks/useChartDataSelection.ts'; import HelpOutline from '@mui/icons-material/HelpOutline'; +import { networkTrafficUsageHighlightPlugin } from './networkTrafficUsageHighlightPlugin.ts'; const ConnectionExplanationBox = styled(Box)(({ theme }) => ({ display: 'flex', @@ -73,7 +73,7 @@ export const BackendConnections: FC = () => { diff --git a/frontend/src/component/admin/network/NetworkTrafficUsage/FrontendNetworkTrafficUsage.tsx b/frontend/src/component/admin/network/NetworkTrafficUsage/FrontendNetworkTrafficUsage.tsx index 34a1c72aca..29627e1808 100644 --- a/frontend/src/component/admin/network/NetworkTrafficUsage/FrontendNetworkTrafficUsage.tsx +++ b/frontend/src/component/admin/network/NetworkTrafficUsage/FrontendNetworkTrafficUsage.tsx @@ -15,12 +15,12 @@ import { import { Bar } from 'react-chartjs-2'; import annotationPlugin from 'chartjs-plugin-annotation'; -import { customHighlightPlugin } from 'component/common/Chart/customHighlightPlugin'; import { PeriodSelector } from './PeriodSelector.tsx'; import { getChartLabel } from './chart-functions.ts'; import { useRequestsStats } from './hooks/useStats.ts'; import { StyledBox, TopRow } from './SharedComponents.tsx'; import { useChartDataSelection } from './hooks/useChartDataSelection.ts'; +import { networkTrafficUsageHighlightPlugin } from './networkTrafficUsageHighlightPlugin.ts'; const FrontendNetworkTrafficUsage: FC = () => { usePageTitle('Network - Frontend Traffic Usage'); @@ -53,7 +53,7 @@ const FrontendNetworkTrafficUsage: FC = () => { diff --git a/frontend/src/component/admin/network/NetworkTrafficUsage/NetworkTrafficUsage.tsx b/frontend/src/component/admin/network/NetworkTrafficUsage/NetworkTrafficUsage.tsx index 857fee467b..b59d96bc1d 100644 --- a/frontend/src/component/admin/network/NetworkTrafficUsage/NetworkTrafficUsage.tsx +++ b/frontend/src/component/admin/network/NetworkTrafficUsage/NetworkTrafficUsage.tsx @@ -17,7 +17,6 @@ import { import { Bar } from 'react-chartjs-2'; import annotationPlugin from 'chartjs-plugin-annotation'; -import { customHighlightPlugin } from 'component/common/Chart/customHighlightPlugin'; import { PeriodSelector } from './PeriodSelector.tsx'; import { useUiFlag } from 'hooks/useUiFlag'; import { OverageInfo, RequestSummary } from './RequestSummary.tsx'; @@ -27,6 +26,7 @@ import { useTrafficStats } from './hooks/useStats.ts'; import { BoldText, StyledBox, TopRow } from './SharedComponents.tsx'; import { useChartDataSelection } from './hooks/useChartDataSelection.ts'; import { useTrafficBundles } from '../../../../hooks/api/getters/useTrafficBundles/useTrafficBundles.ts'; +import { networkTrafficUsageHighlightPlugin } from './networkTrafficUsageHighlightPlugin.ts'; const TrafficInfoBoxes = styled('div')(({ theme }) => ({ display: 'grid', @@ -131,7 +131,7 @@ const NetworkTrafficUsage: FC = () => { diff --git a/frontend/src/component/admin/network/NetworkTrafficUsage/networkTrafficUsageHighlightPlugin.ts b/frontend/src/component/admin/network/NetworkTrafficUsage/networkTrafficUsageHighlightPlugin.ts new file mode 100644 index 0000000000..b94c8defbe --- /dev/null +++ b/frontend/src/component/admin/network/NetworkTrafficUsage/networkTrafficUsageHighlightPlugin.ts @@ -0,0 +1,5 @@ +import { customHighlightPlugin } from 'component/common/Chart/customHighlightPlugin'; + +export const networkTrafficUsageHighlightPlugin = customHighlightPlugin({ + bottomOverflow: 34, +}); diff --git a/frontend/src/component/common/Chart/customHighlightPlugin.ts b/frontend/src/component/common/Chart/customHighlightPlugin.ts index f0c35153e3..b4e8aad54e 100644 --- a/frontend/src/component/common/Chart/customHighlightPlugin.ts +++ b/frontend/src/component/common/Chart/customHighlightPlugin.ts @@ -1,8 +1,34 @@ import type { Chart } from 'chart.js'; -export const customHighlightPlugin = (bottomOverflow = 34) => ({ +type CustomHighlightPluginOptions = { + width?: number | ((chart: Chart) => number); + maxHighlightOpacity?: number; + bottomOverflow?: number; +}; + +const defaultCategoryPercentage = 0.8; +export const categoryWidth = (chart: Chart) => { + return ( + (chart.width / chart.scales.x.ticks.length) * + (chart.options.datasets?.bar?.categoryPercentage ?? + defaultCategoryPercentage) + ); +}; + +// Vertical line on the hovered chart, filled with gradient. Highlights a section of a chart when you hover over datapoints +export const customHighlightPlugin = ( + options?: CustomHighlightPluginOptions, +) => ({ id: 'customLine', beforeDraw: (chart: Chart) => { + const { + width = categoryWidth, + maxHighlightOpacity = 0.12, + bottomOverflow = 0, + } = options ?? {}; + + const highlightWidth = + typeof width === 'function' ? width(chart) : width; if (chart.tooltip?.opacity && chart.tooltip.x) { const x = chart.tooltip.caretX; const yAxis = chart.scales.y; @@ -12,23 +38,27 @@ export const customHighlightPlugin = (bottomOverflow = 34) => ({ x, yAxis.top, x, - yAxis.bottom + 34, + yAxis.bottom + bottomOverflow, ); gradient.addColorStop(0, 'rgba(129, 122, 254, 0)'); - gradient.addColorStop(1, 'rgba(129, 122, 254, 0.12)'); + gradient.addColorStop( + 1, + `rgba(129, 122, 254, ${maxHighlightOpacity})`, + ); ctx.fillStyle = gradient; - const barWidth = - (chart.width / (chart.data.labels?.length ?? 1)) * - (chart.options.datasets?.bar?.categoryPercentage ?? 1); - ctx.roundRect( - x - barWidth / 2, + const args: [number, number, number, number] = [ + x - highlightWidth / 2, yAxis.top, - barWidth, + highlightWidth, yAxis.bottom - yAxis.top + bottomOverflow, - 5, - ); - ctx.fill(); + ]; + if (bottomOverflow) { + ctx.roundRect(...args, 5); + ctx.fill(); + } else { + ctx.fillRect(...args); + } ctx.restore(); } }, diff --git a/frontend/src/component/insights/components/LineChart/LineChartComponent.tsx b/frontend/src/component/insights/components/LineChart/LineChartComponent.tsx index 4f62e77d82..5c684742bc 100644 --- a/frontend/src/component/insights/components/LineChart/LineChartComponent.tsx +++ b/frontend/src/component/insights/components/LineChart/LineChartComponent.tsx @@ -25,6 +25,7 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit import { styled } from '@mui/material'; import { createOptions } from './createChartOptions.ts'; import merge from 'deepmerge'; +import { customHighlightPlugin } from 'component/common/Chart/customHighlightPlugin.ts'; const StyledContainer = styled('div')(({ theme }) => ({ position: 'relative', @@ -52,36 +53,6 @@ const StyledCoverContent = styled('div')(({ theme }) => ({ textAlign: 'center', })); -// Vertical line on the hovered chart, filled with gradient. Highlights a section of a chart when you hover over datapoints -const customHighlightPlugin = { - id: 'customLine', - afterDraw: (chart: Chart) => { - const width = 26; - if (chart.tooltip?.opacity && chart.tooltip.x) { - const x = chart.tooltip.caretX; - const yAxis = chart.scales.y; - const ctx = chart.ctx; - ctx.save(); - const gradient = ctx.createLinearGradient( - x, - yAxis.top, - x, - yAxis.bottom, - ); - gradient.addColorStop(0, 'rgba(129, 122, 254, 0)'); - gradient.addColorStop(1, 'rgba(129, 122, 254, 0.12)'); - ctx.fillStyle = gradient; - ctx.fillRect( - x - width / 2, - yAxis.top, - width, - yAxis.bottom - yAxis.top, - ); - ctx.restore(); - } - }, -}; - function mergeAll(objects: Partial[]): T { return merge.all(objects.filter((i) => i)); } @@ -126,7 +97,7 @@ const LineChartComponent: FC<{ key={cover ? 'cover' : 'chart'} options={options} data={data} - plugins={[customHighlightPlugin]} + plugins={[customHighlightPlugin({ width: 26 })]} height={100} width={100 * aspectRatio} /> diff --git a/frontend/src/component/insights/componentsChart/CreationArchiveChart/CreationArchiveChart.tsx b/frontend/src/component/insights/componentsChart/CreationArchiveChart/CreationArchiveChart.tsx index d8287f3bb1..87652e1433 100644 --- a/frontend/src/component/insights/componentsChart/CreationArchiveChart/CreationArchiveChart.tsx +++ b/frontend/src/component/insights/componentsChart/CreationArchiveChart/CreationArchiveChart.tsx @@ -24,6 +24,7 @@ import { createTooltip } from 'component/insights/components/LineChart/createToo import { CreationArchiveRatioTooltip } from './CreationArchiveRatioTooltip.tsx'; import { Chart } from 'react-chartjs-2'; import { getDateFnsLocale } from '../../getDateFnsLocale.ts'; +import { customHighlightPlugin } from 'component/common/Chart/customHighlightPlugin.ts'; ChartJS.register( CategoryScale, @@ -108,6 +109,8 @@ export const CreationArchiveChart: FC = ({ data: weeks, backgroundColor: theme.palette.charts.A2, borderColor: theme.palette.charts.A2, + hoverBackgroundColor: theme.palette.charts.A2, + hoverBorderColor: theme.palette.charts.A2, parsing: { yAxisKey: 'archivedFlags', xAxisKey: 'date' }, order: 1, }, @@ -116,6 +119,8 @@ export const CreationArchiveChart: FC = ({ data: weeks, backgroundColor: theme.palette.charts.A1, borderColor: theme.palette.charts.A1, + hoverBackgroundColor: theme.palette.charts.A1, + hoverBorderColor: theme.palette.charts.A1, parsing: { yAxisKey: 'totalCreatedFlags', xAxisKey: 'date', @@ -203,6 +208,11 @@ export const CreationArchiveChart: FC = ({ options={options} height={100} width={250} + plugins={[ + customHighlightPlugin({ + maxHighlightOpacity: 0.24, + }), + ]} />