与 angular-nvd3 一起使用的 nvd3 是 slooooowwwww
nvd3 used with angular-nvd3 is slooooowwwww
我相信我有一个问题,可以通过我遗漏的东西很容易地解决,但我似乎看不出真正的问题是什么。我有一个应用程序,每秒 returns 5000 点(1000 x,y 点的 5 个数组元素)我想使用 NVD3 在客户端更新。这是一个 AngularJS 应用程序,所以我使用 krispos angular-nvd3
指令。然而,它使整个应用程序陷入困境,而且根据 Chrome 的开发人员工具捕获的时间线,应用程序似乎正在等待 d3_timer_step
到 return 5-6 秒。
我认为这个问题是由于我们更新数据的方式造成的,但整个问题似乎与实际的 d3 部分有关。客户端的代码是
<nvd3 options="optionsRingdown" data="ringdownAvg" config="{refreshDataOnly:true}"></nvd3>
控制器中的选项定义如下
$scope.options = {
chart: {
type: 'lineChart',
height: 300,
margin: {
top: 20,
right: 40,
bottom: 60,
left: 75
},
x: function(d) {
return d.x;
},
y: function(d) {
return d.y;
},
useInteractiveGuideline: false,
yAxis: {
tickFormat: function(d) {
return d3.format('0.01f')(d);
},
axisLabel: 'Testing'
},
xAxis: {
tickFormat: function(d) {
return d3.time.format('%X')(new Date(d));
},
rotateLabels: -45
},
transitionDuration: 0,
showXAxis: true,
showYAxis: true
}
};
数据在以下模板中定义
var ringdownT = [{
values: [],
key: 'Cell 0'
}, {
values: [],
key: 'Cell 1'
}, {
values: [],
key: 'Cell 2'
}, {
values: [],
key: 'Cell 3'
}, {
values: [],
key: 'Cell 4'
}];
数据是通过使用以下
从服务广播的函数调用更新的
function updateCRD(d){
var dataOut = {
"tauData": [],
"rdFit": ringdownT,
"rdAvg":ringdownT
}
for (k = 0; k < d.cell.length; k++) {
dataOut.rdAvg[k].values = d.cell[k].avg_rd;
dataOut.rdFit[k].values = d.cell[k].fit_rd;
}
return dataOut;
}
该函数在广播中使用以下内容调用(以 1 秒为间隔广播)
$scope.$on('dataAvailable', function() {
$scope.data = Data.crd;
var data = updateCRD(Data.crd);
$scope.tauData = data.tauData;
$scope.ringdownAvg = data.rdAvg;
$scope.ringdownFit = data.rdFit;
});
有没有人看到这里有明显错误的地方,或者我应该采取不同的做法?我缺少一个选项吗?任何帮助都会很棒。
干杯,马特
您在使用 SVG
吗? nvd3.lineChart
是 SVG
所以是的,可能。如果是这样,@mbostock 为您提供了答案:http://bl.ocks.org/mbostock/1276463。使用 canvas
而不是 SVG
以获得更快的速度。
https://www.safaribooksonline.com/blog/2014/02/20/speeding-d3-js-checklist/ 上的大多数建议都非常可靠。
你是在每秒重新绘制所有 5000 个点吗?如果是这样,这是 webGL imo 的工作,而不是 nvd3。 canvas
可能足够快,如果 canvas 不够快,那么我会坚持以前的答案。
它花在 d3_timer_step
上的时间百分比是多少?那个函数会很慢是没有意义的,它可能只是被调用了很多次。实际上,d3_timer_frame
是由 d3_timer_step
调用的,这可能是实际的渲染代码,肯定会占用您所有的时间。尝试做 canvas
.
可能的 nvd3 性能改进:
- 绝对禁用
useInteractiveGuideline
如果你还没有。
尝试将 deepWatchData: false
标志添加到配置(这意味着该指令将不会监视更新数据)并通过 api
:
更新图表
<nvd3 options="optionsRingdown" data="ringdownAvg" api="apiRingdown" config="{refreshDataOnly:true, deepWatchData: false}"></nvd3>
该指令使用 $watch(watchExpression, listener, [objectEquality])
方法监视选项和复杂数据对象的任何更新。在我们的例子中,deepWatchData
是 objectEquality
标志,同时观察图表数据以获取更新。
根据angulardocs,watchExpression的不等式根据angular.equals函数判断。为了保存对象的值以供以后比较,使用了 angular.copy 函数。因此,这意味着观看复杂的对象会对内存和性能产生不利影响。
仅在版本 (1.0.2, 1.0.3) 中,此标志默认为 false
。
然后,要更新图表,我们可以在您的控制器中使用 apiRingdown.update
方法:
$scope.$on('dataAvailable', function() {
$scope.data = Data.crd;
var data = updateCRD(Data.crd);
$scope.tauData = data.tauData;
$scope.ringdownAvg = data.rdAvg;
$scope.ringdownFit = data.rdFit;
//this line updates the chart
$scope.apiRingdown.update();
});
已更新
最新版本[1.0.4+]增加了一些更新。现在标志 deepWatchData
表示使用或不使用数据监视(不像以前那样 objectEquality
)。默认情况下 deepWatchData
是 true
。但现在我们可以使用新标志 deepWatchDataDepth: 2
来管理 $watch
深度,从而调节性能。使用此标志,我们可以为数据指定变化检测策略(范围 $watch 深度):
0 - By Reference (the least powerful, but the most efficient)
1 - By Collection Items
2 - By Value (the most powerful, but also the most expensive; default value)
此外,标志 refreshDataOnly
默认为 true
。
因此,更新后的标签元素可能如下所示:
<nvd3 options="optionsRingdown" data="ringdownAvg" api="apiRingdown" config="{deepWatchDataDepth: 0}"></nvd3>
我相信我有一个问题,可以通过我遗漏的东西很容易地解决,但我似乎看不出真正的问题是什么。我有一个应用程序,每秒 returns 5000 点(1000 x,y 点的 5 个数组元素)我想使用 NVD3 在客户端更新。这是一个 AngularJS 应用程序,所以我使用 krispos angular-nvd3
指令。然而,它使整个应用程序陷入困境,而且根据 Chrome 的开发人员工具捕获的时间线,应用程序似乎正在等待 d3_timer_step
到 return 5-6 秒。
我认为这个问题是由于我们更新数据的方式造成的,但整个问题似乎与实际的 d3 部分有关。客户端的代码是
<nvd3 options="optionsRingdown" data="ringdownAvg" config="{refreshDataOnly:true}"></nvd3>
控制器中的选项定义如下
$scope.options = {
chart: {
type: 'lineChart',
height: 300,
margin: {
top: 20,
right: 40,
bottom: 60,
left: 75
},
x: function(d) {
return d.x;
},
y: function(d) {
return d.y;
},
useInteractiveGuideline: false,
yAxis: {
tickFormat: function(d) {
return d3.format('0.01f')(d);
},
axisLabel: 'Testing'
},
xAxis: {
tickFormat: function(d) {
return d3.time.format('%X')(new Date(d));
},
rotateLabels: -45
},
transitionDuration: 0,
showXAxis: true,
showYAxis: true
}
};
数据在以下模板中定义
var ringdownT = [{
values: [],
key: 'Cell 0'
}, {
values: [],
key: 'Cell 1'
}, {
values: [],
key: 'Cell 2'
}, {
values: [],
key: 'Cell 3'
}, {
values: [],
key: 'Cell 4'
}];
数据是通过使用以下
从服务广播的函数调用更新的function updateCRD(d){
var dataOut = {
"tauData": [],
"rdFit": ringdownT,
"rdAvg":ringdownT
}
for (k = 0; k < d.cell.length; k++) {
dataOut.rdAvg[k].values = d.cell[k].avg_rd;
dataOut.rdFit[k].values = d.cell[k].fit_rd;
}
return dataOut;
}
该函数在广播中使用以下内容调用(以 1 秒为间隔广播)
$scope.$on('dataAvailable', function() {
$scope.data = Data.crd;
var data = updateCRD(Data.crd);
$scope.tauData = data.tauData;
$scope.ringdownAvg = data.rdAvg;
$scope.ringdownFit = data.rdFit;
});
有没有人看到这里有明显错误的地方,或者我应该采取不同的做法?我缺少一个选项吗?任何帮助都会很棒。
干杯,马特
您在使用 SVG
吗? nvd3.lineChart
是 SVG
所以是的,可能。如果是这样,@mbostock 为您提供了答案:http://bl.ocks.org/mbostock/1276463。使用 canvas
而不是 SVG
以获得更快的速度。
https://www.safaribooksonline.com/blog/2014/02/20/speeding-d3-js-checklist/ 上的大多数建议都非常可靠。
你是在每秒重新绘制所有 5000 个点吗?如果是这样,这是 webGL imo 的工作,而不是 nvd3。 canvas
可能足够快,如果 canvas 不够快,那么我会坚持以前的答案。
它花在 d3_timer_step
上的时间百分比是多少?那个函数会很慢是没有意义的,它可能只是被调用了很多次。实际上,d3_timer_frame
是由 d3_timer_step
调用的,这可能是实际的渲染代码,肯定会占用您所有的时间。尝试做 canvas
.
可能的 nvd3 性能改进:
- 绝对禁用
useInteractiveGuideline
如果你还没有。
尝试将 deepWatchData: false
标志添加到配置(这意味着该指令将不会监视更新数据)并通过 api
:
<nvd3 options="optionsRingdown" data="ringdownAvg" api="apiRingdown" config="{refreshDataOnly:true, deepWatchData: false}"></nvd3>
该指令使用 $watch(watchExpression, listener, [objectEquality])
方法监视选项和复杂数据对象的任何更新。在我们的例子中,deepWatchData
是 objectEquality
标志,同时观察图表数据以获取更新。
根据angulardocs,watchExpression的不等式根据angular.equals函数判断。为了保存对象的值以供以后比较,使用了 angular.copy 函数。因此,这意味着观看复杂的对象会对内存和性能产生不利影响。
仅在版本 (1.0.2, 1.0.3) 中,此标志默认为 false
。
然后,要更新图表,我们可以在您的控制器中使用 apiRingdown.update
方法:
$scope.$on('dataAvailable', function() {
$scope.data = Data.crd;
var data = updateCRD(Data.crd);
$scope.tauData = data.tauData;
$scope.ringdownAvg = data.rdAvg;
$scope.ringdownFit = data.rdFit;
//this line updates the chart
$scope.apiRingdown.update();
});
已更新
最新版本[1.0.4+]增加了一些更新。现在标志 deepWatchData
表示使用或不使用数据监视(不像以前那样 objectEquality
)。默认情况下 deepWatchData
是 true
。但现在我们可以使用新标志 deepWatchDataDepth: 2
来管理 $watch
深度,从而调节性能。使用此标志,我们可以为数据指定变化检测策略(范围 $watch 深度):
0 - By Reference (the least powerful, but the most efficient)
1 - By Collection Items
2 - By Value (the most powerful, but also the most expensive; default value)
此外,标志 refreshDataOnly
默认为 true
。
因此,更新后的标签元素可能如下所示:
<nvd3 options="optionsRingdown" data="ringdownAvg" api="apiRingdown" config="{deepWatchDataDepth: 0}"></nvd3>