diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/chart/chart.component.html b/npm/ng-packs/packages/theme-shared/src/lib/components/chart/chart.component.html
new file mode 100644
index 0000000000..211614c90d
--- /dev/null
+++ b/npm/ng-packs/packages/theme-shared/src/lib/components/chart/chart.component.html
@@ -0,0 +1,11 @@
+
+
+
diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/chart/chart.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/chart/chart.component.ts
new file mode 100644
index 0000000000..2c8b7d0fb4
--- /dev/null
+++ b/npm/ng-packs/packages/theme-shared/src/lib/components/chart/chart.component.ts
@@ -0,0 +1,118 @@
+import { AfterViewInit, Component, ElementRef, EventEmitter, Input, OnDestroy, Output } from '@angular/core';
+import { BehaviorSubject } from 'rxjs';
+declare const Chart: any;
+
+@Component({
+ selector: 'abp-chart',
+ templateUrl: './chart.component.html',
+})
+export class ChartComponent implements AfterViewInit, OnDestroy {
+ @Input() type: string;
+
+ @Input() options: any = {};
+
+ @Input() plugins: any[] = [];
+
+ @Input() width: string;
+
+ @Input() height: string;
+
+ @Input() responsive: boolean = true;
+
+ @Output() onDataSelect: EventEmitter = new EventEmitter();
+
+ @Output() initialized = new BehaviorSubject(this);
+
+ private _initialized: boolean;
+
+ _data: any;
+
+ chart: any;
+
+ constructor(public el: ElementRef) {}
+
+ @Input() get data(): any {
+ return this._data;
+ }
+
+ set data(val: any) {
+ this._data = val;
+ this.reinit();
+ }
+
+ get canvas() {
+ return this.el.nativeElement.children[0].children[0];
+ }
+
+ get base64Image() {
+ return this.chart.toBase64Image();
+ }
+
+ ngAfterViewInit() {
+ try {
+ Chart;
+ } catch (error) {
+ console.error(`Chart is not found. Import the Chart from app.module like shown below:
+ import('chart.js');
+ `);
+ return;
+ }
+
+ this.initChart();
+ this._initialized = true;
+ }
+
+ onCanvasClick = event => {
+ if (this.chart) {
+ let element = this.chart.getElementAtEvent(event);
+ let dataset = this.chart.getDatasetAtEvent(event);
+ if (element && element[0] && dataset) {
+ this.onDataSelect.emit({ originalEvent: event, element: element[0], dataset: dataset });
+ }
+ }
+ };
+
+ initChart = () => {
+ let opts = this.options || {};
+ opts.responsive = this.responsive;
+
+ // allows chart to resize in responsive mode
+ if (opts.responsive && (this.height || this.width)) {
+ opts.maintainAspectRatio = false;
+ }
+
+ this.chart = new Chart(this.el.nativeElement.children[0].children[0], {
+ type: this.type,
+ data: this.data,
+ options: this.options,
+ plugins: this.plugins,
+ });
+ };
+
+ generateLegend = () => {
+ if (this.chart) {
+ return this.chart.generateLegend();
+ }
+ };
+
+ refresh = () => {
+ if (this.chart) {
+ this.chart.update();
+ }
+ };
+
+ reinit = () => {
+ if (this.chart) {
+ this.chart.destroy();
+ this.initChart();
+ }
+ };
+
+ ngOnDestroy() {
+ if (this.chart) {
+ this.chart.destroy();
+ this._initialized = false;
+ this.chart = null;
+ }
+ }
+}
diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/index.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/index.ts
index 9665c263e5..e4bcb47597 100644
--- a/npm/ng-packs/packages/theme-shared/src/lib/components/index.ts
+++ b/npm/ng-packs/packages/theme-shared/src/lib/components/index.ts
@@ -1,6 +1,7 @@
-export * from './button/button.component';
export * from './breadcrumb/breadcrumb.component';
+export * from './button/button.component';
export * from './change-password/change-password.component';
+export * from './chart/chart.component';
export * from './confirmation/confirmation.component';
export * from './loader-bar/loader-bar.component';
export * from './modal/modal.component';
diff --git a/npm/ng-packs/packages/theme-shared/src/lib/models/index.ts b/npm/ng-packs/packages/theme-shared/src/lib/models/index.ts
index da311b86be..e42b6ccfa5 100644
--- a/npm/ng-packs/packages/theme-shared/src/lib/models/index.ts
+++ b/npm/ng-packs/packages/theme-shared/src/lib/models/index.ts
@@ -1,3 +1,4 @@
export * from './confirmation';
-export * from './toaster';
export * from './setting-management';
+export * from './statistics';
+export * from './toaster';
diff --git a/npm/ng-packs/packages/theme-shared/src/lib/models/statistics.ts b/npm/ng-packs/packages/theme-shared/src/lib/models/statistics.ts
new file mode 100644
index 0000000000..65bd5dfa8f
--- /dev/null
+++ b/npm/ng-packs/packages/theme-shared/src/lib/models/statistics.ts
@@ -0,0 +1,14 @@
+export namespace Statistics {
+ export interface Response {
+ data: Data;
+ }
+
+ export interface Data {
+ [key: string]: number;
+ }
+
+ export interface Filter {
+ startDate: string | Date;
+ endDate: string | Date;
+ }
+}
diff --git a/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts b/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts
index 49269b59d9..0933a607d2 100644
--- a/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts
+++ b/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts
@@ -17,27 +17,24 @@ import { ValidationErrorComponent } from './components/errors/validation-error.c
import { ChangePasswordComponent } from './components/change-password/change-password.component';
import { ProfileComponent } from './components/profile/profile.component';
import { BreadcrumbComponent } from './components/breadcrumb/breadcrumb.component';
+import { ChartComponent } from './components/chart/chart.component';
-export function appendScript(styles) {
- const higher = (injector: Injector) => {
- const fn = function() {
- const lazyLoadService: LazyLoadService = injector.get(LazyLoadService);
+export function appendScript(injector: Injector) {
+ const fn = function() {
+ const lazyLoadService: LazyLoadService = injector.get(LazyLoadService);
- return forkJoin(
- lazyLoadService.load(
- null,
- 'style',
- styles,
- 'head',
- 'afterbegin',
- ) /* lazyLoadService.load(null, 'script', scripts) */,
- ).pipe(take(1));
- };
-
- return fn;
+ return forkJoin(
+ lazyLoadService.load(
+ null,
+ 'style',
+ styles,
+ 'head',
+ 'afterbegin',
+ ) /* lazyLoadService.load(null, 'script', scripts) */,
+ ).pipe(take(1));
};
- return higher;
+ return fn;
}
@NgModule({
@@ -59,26 +56,28 @@ export function appendScript(styles) {
}),
],
declarations: [
+ BreadcrumbComponent,
ButtonComponent,
+ ChangePasswordComponent,
+ ChartComponent,
ConfirmationComponent,
- ToastComponent,
- ModalComponent,
ErrorComponent,
LoaderBarComponent,
- ValidationErrorComponent,
- ChangePasswordComponent,
+ ModalComponent,
ProfileComponent,
- BreadcrumbComponent,
+ ToastComponent,
+ ValidationErrorComponent,
],
exports: [
+ BreadcrumbComponent,
ButtonComponent,
+ ChangePasswordComponent,
+ ChartComponent,
ConfirmationComponent,
- ToastComponent,
- ModalComponent,
LoaderBarComponent,
- ChangePasswordComponent,
+ ModalComponent,
ProfileComponent,
- BreadcrumbComponent,
+ ToastComponent,
],
entryComponents: [ErrorComponent, ValidationErrorComponent],
})
@@ -91,7 +90,7 @@ export class ThemeSharedModule {
provide: APP_INITIALIZER,
multi: true,
deps: [Injector, ErrorHandler],
- useFactory: appendScript(styles),
+ useFactory: appendScript,
},
{ provide: MessageService, useClass: MessageService },
],