mirror of https://github.com/abpframework/abp.git
9 changed files with 216 additions and 0 deletions
@ -0,0 +1,7 @@ |
|||||
|
{ |
||||
|
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", |
||||
|
"dest": "../../../dist/packages/components/chart.js", |
||||
|
"lib": { |
||||
|
"entryFile": "src/public-api.ts" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
<div |
||||
|
style="position:relative" |
||||
|
[style.width]="responsive && !width ? null : width" |
||||
|
[style.height]="responsive && !height ? null : height" |
||||
|
> |
||||
|
<canvas |
||||
|
[attr.width]="responsive && !width ? null : width" |
||||
|
[attr.height]="responsive && !height ? null : height" |
||||
|
(click)="onCanvasClick($event)" |
||||
|
></canvas> |
||||
|
</div> |
||||
@ -0,0 +1,141 @@ |
|||||
|
import { |
||||
|
AfterViewInit, |
||||
|
ChangeDetectorRef, |
||||
|
Component, |
||||
|
ElementRef, |
||||
|
EventEmitter, |
||||
|
Input, |
||||
|
OnDestroy, |
||||
|
Output |
||||
|
} from '@angular/core'; |
||||
|
import { BehaviorSubject } from 'rxjs'; |
||||
|
import { chartJsLoaded$ } from './widget-utils'; |
||||
|
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 = true; |
||||
|
|
||||
|
// eslint-disable-next-line @angular-eslint/no-output-on-prefix
|
||||
|
@Output() readonly onDataSelect: EventEmitter<any> = new EventEmitter(); |
||||
|
|
||||
|
@Output() readonly initialized = new BehaviorSubject(this); |
||||
|
|
||||
|
private _initialized: boolean; |
||||
|
|
||||
|
_data: any; |
||||
|
|
||||
|
chart: any; |
||||
|
|
||||
|
constructor(public el: ElementRef, private cdRef: ChangeDetectorRef) {} |
||||
|
|
||||
|
@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() { |
||||
|
chartJsLoaded$.subscribe(() => { |
||||
|
this.testChartJs(); |
||||
|
|
||||
|
this.initChart(); |
||||
|
this._initialized = true; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
testChartJs() { |
||||
|
try { |
||||
|
Chart; |
||||
|
} catch (error) { |
||||
|
throw new Error(`Chart is not found. Import the Chart from app.module like shown below:
|
||||
|
import('chart.js'); |
||||
|
`);
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
onCanvasClick = event => { |
||||
|
if (this.chart) { |
||||
|
const element = this.chart.getElementAtEvent(event); |
||||
|
const dataset = this.chart.getDatasetAtEvent(event); |
||||
|
if (element && element.length && dataset) { |
||||
|
this.onDataSelect.emit({ |
||||
|
originalEvent: event, |
||||
|
element: element[0], |
||||
|
dataset, |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
initChart = () => { |
||||
|
const 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.canvas, { |
||||
|
type: this.type, |
||||
|
data: this.data, |
||||
|
options: this.options, |
||||
|
plugins: this.plugins, |
||||
|
}); |
||||
|
|
||||
|
this.cdRef.detectChanges(); |
||||
|
}; |
||||
|
|
||||
|
generateLegend = () => { |
||||
|
if (this.chart) { |
||||
|
return this.chart.generateLegend(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
refresh = () => { |
||||
|
if (this.chart) { |
||||
|
this.chart.update(); |
||||
|
this.cdRef.detectChanges(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
reinit = () => { |
||||
|
if (this.chart) { |
||||
|
this.chart.destroy(); |
||||
|
this.initChart(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
ngOnDestroy() { |
||||
|
if (this.chart) { |
||||
|
this.chart.destroy(); |
||||
|
this._initialized = false; |
||||
|
this.chart = null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
import { APP_INITIALIZER, Injector, ModuleWithProviders, NgModule } from '@angular/core'; |
||||
|
import { ChartComponent } from './chart.component'; |
||||
|
|
||||
|
declare const Chart: any |
||||
|
|
||||
|
@NgModule({ |
||||
|
imports: [], |
||||
|
exports: [], |
||||
|
declarations: [ChartComponent], |
||||
|
providers: [], |
||||
|
}) |
||||
|
export class ChartModule { |
||||
|
static forRoot(): ModuleWithProviders<ChartModule> { |
||||
|
return { |
||||
|
ngModule: ChartModule, |
||||
|
providers: [{ |
||||
|
provide: APP_INITIALIZER, |
||||
|
multi: true, |
||||
|
useFactory: (injector: Injector) => () => { |
||||
|
import('chart.js/auto').then((module) => { |
||||
|
console.dir(module) |
||||
|
}) |
||||
|
return Promise.resolve() |
||||
|
}, |
||||
|
deps: [Injector] |
||||
|
}] |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,4 @@ |
|||||
|
export * from './chart.component'; |
||||
|
export * from './chart.module'; |
||||
|
export * from './widget-utils'; |
||||
|
|
||||
@ -0,0 +1,16 @@ |
|||||
|
import { ReplaySubject } from 'rxjs'; |
||||
|
|
||||
|
export function getRandomBackgroundColor(count) { |
||||
|
const colors = []; |
||||
|
|
||||
|
for (let i = 0; i < count; i++) { |
||||
|
const r = ((i + 5) * (i + 5) * 474) % 255; |
||||
|
const g = ((i + 5) * (i + 5) * 1600) % 255; |
||||
|
const b = ((i + 5) * (i + 5) * 84065) % 255; |
||||
|
colors.push('rgba(' + r + ', ' + g + ', ' + b + ', 0.7)'); |
||||
|
} |
||||
|
|
||||
|
return colors; |
||||
|
} |
||||
|
|
||||
|
export const chartJsLoaded$ = new ReplaySubject(1); |
||||
Loading…
Reference in new issue