Browse Source

Feature/draw a baseline in the performance charts

pull/8284/head
mister-ideas 11 hours ago
parent
commit
e8624ab061
  1. 1
      CHANGELOG.md
  2. 1
      apps/client/src/app/components/home-overview/home-overview.html
  3. 14
      libs/common/src/lib/chart-helper.spec.ts
  4. 77
      libs/common/src/lib/chart-helper.ts
  5. 9
      libs/ui/src/lib/line-chart/line-chart.component.ts

1
CHANGELOG.md

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Added a dashed baseline (0 %) to the performance chart on the overview page and made the zero line of the benchmark comparator and the investment chart dashed and more visible
- Added a link to the holdings tab in the holdings table on the overview tab of the home page (experimental)
### Changed

1
apps/client/src/app/components/home-overview/home-overview.html

@ -70,6 +70,7 @@
<gf-line-chart
class="position-absolute"
unit="%"
[baseline]="0"
[class.pe-3]="deviceType() === 'mobile'"
[colorScheme]="user()?.settings?.colorScheme"
[hidden]="historicalDataItems()?.length === 0"

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

@ -0,0 +1,14 @@
import { getBaselineAnnotation } from './chart-helper';
describe('getBaselineAnnotation', () => {
it('returns a dashed horizontal line at the value', () => {
expect(
getBaselineAnnotation({ colorScheme: 'LIGHT', value: 0 })
).toMatchObject({
borderDash: [4, 4],
scaleID: 'y',
type: 'line',
value: 0
});
});
});

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

@ -217,6 +217,50 @@ export function getValueAxisOptions({
};
}
/**
* Returns a plugin which draws a dashed horizontal line at the baseline of a
* chart above the datasets. Unlike an annotation, it does not follow the
* custom animations of the data points
*/
export function getBaselinePlugin<T extends 'line' | 'bar'>({
colorScheme,
getValue
}: {
colorScheme?: ColorScheme;
getValue: () => number | undefined;
}): Plugin<T> {
return {
afterDatasetsDraw: (chart) => {
const value = getValue();
const yScale = chart.scales['y'];
if (value === undefined || !yScale) {
return;
}
const y = yScale.getPixelForValue(value);
const { bottom, left, right, top } = chart.chartArea;
if (!Number.isFinite(y) || y < top || y > bottom) {
return;
}
const context = chart.ctx;
context.save();
context.beginPath();
context.lineWidth = 1;
context.setLineDash(BASELINE_DASH);
context.strokeStyle = getBaselineColor(colorScheme);
context.moveTo(left, y);
context.lineTo(right, y);
context.stroke();
context.restore();
},
id: 'baseline'
};
}
export function getVerticalHoverLinePlugin<T extends 'line' | 'bar'>(
chartCanvas: ElementRef<HTMLCanvasElement>,
colorScheme?: ColorScheme
@ -253,18 +297,41 @@ export function getVerticalHoverLinePlugin<T extends 'line' | 'bar'>(
};
}
export function getZeroLineAnnotation(
colorScheme?: ColorScheme
): AnnotationOptions<'line'> {
const BASELINE_DASH = [4, 4];
function getBaselineColor(colorScheme?: ColorScheme) {
return `rgba(${getTextColor(colorScheme)}, 0.4)`;
}
/**
* Returns a dashed horizontal line at the baseline of a chart (e.g. 0 % for
* the performance), which stands out from the grid lines
*/
export function getBaselineAnnotation({
colorScheme,
value = 0
}: {
colorScheme?: ColorScheme;
value?: number;
}): AnnotationOptions<'line'> {
return {
borderColor: getChartBorderColor(colorScheme),
borderColor: getBaselineColor(colorScheme),
borderDash: BASELINE_DASH,
borderWidth: 1,
// Above the area of a filled line
drawTime: 'afterDatasetsDraw',
scaleID: 'y',
type: 'line',
value: 0
value
};
}
export function getZeroLineAnnotation(
colorScheme?: ColorScheme
): AnnotationOptions<'line'> {
return getBaselineAnnotation({ colorScheme });
}
export function transformTickToAbbreviation(value: number) {
if (value === 0) {
return '0';

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

@ -1,4 +1,5 @@
import {
getBaselinePlugin,
getChartBorderColor,
getTimeAxisOptions,
getValueAxisOptions,
@ -58,6 +59,8 @@ export class GfLineChartComponent
{
@Input() benchmarkDataItems: NullableLineChartItem[] = [];
@Input() benchmarkLabel = '';
/** Value of a horizontal reference line (e.g. 0 for a change in percent) */
@Input() baseline?: number;
@Input() colorScheme?: ColorScheme;
@Input() currency?: string;
@Input() historicalDataItems: LineChartItem[] | null;
@ -277,6 +280,12 @@ export class GfLineChartComponent
spanGaps: true
},
plugins: [
getBaselinePlugin({
colorScheme: this.colorScheme,
getValue: () => {
return this.baseline;
}
}),
getVerticalHoverLinePlugin(this.chartCanvas, this.colorScheme)
],
type: 'line'

Loading…
Cancel
Save