@coreui/angular-chartjs
Version:
Angular wrapper component for Chart.js
250 lines (244 loc) • 12.5 kB
JavaScript
import * as i0 from '@angular/core';
import { inject, NgZone, Renderer2, ChangeDetectorRef, input, booleanAttribute, numberAttribute, linkedSignal, output, viewChild, computed, afterRenderEffect, untracked, ChangeDetectionStrategy, Component, NgModule } from '@angular/core';
import merge from 'lodash-es/merge';
import { Chart, registerables } from 'chart.js';
import { customTooltips } from '@coreui/chartjs';
Chart.register(...registerables);
let nextId = 0;
class ChartjsComponent {
//
static ngAcceptInputType_redraw;
ngZone = inject(NgZone);
renderer = inject(Renderer2);
changeDetectorRef = inject(ChangeDetectorRef);
/**
* Enables custom html based tooltips instead of standard tooltips.
* @return boolean
* @default true
*/
customTooltips = input(true, ...(ngDevMode ? [{ debugName: "customTooltips", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
/**
* The data object that is passed into the Chart.js chart (more info).
*/
data = input(...(ngDevMode ? [undefined, { debugName: "data" }] : []));
/**
* A fallback when the canvas cannot be rendered. Can be used for accessible chart descriptions.
*/
// @Input() fallbackContent?: TemplateRef<any>;
/**
* Height attribute applied to the rendered canvas.
* @return number | undefined
* @default null
*/
height = input(null, ...(ngDevMode ? [{ debugName: "height", transform: (value) => numberAttribute(value, undefined) }] : [{ transform: (value) => numberAttribute(value, undefined) }]));
/**
* ID attribute applied to the rendered canvas.
* @return string
*/
idInput = input(`c-chartjs-${nextId++}`, ...(ngDevMode ? [{ debugName: "idInput", alias: 'id' }] : [{ alias: 'id' }]));
get id() {
return this.idInput();
}
/**
* The options object that is passed into the Chart.js chart.
*/
optionsInput = input({}, ...(ngDevMode ? [{ debugName: "optionsInput", alias: 'options' }] : [{ alias: 'options' }]));
options = linkedSignal(this.optionsInput);
/**
* The plugins array that is passed into the Chart.js chart
*/
plugins = input([], ...(ngDevMode ? [{ debugName: "plugins" }] : []));
/**
* If true, will tear down and redraw chart on all updates.
* @return boolean
* @default false
*/
redraw = input(false, ...(ngDevMode ? [{ debugName: "redraw", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
/**
* Chart.js chart type.
* @return {'line' | 'bar' | 'radar' | 'doughnut' | 'polarArea' | 'bubble' | 'pie' | 'scatter'}
*/
type = input('bar', ...(ngDevMode ? [{ debugName: "type" }] : []));
/**
* Width attribute applied to the rendered canvas.
* @return number | undefined
* @default null
*/
width = input(null, ...(ngDevMode ? [{ debugName: "width", transform: (value) => numberAttribute(value, undefined) }] : [{ transform: (value) => numberAttribute(value, undefined) }]));
/**
* Put the chart into the wrapper div element.
* @default true
*/
wrapper = input(true, ...(ngDevMode ? [{ debugName: "wrapper", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
getDatasetAtEvent = output();
getElementAtEvent = output();
getElementsAtEvent = output();
chartRef = output();
canvasElement = viewChild.required('canvasElement');
chart;
ctx;
hostClasses = computed(() => {
return {
'chart-wrapper': this.wrapper()
};
}, ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
constructor() {
afterRenderEffect({
read: () => {
const canvasElement = this.canvasElement();
this.ctx = canvasElement?.nativeElement?.getContext('2d');
this.chartRender();
}
});
}
ngOnChanges(changes) {
if (changes['data'] && !changes['data'].firstChange) {
this.chartUpdate();
}
}
ngOnDestroy() {
this.chartDestroy();
}
handleClick($event) {
if (!this.chart) {
return;
}
const datasetAtEvent = this.chart.getElementsAtEventForMode($event, 'dataset', { intersect: true }, false);
this.getDatasetAtEvent.emit(datasetAtEvent);
const elementAtEvent = this.chart.getElementsAtEventForMode($event, 'nearest', { intersect: true }, false);
this.getElementAtEvent.emit(elementAtEvent);
const elementsAtEvent = this.chart.getElementsAtEventForMode($event, 'index', { intersect: true }, false);
this.getElementsAtEvent.emit(elementsAtEvent);
}
chartDestroy() {
this.chart?.destroy();
this.chartRef.emit(undefined);
}
chartRender() {
const canvasElement = this.canvasElement();
if (!canvasElement?.nativeElement || !this.ctx || this.chart) {
return;
}
this.ngZone.runOutsideAngular(() => {
const config = this.chartConfig();
if (config) {
this.chart = new Chart(this.ctx, config);
this.ngZone.run(() => {
this.renderer.setStyle(canvasElement.nativeElement, 'display', 'block');
this.changeDetectorRef.markForCheck();
this.chartRef.emit(this.chart);
});
}
});
}
chartUpdate() {
if (!this.chart) {
return;
}
if (this.redraw()) {
this.chartDestroy();
this.chartRender();
return;
}
const config = this.chartConfig();
if (this.options()) {
Object.assign(this.chart.options ?? {}, config.options ?? {});
}
if (!this.chart.config.data) {
this.chart.config.data = { ...config.data };
this.chartUpdateOutsideAngular();
}
if (this.chart) {
Object.assign(this.chart.config.options ?? {}, config.options ?? {});
Object.assign(this.chart.config.plugins ?? [], config.plugins ?? []);
Object.assign(this.chart.config.data, config.data);
}
this.chartUpdateOutsideAngular();
}
chartUpdateOutsideAngular() {
setTimeout(() => {
this.ngZone.runOutsideAngular(() => {
this.chart?.update();
this.ngZone.run(() => {
this.changeDetectorRef.markForCheck();
});
});
});
}
chartToBase64Image() {
return this.chart?.toBase64Image();
}
chartDataConfig = computed(() => {
const { labels, datasets } = { ...this.data() };
return {
labels: labels ?? [],
datasets: datasets ?? []
};
}, ...(ngDevMode ? [{ debugName: "chartDataConfig" }] : []));
chartOptions = computed(() => this.options() ?? {}, ...(ngDevMode ? [{ debugName: "chartOptions" }] : []));
chartConfig = computed(() => {
this.chartCustomTooltips();
return {
data: this.chartDataConfig(),
options: this.chartOptions(),
plugins: this.plugins(),
type: this.type()
};
}, ...(ngDevMode ? [{ debugName: "chartConfig" }] : []));
chartCustomTooltips() {
if (this.customTooltips()) {
const options = this.options();
const plugins = options?.plugins;
const tooltip = options?.plugins?.tooltip;
untracked(() => {
this.options.set(merge({
...options,
plugins: {
...plugins,
tooltip: {
...tooltip,
enabled: false,
mode: 'index',
position: 'nearest',
external: customTooltips
}
}
}));
});
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ChartjsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.1.4", type: ChartjsComponent, isStandalone: true, selector: "c-chart", inputs: { customTooltips: { classPropertyName: "customTooltips", publicName: "customTooltips", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, idInput: { classPropertyName: "idInput", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, optionsInput: { classPropertyName: "optionsInput", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, plugins: { classPropertyName: "plugins", publicName: "plugins", isSignal: true, isRequired: false, transformFunction: null }, redraw: { classPropertyName: "redraw", publicName: "redraw", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, wrapper: { classPropertyName: "wrapper", publicName: "wrapper", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { getDatasetAtEvent: "getDatasetAtEvent", getElementAtEvent: "getElementAtEvent", getElementsAtEvent: "getElementsAtEvent", chartRef: "chartRef" }, host: { properties: { "class": "hostClasses()", "style.height.px": "height()", "style.width.px": "width()" } }, viewQueries: [{ propertyName: "canvasElement", first: true, predicate: ["canvasElement"], descendants: true, isSignal: true }], exportAs: ["cChart"], usesOnChanges: true, ngImport: i0, template: "<canvas\n #canvasElement\n (click)=\"handleClick($event)\"\n [height]=\"height() || null\"\n [id]=\"id\"\n [width]=\"width() || null\"\n role=\"img\"\n style=\"display: none;\"\n>\n <ng-content />\n <!-- <ng-container *ngTemplateOutlet=\"fallbackContent\"/>-->\n</canvas>\n", styles: [":host.chart-wrapper{display:block}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ChartjsComponent, decorators: [{
type: Component,
args: [{ selector: 'c-chart', exportAs: 'cChart', changeDetection: ChangeDetectionStrategy.OnPush, host: {
'[class]': 'hostClasses()',
'[style.height.px]': 'height()',
'[style.width.px]': 'width()'
}, template: "<canvas\n #canvasElement\n (click)=\"handleClick($event)\"\n [height]=\"height() || null\"\n [id]=\"id\"\n [width]=\"width() || null\"\n role=\"img\"\n style=\"display: none;\"\n>\n <ng-content />\n <!-- <ng-container *ngTemplateOutlet=\"fallbackContent\"/>-->\n</canvas>\n", styles: [":host.chart-wrapper{display:block}\n"] }]
}], ctorParameters: () => [] });
class ChartjsModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ChartjsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.1.4", ngImport: i0, type: ChartjsModule, imports: [ChartjsComponent], exports: [ChartjsComponent] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ChartjsModule });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ChartjsModule, decorators: [{
type: NgModule,
args: [{
imports: [
ChartjsComponent
],
exports: [
ChartjsComponent
]
}]
}] });
/*
* Public API Surface of coreui-angular-chartjs
*/
/**
* Generated bundle index. Do not edit.
*/
export { ChartjsComponent, ChartjsModule };
//# sourceMappingURL=coreui-angular-chartjs.mjs.map