Browse Source

Merge 818153b12b into 2b2ff0b883

pull/7118/merge
Chandranil Bakshi 15 hours ago
committed by GitHub
parent
commit
589a1f863b
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      apps/client/src/app/components/home-overview/home-overview.html
  2. 2
      libs/ui/src/lib/line-chart/line-chart.component.stories.ts
  3. 224
      libs/ui/src/lib/line-chart/line-chart.component.ts

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

@ -69,6 +69,8 @@
unit="%"
[class.pr-3]="deviceType() === 'mobile'"
[colorScheme]="user()?.settings?.colorScheme"
[dataDecimation]="true"
[dataDecimationThreshold]="100"
[hidden]="historicalDataItems()?.length === 0"
[historicalDataItems]="historicalDataItems()"
[isAnimated]="user()?.settings?.dateRange === '1d' ? false : true"

2
libs/ui/src/lib/line-chart/line-chart.component.stories.ts

@ -19,6 +19,8 @@ type Story = StoryObj<GfLineChartComponent>;
export const Simple: Story = {
args: {
dataDecimation: true,
dataDecimationThreshold: 1,
historicalDataItems: [
{
date: '2017-01-01',

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

@ -26,11 +26,14 @@ import {
import {
type AnimationsSpec,
Chart,
type ChartData,
Decimation,
Filler,
LinearScale,
LineController,
LineElement,
PointElement,
type Point,
TimeScale,
Tooltip,
type TooltipOptions
@ -54,6 +57,8 @@ export class GfLineChartComponent
@Input() benchmarkLabel = '';
@Input() colorScheme: ColorScheme;
@Input() currency: string;
@Input() dataDecimation = false;
@Input() dataDecimationThreshold: number;
@Input() historicalDataItems: LineChartItem[];
@Input() isAnimated = false;
@Input() label: string;
@ -71,13 +76,14 @@ export class GfLineChartComponent
@ViewChild('chartCanvas') chartCanvas: ElementRef<HTMLCanvasElement>;
public chart: Chart<'line'>;
public chart: Chart<'line', (number | Point | null)[], string>;
public isLoading = true;
private readonly ANIMATION_DURATION = 1200;
public constructor(private changeDetectorRef: ChangeDetectorRef) {
Chart.register(
Decimation,
Filler,
LineController,
LineElement,
@ -118,14 +124,27 @@ export class GfLineChartComponent
private initialize() {
this.isLoading = true;
const benchmarkPrices: number[] = [];
const benchmarkPrices: (number | Point | null)[] = [];
const labels: string[] = [];
const marketPrices: number[] = [];
const marketPrices: (number | Point | null)[] = [];
this.historicalDataItems?.forEach((historicalDataItem, index) => {
benchmarkPrices.push(this.benchmarkDataItems?.[index]?.value);
labels.push(historicalDataItem.date);
marketPrices.push(historicalDataItem.value);
const label = historicalDataItem.date;
const timestamp = new Date(historicalDataItem.date).getTime();
const benchmarkValue = this.benchmarkDataItems?.[index]?.value;
const marketValue = historicalDataItem.value;
benchmarkPrices.push(
this.dataDecimation
? { x: timestamp, y: benchmarkValue ?? null }
: benchmarkValue
);
labels.push(label);
marketPrices.push(
this.dataDecimation
? { x: timestamp, y: marketValue ?? null }
: marketValue
);
});
const gradient = this.chartCanvas?.nativeElement
@ -148,7 +167,7 @@ export class GfLineChartComponent
gradient.addColorStop(1, getBackgroundColor(this.colorScheme));
}
const data = {
const data: ChartData<'line', (number | Point | null)[], string> = {
labels,
datasets: [
{
@ -181,6 +200,11 @@ export class GfLineChartComponent
if (this.chart) {
this.chart.data = data;
this.chart.options.plugins ??= {};
this.chart.options.parsing = this.dataDecimation ? false : undefined;
this.chart.options.plugins.decimation = {
enabled: this.dataDecimation,
threshold: this.dataDecimationThreshold
};
this.chart.options.plugins.tooltip =
this.getTooltipPluginConfiguration();
this.chart.options.animations = this.isAnimated
@ -189,106 +213,114 @@ export class GfLineChartComponent
this.chart.update();
} else {
this.chart = new Chart(this.chartCanvas.nativeElement, {
data,
options: {
animations: this.isAnimated ? animations : undefined,
aspectRatio: 16 / 9,
elements: {
point: {
hoverBackgroundColor: getBackgroundColor(this.colorScheme),
hoverRadius: 2
}
},
interaction: { intersect: false, mode: 'index' },
plugins: {
legend: {
align: 'start',
display: this.showLegend,
position: 'bottom'
this.chart = new Chart<'line', (number | Point | null)[], string>(
this.chartCanvas.nativeElement,
{
data,
options: {
animations: this.isAnimated ? animations : undefined,
aspectRatio: 16 / 9,
elements: {
point: {
hoverBackgroundColor: getBackgroundColor(this.colorScheme),
hoverRadius: 2
}
},
tooltip: this.getTooltipPluginConfiguration(),
verticalHoverLine: {
color: `rgba(${getTextColor(this.colorScheme)}, 0.1)`
}
},
scales: {
x: {
border: {
color: `rgba(${getTextColor(this.colorScheme)}, 0.1)`
},
display: this.showXAxis,
grid: {
display: false
interaction: { intersect: false, mode: 'index' },
parsing: this.dataDecimation ? false : undefined,
plugins: {
decimation: {
enabled: this.dataDecimation,
threshold: this.dataDecimationThreshold
},
time: {
tooltipFormat: getDateFormatString(this.locale),
unit: 'year'
legend: {
align: 'start',
display: this.showLegend,
position: 'bottom'
},
type: 'time'
tooltip: this.getTooltipPluginConfiguration(),
verticalHoverLine: {
color: `rgba(${getTextColor(this.colorScheme)}, 0.1)`
}
},
y: {
border: {
width: 0
},
display: this.showYAxis,
grid: {
color: ({ scale, tick }) => {
if (
tick.value === 0 ||
tick.value === scale.max ||
tick.value === scale.min ||
tick.value === this.yMax ||
tick.value === this.yMin
) {
return `rgba(${getTextColor(this.colorScheme)}, 0.1)`;
}
return 'transparent';
}
scales: {
x: {
border: {
color: `rgba(${getTextColor(this.colorScheme)}, 0.1)`
},
display: this.showXAxis,
grid: {
display: false
},
time: {
tooltipFormat: getDateFormatString(this.locale),
unit: 'year'
},
type: 'time'
},
max: this.yMax,
min: this.yMin,
position: 'right',
ticks: {
callback: (tickValue, index, ticks) => {
if (index === 0 || index === ticks.length - 1) {
// Only print last and first legend entry
if (index === 0 && this.yMinLabel) {
return this.yMinLabel;
}
if (index === ticks.length - 1 && this.yMaxLabel) {
return this.yMaxLabel;
}
if (typeof tickValue === 'number') {
return tickValue.toLocaleString(this.locale, {
maximumFractionDigits: 2,
minimumFractionDigits: 2
});
y: {
border: {
width: 0
},
display: this.showYAxis,
grid: {
color: ({ scale, tick }) => {
if (
tick.value === 0 ||
tick.value === scale.max ||
tick.value === scale.min ||
tick.value === this.yMax ||
tick.value === this.yMin
) {
return `rgba(${getTextColor(this.colorScheme)}, 0.1)`;
}
return tickValue;
return 'transparent';
}
},
max: this.yMax,
min: this.yMin,
position: 'right',
ticks: {
callback: (tickValue, index, ticks) => {
if (index === 0 || index === ticks.length - 1) {
// Only print last and first legend entry
if (index === 0 && this.yMinLabel) {
return this.yMinLabel;
}
if (index === ticks.length - 1 && this.yMaxLabel) {
return this.yMaxLabel;
}
if (typeof tickValue === 'number') {
return tickValue.toLocaleString(this.locale, {
maximumFractionDigits: 2,
minimumFractionDigits: 2
});
}
return tickValue;
}
return '';
return '';
},
display: this.showYAxis,
mirror: true,
z: 1
},
display: this.showYAxis,
mirror: true,
z: 1
},
type: 'linear'
}
type: 'linear'
}
},
spanGaps: true
},
spanGaps: true
},
plugins: [
getVerticalHoverLinePlugin(this.chartCanvas, this.colorScheme)
],
type: 'line'
});
plugins: [
getVerticalHoverLinePlugin(this.chartCanvas, this.colorScheme)
],
type: 'line'
}
);
}
}

Loading…
Cancel
Save