Browse Source

Fix colors of charts for light color scheme

pull/7975/head
Thomas Kaul 2 weeks ago
parent
commit
59aca4dbd7
  1. 8
      apps/client/src/app/app.component.ts
  2. 7
      apps/client/src/app/components/admin-market-data/asset-profile-dialog-host/asset-profile-dialog-host.component.ts
  3. 2
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/interfaces/interfaces.ts
  4. 22
      apps/client/src/app/components/investment-chart/investment-chart.component.ts
  5. 14
      libs/common/src/lib/chart-helper.ts
  6. 33
      libs/common/src/lib/helper.spec.ts
  7. 20
      libs/common/src/lib/helper.ts
  8. 2
      libs/ui/src/lib/chart/chart.options.ts
  9. 8
      libs/ui/src/lib/line-chart/line-chart.component.ts
  10. 6
      libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts

8
apps/client/src/app/app.component.ts

@ -1,4 +1,4 @@
import { getCssVariable } from '@ghostfolio/common/helper'; import { getCssVariable, isDarkColorScheme } from '@ghostfolio/common/helper';
import { import {
AssetProfileIdentifier, AssetProfileIdentifier,
InfoItem, InfoItem,
@ -260,11 +260,7 @@ export class GfAppComponent implements OnInit {
} }
private initializeTheme(userPreferredColorScheme?: ColorScheme) { private initializeTheme(userPreferredColorScheme?: ColorScheme) {
const isDarkTheme = userPreferredColorScheme this.toggleTheme(isDarkColorScheme(userPreferredColorScheme));
? userPreferredColorScheme === 'DARK'
: window.matchMedia('(prefers-color-scheme: dark)').matches;
this.toggleTheme(isDarkTheme);
// Default chart styles // Default chart styles
Chart.defaults.font.family = getCssVariable('--font-family-sans-serif'); Chart.defaults.font.family = getCssVariable('--font-family-sans-serif');

7
apps/client/src/app/components/admin-market-data/asset-profile-dialog-host/asset-profile-dialog-host.component.ts

@ -1,8 +1,5 @@
import { UserService } from '@ghostfolio/client/services/user/user.service'; import { UserService } from '@ghostfolio/client/services/user/user.service';
import { import { DEFAULT_LOCALE } from '@ghostfolio/common/config';
DEFAULT_COLOR_SCHEME,
DEFAULT_LOCALE
} from '@ghostfolio/common/config';
import { AssetProfileIdentifier, User } from '@ghostfolio/common/interfaces'; import { AssetProfileIdentifier, User } from '@ghostfolio/common/interfaces';
import { internalRoutes } from '@ghostfolio/common/routes/routes'; import { internalRoutes } from '@ghostfolio/common/routes/routes';
import { DataSource } from '@ghostfolio/prisma/enums'; import { DataSource } from '@ghostfolio/prisma/enums';
@ -150,7 +147,7 @@ export class GfAssetProfileDialogHostComponent implements OnDestroy, OnInit {
data: { data: {
dataSource, dataSource,
symbol, symbol,
colorScheme: user?.settings.colorScheme ?? DEFAULT_COLOR_SCHEME, colorScheme: user?.settings?.colorScheme,
deviceType: this.deviceType(), deviceType: this.deviceType(),
locale: user?.settings?.locale ?? DEFAULT_LOCALE locale: user?.settings?.locale ?? DEFAULT_LOCALE
} satisfies AssetProfileDialogParams, } satisfies AssetProfileDialogParams,

2
apps/client/src/app/components/admin-market-data/asset-profile-dialog/interfaces/interfaces.ts

@ -2,7 +2,7 @@ import { ColorScheme } from '@ghostfolio/common/types';
import { DataSource } from '@ghostfolio/prisma/enums'; import { DataSource } from '@ghostfolio/prisma/enums';
export interface AssetProfileDialogParams { export interface AssetProfileDialogParams {
colorScheme: ColorScheme; colorScheme?: ColorScheme;
dataSource: DataSource; dataSource: DataSource;
deviceType: string; deviceType: string;
locale: string; locale: string;

22
apps/client/src/app/components/investment-chart/investment-chart.component.ts

@ -7,11 +7,7 @@ import {
getZeroLineAnnotation, getZeroLineAnnotation,
transformTickToAbbreviation transformTickToAbbreviation
} from '@ghostfolio/common/chart-helper'; } from '@ghostfolio/common/chart-helper';
import { import { primaryColorRgb, secondaryColorRgb } from '@ghostfolio/common/config';
DEFAULT_COLOR_SCHEME,
primaryColorRgb,
secondaryColorRgb
} from '@ghostfolio/common/config';
import { getLocale, parseDate } from '@ghostfolio/common/helper'; import { getLocale, parseDate } from '@ghostfolio/common/helper';
import { LineChartItem } from '@ghostfolio/common/interfaces'; import { LineChartItem } from '@ghostfolio/common/interfaces';
import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface'; import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface';
@ -174,15 +170,13 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy {
this.chart.update(); this.chart.update();
} else { } else {
const colorScheme = this.colorScheme ?? DEFAULT_COLOR_SCHEME;
this.chart = new Chart<'bar' | 'line'>( this.chart = new Chart<'bar' | 'line'>(
this.chartCanvas().nativeElement, this.chartCanvas().nativeElement,
{ {
data: chartData, data: chartData,
options: { options: {
animation: false, animation: false,
elements: getChartElementsOptions(colorScheme), elements: getChartElementsOptions(this.colorScheme),
interaction: { intersect: false, mode: 'index' }, interaction: { intersect: false, mode: 'index' },
maintainAspectRatio: true, maintainAspectRatio: true,
plugins: { plugins: {
@ -210,7 +204,7 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy {
value: this.savingsRate value: this.savingsRate
} }
: undefined, : undefined,
yAxis: getZeroLineAnnotation(colorScheme) yAxis: getZeroLineAnnotation(this.colorScheme)
} }
}, },
legend: { legend: {
@ -218,18 +212,18 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy {
}, },
tooltip: this.getTooltipPluginConfiguration(), tooltip: this.getTooltipPluginConfiguration(),
verticalHoverLine: { verticalHoverLine: {
color: getChartBorderColor(colorScheme) color: getChartBorderColor(this.colorScheme)
} }
}, },
responsive: true, responsive: true,
scales: { scales: {
x: getTimeAxisOptions({ x: getTimeAxisOptions({
colorScheme,
borderWidth: this.groupBy ? 0 : 1, borderWidth: this.groupBy ? 0 : 1,
colorScheme: this.colorScheme,
locale: this.locale locale: this.locale
}), }),
y: getValueAxisOptions({ y: getValueAxisOptions({
colorScheme, colorScheme: this.colorScheme,
display: !this.isInPercentage, display: !this.isInPercentage,
tickCallback: (tickValue) => { tickCallback: (tickValue) => {
return transformTickToAbbreviation(Number(tickValue)); return transformTickToAbbreviation(Number(tickValue));
@ -238,7 +232,7 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy {
} }
}, },
plugins: [ plugins: [
getVerticalHoverLinePlugin(this.chartCanvas(), colorScheme) getVerticalHoverLinePlugin(this.chartCanvas(), this.colorScheme)
], ],
type: this.groupBy ? 'bar' : 'line' type: this.groupBy ? 'bar' : 'line'
} }
@ -251,7 +245,7 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy {
TooltipOptions<'bar' | 'line'> TooltipOptions<'bar' | 'line'>
> { > {
return getTimeSeriesTooltipOptions<'bar' | 'line'>({ return getTimeSeriesTooltipOptions<'bar' | 'line'>({
colorScheme: this.colorScheme ?? DEFAULT_COLOR_SCHEME, colorScheme: this.colorScheme,
currency: this.isInPercentage ? undefined : this.currency, currency: this.isInPercentage ? undefined : this.currency,
groupBy: this.groupBy, groupBy: this.groupBy,
locale: this.isInPercentage ? undefined : this.locale, locale: this.isInPercentage ? undefined : this.locale,

14
libs/common/src/lib/chart-helper.ts

@ -41,12 +41,12 @@ export function formatGroupedDate({
return format(date, DATE_FORMAT); return format(date, DATE_FORMAT);
} }
export function getChartBorderColor(colorScheme: ColorScheme) { export function getChartBorderColor(colorScheme?: ColorScheme) {
return `rgba(${getTextColor(colorScheme)}, 0.1)`; return `rgba(${getTextColor(colorScheme)}, 0.1)`;
} }
export function getChartElementsOptions( export function getChartElementsOptions(
colorScheme: ColorScheme colorScheme?: ColorScheme
): ChartOptions<'bar' | 'line'>['elements'] { ): ChartOptions<'bar' | 'line'>['elements'] {
return { return {
line: { line: {
@ -67,7 +67,7 @@ export function getTimeAxisOptions({
locale = getLocale() locale = getLocale()
}: { }: {
borderWidth?: number; borderWidth?: number;
colorScheme: ColorScheme; colorScheme?: ColorScheme;
display?: boolean; display?: boolean;
locale?: string; locale?: string;
}): ScaleOptions<'time'> { }): ScaleOptions<'time'> {
@ -95,7 +95,7 @@ export function getTooltipOptions<T extends ChartType>({
locale = getLocale(), locale = getLocale(),
unit = '' unit = ''
}: { }: {
colorScheme: ColorScheme; colorScheme?: ColorScheme;
currency?: string; currency?: string;
groupBy?: GroupBy; groupBy?: GroupBy;
locale?: string; locale?: string;
@ -174,7 +174,7 @@ export function getValueAxisOptions({
highlightedValues = [], highlightedValues = [],
tickCallback tickCallback
}: { }: {
colorScheme: ColorScheme; colorScheme?: ColorScheme;
display?: boolean; display?: boolean;
highlightedValues?: number[]; highlightedValues?: number[];
tickCallback: ( tickCallback: (
@ -214,7 +214,7 @@ export function getValueAxisOptions({
export function getVerticalHoverLinePlugin<T extends 'line' | 'bar'>( export function getVerticalHoverLinePlugin<T extends 'line' | 'bar'>(
chartCanvas: ElementRef<HTMLCanvasElement>, chartCanvas: ElementRef<HTMLCanvasElement>,
colorScheme: ColorScheme colorScheme?: ColorScheme
): Plugin<T, { color: string; width: number }> { ): Plugin<T, { color: string; width: number }> {
return { return {
afterDatasetsDraw: (chart, _, options) => { afterDatasetsDraw: (chart, _, options) => {
@ -249,7 +249,7 @@ export function getVerticalHoverLinePlugin<T extends 'line' | 'bar'>(
} }
export function getZeroLineAnnotation( export function getZeroLineAnnotation(
colorScheme: ColorScheme colorScheme?: ColorScheme
): AnnotationOptions<'line'> { ): AnnotationOptions<'line'> {
return { return {
borderColor: getChartBorderColor(colorScheme), borderColor: getChartBorderColor(colorScheme),

33
libs/common/src/lib/helper.spec.ts

@ -13,6 +13,7 @@ import {
isAccountExcluded, isAccountExcluded,
isCurrency, isCurrency,
isCurrencySymbol, isCurrencySymbol,
isDarkColorScheme,
isSplitRatio, isSplitRatio,
isValidCurrencyCode, isValidCurrencyCode,
isValidCustomAssetProfileSymbol, isValidCustomAssetProfileSymbol,
@ -348,6 +349,38 @@ describe('Helper', () => {
}); });
}); });
describe('Is dark color scheme', () => {
const mockPrefersColorSchemeDark = (matches: boolean) => {
window.matchMedia = jest.fn(() => {
return { matches } as MediaQueryList;
});
};
afterEach(() => {
Reflect.deleteProperty(window, 'matchMedia');
});
it('Dark color scheme with operating system in light mode', () => {
mockPrefersColorSchemeDark(false);
expect(isDarkColorScheme('DARK')).toEqual(true);
});
it('Light color scheme with operating system in dark mode', () => {
mockPrefersColorSchemeDark(true);
expect(isDarkColorScheme('LIGHT')).toEqual(false);
});
it('Auto color scheme with operating system in dark mode', () => {
mockPrefersColorSchemeDark(true);
expect(isDarkColorScheme()).toEqual(true);
});
it('Auto color scheme with operating system in light mode', () => {
mockPrefersColorSchemeDark(false);
expect(isDarkColorScheme()).toEqual(false);
});
});
describe('Is split ratio', () => { describe('Is split ratio', () => {
it('Forward split', () => { it('Forward split', () => {
expect(isSplitRatio({ denominator: 1, numerator: 2 })).toEqual(true); expect(isSplitRatio({ denominator: 1, numerator: 2 })).toEqual(true);

20
libs/common/src/lib/helper.ts

@ -345,12 +345,9 @@ export function getAssetProfileIdentifier({
return `${dataSource}-${symbol}`; return `${dataSource}-${symbol}`;
} }
export function getBackgroundColor(aColorScheme: ColorScheme) { export function getBackgroundColor(aColorScheme?: ColorScheme) {
return getCssVariable( return getCssVariable(
aColorScheme === 'DARK' || isDarkColorScheme(aColorScheme) ? '--dark-background' : '--light-background'
window.matchMedia('(prefers-color-scheme: dark)').matches
? '--dark-background'
: '--light-background'
); );
} }
@ -531,10 +528,9 @@ export function getSum(aArray: Big[]) {
return new Big(0); return new Big(0);
} }
export function getTextColor(aColorScheme: ColorScheme) { export function getTextColor(aColorScheme?: ColorScheme) {
const cssVariable = getCssVariable( const cssVariable = getCssVariable(
aColorScheme === 'DARK' || isDarkColorScheme(aColorScheme)
window.matchMedia('(prefers-color-scheme: dark)').matches
? '--light-primary-text' ? '--light-primary-text'
: '--dark-primary-text' : '--dark-primary-text'
); );
@ -612,6 +608,14 @@ export function isCurrencySymbol(aSymbol: string) {
); );
} }
export function isDarkColorScheme(aColorScheme?: ColorScheme) {
if (aColorScheme) {
return aColorScheme === 'DARK';
}
return window.matchMedia('(prefers-color-scheme: dark)').matches;
}
export function isDerivedCurrency(aCurrency: string) { export function isDerivedCurrency(aCurrency: string) {
if (aCurrency === 'USX') { if (aCurrency === 'USX') {
return true; return true;

2
libs/ui/src/lib/chart/chart.options.ts

@ -12,7 +12,7 @@ export function getTimeSeriesTooltipOptions<T extends 'bar' | 'line'>({
locale, locale,
unit unit
}: { }: {
colorScheme: ColorScheme; colorScheme?: ColorScheme;
currency?: string; currency?: string;
groupBy?: GroupBy; groupBy?: GroupBy;
locale?: string; locale?: string;

8
libs/ui/src/lib/line-chart/line-chart.component.ts

@ -4,11 +4,7 @@ import {
getValueAxisOptions, getValueAxisOptions,
getVerticalHoverLinePlugin getVerticalHoverLinePlugin
} from '@ghostfolio/common/chart-helper'; } from '@ghostfolio/common/chart-helper';
import { import { primaryColorRgb, secondaryColorRgb } from '@ghostfolio/common/config';
DEFAULT_COLOR_SCHEME,
primaryColorRgb,
secondaryColorRgb
} from '@ghostfolio/common/config';
import { getBackgroundColor, getLocale } from '@ghostfolio/common/helper'; import { getBackgroundColor, getLocale } from '@ghostfolio/common/helper';
import { LineChartItem } from '@ghostfolio/common/interfaces'; import { LineChartItem } from '@ghostfolio/common/interfaces';
import { ColorScheme } from '@ghostfolio/common/types'; import { ColorScheme } from '@ghostfolio/common/types';
@ -56,7 +52,7 @@ export class GfLineChartComponent
{ {
@Input() benchmarkDataItems: LineChartItem[] = []; @Input() benchmarkDataItems: LineChartItem[] = [];
@Input() benchmarkLabel = ''; @Input() benchmarkLabel = '';
@Input() colorScheme: ColorScheme = DEFAULT_COLOR_SCHEME; @Input() colorScheme?: ColorScheme;
@Input() currency: string; @Input() currency: string;
@Input() historicalDataItems: LineChartItem[]; @Input() historicalDataItems: LineChartItem[];
@Input() isAnimated = false; @Input() isAnimated = false;

6
libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts

@ -1,5 +1,5 @@
import { getTooltipOptions } from '@ghostfolio/common/chart-helper'; import { getTooltipOptions } from '@ghostfolio/common/chart-helper';
import { DEFAULT_COLOR_SCHEME, UNKNOWN_KEY } from '@ghostfolio/common/config'; import { UNKNOWN_KEY } from '@ghostfolio/common/config';
import { getLocale, getSum, getTextColor } from '@ghostfolio/common/helper'; import { getLocale, getSum, getTextColor } from '@ghostfolio/common/helper';
import { PortfolioPosition } from '@ghostfolio/common/interfaces'; import { PortfolioPosition } from '@ghostfolio/common/interfaces';
import { ColorScheme } from '@ghostfolio/common/types'; import { ColorScheme } from '@ghostfolio/common/types';
@ -124,7 +124,7 @@ export class GfPortfolioProportionChartComponent
}; };
} = {}; } = {};
const textColor = getTextColor(this.colorScheme ?? DEFAULT_COLOR_SCHEME); const textColor = getTextColor(this.colorScheme);
this.colorMap = { this.colorMap = {
[this.OTHER_KEY]: `rgba(${textColor}, 0.24)`, [this.OTHER_KEY]: `rgba(${textColor}, 0.24)`,
@ -448,7 +448,7 @@ export class GfPortfolioProportionChartComponent
): Partial<TooltipOptions<'doughnut'>> { ): Partial<TooltipOptions<'doughnut'>> {
return { return {
...getTooltipOptions({ ...getTooltipOptions({
colorScheme: this.colorScheme ?? DEFAULT_COLOR_SCHEME, colorScheme: this.colorScheme,
currency: this.baseCurrency, currency: this.baseCurrency,
locale: this.locale locale: this.locale
}), }),

Loading…
Cancel
Save