在 Angular 10 中使用 chart.js 创建多个动态堆叠图表?
Create multiple dynamic stacked chart using chart.js in Angular 10?
我正在尝试在 angular 中创建多个图表,但我不确定我尝试实施的方式是否正确,而且我无法创建多个图表并将一个图表替换为另一个图表
<div *ngIf="chartData.length !== 0">
<app-limus-utilisation-chart
*ngFor="let entity of chartData" [chartdata]="entity"
></app-limus-utilisation-chart>
</div>
ChartComponent.ts
getStackedChart() {
const canvas: any = document.getElementById('canvas1');
const ctx = canvas.getContext('2d');
var data = {
labels: this.chartdata.buyernames,
datasets: [{
label: 'Utilised Limit',
data: this.chartdata.utilisedlimitData,
backgroundColor: '#22aa99'
}, {
label: 'Available Limit',
data: this.chartdata.availablelimit,
backgroundColor: '#994499'
}]
}
chartJsLoaded$.pipe(take(1)).subscribe(() => {
setTimeout(() => {
this.myChart = new Chart(ctx, {
type: 'bar',
data: data,
options: {
tooltips: {
mode: 'index',
intersect: true,
position: 'custom',
yAlign: 'bottom'
},
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
stacked: false,
display: false
}]
}
}
});
})
})
}
我试了两种方法
使用视图子图表未创建,getElementById 图表已创建但第二个图表替换了第一个。但我想要并排放置两个堆叠图表 如何实现这一点
当前图表采用低于 100 个值,但根据我的实际要求,我需要显示 tootip 金额,如 (1000000, 700000) 也是货币格式
像这样我试图实现
https://stackblitz.com/edit/angular-chart-js-j26qhm?file=src%2Fapp%2Fapp.component.html
请多多指教
得到答案后,我取得了一些成就
问题是这里的这一行:
const canvas: any = document.getElementById('canvas1');
您在页面上有多个具有该 ID 的元素(因为您使用了 *ngFor),因此它始终将自身附加到页面上的第一个元素。
您应该使用 Angular 的 built-in @ViewChild
.
而不是使用 getElementByID
像这样:
chart.component.html:
<canvas #stackchartcanvas></canvas>
chart.component.ts:
@ViewChild("stackchartcanvas") myCanvas: ElementRef<HTMLCanvasElement>;
....
....
....
getStackedChart() {
const canvas = this.myCanvas.nativeElement;
}
Stackblitz:https://stackblitz.com/edit/angular-chart-js-kny4en?file=src%2Fapp%2Fchart.component.ts
(此外,在您的原始代码中,this.chartData.push()
运行 每次单击复选框时,即使该复选框为假,但这是一个不同的、不相关的问题,也已修复.)
您可以使用 ViewChild
来引用 html 元素并在您的组件中使用它。我还修改了您的代码中的一些内容以切换图表。
总结:
- 使用
ViewChild
访问组件中的 html 元素
- 更新了应用程序组件以切换图表,而不是仅仅添加数据
- 更新标签以接受点击事件来切换复选框
app.component.html
<label>
<input type="checkbox" value=1
(change)="chooseEntity($event.target.checked, 1, entityData[0])">
Microsoft
</label>
<label>
<input type="checkbox" (change)="chooseEntity($event.target.checked, 2, entityData[1])">
IBM
</label>
<div *ngIf="chartData.length !== 0">
<app-limus-utilisation-chart *ngFor="let entity of chartData" [chartdata]="entity"></app-limus-utilisation-chart>
</div>
chart.component.html
<div #chartReport>
<canvas #canvas></canvas>
</div>
chart.component.ts
import {
Component,
ElementRef,
Input,
OnInit,
ViewChild,
ViewEncapsulation
} from "@angular/core";
import { Chart } from "chart.js";
import { OnChanges } from "@angular/core";
@Component({
selector: "app-limus-utilisation-chart",
templateUrl: "./chart.component.html",
encapsulation: ViewEncapsulation.None
})
export class LimusUtilisationChartComponent implements OnInit, OnChanges {
myChart: Chart;
@Input() chartdata: any;
@ViewChild("canvas") stackchartcanvas: ElementRef;
constructor() {}
ngOnChanges() {
this.getStackedChart();
}
ngOnInit(): void {
this.getStackedChart();
}
getStackedChart() {
Chart.Tooltip.positioners.custom = function(elements, position) {
//debugger;
return {
x: position.x,
y:
elements[0]._view.base - (elements[0].height() + elements[1].height())
};
};
const canvas: any = this.stackchartcanvas.nativeElement;
const ctx = canvas.getContext("2d");
var data = {
labels: this.chartdata.buyernames,
datasets: [
{
label: "Utilised Limit",
data: this.chartdata.utilisedlimitData,
backgroundColor: "#22aa99"
},
{
label: "Available Limit",
data: this.chartdata.availablelimit,
backgroundColor: "#994499"
}
]
};
setTimeout(() => {
this.myChart = new Chart(ctx, {
type: "bar",
data: data,
options: {
tooltips: {
mode: "index",
intersect: true,
position: "custom",
yAlign: "bottom"
},
scales: {
xAxes: [
{
stacked: true
}
],
yAxes: [
{
stacked: false,
display: false
}
]
}
}
});
});
}
}
我正在尝试在 angular 中创建多个图表,但我不确定我尝试实施的方式是否正确,而且我无法创建多个图表并将一个图表替换为另一个图表
<div *ngIf="chartData.length !== 0">
<app-limus-utilisation-chart
*ngFor="let entity of chartData" [chartdata]="entity"
></app-limus-utilisation-chart>
</div>
ChartComponent.ts
getStackedChart() {
const canvas: any = document.getElementById('canvas1');
const ctx = canvas.getContext('2d');
var data = {
labels: this.chartdata.buyernames,
datasets: [{
label: 'Utilised Limit',
data: this.chartdata.utilisedlimitData,
backgroundColor: '#22aa99'
}, {
label: 'Available Limit',
data: this.chartdata.availablelimit,
backgroundColor: '#994499'
}]
}
chartJsLoaded$.pipe(take(1)).subscribe(() => {
setTimeout(() => {
this.myChart = new Chart(ctx, {
type: 'bar',
data: data,
options: {
tooltips: {
mode: 'index',
intersect: true,
position: 'custom',
yAlign: 'bottom'
},
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
stacked: false,
display: false
}]
}
}
});
})
})
}
我试了两种方法
使用视图子图表未创建,getElementById 图表已创建但第二个图表替换了第一个。但我想要并排放置两个堆叠图表 如何实现这一点
当前图表采用低于 100 个值,但根据我的实际要求,我需要显示 tootip 金额,如 (1000000, 700000) 也是货币格式
像这样我试图实现 https://stackblitz.com/edit/angular-chart-js-j26qhm?file=src%2Fapp%2Fapp.component.html
请多多指教
得到答案后,我取得了一些成就
问题是这里的这一行:
const canvas: any = document.getElementById('canvas1');
您在页面上有多个具有该 ID 的元素(因为您使用了 *ngFor),因此它始终将自身附加到页面上的第一个元素。
您应该使用 Angular 的 built-in @ViewChild
.
像这样:
chart.component.html:
<canvas #stackchartcanvas></canvas>
chart.component.ts:
@ViewChild("stackchartcanvas") myCanvas: ElementRef<HTMLCanvasElement>;
....
....
....
getStackedChart() {
const canvas = this.myCanvas.nativeElement;
}
Stackblitz:https://stackblitz.com/edit/angular-chart-js-kny4en?file=src%2Fapp%2Fchart.component.ts
(此外,在您的原始代码中,this.chartData.push()
运行 每次单击复选框时,即使该复选框为假,但这是一个不同的、不相关的问题,也已修复.)
您可以使用 ViewChild
来引用 html 元素并在您的组件中使用它。我还修改了您的代码中的一些内容以切换图表。
总结:
- 使用
ViewChild
访问组件中的 html 元素 - 更新了应用程序组件以切换图表,而不是仅仅添加数据
- 更新标签以接受点击事件来切换复选框
app.component.html
<label>
<input type="checkbox" value=1
(change)="chooseEntity($event.target.checked, 1, entityData[0])">
Microsoft
</label>
<label>
<input type="checkbox" (change)="chooseEntity($event.target.checked, 2, entityData[1])">
IBM
</label>
<div *ngIf="chartData.length !== 0">
<app-limus-utilisation-chart *ngFor="let entity of chartData" [chartdata]="entity"></app-limus-utilisation-chart>
</div>
chart.component.html
<div #chartReport>
<canvas #canvas></canvas>
</div>
chart.component.ts
import {
Component,
ElementRef,
Input,
OnInit,
ViewChild,
ViewEncapsulation
} from "@angular/core";
import { Chart } from "chart.js";
import { OnChanges } from "@angular/core";
@Component({
selector: "app-limus-utilisation-chart",
templateUrl: "./chart.component.html",
encapsulation: ViewEncapsulation.None
})
export class LimusUtilisationChartComponent implements OnInit, OnChanges {
myChart: Chart;
@Input() chartdata: any;
@ViewChild("canvas") stackchartcanvas: ElementRef;
constructor() {}
ngOnChanges() {
this.getStackedChart();
}
ngOnInit(): void {
this.getStackedChart();
}
getStackedChart() {
Chart.Tooltip.positioners.custom = function(elements, position) {
//debugger;
return {
x: position.x,
y:
elements[0]._view.base - (elements[0].height() + elements[1].height())
};
};
const canvas: any = this.stackchartcanvas.nativeElement;
const ctx = canvas.getContext("2d");
var data = {
labels: this.chartdata.buyernames,
datasets: [
{
label: "Utilised Limit",
data: this.chartdata.utilisedlimitData,
backgroundColor: "#22aa99"
},
{
label: "Available Limit",
data: this.chartdata.availablelimit,
backgroundColor: "#994499"
}
]
};
setTimeout(() => {
this.myChart = new Chart(ctx, {
type: "bar",
data: data,
options: {
tooltips: {
mode: "index",
intersect: true,
position: "custom",
yAlign: "bottom"
},
scales: {
xAxes: [
{
stacked: true
}
],
yAxes: [
{
stacked: false,
display: false
}
]
}
}
});
});
}
}