How show chart ng2-chart from database? - html

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();
}
}

Related

The chart.js/ng2-charts is not displaying the data given

I've developed a website in Angular 14 that treat about cryptocurrencies using the CoinGecko API.
I wanted to display a chart for every cryptocurrency on a specific page using chart.js and ng2-charts.
I've parsed the data sent by the API and used it in my chart but it is not showing the line chart expected.
Here is a service that is getting the data from the API and parse it:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import {map, Observable, Subscription } from 'rxjs';
#Injectable({
providedIn: 'root',
})
export class SingleCryptoGraphService {
subscription: Subscription;
doubletab: any = {
date : Array<string>(),
price: Array<number>(),
};
constructor(private httpClient: HttpClient) {
this.subscription = Subscription.EMPTY;
}
HistoricalChart(id: string, currency: string, days: number): Observable<any> {
return this.httpClient
.get<any[]>(
'https://api.coingecko.com/api/v3/coins/'+id+'/market_chart?vs_currency='+currency+'&days='+days+'&interval=daily').pipe(
map( (obj: any) => obj['prices']),
map((tab: any[]) => {
const res = [];
for (let i = 0; i < tab.length; i++) {
this.doubletab.date.push(this.getDate(tab[i][0]));
this.doubletab.price.push(this.convertToNumber(tab[i][1]));
}
console.log(this.doubletab);
return this.doubletab;
}
)
);
}
getDate = (date: number) : string => {
let d = new Date(date)
let day = d.getDate()
let month = d.getMonth() + 1
let year = d.getFullYear()
return day + "/" + month + "/" + year
}
convertToNumber = (str: string) : number => {
return Number(str)
}
}
Here is the chart component TypeScript:
import { Component, OnDestroy, OnInit, Input, ViewChild } from '#angular/core';
import { SingleCryptoGraphService } from '../single-crypto-graph.service';
import { Subscription } from 'rxjs';
import { Chart, ChartConfiguration, ChartEvent, ChartType } from 'chart.js';
import { BaseChartDirective } from 'ng2-charts';
#Component({
selector: 'app-crypto-graph',
templateUrl: './crypto-graph.component.html',
styleUrls: ['./crypto-graph.component.css']
})
export class CryptoGraphComponent implements OnInit, OnDestroy {
subscription3: Subscription
chartInfoTabs: any = {
date: Array<string>(),
price: Array<number>(),
}
#Input() id = ''
constructor(private SingleCryptoGraphService:SingleCryptoGraphService) {
this.subscription3 = Subscription.EMPTY;
this.id = "none";
}
ngOnInit(): void {
this.subscription3.unsubscribe()
this.subscription3 = this.SingleCryptoGraphService.HistoricalChart(this.id,"eur",30).subscribe(
(data) => {
this.chartInfoTabs.date = data.date;
this.chartInfoTabs.price = data.price;
}
);
}
ngOnDestroy() {
this.subscription3.unsubscribe()
}
public lineChartData: ChartConfiguration['data'] = {
datasets: [{
data: this.chartInfoTabs.price,
label: this.id,
backgroundColor: 'rgba(148,159,177,0.2)',
borderColor: 'rgba(148,159,177,1)',
pointBackgroundColor: 'rgba(148,159,177,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(148,159,177,0.8)',
fill: 'origin',
}],
labels: this.chartInfoTabs.date,
}
public lineChartOptions: ChartConfiguration['options'] = {
elements: {
line: {
tension: 0.5
}
},
scales: {
y:
{
position: 'left',
},
},
};
public lineChartType: ChartType = 'line';
#ViewChild(BaseChartDirective) chart?: BaseChartDirective;
}
And here is the canvas used to display the chart and the result I got:
<canvas baseChart class="chart"
[data]="lineChartData"
[options]="lineChartOptions"
[type]="lineChartType"
(chartHover)="chartHovered($event)">
</canvas>
What's actually shown by my code
I suspect my tables of data implement the wrong type but I can't figure out why because they seem to be right.
I would really appreciate help with this problem because I really don't understand why it is not working.

Pass data from parent component to child component using input, how to implement?

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.

Dynamic id with canvas on html and angular

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();
}

#Input data binding not rendering to the child using Highcharts api

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();
}
}
}

how to get data from static JSON for table, https://github.com/valor-software/ng2-table.iam using ng-2 table

how to get data from json rather from table-data.ts
iam confused.tried my best cant able to find the solution.where should i do alteration i think from private data:array=TableData;
It will be helpful if anyone give a solution.
Demo.component.ts
export class TableDemoComponent implements OnInit { public rows:Array<any> = [];
public columns:Array<any> = [
{title: 'Company', name: 'name', filtering: {filterString: '', placeholder: 'Filter by name'}},
{
title: 'Position',
name: 'position',
sort: false,
filtering: {filterString: '', placeholder: 'Filter by position'}
},
{title: 'Location', name: 'office', sort: '', filtering: {filterString: '', placeholder: 'Filter by Location'}},
{title: 'Date', className: 'text-warning', name: 'startDate'},];
public page:number = 1;
public itemsPerPage:number = 10;
public maxSize:number = 5;
public numPages:number = 1;
public length:number = 0;
public config:any = {
paging: true,
sorting: {columns: this.columns},
filtering: {filterString: ''},
className: ['table-striped', 'table-bordered']
};
private data:Array<any> = TableData;
public constructor() {
this.length = this.data.length;
}
public ngOnInit():void {
this.onChangeTable(this.config);
}
public changePage(page:any, data:Array<any> = this.data):Array<any> {
let start = (page.page - 1) * page.itemsPerPage;
let end = page.itemsPerPage > -1 (startpage.itemsPerPage):data.length;
return data.slice(start, end);
}
public changeSort(data:any, config:any):any {
if (!config.sorting) {
return data;
}
let columns = this.config.sorting.columns || [];
let columnName:string = void 0;
let sort:string = void 0;
for (let i = 0; i < columns.length; i++) { if(columns[i].sort!==''&&columns[i].sort!==false{columnNamecolumns[i].name;
sort = columns[i].sort;
}
}
if (!columnName) {
return data;
}
// simple sorting
return data.sort((previous:any, current:any) => {
if (previous[columnName] > current[columnName]) {
return sort === 'desc' ? -1 : 1;
} else if (previous[columnName] < current[columnName]) {
return sort === 'asc' ? -1 : 1;
}
return 0;
});
}
public changeFilter(data:any, config:any):any {
let filteredData:Array<any> = data;
this.columns.forEach((column:any) => {
if (column.filtering) {
filteredData = filteredData.filter((item:any) => {
return item[column.name].match(column.filtering.filterString); });
}
});
if (!config.filtering) {
return filteredData;
}
if (config.filtering.columnName) {
return filteredData.filter((item:any) => item[config.filtering.columnName].match(this.config.filtering.filterString));
}
let tempArray:Array<any> = [];
filteredData.forEach((item:any) => {
let flag = false;
this.columns.forEach((column:any) => {
if (item[column.name].toString().match(this.config.filtering.filterString)) {
flag = true;
}
});
if (flag) {
tempArray.push(item);
}
});
filteredData = tempArray;
return filteredData;
}
public onChangeTable(config:any, page:any = {page: this.page,itemsPerPage: this.itemsPerPage}):any {
if (config.filtering) {
Object.assign(this.config.filtering, config.filtering);
}
if (config.sorting) {
Object.assign(this.config.sorting, config.sorting);
}
let filteredData = this.changeFilter(this.data, this.config);
let sortedData = this.changeSort(filteredData, this.config);
this.rows = page && config.paging ? this.changePage(page,sortedData):sortedData;
this.length = sortedData.length;
}
public onCellClick(data: any): any {
console.log(data);
}}
Datatable.ts
export const TableData:Array<any> = [
{
'name': 'Victoria Cantrell',
'position': 'Integer Corporation',
'office': 'Croatia',
'ext': `<strong>0839</strong>`,
'startDate': '2015/08/19',
'salary': 208.178
}, {
'name': 'Pearl Crosby',
'position': 'In PC',
'office': 'Cambodia',
'ext': `<strong>8262</strong>`,
'startDate': '2014/10/08',
'salary': 114.367
}, {
'name': 'Colette Foley',
'position': 'Lorem Inc.',
'office': 'Korea, North',
'ext': '8968',
'startDate': '2015/07/19',
'salary': 721.473
}
];
Table-demo.html
<div class="row">
<div class="col-md-4">
<input *ngIf="config.filtering" placeholder="Filter allcolumns"
[ngTableFiltering]="config.filtering"
class="form-control"
(tableChanged)="onChangeTable(config)"/>
</div>
</div>
<br>
<ng-table [config]="config"
(tableChanged)="onChangeTable(config)"
(cellClicked)="onCellClick($event)"
[rows]="rows" [columns]="columns">
</ng-table>
<pagination *ngIf="config.paging"
class="pagination-sm"
[(ngModel)]="page"
[totalItems]="length"
[itemsPerPage]="itemsPerPage"
[maxSize]="maxSize"
[boundaryLinks]="true"
[rotate]="false"
(pageChanged)="onChangeTable(config, $event)"
(numPages)="numPages = $event">
</pagination>
If you wanted to use the TableData in a different file you would have to import it. I have added an example at the top that show you how to import it. All you do is just create another file and import what you need. I tidied up your code and fixed some syntax errors and put some notes next to bits where stuff was undefined which would throw errors also put some explanations next to the top in how to import things:
import {OnInit} from "#angular/core"
import {TableData} from "./test2" //test2 is the name of the file
// ./ current directory
// ../../ up two directories
export class TableDemoComponent implements OnInit {
public rows: Array<any> = [];
public columns: Array<any> =
[
{
title: 'Company',
name: 'name',
filtering: {
filterString: '', placeholder: 'Filter by name'
}
},
{
title: 'Position',
name: 'position',
sort: false,
filtering: {
filterString: '', placeholder: 'Filter by position'
}
},
{
title: 'Location',
name: 'office',
sort: '',
filtering: {
filterString: '', placeholder: 'Filter by Location'
}
},
{
title: 'Date',
className: 'text-warning',
name: 'startDate'
}
];
public page: number = 1;
public itemsPerPage: number = 10;
public maxSize: number = 5;
public numPages: number = 1;
public length: number = 0;
public config: any = {
paging: true,
sorting: {columns: this.columns},
filtering: {filterString: ''},
className: ['table-striped', 'table-bordered']
};
private data: Array<any> = TableData;
public constructor() {
this.length = this.data.length;
}
public ngOnInit(): void {
this.onChangeTable(this.config);
}
public changePage(page: any, data: Array<any> = this.data): Array<any> {
let start = (page.page - 1) * page.itemsPerPage;
//startpage is not defined
let end = page.itemsPerPage > -1 ? startpage.itemsPerPage : data.length;
return data.slice(start, end);
}
public changeSort(data: any, config: any): any {
if (!config.sorting) {
return data;
}
let columns = this.config.sorting.columns || [];
let columnName: string = void 0;
let sort: string = void 0;
for (let i = 0; i < columns.length; i++) {
if (columns[i].sort !== '' && columns[i].sort !== false) {
//columnNamecolumns is not defined
columnNamecolumns[i].name;
sort = columns[i].sort;
}
}
if (!columnName) {
return data;
}
// simple sorting
return data.sort((previous: any, current: any) => {
if (previous[columnName] > current[columnName]) {
return sort === 'desc' ? -1 : 1;
} else if (previous[columnName] < current[columnName]) {
return sort === 'asc' ? -1 : 1;
}
return 0;
});
}
public changeFilter(data: any, config: any): any {
let filteredData: Array<any> = data;
this.columns.forEach((column: any) => {
if (column.filtering) {
filteredData = filteredData.filter((item: any) => {
return item[column.name].match(column.filtering.filterString);
});
}
});
if (!config.filtering) {
return filteredData;
}
if (config.filtering.columnName) {
return filteredData.filter((item: any) => item[config.filtering.columnName].match(this.config.filtering.filterString));
}
let tempArray: Array<any> = [];
filteredData.forEach((item: any) => {
let flag = false;
this.columns.forEach((column: any) => {
if (item[column.name].toString().match(this.config.filtering.filterString)) {
flag = true;
}
});
if (flag) {
tempArray.push(item);
}
});
filteredData = tempArray;
return filteredData;
}
public onChangeTable(config: any, page: any = {page: this.page, itemsPerPage: this.itemsPerPage}): any {
if (config.filtering) {
Object.assign(this.config.filtering, config.filtering);
}
if (config.sorting) {
Object.assign(this.config.sorting, config.sorting);
}
let filteredData = this.changeFilter(this.data, this.config);
let sortedData = this.changeSort(filteredData, this.config);
this.rows = page && config.paging ? this.changePage(page, sortedData) : sortedData;
this.length = sortedData.length;
}
public onCellClick(data: any): any {
console.log(data);
}
}
I hope this is what you meant for. I am reading my data from external source (not json - but I think this is the same) by this way:
public constructor(private dataService: DataService ){
this.dataService.getUsers().then(users => {this.data = users; this.length = this.data.length;}).
catch(error => this.error = error);
}
public ngOnInit():void {
this.dataService.getUsers().then(users => {this.data = users; this.onChangeTable(this.config);}).
catch(error => this.error = error);
}
in this example my data is users. I am calling it from my data service. I hope it helps.