我使用am4chart,我得到了一个错误,在我的控制台: html container not found
. 导致这个错误的是我的angular组件的这一行。 var chart = am4core.create("graphdiv", am4charts.XYChart);
控制台中的stacktrace 。
function createChild(htmlElement, classType) {
var htmlContainer = $dom.getElement(htmlElement);
if (htmlContainer) {
...
}
else {
system.log("html container not found");
throw new Error("html container not found");
}
}
所以基本上我的理解是,这行......是在图形div元素存在之前执行的。var chart = am4core.create("graphdiv", am4charts.XYChart);
是在DOM中graphdiv元素存在之前执行的,因为它没有找到graphdiv的HTML元素。
所以我所做的是,我把我的代码复制粘贴到了 ngAfterViewInit
angular函数,以确保创建am4chart图表的脚本是在运行脚本之前执行的,以确保DOM存在。
我的afterViewInit函数 。
ngAfterViewInit(): void {
console.log("CREATE GRAPH AFTER VIEW INIT")
this.createGraph();
}
但我看到的是 console.log("CREATE GRAPH AFTER VIEW INIT")实际上是在DOM完全渲染之前执行的,所以我所做的并没有让我的错误消失。html container not found
createGraph()。
createGraph() {
console.log("CREATE GRAAAAPH");
// Create chart instance
am4core.ready(function() {
var chart = am4core.create("graphdiv", am4charts.XYChart);
chart.numberFormatter.numberFormat = this.currencyBefore + "#,####,###.##" + this.currencyAfter;
chart.data = [];
var cumul = 0;
for (var i = 0; i < 37; i++) {
if (i == 0) {
chart.data.push({ "month": "", "units": 0 });
}
else if (i == 1) {
cumul = cumul + this.AppComponent.activeDetailedResults.prices.upfrontYear1 + this.AppComponent.activeDetailedResults.prices.monthlyPrice;
chart.data.push({ "month": "M" + i, "units": cumul });
}
else if (i == 13) {
cumul = cumul + this.AppComponent.activeDetailedResults.prices.upfrontYear2 + this.AppComponent.activeDetailedResults.prices.monthlyPrice;
chart.data.push({ "month": "M" + i, "units": cumul });
}
else if (i == 25) {
cumul = cumul + this.AppComponent.activeDetailedResults.prices.upfrontYear3 + this.AppComponent.activeDetailedResults.prices.monthlyPrice;
chart.data.push({ "month": "M" + i, "units": cumul });
}
else {
cumul = cumul + this.AppComponent.activeDetailedResults.prices.monthlyPrice;
chart.data.push({ "month": "M" + i, "units": cumul });
}
}
// Create axes
let categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "month";
categoryAxis.renderer.labels.template.disabled = true
categoryAxis.title.text = "Time (36 months)";
let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.renderer.labels.template.disabled = false;
// Create series
var series2 = chart.series.push(new am4charts.LineSeries());
series2.name = "Units";
series2.stroke = am4core.color("#551A8B");
series2.strokeWidth = 3;
series2.dataFields.valueY = "units";
series2.dataFields.categoryX = "month";
series2.fillOpacity = 0.5;
});
}
模板 :
<mat-card class="startcard">
<p class="mat-title">Cumulative expenses: </p>
<mat-card-content style="text-align: center;">
<div fxLayout="row" fxLayoutAlign="space-around center">
<div id="graphdiv"></div>
</div>
</mat-card-content>
</mat-card>
所以问题是在创建组件时元素不可见,因为你在等待API调用。你可以让 ViewChild
一个设定器。
如果这是你的模板,
<mat-card class="startcard">
<p class="mat-title">Cumulative expenses: </p>
<mat-card-content style="text-align: center;">
<div fxLayout="row" fxLayoutAlign="space-around center">
<div #graphdiv></div>
</div>
</mat-card-content>
</mat-card>
你可以把你的组件做成下面这个样子。
private _div?: HTMLElement;
@ViewChild('graphdiv')
set graphDiv(div: ElementRef<HTMLElement>) {
if (div && div.nativeElement && this._div !== div.nativeElement) {
this._div = div.nativeElement;
this.createGraph();
}
}
createGraph() {
am4core.ready(() => {
const chart = am4core.create(this._div, am4charts.XYChart);
});
}
这样你就不需要再去做了。ngAfterViewInit
钩子或API调用后。它将自动完成
你可以试着把你的代码移到 ngAfterViewChecked
的方法。作为另一种尝试是使用 setTimeout
用0时间和你的代码里面。