AngularJS整合Echarts做饼图

还记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性能更好。

发表评论

电子邮件地址不会被公开。 必填项已用*标注