还记Angularjs指令怎样传递函数参数吗?我们将表格封装成了一个指令。如果不封装就没有传递函数参数的问题了吗?我们要重申的是,封装是必要的,封装可以复用代码。试想,如果在再加入一个图表,要求也可以按时间段下钻。如果不封装的话,下钻这块实现要写两次。而且真实场景多数是表格图表都会的。所以说还是封装成组件好。
看一下最终效果:https://codepen.io/riafan/pen/VXvdjZ。在前面我们已经将下钻功能放父作用域中,现在只用自定义图表组件,就可以通过指令中传递函数参数的方式调用父作用域中的下钻逻辑。看代码:
<div class="pie-chart" pie-chart source="profits" drill-down="drillDown(profit)"></div>
很简单吧?剩下的工作就是实现echarts插件的AngularJS版本。Echats是Enterprise Charts的缩写,商业级数据图表,一个纯Javascript的图表库,可以流畅的运行在PC和移动设备上,兼容当前绝大部分浏览器。此处我们把问题简化,只封装饼图。其实就是AngularJS整合第三方库Javasctipt。
AngularJS把Javascript的context分隔成两部分,一部分是原生的Javascript的context,另一部分是AngularJS的context。只有处在AngularJS的context中的操作才能享受到Angular的data-binding、exception handling、$watch等服务,但是对于外来者(如原生的Javascript操作、自定义的事件回调、第三方的库等)Angular也不是一概不接见,可以使用AngularJS提供的$apply()函数将这些外来者包进AngularJS的context中,让Angular感知到他们产生的变化。如下面代码:
angular.module('myApp') /** * Define pie echart directive * @param source {Array} chart data provider * @param drillDown {Function} click to drill down */ .directive('pieChart', function($filter) { return { restrict: 'EA', scope: { source: '=', drillDown: '&' }, link: function($scope, element, attrs) { var myChart = echarts.init(element[0]); /** * watch data source */ $scope.$watchCollection('source', function(newValue, oldValue) { if (newValue) { var legend = []; angular.forEach(newValue, function(val) { legend.push(val.name); }); var option = { tooltip: { trigger: 'item', formatter: function(params) { return params.name + ' : ' + $filter('number')(params.value) + ' (' + params.percent.toFixed(2) + '%)'; } }, legend: { orient: 'vertical', left: 'left', data: legend }, series: [{ type: 'pie', radius: '55%', center: ['50%', '60%'], data: newValue, itemStyle: { emphasis: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' } } }] }; myChart.setOption(option); } myChart.resize(); }); /** * click chart item to drill down */ myChart.on('click', function(params) { $scope.$apply(function() { $scope.drillDown({profit: params.data}); }); }); /** * adjust the chart size when resizing the window */ window.onresize = function() { myChart.resize(); }; } }; })
上面代码我们将click事件的回调处理包进AngularJS的context中让AngularJS来管理,然后就可以使用强大的AngularJS机制来处理问题了。另外,我们使用$watchCollection监听图表数据源source的变化并相应更新图表的配置。可以看到表格、图表、面包屑实现了三方联动,很酷吗?值得注意的是,使用$watchCollection只会监听数组类型的数据变化,通常比$watch性能更好。