ui: fixing bars under comparison

This commit is contained in:
nick-delirium 2025-01-07 16:20:15 +01:00
parent 8e1f50e4a3
commit 1c200452b5
No known key found for this signature in database
GPG key ID: 93ABD695DF5FDBA0
4 changed files with 114 additions and 78 deletions

View file

@ -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,

View file

@ -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<string>();
/**
* 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,
}
}
};
}

View file

@ -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<number, string> {
const colorMap: Record<number, string> = {};
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).
*/

View file

@ -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: (
<Tooltip title="Horizontal Layout">
<LayoutPanelLeft size={16} />
@ -158,22 +159,30 @@ function WidgetView(props: Props) {
)
},
{
value: 'vertical',
value: 'flex-col',
icon: (
<Tooltip title="Vertical Layout">
<LayoutPanelTop size={16} />
</Tooltip>
)
},
{
value: 'flex-row-reverse',
icon: (
<Tooltip title="Reversed Horizontal Layout">
<div className={'rotate-180'}><LayoutPanelLeft size={16} /></div>
</Tooltip>
)
}
]}
/>
}
/>
<div className={layout === 'horizontal' ? 'flex gap-4' : ''}>
<div className={layout === 'horizontal' ? 'w-1/3 ' : 'w-full'}>
<div className={cn('flex gap-4', layout)}>
<div className={layout.startsWith('flex-row') ? 'w-1/3 ' : 'w-full'}>
<WidgetFormNew />
</div>
<div className={layout === 'horizontal' ? 'w-2/3' : 'w-full'}>
<div className={layout.startsWith('flex-row') ? 'w-2/3' : 'w-full'}>
<WidgetPreview name={widget.name} isEditing={expanded} />
{widget.metricOf !== FilterKey.SESSIONS &&