使用D3js和Angularjs创建动态条形图

时间:2016-06-16 18:10:45

标签: angularjs d3.js bar-chart momentjs

我有一些数据需要放入条形图中,数据应根据所选日期进行更新。 该图表应显示所选周数的7天数据。

我在页面上有一个日期分页,当我移动到前一周时,我希望那个星期的数据在条形图上显示

我在plunker上的代码是@ https://plnkr.co/edit/raVy7y3KcOX757jcy3pL?p=preview

我的代码:

的index.html

<!DOCTYPE html>
<html>
<head>
    <style>
        .chart {
            background: #eee;
            padding: 3px;
        }

        .chart div {
          width: 0;
          transition: all 1s ease-out;
          -moz-transition: all 1s ease-out;
          -webkit-transition: all 1s ease-out;
        }

        .chart div {
          font: 10px sans-serif;
          background-color: steelblue;
          text-align: right;
          padding: 3px;
          margin: 5px;
          color: white;
          box-shadow: 2px 2px 2px #666;
        }

        .bar {
            fill: steelblue;
        }
        .bar:hover {
          fill: blue ;
        }
        .d3-tip {
          line-height: 1;
          font-weight: bold;
          padding: 12px;
          background: rgba(0, 0, 0, 0.8);
          color: #fff;
          border-radius: 2px;
        }

        /* Creates a small triangle extender for the tooltip */
        .d3-tip:after {
          box-sizing: border-box;
          display: inline;
          font-size: 10px;
          width: 100%;
          line-height: 1;
          color: rgba(0, 0, 0, 0.8);
          content: "\25BC";
          position: absolute;
          text-align: center;
        }

        /* Style northward tooltips differently */
        .d3-tip.n:after {
          margin: -1px 0 0 0;
          top: 100%;
          left: 0;
        }

        ul {
          width: 800px;
        }

        li {
          float: left;
          list-style: none;
          margin: 25px;
          /*border-bottom: 1px solid grey;*/
        }

        input {
          width: 100%;
          /*margin-top: 12px;
          margin-bottom: 12px;*/
          padding: 24px;
        }

        .event__container {
          width: 100%;
          height: 100px;
        }

        .date {
          float: left;
            width: 100%;
            background-color: grey;
            text-align: center;
            color: grey;
            font-weight: 700;
            margin-left: 0;
            margin: 0;
            padding: 12px;
          color: white;
        }
    </style>

</head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.3/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js"></script>
<script src="main.js"></script>

<body>
    <div ng-app="myApp" ng-controller="Ctrl">

        <div>

            <h2><i class="fa fa-arrow-left"></i>Week Of {{currentWeekStart()}} - {{currentWeekEnd()}}<i class="fa fa-arrow-right"></i></h2>
                <button ng-click="prevWeek()">previous week</button>
                <button ng-click="nextWeek()">next week</button>


        </div>




        <cr-d3-bars data='myData'></cr-d3-bars>
    </div>
    <script>
        $('.filter').click(function() {
            $(this).toggleClass('clicked');
        });
  </script>
    </script>
</body>
</html>

main.js

angular.module( 'myApp',[]).directive( 'crD3Bars', [
  function () {
    return {
      restrict: 'E',
      scope: {
        data: '='
      },
      link: function (scope, element) {
            scope.data.forEach(function(d) {
            d.name = d.name._i;
            d.value = +d.value;
            //console.log(d.name, d.value)
        });
        var margin = {top: 20, right: 20, bottom: 30, left: 40},
          width = 800 - margin.left - margin.right,
          height = 500 - margin.top - margin.bottom;
        var svg = d3.select(element[0])
          .append("svg")
          .attr('width', 800)
          .attr('height', 800)
          .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        var x = d3.scale.ordinal().rangeRoundBands([0, width], .1);
        var y = d3.scale.linear().range([height, 0]);

        var xAxis = d3.svg.axis()
            .scale(x)
            .orient("bottom");

        var yAxis = d3.svg.axis()
            .scale(y)
            .orient("left")
            .ticks(10);

        //For tool tip

        var tip = d3.tip()
      .attr('class', 'd3-tip')
      .offset([-10, 0])
      .html(function(d) {
        return "<span style='color:red'>" + d.date,  d.value + "</span>";
    });

     svg.call(tip); 
        //Render graph based on 'data'
        scope.render = function(data) {
          //Set our scale's domains
          x.domain(data.map(function(d) { return d.name; }));
          y.domain([0, d3.max(data, function(d) { return d.value; })]);

          //Redraw the axes
          svg.selectAll('g.axis').remove();
          //X axis
          svg.append("g")
              .attr("class", "x axis")
              .attr("transform", "translate(0," + height + ")")
              .call(xAxis)
              .selectAll("text")
          .style("text-anchor", "end")
          .attr("dx", "-.8em")
          .attr("dy", "-.55em")
          .attr("transform", "rotate(-60)" );

          //Y axis
          svg.append("g")
              .attr("class", "y axis")
              .call(yAxis)
            .append("text")
              .attr("transform", "rotate(-90)")
              .attr("y", 6)
              .attr("dy", ".55em")
              .attr("transform", "rotate(-90)" )
              .style("text-anchor", "end")
              .text("value");


          var bars = svg.selectAll(".bar").data(data);
          bars.enter()
            .append("rect")
            .attr("class", "bar")
            .attr("x", function(d) { return x(d.name); })
            .attr("width", x.rangeBand())
            .attr('height', function(d) { return height - y(d.value); })
            .attr("y", function(d) { return y(d.value); })
            .on('mouseover', tip.show)
          .on('mouseout', tip.hide)
          //Animate bars
          // bars
          //     .transition()
          //     .duration(1000)
          //     .attr('height', function(d) { return height - y(d.value); })
          //     .attr("y", function(d) { return y(d.value); })
          // //     .on('mouseover', tip.show)
            // // .on('mouseout', tip.hide)

        };

         //Watch 'data' and run scope.render(newVal) whenever it changes
         //Use true for 'objectEquality' property so comparisons are done on equality and not reference
          scope.$watch('data', function(){
              scope.render(scope.data);
          }, true);  
        }
    };
  }
])


   .controller('Ctrl', function($scope, $http) {
      var currentDate,
        weekStart,
        weekEnd,
        shortWeekFormat = 'MMMM Do';
        $scope.currentWeekStart;
        $scope.currentWeekEnd; 

    function setCurrentDate(aMoment){
      currentDate = aMoment,
      weekStart = currentDate.clone().startOf('week'),
      weekEnd = currentDate.clone().endOf('week')
    }    

    setCurrentDate(moment());

    $scope.currentWeekStart = function(){ return weekStart.format(shortWeekFormat); };
    $scope.currentWeekEnd = function(){ return weekEnd.format(shortWeekFormat); };

    $scope.week = function(item) {
      var eventTime = moment(item.name);
      return (eventTime >= weekStart && eventTime <= weekEnd);
    };
       var data  = [
                 {name: moment('May 29 2016'), value: 300},
             {name: moment('May 30 2016'), value: 150},
             {name: moment('May 31 2016'), value: 400},
             {name: moment('Jun 1 2016'), value: 300},
             {name: moment('Jun 2 2016'), value: 100},
             {name: moment('Jun 3 2016'), value: 300},
             {name: moment('Jun 4 2016'), value: 150},  
                 {name: moment('Jun 5 2016'), value: 300},
             {name: moment('Jun 6 2016'), value: 150},
             {name: moment('Jun 7 2016'), value: 400},
             {name: moment('Jun 8 2016'), value: 300},
             {name: moment('Jun 9 2016'), value: 100},
             {name: moment('Jun 10 2016'), value: 300},
             {name: moment('Jun 11 2016'), value: 150},
             {name: moment('Jun 12 2016'), value: 400},
             {name: moment('Jun 13 2016'), value: 300},
             {name: moment('Jun 14 2016'), value: 100},
             {name: moment('Jun 15 2016'), value: 400},
             {name: moment('Jun 16 2016'), value: 300},
             {name: moment('Jun 17 2016'), value: 100},
             {name: moment('Jun 18 2016'), value: 100}
          ];

      var beginValue = weekStart._d;
      var endValue = weekEnd._d;

      $scope.myData  = data.filter(function(d){
        return d.name >= beginValue && d.name <= endValue;
      });

    $scope.nextWeek = function(){
      var next = setCurrentDate(currentDate.add(7,'days'));
      next = currentDate;
      beginValue = weekStart._d;
      endValue = weekEnd._d;

      $scope.myData  = data.filter(function(d){
        return d.name >= beginValue && d.name <= endValue;
      });


      $scope.$watch('myData', function(){
              $scope.render($scope.myData);
      }, true);  
        console.log($scope.myData)

  };


    $scope.prevWeek = function(){
      var prev = setCurrentDate(currentDate.subtract(7,'days'));
      prev = currentDate;
      //console.log(weekStart)
      //console.log(weekEnd)
      $scope.myData  = data.filter(function(d){
        return d.name >= weekStart._d && d.name <= weekEnd._d;
      });
     // console.log($scope.myData)
    };


  });

我无法根据所选日期更改条形图值。

我是D3js的新手,我不确定我做错了什么。

请让我知道你的想法。

1 个答案:

答案 0 :(得分:0)

您无法正确处理enterupdateexit pattern。您的代码应如下所示:

      // join the data
      var bars = svg.selectAll(".bar").data(data);

      // any bars that no longer exist should be removed
      bars.exit().remove();

      // new bars should be created
      bars.enter()
        .append("rect")
        .attr("class", "bar")
        .on('mouseover', tip.show)
        .on('mouseout', tip.hide);

      // all bars need to have new x positions, width and height
      bars
        .attr("x", function(d) {
          return x(d.name);
        })
        .attr("width", x.rangeBand())
        .attr('height', function(d) {
          return height - y(d.value);
        })
        .attr("y", function(d) {
          return y(d.value);
        });

更新了Plunker here