i want to set a dynamic id for my report (canvas) in my html with angular but im getting an error if u can help me pls, this is the code of my class and my html
export class CardKPIReporteComponent implements OnInit {
#BlockUI() blockUI: NgBlockUI;
#Input() datos_kpi_reporte: any
fetcher: any
arrayListaKpis: any
tituloreporte: any
id: any = 1
chartBienesUbicacion: any;
constructor(private procesoOperacionService: ProcesoOperacionesService
) {
}
ngOnInit() {
this.tituloreporte = this.datos_kpi_reporte.servicio_nombre
this.id = this.datos_kpi_reporte.cont //this.id = 1
this.Grafico2();
}
Grafico2() {
// this.id = this.datos_kpi_reporte.cont
var nombrechart = "Reporte" + this.datos_kpi_reporte.cont
this.chartBienesUbicacion = new Chart(nombrechart, {
type: 'pie',
data: {
labels: ['ENTREGADO', 'NO ENTREGADO', '1', '1'],
datasets: [
{
label: 'Cantidad',
data: ['1', '1', '1', '1'], // this.chartsTotal,
backgroundColor: 'rgba(54, 162, 235, 0.2)',
borderColor:
'rgba(54, 162, 235, 1)',
borderWidth: 1
}
]
},
options: {
title: {
text: nombrechart,
display: true
},
scales: {
yAxes: [
{
ticks: {
beginAtZero: true
}
}
]
}
}
});
}
}
<mat-card-content>
<!--<app-alert></app-alert> -->
<div class="row">
<canvas id="Reporte{{ this.id }}"></canvas>
</div>
</mat-card-content>
ive been trying this way but im getting this error: "Chart.js:8459 Failed to create chart: can't acquire context from the given item"
This is happening because your trying to add the canvas before you set the id in the template. You need to set the ID in the template, and after the view initializes then add your chart.
make sure you implement AfterViewInit and update your code as such.
ngOnInit() {
this.tituloreporte = this.datos_kpi_reporte.servicio_nombre
this.id = this.datos_kpi_reporte.cont
}
ngAfterViewInit() {
this.Grafico2();
}
Related
There is a parent component with all the logic of the chart, you need to transfer data to the child component using #Input (), that is, so that I can display the chart in any of the components using #Input.
The parent component is logs.component and the child component is echarts.component. It is necessary to pass the data to LoadEcharts(), it contains all the logic of the Chart, that is, that I could call it on any html component
logs.components.ts
export class LogsComponent implements OnInit {
sideNavStatus: boolean = false;
subscription!: Subscription;
logs!: Logs[];
constructor(private dataService: DataService) {
}
columnDefs = [
{ headerName: 'Username', field: 'username', flex: 1},
{ headerName: 'Event', field: 'event', flex: 1 },
{ headerName: 'Date', field: 'date', flex: 1 }
];
ngOnInit() {
this.LoadLogs();
this.LoadEcharts();
}
LoadLogs(): void {
this.dataService.getLogs().subscribe(logs => this.logs = logs);
}
LoadEcharts(): void {
const chartDom: HTMLElement = document.getElementById('main') as HTMLElement;
const myChart = echarts.init(chartDom);
this.subscription = this.dataService.getLogs().subscribe(data => {
myChart.setOption(this.initBasicEchart(data))
})
}
private initBasicEchart(data: Logs[]) {
const result: any = {};
data.forEach(el => {
const date = el.date.toString().substring(0, 10);
if (!result[el.event]) {
result[el.event] = {};
if (!result[el.event][date]) {
result[el.event][date] = 1;
}
} else {
if (!result[el.event][date]) {
result[el.event][date] = 1;
} else {
result[el.event][date] += 1;
}
}
});
const login = {
x: Object.keys(result.Login),
y: Object.values(result.Login)};
const reg = {
c: Object.keys(result.Registration),
z: Object.values(result.Registration)};
return {
title: {
text: 'Graphic login and registration.'
},
tooltip: {},
xAxis: {
type: 'category',
data: (reg.c, login.x)
},
yAxis: {
},
series: [
{
name: 'Login',
type: 'bar',
data: login.y,
},
{
name: 'Registration',
type: 'bar',
data: reg.z,
}
]
};
}
}
logs.component.html
<div class="container-fluid g-0">
<app-header (sideNavToggled)="sideNavStatus = $event;"></app-header>
<main>
<app-sidebar [sideNavStatus]="sideNavStatus"
[ngClass]="{'app-side-nav-open': sideNavStatus}"></app-sidebar>
<div class="display-area p-3" [ngClass]="{'display-area-shrink': sideNavStatus}">
<p class="fs-1 fw-bold fst-italic text-center">Login and registration statistics.
</p>
<app-aggreed
*ngIf="logs"
[logs]="logs"
[columnDefs]="columnDefs"
></app-aggreed>
</div>
</main>
</div>
<app-echarts
></app-echarts>
<app-footer></app-footer>
echarts.component.html
<div class="container-fluid g-0">
<app-header (sideNavToggled)="sideNavStatus = $event;"></app-header>
<main>
<app-sidebar [sideNavStatus]="sideNavStatus"
[ngClass]="{'app-side-nav-open': sideNavStatus}"></app-sidebar>
<div class="display-area p-3" [ngClass]="{'display-area-shrink': sideNavStatus}">
<div
id="main"
style="width: 500px; height: 300px"
>
</div >
</div>
</main>
</div>
<app-footer></app-footer>
export class EchartsComponent implements OnInit {
sideNavStatus: boolean = false;
subscription!: Subscription;
constructor(private dataService: DataService) {
}
ngOnInit(): void {
}
}
I tried to pass methods to the child component through the input but nothing comes out
From your code sample, I'm assuming you're trying to access the EchartsComponent ViewChild in the logs component and pass data to it.
Here's an example of how you can do that, minus some pieces from your sample code for brevity...
class LogsComponent {
#ViewChild(EchartsComponent)
echartsComponent: EchartsComponent;
LoadEcharts(): void {
const chartDom: HTMLElement = document.getElementById('main') as HTMLElement; // <-- not sure what this is
const myChart = echarts.init(chartDom); // <-- not sure what this is
this.subscription = this.dataService.getLogs().subscribe(data => {
this.echartsComponent.logs = data;
// `logs` doesn't exist in the current code for EchartsComponent.
// You'll need to add it.
});
}
}
What I don't see in your EchartsComponent is a logs property to set. If you're using a ViewChild in the parent component, you don't have to use #Input on the ViewChild instance, you have programmatic access to the component and can set properties or call methods.
If you want to use #Input(), you can do that too:
class EchartsComponent {
#Input()
logs: Logs[];
}
// logs.component.ts
class LogsComponent {
LoadEcharts(): void {
this.subscription = this.dataService.getLogs().subscribe(data => {
this.logs = data;
})
}
}
// logs.component.html
<app-echarts [logs]="logs"></app-echarts>
In this scenario, when the observable for getLogs() emits, the property logs is set to the new value. That value, being a new reference is passed to the child component via its input.
Hope that helps you out.
Excuse me, i am newbie in angular, i have chart with static data,and how to show chart with ng2-chart where data is taken from databse / sql?
html :
<div>
<div style="display: block">
<canvas baseChart
[datasets]="barChartData"
[labels]="barChartLabels"
[options]="barChartOptions"
[legend]="barChartLegend"
[chartType]="barChartType"
(chartHover)="chartHovered($event)"
(chartClick)="chartClicked($event)"></canvas>
</div>
<button (click)="randomize()">Update</button>
</div>
typescript :
export class BarChartDemoComponent {
public barChartOptions:any = {
scaleShowVerticalLines: false,
responsive: true
};
public barChartLabels:string[] = ['2006', '2007', '2008', '2009', '2010', '2011', '2012'];
public barChartType:string = 'bar';
public barChartLegend:boolean = true;
public barChartData:any[] = [
{data: [165, 159, 180, 181, 156, 155, 140], label: 'Maba'},
{data: [128, 148, 140, 119, 86, 127, 90], label: 'Alumni'}
];
}
You need to group the data and create the graph accordingly,
export class DashboardComponent implements OnInit {
#ViewChild(BaseChartDirective) private _chart;
lineChartLabels: String[] = [];
fromDate: NgbDateStruct;
toDate: NgbDateStruct;
role: string;
datasets: any[];
public lineChartOptions: any = {
animation: false,
responsive: true
};
public lineChartLegend = true;
public lineChartType = 'line';
constructor() { }
ngOnInit() {
this.datasets = [{ data: [] }];
}
forceChartRefresh() {
setTimeout(() => {
this._chart.refresh();
}, 10);
}
getChartDetails() {
this.lineChartLabels = [];
this.datasets = [];
this._reportService.getChartInfo(yourApi).subscribe((response) => {
const grouped = response.lstBalances.map(function (o) {
return {
data: o.AccountBalanceOnMonth.map(function (p) { return +p.year; }),
label: o.totalAlumni
};
});
this.buildchart(grouped, response.lstYears);
});
}
buildchart(data: any, labels: any) {
this.datasets = data;
for (const label of labels) {
this.lineChartLabels.push(label);
}
this.datasets = this.datasets.slice();
this.forceChartRefresh();
}
}
I've been going insane with this and can't figure this one out. I have data from my API formated like this:
"data": [
{
"sr_count": 91,
"month_name": "October",
"month_num": 10,
"year": 2017
},
{
"sr_count": 50,
"month_name": "September",
"month_num": 9,
"year": 2017
}
]
Which I need to take the data from "sr_count" and "month_name" re-format into their own array in order for chart.js to handed the data.
for instance:
["91","50"]
["October", "September"]
I have a reportService which is grabbing the data from my API
getSR(groupBy: string, beginDate:string, endDate:string): Observable<Report[]> {
return this.http.get(`${this.reportUrl}/SR?group_by="${groupBy}"&begin_date="${beginDate}"&end_date="${endDate}"`)
.map(res => res.json().data)
.catch(this.handleError);
}
From my component code I'm figured that I could map all the data from sr_count and month_name into an array, then push it into a local variable so that I could use it in the data for chart.js
export class SrReportsComponent implements OnInit {
monthName: [];
srCount1: [];
srCount2: [];
data: any;
ngOnInit() {
this.reportService.getSRLastMonth()
.subscribe(data => {
srCount= data.map(item => {
return item.sr_count
})
console.log(srCount) // ["October", "September"]
this.srCount2.push(srCount) // [["52", "41"]]
});
this.reportService.getSRThisMonth('Month',lastMonth,today)
.subscribe(data => {
monthName= data.map(item => {
return item.month_name
}
srCount= data.map(item => {
return item.sr_count
}
console.log(monthName) // ["October", "September"]
this.monthName.push(monthName) // [["October", "September"]]
this.srCount1.push(srCount) //[["91","50"]]
});
console.log(this.monthName)// [["October", "September"]]
this.data = {
labels: this.monthName, //returns []
datasets: [
{
label: 'First Dataset',
data: this.srCount1,
fill: false,
borderColor: '#4bc0c0'
},
{
label: 'Second Dataset',
data: this.srCount2,
fill: true,
borderColor: '#4ba0c0'
}
]
}
}
because using the push() method it seems to be nesting my the array which chart.js can't see. I've tried monthName[0] as well and get undefined in the console
What's the best way to get the array from the observable passed into a local variable so that I can get chart.js working?
just move your data inside your observable. You're working with asynchronous operation.
ngOnInit() {
this.reportService.getSR('Month',lastMonth,today)
.subscribe(response => {
this.data = {
labels: response.map(item => { return item.month_name });
datasets: [
{
label: 'First Dataset',
data: this.srCount,
fill: false,
borderColor: '#4bc0c0'
}
]
}
});
}
If all you need is to not "nest" the month name array you can use the array.push.apply(array, array2) approach (see link below).
So for your array:
this.monthName.push.apply(this.monthName, monthName);
https://stackoverflow.com/a/4156156/4219717
When I triggered an event coming from a method via an input it don't render properly the data to the chart here's an example of my pb:
My chart was working until I put it in the child. It looks like the data are not coming trough the child.
parent.html:
<div class="parent" >
<img src="black.png" type="button" (click)="displayChild()"/>
<my-child [displayDetail]="displayMe"></my-child>
</div>
parent.ts:
displayChild() {
this.displayMe = !this.displayMe;
child.html:
<div class="chart-pie">
<chart [options]="options" (load)="saveInstance($event.context)"
</chart>
</div>
child.ts:
#Input() displayDetail: boolean;
options: any;
data: Object[];
chart: any;
dataSubscription: Subscription;
constructor(private userService3: UserService3) {
this.options = {
chart: { type: 'pie',
series: [{
name: 'Dispo',
data: []
}]
};
saveInstance(chartInstance) {
this.chart = chartInstance;
console.log(chartInstance);
}
public ngOnInit () {
this.dataSubscription =
this.userService3.getData().subscribe((data) => {
this.options.series[0].data = data.data.operating_rate;
// Code for the pie
let percentUp = data.data.operating_rate; // 88.14
let percentDown = 100 - percentUp; // 11.86
this.options.series[0].data = [
{
name: 'Up',
y: percentUp,
color: '#648e59'
},
{
name: 'Down',
y: percentDown,
color: 'white'
}
];
console.log(data);
});
}
public ngOnDestroy() {
if (this.dataSubscription) {
this.dataSubscription.unsubscribe();
}
}
}
jsPDF allows to create a table form JSON data and save that table into a PDF document. I have created a Angualr2/Typescript application to do the same. This create table form my JSON data. I'm trying to use jsPDF is create a table with horizontal headers. Example for this given here. Code to create that is as follows.
// Horizontal - shows how tables can be drawn with horizontal headers
examples.horizontal = function () {
var doc = new jsPDF('p', 'pt');
doc.autoTable(getColumns().splice(1,4), getData(), {
drawHeaderRow: function() {
// Don't draw header row
return false;
},
columnStyles: {
first_name: {fillColor: [41, 128, 185], textColor: 255, fontStyle: 'bold'}
}
});
return doc;
};
Complete code is available here. This code is written in JavaScript. I'm looking for a way to convert this into Typescript. Does anyone have any idea how to do it?
Your component might look like this:
#Component({
selector: 'my-app',
template:
`<h1>JSON to PDF app</h1>
<div class="container" id="div1">
<button id="create" (click)="convert('base')">Create file</button>
<button id="create" (click)="convert('horizontal')">
Create file with horizontal table
</button>
</div>
`
})
export class AppComponent {
cols: Array<any> = [{
title: "Details",
dataKey: 'details'
}, {
title: "Values",
dataKey: 'values'
}];
optionsContainer = {
base: {},
horizontal: {
drawHeaderRow: () => false,
columnStyles: {
details: {fillColor: [41, 128, 185], textColor: 255, fontStyle: 'bold'}
}
}
};
rows: Array<any> = [];
constructor() {
const item = {
"Name" : "XYZ",
"Age" : "22",
"Gender" : "Male"
};
this.rows = Object.keys(item).map((key) => {
return { 'details': key, 'values': item[key] };
});
}
convert(action){
const doc = new jsPDF()
.autoTable(this.cols, this.rows, this.optionsContainer[action]);
doc.save('Test.pdf');
}
}
Demo Plunker