mirror of https://github.com/buster-so/buster.git
add scales
This commit is contained in:
parent
67ec530a5a
commit
0a43738992
|
@ -20,7 +20,8 @@ import {
|
||||||
BubbleController,
|
BubbleController,
|
||||||
PieController,
|
PieController,
|
||||||
ScatterController,
|
ScatterController,
|
||||||
DoughnutController
|
DoughnutController,
|
||||||
|
registry
|
||||||
} from 'chart.js';
|
} from 'chart.js';
|
||||||
import { ChartMountedPlugin } from './core/plugins';
|
import { ChartMountedPlugin } from './core/plugins';
|
||||||
import ChartDeferred from 'chartjs-plugin-deferred';
|
import ChartDeferred from 'chartjs-plugin-deferred';
|
||||||
|
@ -31,6 +32,11 @@ import { isServer } from '@tanstack/react-query';
|
||||||
import './core/plugins/chartjs-plugin-dayjs';
|
import './core/plugins/chartjs-plugin-dayjs';
|
||||||
import { truncateText } from '@/lib/text';
|
import { truncateText } from '@/lib/text';
|
||||||
|
|
||||||
|
import { DeduplicatedTimeScale } from './core/plugins/chartjs-plugin-tick-duplicate';
|
||||||
|
|
||||||
|
// Register the scale properly
|
||||||
|
registry.addScales(DeduplicatedTimeScale);
|
||||||
|
|
||||||
const fontFamily = isServer
|
const fontFamily = isServer
|
||||||
? 'Roobert_Pro'
|
? 'Roobert_Pro'
|
||||||
: getComputedStyle(document.documentElement).getPropertyValue('--font-sans');
|
: getComputedStyle(document.documentElement).getPropertyValue('--font-sans');
|
||||||
|
|
|
@ -1,10 +1,25 @@
|
||||||
import { ChartType, Chart, Plugin } from 'chart.js';
|
import { ChartType, TimeScale } from 'chart.js';
|
||||||
|
|
||||||
declare module 'chart.js' {
|
declare module 'chart.js' {
|
||||||
interface PluginOptionsByType<TType extends ChartType> {}
|
interface PluginOptionsByType<TType extends ChartType> {}
|
||||||
}
|
|
||||||
|
|
||||||
import { TimeScale } from 'chart.js';
|
// Add interface extension for TimeScale
|
||||||
|
interface TimeScale {
|
||||||
|
_unit:
|
||||||
|
| 'millisecond'
|
||||||
|
| 'second'
|
||||||
|
| 'minute'
|
||||||
|
| 'hour'
|
||||||
|
| 'day'
|
||||||
|
| 'week'
|
||||||
|
| 'month'
|
||||||
|
| 'year'
|
||||||
|
| 'quarter';
|
||||||
|
_adapter: {
|
||||||
|
format(time: unknown, format: string): string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const originalBuildTicks = TimeScale.prototype.buildTicks;
|
const originalBuildTicks = TimeScale.prototype.buildTicks;
|
||||||
|
|
||||||
|
@ -12,6 +27,7 @@ const originalBuildTicks = TimeScale.prototype.buildTicks;
|
||||||
TimeScale.prototype.buildTicks = function () {
|
TimeScale.prototype.buildTicks = function () {
|
||||||
// Step 1: Get default ticks using the original method
|
// Step 1: Get default ticks using the original method
|
||||||
const defaultTicks = originalBuildTicks.call(this);
|
const defaultTicks = originalBuildTicks.call(this);
|
||||||
|
console.log('defaultTicks', defaultTicks);
|
||||||
|
|
||||||
// Step 2: Access tick callback and display format
|
// Step 2: Access tick callback and display format
|
||||||
const tickCallback = this.options.ticks?.callback;
|
const tickCallback = this.options.ticks?.callback;
|
||||||
|
@ -57,3 +73,64 @@ TimeScale.prototype.buildTicks = function () {
|
||||||
// Step 6: Return the filtered ticks
|
// Step 6: Return the filtered ticks
|
||||||
return uniqueTicks;
|
return uniqueTicks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export class DeduplicatedTimeScale extends TimeScale {
|
||||||
|
static id = 'deduplicated-time';
|
||||||
|
static defaults = TimeScale.defaults;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override buildTicks to eliminate duplicate ticks based on formatted values.
|
||||||
|
* @returns {Array} Array of unique tick objects
|
||||||
|
*/
|
||||||
|
buildTicks() {
|
||||||
|
console.log('buildTicks');
|
||||||
|
// Step 1: Get default ticks from parent TimeScale
|
||||||
|
const defaultTicks = super.buildTicks();
|
||||||
|
|
||||||
|
// Step 2: Access tick callback and display format
|
||||||
|
const tickCallback = this.options.ticks?.callback;
|
||||||
|
const displayFormat =
|
||||||
|
this.options.time?.displayFormats?.[this._unit] ||
|
||||||
|
this.options.time?.displayFormats?.month ||
|
||||||
|
'MMM';
|
||||||
|
const format = this._adapter.format.bind(this._adapter);
|
||||||
|
|
||||||
|
// Step 3: Track seen labels and collect unique ticks
|
||||||
|
const seen = new Set();
|
||||||
|
const uniqueTicks = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < defaultTicks.length; i++) {
|
||||||
|
const tick = defaultTicks[i];
|
||||||
|
|
||||||
|
// Step 4: Generate tick label
|
||||||
|
let label;
|
||||||
|
try {
|
||||||
|
if (typeof tickCallback === 'function') {
|
||||||
|
// Pass tick value, index, and ticks array to callback
|
||||||
|
label = tickCallback.call(this, tick.value, i, defaultTicks);
|
||||||
|
} else {
|
||||||
|
// Format using the adapter with the appropriate display format
|
||||||
|
label = format(tick.value, displayFormat);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Tick callback error at index', i, e);
|
||||||
|
label = '???';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure label is a string for consistent comparison
|
||||||
|
const stringLabel = String(label ?? '');
|
||||||
|
|
||||||
|
// Step 5: Only include tick if label is unique
|
||||||
|
if (!seen.has(stringLabel)) {
|
||||||
|
seen.add(stringLabel);
|
||||||
|
uniqueTicks.push({
|
||||||
|
...tick,
|
||||||
|
label: stringLabel // Ensure the tick object has the correct label
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6: Return the filtered ticks
|
||||||
|
return uniqueTicks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
import { useMemoizedFn } from '@/hooks';
|
import { useMemoizedFn } from '@/hooks';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { DeepPartial } from 'utility-types';
|
import { DeepPartial } from 'utility-types';
|
||||||
import type { ScaleChartOptions, Scale, GridLineOptions } from 'chart.js';
|
import type { ScaleChartOptions, Scale, GridLineOptions, TimeScale } from 'chart.js';
|
||||||
import { useXAxisTitle } from '../../../../commonHelpers/useXAxisTitle';
|
import { useXAxisTitle } from '../../../../commonHelpers/useXAxisTitle';
|
||||||
import { useIsStacked } from '../useIsStacked';
|
import { useIsStacked } from '../useIsStacked';
|
||||||
import { formatLabel, isNumericColumnType, truncateText } from '@/lib';
|
import { formatLabel, isNumericColumnType, truncateText } from '@/lib';
|
||||||
|
@ -145,8 +145,7 @@ export const useXAxis = ({
|
||||||
const xColumnLabelFormat = xAxisColumnFormats[xKey];
|
const xColumnLabelFormat = xAxisColumnFormats[xKey];
|
||||||
const isAutoFormat = xColumnLabelFormat.dateFormat === 'auto';
|
const isAutoFormat = xColumnLabelFormat.dateFormat === 'auto';
|
||||||
if (isAutoFormat) {
|
if (isAutoFormat) {
|
||||||
//@ts-ignore
|
const unit = (this.chart.scales['x'] as TimeScale)._unit as
|
||||||
const unit = this.chart.scales['x']._unit as
|
|
||||||
| 'millisecond'
|
| 'millisecond'
|
||||||
| 'second'
|
| 'second'
|
||||||
| 'minute'
|
| 'minute'
|
||||||
|
|
Loading…
Reference in New Issue