mirror of https://github.com/buster-so/buster.git
Update barSeriesBuilder.ts
This commit is contained in:
parent
2221de1836
commit
9a7698596d
|
@ -9,6 +9,7 @@ import { defaultLabelOptionConfig } from '../useChartSpecificOptions/labelOption
|
|||
import type { Options } from 'chartjs-plugin-datalabels/types/options';
|
||||
import { DEFAULT_CHART_LAYOUT } from '../../ChartJSTheme';
|
||||
import { extractFieldsFromChain } from '../../../chartHooks';
|
||||
import { IColumnLabelFormat } from '@/api/asset_interfaces/metric';
|
||||
|
||||
export const barSeriesBuilder = ({
|
||||
selectedDataset,
|
||||
|
@ -33,12 +34,6 @@ export const barSeriesBuilder = ({
|
|||
|
||||
dataLabelOptions.stackTotal = {
|
||||
display: function (context) {
|
||||
// Reset the global rotation flag when processing the first data point
|
||||
if (context.dataIndex === 0 && context.datasetIndex === 0) {
|
||||
context.chart.$barDataLabelsGlobalRotation = false;
|
||||
context.chart.$barDataLabelsUpdateInProgress = false;
|
||||
}
|
||||
|
||||
const chart = context.chart;
|
||||
const shownDatasets = context.chart.data.datasets.filter(
|
||||
(dataset, index) =>
|
||||
|
@ -52,18 +47,8 @@ export const barSeriesBuilder = ({
|
|||
const chartLayout = context.chart.options.layout;
|
||||
const padding = { ...DEFAULT_CHART_LAYOUT.padding, top: 24 };
|
||||
context.chart.options.layout = { ...chartLayout, padding };
|
||||
//use setTimeout to ensure that the chart data label almost always overflows.
|
||||
requestAnimationFrame(() => {
|
||||
if (!context.chart.$barDataLabelsUpdateInProgress) {
|
||||
context.chart.$barDataLabelsUpdateInProgress = true;
|
||||
console.log('updating');
|
||||
context.chart.update('none'); //this is hack because the chart data label almost always overflows
|
||||
|
||||
// Reset the flag after the update completes
|
||||
setTimeout(() => {
|
||||
context.chart.$barDataLabelsUpdateInProgress = false;
|
||||
}, 100);
|
||||
}
|
||||
context.chart.update(); //this is hack because the chart data label almost always overflows
|
||||
});
|
||||
hasBeenDrawn = true;
|
||||
}
|
||||
|
@ -115,6 +100,9 @@ declare module 'chart.js' {
|
|||
}
|
||||
|
||||
const TEXT_WIDTH_BUFFER = 4;
|
||||
const MAX_BAR_HEIGHT = 16;
|
||||
const MAX_BAR_WIDTH = 13;
|
||||
const FULL_ROTATION_ANGLE = -90;
|
||||
|
||||
export const barBuilder = ({
|
||||
selectedDataset,
|
||||
|
@ -166,91 +154,37 @@ export const barBuilder = ({
|
|||
}
|
||||
|
||||
// First dataset - analyze all data points to determine if any need rotation
|
||||
if (index === 0 && context.dataIndex === 0) {
|
||||
// Reset the rotation flag at the start of each render cycle
|
||||
context.chart.$barDataLabelsGlobalRotation = false;
|
||||
|
||||
// Analyze all datasets and datapoints in this first call
|
||||
const checkAllLabelsForRotation = () => {
|
||||
const datasets = context.chart.data.datasets;
|
||||
const needsGlobalRotation = datasets.some((dataset, datasetIndex) => {
|
||||
if (dataset.type !== 'bar') return false;
|
||||
|
||||
return Array.from({ length: dataset.data.length }).some((_, dataIndex) => {
|
||||
const value = dataset.data[dataIndex] as number;
|
||||
if (!value) return false;
|
||||
|
||||
// Get dimensions for this data point
|
||||
const meta = context.chart.getDatasetMeta(datasetIndex);
|
||||
if (!meta || !meta.data[dataIndex]) return false;
|
||||
|
||||
const barElement = meta.data[dataIndex] as BarElement;
|
||||
const { width: barWidth } = barElement.getProps(['width'], true);
|
||||
|
||||
// Only proceed if bar is visible and has reasonable width
|
||||
if (barWidth < 13) return false;
|
||||
|
||||
// Check if formatted value would need rotation
|
||||
const formattedValue = formatBarAndLineDataLabel(
|
||||
value,
|
||||
{ ...context, datasetIndex, dataIndex } as Context,
|
||||
false, // We're just checking width, not actual formatting
|
||||
columnLabelFormat
|
||||
);
|
||||
|
||||
const { width: textWidth } = context.chart.ctx.measureText(formattedValue);
|
||||
return textWidth > barWidth - TEXT_WIDTH_BUFFER;
|
||||
});
|
||||
});
|
||||
|
||||
if (needsGlobalRotation) {
|
||||
context.chart.$barDataLabelsGlobalRotation = true;
|
||||
|
||||
// Schedule update after all display calculations
|
||||
if (!context.chart.$barDataLabelsUpdateInProgress) {
|
||||
context.chart.$barDataLabelsUpdateInProgress = true;
|
||||
setTimeout(() => {
|
||||
context.chart.update('none');
|
||||
setTimeout(() => {
|
||||
context.chart.$barDataLabelsUpdateInProgress = false;
|
||||
}, 100);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Run rotation analysis immediately
|
||||
checkAllLabelsForRotation();
|
||||
if (index === 0 && context.datasetIndex === 0) {
|
||||
setGlobalRotation(context);
|
||||
}
|
||||
|
||||
const rawValue = context.dataset.data[context.dataIndex] as number;
|
||||
|
||||
if (!showLabels || !rawValue) return false;
|
||||
|
||||
const { barWidth, barHeight } = getBarDimensions(context);
|
||||
if (barWidth < 13) return false;
|
||||
|
||||
const formattedValue = formatBarAndLineDataLabel(
|
||||
rawValue,
|
||||
context,
|
||||
if (barWidth < MAX_BAR_WIDTH) return false;
|
||||
|
||||
const formattedValue = getFormattedValue(context, {
|
||||
usePercentage,
|
||||
columnLabelFormat
|
||||
);
|
||||
});
|
||||
|
||||
// Get text width for this specific label
|
||||
const { width: textWidth } = context.chart.ctx.measureText(formattedValue);
|
||||
|
||||
// Use the global rotation setting
|
||||
const rotation = context.chart.$barDataLabelsGlobalRotation ? -90 : 0;
|
||||
const rotation = context.chart.$barDataLabelsGlobalRotation ? FULL_ROTATION_ANGLE : 0;
|
||||
|
||||
// Check if this label can be displayed even with rotation
|
||||
if (rotation === -90 && textWidth > barHeight - TEXT_WIDTH_BUFFER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store only the formatted value, rotation is handled globally
|
||||
setBarDataLabelsManager(context, formattedValue);
|
||||
// Check if the bar height is too small to display the label
|
||||
if (barHeight < MAX_BAR_HEIGHT) return false;
|
||||
|
||||
if (barHeight < 16) return false;
|
||||
return 'auto';
|
||||
},
|
||||
formatter: (_, context) => {
|
||||
|
@ -258,7 +192,7 @@ export const barBuilder = ({
|
|||
},
|
||||
rotation: (context) => {
|
||||
// Always use the global rotation setting
|
||||
return context.chart.$barDataLabelsGlobalRotation ? -90 : 0;
|
||||
return context.chart.$barDataLabelsGlobalRotation ? FULL_ROTATION_ANGLE : 0;
|
||||
},
|
||||
color: dataLabelFontColorContrast,
|
||||
borderWidth: 0,
|
||||
|
@ -299,6 +233,50 @@ const getBarDimensions = (context: Context) => {
|
|||
return { barWidth, barHeight };
|
||||
};
|
||||
|
||||
const setGlobalRotation = (context: Context) => {
|
||||
context.chart.$barDataLabelsGlobalRotation = false;
|
||||
|
||||
const labels = context.chart.data.datasets
|
||||
.filter((d) => !d.hidden)
|
||||
.flatMap((dataset, datasetIndex) => {
|
||||
return dataset.data.map((value, dataIndex) => {
|
||||
const currentValue = context.chart.$barDataLabels?.[datasetIndex]?.[dataIndex] || '';
|
||||
return currentValue || '';
|
||||
});
|
||||
});
|
||||
|
||||
const labelNeedsToBeRotated = labels.some((label) => {
|
||||
const { width: textWidth } = context.chart.ctx.measureText(label);
|
||||
const { barWidth, barHeight } = getBarDimensions(context);
|
||||
return textWidth > barWidth - TEXT_WIDTH_BUFFER;
|
||||
});
|
||||
|
||||
if (labelNeedsToBeRotated) {
|
||||
context.chart.$barDataLabelsGlobalRotation = true;
|
||||
}
|
||||
};
|
||||
|
||||
const getFormattedValue = (
|
||||
context: Context,
|
||||
{
|
||||
usePercentage,
|
||||
columnLabelFormat
|
||||
}: {
|
||||
usePercentage: boolean;
|
||||
columnLabelFormat: IColumnLabelFormat;
|
||||
}
|
||||
) => {
|
||||
const rawValue = context.dataset.data[context.dataIndex] as number;
|
||||
const currentValue =
|
||||
context.chart.$barDataLabels?.[context.datasetIndex]?.[context.dataIndex] || '';
|
||||
const formattedValue =
|
||||
currentValue || formatBarAndLineDataLabel(rawValue, context, usePercentage, columnLabelFormat);
|
||||
// Store only the formatted value, rotation is handled globally
|
||||
setBarDataLabelsManager(context, formattedValue);
|
||||
|
||||
return formattedValue;
|
||||
};
|
||||
|
||||
export const barSeriesBuilder_labels = (props: LabelBuilderProps) => {
|
||||
const { dataset, columnLabelFormats } = props;
|
||||
|
||||
|
|
|
@ -297,7 +297,7 @@ export const WithDataLabelsAndStackTotal: Story = {
|
|||
showDataLabelsAsPercentage: false
|
||||
},
|
||||
units: {
|
||||
showDataLabels: false,
|
||||
showDataLabels: true,
|
||||
showDataLabelsAsPercentage: false
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue