创建饼图指令的问题

时间:2014-07-24 20:00:43

标签: javascript angularjs d3.js

我正在努力尝试使用Angular和D3js创建一个简单的饼图指令。我觉得我在这里遗漏了一些关于JavaScript的明显内容但是我错过了它。任何帮助将不胜感激。

Plunkr:http://plnkr.co/lFluzdfLOINBzEGVRHwA

我的最终目标是让一个对象充当我的控制器可以引用的模型,但是现在我只是从带有工厂的JSON文件中获取数据。我的问题是我可以控制记录所有数据,它看起来像你期望的那样。我也可以在HTML中使用把手,即{{company}},整个对象将被打印到屏幕上。

但行:

var arcs = svg.selectAll(".slice")
                    .data(pie);

始终抛出以下错误:

"Error: i is undefined
n@http://localhost:63342/explorer/vendor/d3/d3.min.js:4:21667
pa.data@http://localhost:63342/explorer/vendor/d3/d3.min.js:3:11196
link@http://localhost:63342/explorer/app/features/pieChart/pieChartDirective.js:34:1
K@http://localhost:63342/explorer/vendor/angular/angular.min.js:54:390
A/<@http://localhost:63342/explorer/vendor/angular/angular.min.js:61:129
r/f.success/<@http://localhost:63342/explorer/vendor/angular/angular.min.js:72:199
ye/e/l.promise.then/J@http://localhost:63342/explorer/vendor/angular/angular.min.js:99:449
ye/e/l.promise.then/J@http://localhost:63342/explorer/vendor/angular/angular.min.js:99:449
ye/g/<.then/<@http://localhost:63342/explorer/vendor/angular/angular.min.js:101:116
Zd/this.$get</k.prototype.$eval@http://localhost:63342/explorer/vendor/angular/angular.min.js:111:342
Zd/this.$get</k.prototype.$digest@http://localhost:63342/explorer/vendor/angular/angular.min.js:108:411
Zd/this.$get</k.prototype.$apply@http://localhost:63342/explorer/vendor/angular/angular.min.js:112:171
h@http://localhost:63342/explorer/vendor/angular/angular.min.js:72:441
w@http://localhost:63342/explorer/vendor/angular/angular.min.js:77:347
we/</z.onreadystatechange@http://localhost:63342/explorer/vendor/angular/angular.min.js:78:420
" "<pie-chart-directive class="ng-binding">" angular.min.js:92

以下是所有相关代码:

的index.html

<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
    <meta charset="utf-8">
    <title>Explorer</title>

    <link rel="stylesheet" href="vendor/bootstrap/dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="vendor/bootstrap/dist/css/bootstrap-theme.min.css">
</head>
<body>

<div class="container-fluid">
    <div class="row">
        <h1>Data Explorer</h1>
    </div>
    <div class="row">
        Path Navigator
    </div>
    <div class="row" ng-controller="PieChartController">
        <pie-chart-directive></pie-chart-directive>
    </div>
</div>

<!-- framework scripts -->
<script src="vendor/angular/angular.min.js"></script>
<script src="vendor/angular-route/angular-route.min.js"></script>
<script src="vendor/jquery/dist/jquery.min.js"></script>
<script src="vendor/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="vendor/d3/d3.min.js"></script>
<script src="vendor/topojson/topojson.js"></script>
<script src="vendor/lodash/dist/lodash.min.js"></script>

<script src="app/app.js"></script>

<!-- pieChart scripts -->
<script src="app/features/pieChart/pieChartModule.js"></script>
<script src="app/features/pieChart/PieChartController.js"></script>
<script src="app/features/pieChart/pieChartDirective.js"></script>

<!-- navigator scripts -->
<script src="app/features/navigator/navigatorModule.js"></script>
<script src="app/features/navigator/NavigatorController.js"></script>
<script src="app/features/navigator/navigatorDirective.js"></script>


</body>
</html>

app.js

angular.module('d3', []).factory('d3Service', [function() {
    var d3;
    return d3;
}]);

angular.module('lodash', []).factory('lodashService', [function() {
    var _;
    return _;
}]);

angular.module('myApp', [
    'ngRoute',
    'd3',
    'lodash',
    'pieChart',
    'navigator'
]);

angular.module('myApp').factory('Company', ['$http', function($http) { 'use strict';
    function Company(companyData) {
        if(companyData) {
            this.setData(companyData);
        }
    };
    Company.prototype = {
        setData: function(companyData) {
            angular.extend(this, companyData); // Copies the properties of the second arg obj to the first arg obj
        },
        load: function() {
            var scope = this;
            return $http.get('app/data.json'); // Return this and use .then() in the controller to avoid using $watch
            /*$http.get('app/data.json').success(function(data) {
                scope.setData(data);
            })
            .error(function(err) {
                console.log("Error getting data in Company.");
            });*/
        }
    };
    return Company;
}]);

pieChartModule.js

angular.module('pieChart', [
    'd3',
    'lodash'
]);

PieChartController.js

angular.module('pieChart')
    .controller('PieChartController', ['$scope', 'Company', function($scope, Company) { 'use strict';
        $scope.company = new Company();
        //$scope.company.load();
        $scope.company.load().then(function(d) {
          $scope.company.setData(d.data);
        });
}]);

pieChartDirective.js

angular.module('pieChart')
    .directive('pieChartDirective', ['d3Service', function(d3Service) { 'use strict';
        function link(scope, element, attrs) {
            var initializing = true;
            var w = 500, //width
                h = 500, //height
                r = 200, //radius
                rP = 248,
                color = d3.scale.category20c(); //builtin range of colors

            //Set margins, width, and height
            var margin = {top: 20, right: 20, bottom: 30, left: 40},
                width = w - margin.left - margin.right,
                height = h - margin.top - margin.bottom;

            var svg = d3.select(element[0])
                .append("svg:svg")
                .data([scope.company.campaigns])
                .attr("width", w)
                .attr("height", h);

            var arc = d3.svg.arc()
                .outerRadius(r);
            var popOut = d3.svg.arc()
                .outerRadius(rP);

            var pie = d3.layout.pie()
                .value(function(d) { return d.budget; })
                .sort(null);

            //scope.render = function() {
                var arcs = svg.selectAll(".slice")
                    .data(pie);

                arcs.enter().append("path")
                    .attr("class", "slice")
                    .attr("fill", function (d, i) { return color(i); })
                    .attr("d", arc)
                    .attr("transform", "translate(" + (w / 2) + "," + (h / 2) + ")")
                    .on('mouseenter', function(d, i) {
                        d3.select(this)
                            .transition()
                            .duration(300)
                            .attr("d", popOut)
                            .style("opacity", 1)
                            .style("stroke", "black");

                        var tooltip = d3.select("body").append("div")
                            .attr("id", "tooltip")
                            .attr("class", "badge")
                            .style("position", "absolute")
                            .style("left", (d3.event.pageX-100 + "px"))
                            .style("top", (d3.event.pageY-100 + "px"))
                            .html("<h4>" + d.data.campaignName + "</h4>");

                        // Call digest when a change has been made that Angular is not automatically
                        // informed of (dirty-checking)
                        scope.$digest();
                    })
                    .on('mouseout', function(d, i) {
                        d3.select(this)
                            .transition()
                            .duration(300)
                            .attr("d", arc)
                            .style("stroke", "none")
                            .duration(300)
                            .style("opacity", .8);

                        $('#tooltip').remove();
                    });

                arcs.transition().duration(1500).attrTween("d", tweenPie); // Original transition

                function tweenPie(b) {
                    b.innerRadius = 0;
                    var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
                    return function(t) { return arc(i(t)); };
                }

                function change() {
                    if(!initializing) {
                        pie.value(function (d) { return d.budget; }); // change the value function
                        arcs = arcs.data(pie); // compute the new angles
                        arcs.transition()
                            .attr("d", arc);
                    }
                }
            //}

            // Use true for 'objectEquality' property so comparisons are done on equality and not reference
            /*scope.$watchCollection('company.campaigns', function(value) {
                if(value) {
                    scope.render();

                    // Don't change this flag until all watched variables have been set
                    initializing = false;
                }
            }, true);*/
        };

        return {
            restrict: 'E',
            link: link,
            templateUrl: 'app/features/pieChart/pieChart.html'
        }
    }]);

pieChart.html

<p>Pie Chart</p>

0 个答案:

没有答案