From 1c200452b5cb4547ef1556c50312b2430094fa16 Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Tue, 7 Jan 2025 16:20:15 +0100 Subject: [PATCH] ui: fixing bars under comparison --- .../app/components/Charts/ColumnChart.tsx | 3 +- frontend/app/components/Charts/barUtils.ts | 124 ++++++++---------- frontend/app/components/Charts/utils.ts | 40 +++++- .../components/WidgetView/WidgetView.tsx | 25 ++-- 4 files changed, 114 insertions(+), 78 deletions(-) diff --git a/frontend/app/components/Charts/ColumnChart.tsx b/frontend/app/components/Charts/ColumnChart.tsx index 275689b50..1ab012c38 100644 --- a/frontend/app/components/Charts/ColumnChart.tsx +++ b/frontend/app/components/Charts/ColumnChart.tsx @@ -44,6 +44,7 @@ function ColumnChart(props: ColumnChartProps) { const { yAxisData, series } = buildColumnChart(chartUuid.current, data, compData); + console.log(yAxisData) chart.setOption({ ...defaultOptions, tooltip: { @@ -51,6 +52,7 @@ function ColumnChart(props: ColumnChartProps) { formatter: customTooltipFormatter(chartUuid.current), }, legend: { + ...defaultOptions.legend, data: series .filter((s: any) => !s._hideInLegend) .map((s: any) => s.name), @@ -64,7 +66,6 @@ function ColumnChart(props: ColumnChartProps) { }, xAxis: { type: 'value', - boundaryGap: [0, 0.01], name: label ?? 'Total', nameLocation: 'middle', nameGap: 35, diff --git a/frontend/app/components/Charts/barUtils.ts b/frontend/app/components/Charts/barUtils.ts index 826230935..86c55a95d 100644 --- a/frontend/app/components/Charts/barUtils.ts +++ b/frontend/app/components/Charts/barUtils.ts @@ -1,5 +1,5 @@ import type { DataProps, DataItem } from './utils'; -import { createDataset, assignColorsByBaseName } from './utils'; +import { createDataset, assignColorsByBaseName, assignColorsByCategory } from './utils'; export function createBarSeries( data: DataProps['data'], @@ -48,94 +48,82 @@ export function buildBarDatasetsAndSeries(props: DataProps) { } +// START GEN function sumSeries(chart: DataItem[], seriesName: string): number { return chart.reduce((acc, row) => acc + (Number(row[seriesName]) || 0), 0); } -export function buildColumnChart(chartUuid: string, data: DataProps['data'], compData: DataProps['compData'],) { - const baseNamesSet = new Set(); +/** + * Build a horizontal bar chart with: + * - yAxis categories = each name in data.namesMap + * - 1 bar series for "Current" + * - 1 bar series for "Previous" (optional, if compData present) + */ +export function buildColumnChart( + chartUuid: string, + data: DataProps['data'], + compData: DataProps['compData'] +) { + const categories = data.namesMap.filter(Boolean); - data.namesMap.filter(Boolean).forEach((fullName) => { - const baseName = fullName.replace(/^Previous\s+/, ''); - baseNamesSet.add(baseName); + const currentValues = categories.map((name) => { + const val = sumSeries(data.chart, name); + (window as any).__seriesValueMap[chartUuid][name] = val; + return val; }); + let previousValues: number[] = []; if (compData && compData.chart?.length) { - compData.namesMap.filter(Boolean).forEach((fullName) => { - const baseName = fullName.replace(/^Previous\s+/, ''); - baseNamesSet.add(baseName); + previousValues = categories.map((name) => { + const val = sumSeries(compData.chart, `Previous ${name}`); + (window as any).__seriesValueMap[chartUuid][`Previous ${name}`] = val; + return val; }); } - const baseNames = Array.from(baseNamesSet); // e.g. ["Series 1","Series 2"] + const currentSeries = { + name: 'Current', + type: 'bar', + barWidth: 16, + data: currentValues, + _baseName: 'Current', + itemStyle: { + borderRadius: [0, 6, 6, 0], + }, + }; - const yAxisData = baseNames; - - const series: any[] = []; - - data.namesMap.filter(Boolean).forEach((fullName) => { - const baseName = fullName.replace(/^Previous\s+/, ''); - const idx = baseNames.indexOf(baseName); - - const val = sumSeries(data.chart, fullName); - const dataArr = new Array(baseNames.length).fill(0); - dataArr[idx] = val; - (window as any).__seriesValueMap[chartUuid][ - `Previous ${fullName}` - ] = val; - series.push({ - name: fullName, + let previousSeries: any = null; + if (previousValues.length > 0) { + previousSeries = { + name: 'Previous', type: 'bar', barWidth: 16, - data: dataArr, - _hideInLegend: false, - _baseName: baseName, + data: previousValues, + _baseName: 'Previous', itemStyle: { borderRadius: [0, 6, 6, 0], - }, - }); - }); - - if (compData && compData.chart?.length) { - compData.namesMap.filter(Boolean).forEach((fullName) => { - const baseName = fullName.replace(/^Previous\s+/, ''); - const idx = baseNames.indexOf(baseName); - const val = sumSeries(compData.chart, fullName); - - const dataArr = new Array(baseNames.length).fill(0); - dataArr[idx] = val; - (window as any).__seriesValueMap[chartUuid][baseName] = val; - series.push({ - name: fullName, - type: 'bar', - barWidth: 16, - barGap: '1%', - data: dataArr, - _hideInLegend: true, - _baseName: baseName, - itemStyle: { - borderRadius: [0, 6, 6, 0], - decal: { - show: true, - symbol: 'line', - symbolSize: 6, - rotation: 1, - dashArrayX: 4, - dashArrayY: 4, - }, + decal: { + show: true, + symbol: 'line', + symbolSize: 6, + rotation: 1, + dashArrayX: 4, + dashArrayY: 4, }, - }); - }); + }, + }; } - assignColorsByBaseName(series); + const series = previousSeries ? [currentSeries, previousSeries] : [currentSeries]; + + assignColorsByCategory(series, categories); + series.forEach((s) => { - (window as any).__seriesColorMap[chartUuid][s.name] = - s.itemStyle.color; + (window as any).__seriesColorMap[chartUuid][s.name] = s.itemStyle.color; }); return { - yAxisData, + yAxisData: categories, series, - } -} \ No newline at end of file + }; +} diff --git a/frontend/app/components/Charts/utils.ts b/frontend/app/components/Charts/utils.ts index 7e42e8349..202e44277 100644 --- a/frontend/app/components/Charts/utils.ts +++ b/frontend/app/components/Charts/utils.ts @@ -40,7 +40,6 @@ export function assignColorsByBaseName(series: any[]) { } }); - // Then apply color to each series series.forEach((s) => { const baseName = s._baseName || s.name; const color = colorMap[baseName]; @@ -49,6 +48,45 @@ export function assignColorsByBaseName(series: any[]) { }); } +function buildCategoryColorMap(categories: string[]): Record { + const colorMap: Record = {}; + categories.forEach((_, i) => { + colorMap[i] = colors[i % colors.length]; + }); + return colorMap; +} + +/** + * For each series, transform its data array to an array of objects + * with `value` and `itemStyle.color` based on the category index. + */ +export function assignColorsByCategory( + series: any[], + categories: string[] +) { + const categoryColorMap = buildCategoryColorMap(categories); + + series.forEach((s, si) => { + s.data = s.data.map((val: any, i: number) => { + const color = categoryColorMap[i]; + if (typeof val === 'number') { + return { + value: val, + itemStyle: { color }, + }; + } + return { + ...val, + itemStyle: { + ...(val.itemStyle || {}), + color, + }, + }; + }); + s.itemStyle = { ...s.itemStyle, color: colors[si] }; + }); +} + /** * Show the hovered “current” or “previous” line + the matching partner (if it exists). */ diff --git a/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx b/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx index 916eaac84..ddc6e98f9 100644 --- a/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx +++ b/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx @@ -25,7 +25,7 @@ import { Space, Segmented, Tooltip } from 'antd'; import { renderClickmapThumbnail } from 'Components/Dashboard/components/WidgetForm/renderMap'; import Widget from 'App/mstore/types/widget'; import { LayoutPanelTop, LayoutPanelLeft } from 'lucide-react'; -import classNames from 'classnames'; +import cn from 'classnames' interface Props { history: any; @@ -34,13 +34,13 @@ interface Props { } function WidgetView(props: Props) { - const [layout, setLayout] = useState('horizontal'); + const [layout, setLayout] = useState('flex-row'); const { match: { params: { siteId, dashboardId, metricId }, }, } = props; - const { metricStore, dashboardStore } = useStore(); + const { metricStore, dashboardStore, settingsStore } = useStore(); const widget = metricStore.instance; const loading = metricStore.isLoading; const [expanded, setExpanded] = useState(!metricId || metricId === 'create'); @@ -65,6 +65,7 @@ function WidgetView(props: Props) { metricStore.init(); } } + settingsStore.updateMenuCollapsed(true) }, []); const undoChanges = () => { @@ -150,7 +151,7 @@ function WidgetView(props: Props) { onChange={setLayout} options={[ { - value: 'horizontal', + value: 'flex-row', icon: ( @@ -158,22 +159,30 @@ function WidgetView(props: Props) { ) }, { - value: 'vertical', + value: 'flex-col', icon: ( ) + }, + { + value: 'flex-row-reverse', + icon: ( + +
+
+ ) } ]} /> } /> -
-
+
+
-
+
{widget.metricOf !== FilterKey.SESSIONS &&