import { IndicatorConfig, IndicatorSerie } from '@src/types';
export const indicatorColorPalette = [
'#2962FF',
'#089981',
'#F23645',
'#FF9800',
'#9C27B0',
'#00BCD4',
'#FFEB3B',
'#673AB7',
'#4CAF50',
'#E91E63',
'#795548',
'#607D8B',
];
type SerieOptionsWithColor = {
color?: string;
visible?: boolean;
};
export function applyNextIndicatorColors(config: IndicatorConfig, usedColors: readonly string[]): IndicatorConfig {
const reservedColors = new Set(usedColors.map(normalizeColor));
return {
...config,
settings: config.settings ? [...config.settings] : undefined,
seriesLabels: config.seriesLabels ? { ...config.seriesLabels } : undefined,
series: config.series.map((serie) => {
const nextSerie = cloneSerie(serie);
if (!shouldColorizeSerie(serie)) {
return nextSerie;
}
const currentColor = getSerieColor(serie);
const color =
currentColor && !reservedColors.has(normalizeColor(currentColor))
? currentColor
: getNextPaletteColor(reservedColors);
reservedColors.add(normalizeColor(color));
return {
...nextSerie,
seriesOptions: {
...nextSerie.seriesOptions,
color,
},
};
}),
};
}
export function getIndicatorColors(config: IndicatorConfig): string[] {
return config.series.reduce<string[]>((colors, serie) => {
const color = getSerieColor(serie);
if (shouldColorizeSerie(serie) && color) {
colors.push(color);
}
return colors;
}, []);
}
function getNextPaletteColor(usedColors: Set<string>): string {
const color = indicatorColorPalette.find((item) => !usedColors.has(normalizeColor(item)));
if (color) {
return color;
}
return createFallbackColor(usedColors.size);
}
function createFallbackColor(index: number): string {
const hue = Math.round((index * 137.508) % 360);
return `hsl(${hue}deg 72% 56%)`;
}
function shouldColorizeSerie(serie: IndicatorSerie): boolean {
const options = serie.seriesOptions as SerieOptionsWithColor | undefined;
return serie.name === 'Line' && options?.visible !== false;
}
function getSerieColor(serie: IndicatorSerie): string | null {
const options = serie.seriesOptions as SerieOptionsWithColor | undefined;
const color = options?.color;
return typeof color === 'string' && color.trim() ? color : null;
}
function cloneSerie(serie: IndicatorSerie): IndicatorSerie {
return {
...serie,
seriesOptions: serie.seriesOptions ? { ...serie.seriesOptions } : undefined,
priceScaleOptions: serie.priceScaleOptions ? { ...serie.priceScaleOptions } : undefined,
};
}
function normalizeColor(color: string): string {
return color.trim().toLowerCase();
}