Skip to content

Commit 6c3cfa5

Browse files
committed
fix(chartjs): customTooltips overwrites chartjs.defaults, refactor
1 parent 3e9432e commit 6c3cfa5

File tree

1 file changed

+69
-64
lines changed

1 file changed

+69
-64
lines changed

projects/coreui-angular-chartjs/src/lib/chartjs.component.ts

Lines changed: 69 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@ import {
1515
} from '@angular/core';
1616
import { BooleanInput, coerceBooleanProperty, coerceNumberProperty, NumberInput } from '@angular/cdk/coercion';
1717

18-
import { assign, find, merge } from 'lodash';
18+
import { merge } from 'lodash';
1919

2020
import Chart, { ChartData, ChartOptions, ChartType, Plugin } from 'chart.js/auto';
21-
import * as chartjs from 'chart.js';
2221

2322
import { customTooltips as cuiCustomTooltips } from '@coreui/chartjs';
2423
import { IChartjs } from './chartjs.interface';
@@ -52,7 +51,7 @@ export class ChartjsComponent implements IChartjs, AfterViewInit, OnDestroy, OnC
5251

5352
@Input() id = `c-chartjs-${nextId++}`;
5453
@Input() options?: ChartOptions;
55-
@Input() plugins?: Plugin[];
54+
@Input() plugins: Plugin[] = [];
5655

5756
@Input()
5857
set redraw(value: boolean) {
@@ -92,13 +91,13 @@ export class ChartjsComponent implements IChartjs, AfterViewInit, OnDestroy, OnC
9291
};
9392
}
9493

95-
get computedData() {
94+
get chartData() {
9695
const canvasRef = this.canvasElement.nativeElement;
9796
return typeof this.data === 'function'
9897
? canvasRef.value
9998
? this.data(canvasRef.value)
100-
: { datasets: [] }
101-
: merge({}, this.data);
99+
: { labels: [], datasets: [] }
100+
: merge({ labels: [], datasets: [] }, { ...this.data });
102101
}
103102

104103
constructor(
@@ -108,21 +107,21 @@ export class ChartjsComponent implements IChartjs, AfterViewInit, OnDestroy, OnC
108107
) {}
109108

110109
ngAfterViewInit(): void {
111-
this.setupChart();
112-
this.updateChart();
110+
this.chartRender();
111+
this.chartUpdate();
113112
}
114113

115114
ngOnChanges(changes: SimpleChanges): void {
116115
if (!changes.data.firstChange) {
117-
this.updateChart();
116+
this.chartUpdate();
118117
}
119118
}
120119

121120
ngOnDestroy(): void {
122-
this.destroyChart();
121+
this.chartDestroy();
123122
}
124123

125-
handleOnClick($event: MouseEvent) {
124+
public handleOnClick($event: MouseEvent) {
126125
if (!this.chart) return;
127126

128127
const datasetAtEvent = this.chart.getElementsAtEventForMode($event, 'dataset', { intersect: true }, false);
@@ -135,42 +134,50 @@ export class ChartjsComponent implements IChartjs, AfterViewInit, OnDestroy, OnC
135134
this.getElementsAtEvent.emit(elementsAtEvent);
136135
}
137136

138-
destroyChart() {
137+
public chartDestroy() {
139138
this.chart?.destroy();
140139
}
141140

142-
setupChart() {
141+
public chartRender() {
143142
if (!this.canvasElement) return;
144143

145144
if (this.customTooltips) {
146-
chartjs.defaults.plugins.tooltip.enabled = false;
147-
chartjs.defaults.plugins.tooltip.mode = 'index';
148-
chartjs.defaults.plugins.tooltip.position = 'nearest';
149-
chartjs.defaults.plugins.tooltip.external = cuiCustomTooltips;
145+
const options = this.options
146+
this.options = {
147+
...options,
148+
plugins: {
149+
...options?.plugins,
150+
tooltip: {
151+
...options?.plugins?.tooltip,
152+
enabled: false,
153+
mode: 'index',
154+
position: 'nearest',
155+
external: cuiCustomTooltips
156+
}
157+
}
158+
};
150159
}
151160

152161
const ctx: CanvasRenderingContext2D = this.canvasElement.nativeElement.getContext('2d');
153162

154163
return this.ngZone.runOutsideAngular(() => {
155-
this.chart = new Chart(ctx, {
156-
type: this.type,
157-
data: this.computedData,
158-
options: this.options as ChartOptions,
159-
plugins: this.plugins
160-
});
161-
setTimeout(() => {
162-
this.renderer.setStyle(this.canvasElement.nativeElement, 'display', 'block');
163-
})
164+
const config = this.chartConfig();
165+
if (config) {
166+
this.chart = new Chart(ctx, config);
167+
setTimeout(() => {
168+
this.renderer.setStyle(this.canvasElement.nativeElement, 'display', 'block');
169+
});
170+
}
164171
});
165172
}
166173

167-
updateChart() {
174+
chartUpdate() {
168175
if (!this.chart) return;
169176

170177
if (this.redraw) {
171-
this.destroyChart();
178+
this.chartDestroy();
172179
setTimeout(() => {
173-
this.setupChart();
180+
this.chartRender();
174181
});
175182
return;
176183
}
@@ -179,49 +186,47 @@ export class ChartjsComponent implements IChartjs, AfterViewInit, OnDestroy, OnC
179186
this.chart.options = { ...this.options };
180187
}
181188

189+
const config = this.chartConfig();
190+
182191
if (!this.chart.config.data) {
183-
this.chart.config.data = this.computedData;
184-
this.ngZone.runOutsideAngular(() => {
185-
this.chart?.update();
186-
});
187-
return;
192+
this.chart.config.data = { ...config.data };
193+
this.chartUpdateOutsideAngular();
188194
}
189195

190-
const { datasets: newDataSets = [], ...newChartData } = this.computedData;
191-
const { datasets: currentDataSets = [] } = this.chart.config.data;
192-
193-
// copy values
194-
assign(this.chart.config.data, newChartData);
195-
this.chart.config.data.datasets = newDataSets.map((newDataSet: any) => {
196-
// given the new set, find it's current match
197-
const currentDataSet = find(
198-
currentDataSets,
199-
(d: any) => d.label === newDataSet.label && d.type === newDataSet.type
200-
);
201-
202-
// There is no original to update, so simply add new one
203-
if (!currentDataSet || !newDataSet.data) return newDataSet;
204-
205-
if (!currentDataSet.data) {
206-
currentDataSet.data = [];
207-
} else {
208-
currentDataSet.data.length = newDataSet.data.length;
209-
}
196+
if (this.chart) {
197+
Object.assign(this.chart.config.options, config.options);
198+
Object.assign(this.chart.config.plugins, config.plugins);
199+
Object.assign(this.chart.config.data, config.data);
200+
}
210201

211-
// copy in values
212-
assign(currentDataSet.data, newDataSet.data);
202+
this.chartUpdateOutsideAngular();
203+
}
213204

214-
// apply dataset changes, but keep copied data
215-
return {
216-
...currentDataSet,
217-
...newDataSet,
218-
data: currentDataSet.data
219-
};
220-
});
205+
private chartUpdateOutsideAngular() {
221206
setTimeout(() => {
222207
this.ngZone.runOutsideAngular(() => {
223208
this.chart?.update();
224209
});
225-
})
210+
});
211+
}
212+
213+
public chartToBase64Image(): string | undefined {
214+
return this.chart?.toBase64Image();
215+
}
216+
217+
private chartDataConfig() {
218+
return {
219+
labels: this.chartData?.labels ?? [],
220+
datasets: [...this.chartData?.datasets] ?? []
221+
};
222+
}
223+
224+
private chartConfig() {
225+
return {
226+
data: this.chartDataConfig(),
227+
options: this.options as ChartOptions,
228+
plugins: this.plugins,
229+
type: this.type
230+
};
226231
}
227232
}

0 commit comments

Comments
 (0)