当 ng2-nvd3 图表不在视图中时,浏览器会出现大小更改错误
Browser errors on size change when ng2-nvd3 chart is out of view
在结合使用 ng2-nvd3 和 angular 2 路由功能时,我注意到控制台已满并出现以下错误:
d3.min.js:1 Error: <g> attribute transform: Expected number, "translate(NaN,5)"
我设法将问题确定为一个用例:
- 更改路线出口以指向带有 ng2-nvd3 图表的路线
- 将其改回指向没有 ng2-nvd3 图表的路线
- 更改 window 的大小(或开发者控制台的大小)
- 在控制台中看到错误
这可以很容易地用这个 plunker:
重现
- 打开开发者控制台
- 点击"Chart"link
- 点击"No Chart"link
- 更改开发人员控制台(或浏览器 window - 相同效果)的大小 - 确保释放鼠标按钮,而不仅仅是更改大小。
- 控制台出现错误
如何避免这一错误?
在 ng2-nvd3 source code 第 118 行我们可以看到有一个调整大小的处理程序正在注册
self.chart.resizeHandler = nv.utils.windowResize(function() {...})
当图表离开视图时(如上述情况)需要清除此调整大小处理程序 - 但它不会自动发生。
要解决这个问题,需要通过添加
来获取对图表本身的引用
@ViewChild('chart') chart;
到组件(并通过向 nvd3 元素添加 #chart
属性来命名模板中的图表)
这将允许我们调用
this.chart.chart.resizeHandler.clear();
从调整大小事件中清除处理程序。
但我们仍然需要知道图表何时超出视野 - 有许多方法可以实现这一点,每种方法都有其自身的微妙之处(ngOnDestroy
/ ngOnChanges
等)。
对我有用的是,虽然有点激进,但完全解决了问题:
我已经将根 Router 注入主要组件并订阅了它的更改,通过具有 EventEmitter
的服务委托它们
然后我将该服务注入图表组件并注册到该事件(据我检查,您不能只将路由器注入图表组件,因为它不是根路由器而是一些子路由器和因此不会得到所有的路线变化)
在事件处理程序中,我创建了
的一次性调用
this.chart.chart.resizeHandler.clear();
RoutingService
:
import { Injectable, EventEmitter } from 'angular2/core';
@Injectable()
export class RoutingService {
public onRouteChange$: EventEmitter<string>;
constructor() {
this.onRouteChange$ = new EventEmitter();
}
routeChange(route: string) {
this.onRouteChange$.emit(route);
}
}
MainComponent
构造函数:
constructor(private router:Router, private routingService:RoutingService){
router.subscribe( val => routingService.routeChange(val));
}
ChartComponent
构造函数:
constructor(private routingService:RoutingService) {
let sub:any = routingService.onRouteChange$.subscribe(route => {
if (route != 'chart') {
this.chart.chart.resizeHandler.clear();
if (sub) {
sub.unsubscribe();
}
}
});
}
你可以在这个plunker
中看到它
在结合使用 ng2-nvd3 和 angular 2 路由功能时,我注意到控制台已满并出现以下错误:
d3.min.js:1 Error: <g> attribute transform: Expected number, "translate(NaN,5)"
我设法将问题确定为一个用例:
- 更改路线出口以指向带有 ng2-nvd3 图表的路线
- 将其改回指向没有 ng2-nvd3 图表的路线
- 更改 window 的大小(或开发者控制台的大小)
- 在控制台中看到错误
这可以很容易地用这个 plunker:
重现- 打开开发者控制台
- 点击"Chart"link
- 点击"No Chart"link
- 更改开发人员控制台(或浏览器 window - 相同效果)的大小 - 确保释放鼠标按钮,而不仅仅是更改大小。
- 控制台出现错误
如何避免这一错误?
在 ng2-nvd3 source code 第 118 行我们可以看到有一个调整大小的处理程序正在注册
self.chart.resizeHandler = nv.utils.windowResize(function() {...})
当图表离开视图时(如上述情况)需要清除此调整大小处理程序 - 但它不会自动发生。
要解决这个问题,需要通过添加
来获取对图表本身的引用@ViewChild('chart') chart;
到组件(并通过向 nvd3 元素添加 #chart
属性来命名模板中的图表)
这将允许我们调用
this.chart.chart.resizeHandler.clear();
从调整大小事件中清除处理程序。
但我们仍然需要知道图表何时超出视野 - 有许多方法可以实现这一点,每种方法都有其自身的微妙之处(ngOnDestroy
/ ngOnChanges
等)。
对我有用的是,虽然有点激进,但完全解决了问题:
我已经将根 Router 注入主要组件并订阅了它的更改,通过具有 EventEmitter
的服务委托它们
然后我将该服务注入图表组件并注册到该事件(据我检查,您不能只将路由器注入图表组件,因为它不是根路由器而是一些子路由器和因此不会得到所有的路线变化)
在事件处理程序中,我创建了
this.chart.chart.resizeHandler.clear();
RoutingService
:
import { Injectable, EventEmitter } from 'angular2/core';
@Injectable()
export class RoutingService {
public onRouteChange$: EventEmitter<string>;
constructor() {
this.onRouteChange$ = new EventEmitter();
}
routeChange(route: string) {
this.onRouteChange$.emit(route);
}
}
MainComponent
构造函数:
constructor(private router:Router, private routingService:RoutingService){
router.subscribe( val => routingService.routeChange(val));
}
ChartComponent
构造函数:
constructor(private routingService:RoutingService) {
let sub:any = routingService.onRouteChange$.subscribe(route => {
if (route != 'chart') {
this.chart.chart.resizeHandler.clear();
if (sub) {
sub.unsubscribe();
}
}
});
}
你可以在这个plunker
中看到它