尝试在 Bootstrap 模态内动态生成图表,出现 offsetWidth 错误
Trying to dynamically generate chart inside a Bootstrap modal, getting offsetWidth Error
我正在使用基于 HTML5 的库 chartjs 在 Bootstrap 模态主体内动态绘制图表。一切都很好,我可以看到正确的数据和标签数组已被传递,并且 canvas HTML 节点已创建,但我收到此错误:
Uncaught TypeError: Cannot read property 'offsetWidth' of undefined
我想也许我调用这个函数太早了:
new Chart(--> HTML node <--).get(0).getContext("2d").Bar(--> data <--);
所以我把它放在 setTimeout() 块中,以便在附加 canvas HTML 节点大约 2 秒后调用该函数,但我仍然收到该错误并且看不到图表。
这是完整的代码 (github, Dropbox),这是我调用图表库的部分:
document.getElementById("modalBody").appendChild(canvasElement);
setTimeout(function () {
var ctx = document.getElementsByTagName("canvas")[0];
var myNewChart = new Chart(ctx).get(0).getContext("2d").Bar(finalData);
return finalData;
}, 2000);
我设法让这个在 Plunkr 中工作。
我为 contextualizeForType2()
和 contextualizeForType3()
所做的基本更改如下:
- 实例化条形图组件的正确方法是使用您附加的 canvas 元素的 2D 上下文。在代码中,
var ctx = ...
行后有 new Chart(ctx.getContext('2d')).Bar(finalData);
。但是,由于模态框尚未显示,因此它的高度和宽度将为 0。
- 要让图表使用正确的高度和宽度,您应该绑定到
shown.bs.modal
事件,该事件在模态完成动画后触发。在该事件处理程序中是您创建图表的地方。棘手的部分是因为您有两个不同的问题重用相同的模式。所以我添加了一个额外的命名空间 .typeX
,当模态被隐藏时我取消注册我的事件。
我知道第二点令人困惑,但希望代码能解决问题:
var ctx = document.getElementsByTagName("canvas")[0];
$('#myModal').on({
'shown.bs.modal.type2': function() {
new Chart(ctx.getContext("2d")).Bar(finalData);
},
'hidden.bs.modal.type2': function() {
this.off('.type2');
}
});
这意味着一旦模态被隐藏,这两个函数将不会在为另一种类型显示相同模态时再次获得 运行。此外,由于每次单击按钮时都会添加一个新的处理程序,因此您不会创建比需要更多的图表。
替代方法
我有 a further play,发现我可以将代码重构为一个函数,可以从 contextualizeForType2()
和 contextualizeForType3()
调用,传入 finalData
.这样做的好处是将所有 canvas 和图表初始化代码放在一个地方,稍微简化您的大型函数并使其更易于维护。
函数是:
function showModalChart(data) {
var canvasElement = document.createElement("CANVAS");
canvasElement.setAttribute("width", "400");
canvasElement.setAttribute("height", "400");
document.getElementById("modalBody").appendChild(canvasElement);
var ctx = document.getElementsByTagName("canvas")[0];
$('#myModal').off('.modalchart').on('shown.bs.modal.modalchart', function () {
new Chart(ctx.getContext('2d')).Bar(data);
});
}
我正在使用基于 HTML5 的库 chartjs 在 Bootstrap 模态主体内动态绘制图表。一切都很好,我可以看到正确的数据和标签数组已被传递,并且 canvas HTML 节点已创建,但我收到此错误:
Uncaught TypeError: Cannot read property 'offsetWidth' of undefined
我想也许我调用这个函数太早了:
new Chart(--> HTML node <--).get(0).getContext("2d").Bar(--> data <--);
所以我把它放在 setTimeout() 块中,以便在附加 canvas HTML 节点大约 2 秒后调用该函数,但我仍然收到该错误并且看不到图表。
这是完整的代码 (github, Dropbox),这是我调用图表库的部分:
document.getElementById("modalBody").appendChild(canvasElement);
setTimeout(function () {
var ctx = document.getElementsByTagName("canvas")[0];
var myNewChart = new Chart(ctx).get(0).getContext("2d").Bar(finalData);
return finalData;
}, 2000);
我设法让这个在 Plunkr 中工作。
我为 contextualizeForType2()
和 contextualizeForType3()
所做的基本更改如下:
- 实例化条形图组件的正确方法是使用您附加的 canvas 元素的 2D 上下文。在代码中,
var ctx = ...
行后有new Chart(ctx.getContext('2d')).Bar(finalData);
。但是,由于模态框尚未显示,因此它的高度和宽度将为 0。 - 要让图表使用正确的高度和宽度,您应该绑定到
shown.bs.modal
事件,该事件在模态完成动画后触发。在该事件处理程序中是您创建图表的地方。棘手的部分是因为您有两个不同的问题重用相同的模式。所以我添加了一个额外的命名空间.typeX
,当模态被隐藏时我取消注册我的事件。
我知道第二点令人困惑,但希望代码能解决问题:
var ctx = document.getElementsByTagName("canvas")[0];
$('#myModal').on({
'shown.bs.modal.type2': function() {
new Chart(ctx.getContext("2d")).Bar(finalData);
},
'hidden.bs.modal.type2': function() {
this.off('.type2');
}
});
这意味着一旦模态被隐藏,这两个函数将不会在为另一种类型显示相同模态时再次获得 运行。此外,由于每次单击按钮时都会添加一个新的处理程序,因此您不会创建比需要更多的图表。
替代方法
我有 a further play,发现我可以将代码重构为一个函数,可以从 contextualizeForType2()
和 contextualizeForType3()
调用,传入 finalData
.这样做的好处是将所有 canvas 和图表初始化代码放在一个地方,稍微简化您的大型函数并使其更易于维护。
函数是:
function showModalChart(data) {
var canvasElement = document.createElement("CANVAS");
canvasElement.setAttribute("width", "400");
canvasElement.setAttribute("height", "400");
document.getElementById("modalBody").appendChild(canvasElement);
var ctx = document.getElementsByTagName("canvas")[0];
$('#myModal').off('.modalchart').on('shown.bs.modal.modalchart', function () {
new Chart(ctx.getContext('2d')).Bar(data);
});
}