使用AngularJS和D3.js创建制图指令

D3是一个JavaScript库,可用于使用HTML5技术可缩放矢量图形(SVG)创建交互式图表。 直接与SVG一起创建图表可能会很痛苦,因为人们需要记住SVG支持的形状并多次调用API以使图表动态化。 D3抽象了大部分的痛苦,并提供了一个简单的界面来构建基于SVG的图表。 Jay Raj发表了两篇有关使用D3的不错的SitePoint文章,如果您还不熟悉D3,请检查一下。

你们大多数人可能不需要AngularJS的正式介绍。 AngularJS是用于构建富Web应用程序的客户端JavaScript框架。 AngularJS的最大卖点之一就是对指令的支持。 指令提供了一种极好的方式来定义我们自己的HTML属性和元素。 它还有助于使标记和代码彼此分离。

AngularJS在数据绑定方面也非常强大。 此功能节省了根据模型中的数据更新UI所需的大量时间和精力。 在现代网络世界中,客户要求开发人员构建实时响应的网站。 这意味着客户希望始终在屏幕上看到最新数据。 一旦有人在后端修改了一条数据,就必须更新数据UI。 如果我们不支持数据绑定,那么执行这样的实时更新将非常困难且效率低下。

在本文中,我们将看到如何构建包装D3图表的实时AngularJS指令。

配置

首先,我们需要建立环境。 我们需要HTML页面中包含AngularJS和D3。 由于我们将仅构建图表指令,因此需要创建AngularJS控制器和指令。 在控制器中,我们需要一个保存数据的集合,以将其绘制在图表中。 以下代码段显示了初始控制器和指令。 稍后我们将向这些组件添加更多代码。

var app = angular.module("chartApp", []);

app.controller("SalesController", ["$scope", function($scope) {
  $scope.salesData = [
    {hour: 1,sales: 54},
    {hour: 2,sales: 66},
    {hour: 3,sales: 77},
    {hour: 4,sales: 70},
    {hour: 5,sales: 60},
    {hour: 6,sales: 63},
    {hour: 7,sales: 55},
    {hour: 8,sales: 47},
    {hour: 9,sales: 55},
    {hour: 10,sales: 30}
  ];
}]);

app.directive("linearChart", function($window) {
  return{
    restrict: "EA",
    template: "<svg width='850' height='200'></svg>",
    link: function(scope, elem, attrs){
    }
  };
});

我们将在上述指令中填充链接功能,以使用存储在控制器中的数据,并使用D3绘制折线图。 指令的模板包含一个svg元素。 我们将在此元素上应用D3的API,以绘制图表。 以下代码段显示了该指令的示例用法:

<div linear-chart chart-data="salesData"></div>

现在,让我们收集绘制图表所需的基本数据。 它包括要绘制的数据,SVG元素的JavaScript对象以及其他静态数据。

var salesDataToPlot=scope[attrs.chartData];
var padding = 20;
var pathClass = "path";
var xScale, yScale, xAxisGen, yAxisGen, lineFun;
    
var d3 = $window.d3;
var rawSvg = elem.find("svg")[0];
var svg = d3.select(rawSvg);

加载d3的库后, d3对象就可以用作全局变量。 但是,如果我们直接在代码块中使用它,则很难测试该代码块。 为了使指令可测试,我通过$ window使用对象。

绘制简单的折线图

让我们设置绘制图表所需的参数。 图表需要一个x轴,一个y轴以及要由这些轴表示的数据域。 在该示例中,x轴表示以小时为单位的时间。 我们可以采用数组中的第一个和最后一个值。 在y轴上,可能的值是从零到最大销售额。 可以使用d3.max()找到最大的销售价值。 轴的范围根据svg元素的高度和宽度而变化。

使用上述值,我们需要让d3绘制具有所需方向和刻度数的轴。 最后,我们需要使用d3.svg.line()定义一个函数,该函数根据上面定义的比例绘制线条。 以上所有组件都必须附加到指令模板中的svg元素。 我们可以在添加项目时将样式和变换应用于图表。 以下代码设置参数并附加到SVG:

function setChartParameters(){
  xScale = d3.scale.linear()
             .domain([salesDataToPlot[0].hour, salesDataToPlot[salesDataToPlot.length - 1].hour])
             .range([padding + 5, rawSvg.clientWidth - padding]);

              yScale = d3.scale.linear()
                .domain([0, d3.max(salesDataToPlot, function (d) {
                  return d.sales;
                })])
             .range([rawSvg.clientHeight - padding, 0]);

  xAxisGen = d3.svg.axis()
               .scale(xScale)
               .orient("bottom")
               .ticks(salesDataToPlot.length - 1);

  yAxisGen = d3.svg.axis()
               .scale(yScale)
               .orient("left")
               .ticks(5);

  lineFun = d3.svg.line()
              .x(function (d) {
                return xScale(d.hour);
              })
              .y(function (d) {
                return yScale(d.sales);
              })
              .interpolate("basis");
}
         
function drawLineChart() {

  setChartParameters();

  svg.append("svg:g")
     .attr("class", "x axis")
     .attr("transform", "translate(0,180)")
     .call(xAxisGen);

   svg.append("svg:g")
      .attr("class", "y axis")
      .attr("transform", "translate(20,0)")
      .call(yAxisGen);

   svg.append("svg:path")
      .attr({
        d: lineFun(salesDataToPlot),
        "stroke": "blue",
        "stroke-width": 2,
        "fill": "none",
        "class": pathClass
   });
}

drawLineChart();

是展示上面图表的演示。

实时更新图表

如前所述,随着当今网络的发展,我们的用户希望看到数据图表随基础数据的变化而立即更新。 可以使用WebSockets等技术将更改后的信息推送到客户端。 我们刚刚创建的chart指令应该能够响应此类更改并更新图表。

要通过WebSocket推送数据,我们需要在服务器上使用Socket.IO和Node.js,SignalR和.NET或其他平台上的类似技术构建的组件。 对于演示 ,我使用AngularJS的$interval服务将十个随机销售值推入销售额数组,但延迟了一秒:

$interval(function() {
  var hour = $scope.salesData.length + 1;
  var sales = Math.round(Math.random() * 100);

  $scope.salesData.push({hour: hour, sales: sales});
}, 1000, 10);

要在推送新数据后立即更新图表,我们需要使用更新后的数据重新绘制图表。 指令中必须使用集合监视程序来监视集合数据的更改。 对集合进行任何更改时,将调用观察程序。 该图表将在观察程序中重绘。

scope.$watchCollection(exp, function(newVal, oldVal) {
  salesDataToPlot = newVal;
  redrawLineChart();
});

function redrawLineChart() {

  setChartParameters();
  svg.selectAll("g.y.axis").call(yAxisGen);
  svg.selectAll("g.x.axis").call(xAxisGen);

  svg.selectAll("." + pathClass)
     .attr({
       d: lineFun(salesDataToPlot)
     });
}

完整的演示可以在这里找到。

结论

AngularJS和D3是非常有用的库,用于在Web上构建丰富的业务应用程序。 我们讨论了如何一起使用它们来创建简单的图表。 您可以扩展此知识来为您的应用程序创建图表。

From: https://www.sitepoint.com/creating-charting-directives-using-angularjs-d3-js/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值