AngularJS 标签中的 Highcharts 动态(重新)调整大小
Highcharts dynamic (re-)sizing in AngularJS tabs
我的应用程序在各种选项卡中显示 HighCharts 图表(使用 AngularJS)。请注意,图表会在运行时重新生成 每次选择选项卡时 (意味着每次 Angular "removes or recreates a portion of the DOM tree")。
我的问题是图表的大小是正确的只是第一次我单击了一个选项卡。当我切换选项卡时,创建的图表大大超过了它们容器的大小。令人惊讶的是,图表在 window 调整大小后(即调用 chart.reflow()
时)正确调整大小。
所以我尝试了以下方法,但没有帮助:
$(element).highcharts({
chart: {
type: 'scatter',
zoomType: 'xy',
events: {
load: function () {
this.reflow();
}
}
},
...
最后,下面的方法确实奏效了,但感觉像是 hack。
$(element).highcharts({
chart: {
type: 'scatter',
zoomType: 'xy',
events: {
load: function () {
var chart = this;
setTimeout(function () { chart.reflow(); }, 0);
}
}
},
...
知道问题出在哪里吗?我在这上面花了好几个小时,这真令人沮丧...
编辑:我还有另一个相关问题:默认情况下,我的图表具有给定的大小,但我有一个 "enlarge" 按钮可以让它们占据完整的 space。该按钮只需切换 CSS class 即可。但是,这样做 不会 触发调整大小事件,因此不会触发重排。所以我有同样的问题,图表没有填满他们的容器。
这里有一个 fiddle 来演示这个问题:
http://jsfiddle.net/swaek268/3/
再次,我找到了解决问题的方法,但感觉更像是一个更大的 hack。
var width = 0;
var planreflow = function(){
setTimeout(function(){
if(width!==$('#container').width()){
$('#container').highcharts().reflow();
console.log('reflow!')
}
width = $('#container').width();
planreflow();
}, 10);
};
planreflow();
所以,其实你有两个问题:
1) 第二次点击时尺寸不正确。这很可能是由于隐藏 (display: none
) 容器的宽度和高度错误造成的。在这种情况下,浏览器会报告不正确的 width/height(如 0px
)。同样的问题here and here.
2) 为容器设置 class 不会触发图表的 resize
(或者 reflow
)事件。这意味着您需要自己调用 chart.reflow()
。我建议在您更改 class.
的同一位置执行此操作
我想我找到了两个问题的解决方案:
- 图表完成加载时尺寸错误:
问题不是出在Highcharts,而是出在图表创建的时间上。我直接从 Angular 指令的 link()
函数中调用了 .highcharts()
。 JS 看起来基本上是这样的:
app.directive('dynamicView', function() {
return {
link: function(scope, element, attrs){
$(element).highcharts({...});
},
};
});
由于我的元素也有一个 ng-if
指令,具体取决于选项卡是否被选中,我想当该条件变为 true
时,angular 调用 link()
函数在确定元素的尺寸之前(我想 HTML 必须准备好才能确定元素的大小)。所以我认为问题是我在文档准备好之前调用了 .highcharts()
。由于某些我仍然不明白的原因,元素的大小在第一次 ng-if 变为 true 时是正确的,但下一次就不正确了。
无论如何,一个解决方案(仍然不是很优雅 - 但比调用 reflow()
更好)是延迟对 .highcharts()
本身的调用,以确保 HTML 已准备就绪创建图表时:
link: function(scope, element, attrs){
setTimeout(function () {
$(element).highcharts({...});
}, 0);
}
感谢 @Pavel Fus 对 .highcharts()
和 setTimeout()
.
行为的评论
- 切换 class
时图表未调整大小
对于这个问题,我利用了 Angular 的事件系统。
在我控制全屏按钮的控制器中:
$scope.toggleFullScreen = function(e){
$scope.$broadcast('fullscreen');
}
此事件沿层次结构向下传递,最终到达包含图表的我的指令。在创建我的图表时,我所要做的就是监听这个事件,并相应地触发一个 reflow()
:
scope.$on('fullscreen', function(){
setTimeout(function () {
$(element).highcharts().reflow();
}, 0);
});
请注意 --again-- 这个技巧只有在我使用 setTimeout()
延迟回流时才有效。不知道为什么。
希望对您有所帮助!在这上面花了很多时间...
我的应用程序在各种选项卡中显示 HighCharts 图表(使用 AngularJS)。请注意,图表会在运行时重新生成 每次选择选项卡时 (意味着每次 Angular "removes or recreates a portion of the DOM tree")。
我的问题是图表的大小是正确的只是第一次我单击了一个选项卡。当我切换选项卡时,创建的图表大大超过了它们容器的大小。令人惊讶的是,图表在 window 调整大小后(即调用 chart.reflow()
时)正确调整大小。
所以我尝试了以下方法,但没有帮助:
$(element).highcharts({
chart: {
type: 'scatter',
zoomType: 'xy',
events: {
load: function () {
this.reflow();
}
}
},
...
最后,下面的方法确实奏效了,但感觉像是 hack。
$(element).highcharts({
chart: {
type: 'scatter',
zoomType: 'xy',
events: {
load: function () {
var chart = this;
setTimeout(function () { chart.reflow(); }, 0);
}
}
},
...
知道问题出在哪里吗?我在这上面花了好几个小时,这真令人沮丧...
编辑:我还有另一个相关问题:默认情况下,我的图表具有给定的大小,但我有一个 "enlarge" 按钮可以让它们占据完整的 space。该按钮只需切换 CSS class 即可。但是,这样做 不会 触发调整大小事件,因此不会触发重排。所以我有同样的问题,图表没有填满他们的容器。
这里有一个 fiddle 来演示这个问题: http://jsfiddle.net/swaek268/3/
再次,我找到了解决问题的方法,但感觉更像是一个更大的 hack。
var width = 0;
var planreflow = function(){
setTimeout(function(){
if(width!==$('#container').width()){
$('#container').highcharts().reflow();
console.log('reflow!')
}
width = $('#container').width();
planreflow();
}, 10);
};
planreflow();
所以,其实你有两个问题:
1) 第二次点击时尺寸不正确。这很可能是由于隐藏 (display: none
) 容器的宽度和高度错误造成的。在这种情况下,浏览器会报告不正确的 width/height(如 0px
)。同样的问题here and here.
2) 为容器设置 class 不会触发图表的 resize
(或者 reflow
)事件。这意味着您需要自己调用 chart.reflow()
。我建议在您更改 class.
我想我找到了两个问题的解决方案:
- 图表完成加载时尺寸错误:
问题不是出在Highcharts,而是出在图表创建的时间上。我直接从 Angular 指令的 link()
函数中调用了 .highcharts()
。 JS 看起来基本上是这样的:
app.directive('dynamicView', function() {
return {
link: function(scope, element, attrs){
$(element).highcharts({...});
},
};
});
由于我的元素也有一个 ng-if
指令,具体取决于选项卡是否被选中,我想当该条件变为 true
时,angular 调用 link()
函数在确定元素的尺寸之前(我想 HTML 必须准备好才能确定元素的大小)。所以我认为问题是我在文档准备好之前调用了 .highcharts()
。由于某些我仍然不明白的原因,元素的大小在第一次 ng-if 变为 true 时是正确的,但下一次就不正确了。
无论如何,一个解决方案(仍然不是很优雅 - 但比调用 reflow()
更好)是延迟对 .highcharts()
本身的调用,以确保 HTML 已准备就绪创建图表时:
link: function(scope, element, attrs){
setTimeout(function () {
$(element).highcharts({...});
}, 0);
}
感谢 @Pavel Fus 对 .highcharts()
和 setTimeout()
.
- 切换 class 时图表未调整大小
对于这个问题,我利用了 Angular 的事件系统。
在我控制全屏按钮的控制器中:
$scope.toggleFullScreen = function(e){
$scope.$broadcast('fullscreen');
}
此事件沿层次结构向下传递,最终到达包含图表的我的指令。在创建我的图表时,我所要做的就是监听这个事件,并相应地触发一个 reflow()
:
scope.$on('fullscreen', function(){
setTimeout(function () {
$(element).highcharts().reflow();
}, 0);
});
请注意 --again-- 这个技巧只有在我使用 setTimeout()
延迟回流时才有效。不知道为什么。
希望对您有所帮助!在这上面花了很多时间...