使用 angularjs 和 d3.js 在一页中显示多个图表

Multiple graphs in one single page using angularjs and d3.js

我刚刚开始学习 AngularJS 和 D3.js 绘制条形图。我成功地在一页中绘制了一个条形图。但是我在用不同数据绘制多个图表时遇到了问题。例如:我的 app.js 看起来如下:

// Module name to be included in html app
var app = angular.module('App', []);

// FundamoCtrl controller which holds the data from the JSON
app.controller("FundamoCtrl", function($scope) {

    $scope.tags = [
      {'#text': "author-vimal",    '@pass':  4},
      {'#text': "author-raj",      '@pass':  8},
      {'#text': "tt-positive",     '@pass': 15},
      {'#text': "tt-negative",     '@pass': 16},
      {'#text': "author-selvam",   '@pass': 23},
      {'#text': "author-inba",     '@pass': 42}
    ];

});

// Custom filter for the json data
app.filter('filterData', function() {

    return function(data, searchFor) {
        var property = Object.keys(searchFor)[0];
        var result = [];

        for (var i = 0; i < data.length; i++) {
            if (data[i][property].indexOf(searchFor[property]) > -1) {
                result.push(data[i]);
            }
        }

        return result;
    };

});

// Bar Graph to show the result
app.directive('barGraph', [
    '$filter',
    function($filter) {
        return {
            restrict: 'EA',
            scope: {
                data: '=',
                filtername: '=',
                filtervalue: '=',
            },
            link: function(scope, element, attrs) {
                var margin = {top: 20, right: 30, bottom: 30, left: 40}, 
                    width = 500 - margin.left - margin.right,
                    height = 300 - margin.top - margin.bottom;

                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(5);

                var svg = d3.select(element[0])
                                .append("svg")
                                .attr("class", "chart");

                scope.render = function(data) {

                    x.domain(data.map(function(d) { return d['#text']; }));
                    y.domain([0, d3.max(data, function(d) { return d['@pass']; })]);

                    var chart = d3.select(".chart")
                                .attr("width", width + margin.left + margin.right)
                                .attr("height", height + margin.top + margin.bottom)
                                .append("g")
                                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

                    var bar = chart.selectAll("g")
                                .data(data)
                                .enter()
                                .append("g")
                                .attr("transform", function(d, i) { return "translate(" + x(d['#text']) + ", 0)"; });

                    bar.append("rect")
                        .attr("class", "rect-bar")
                        .attr("y", function(d) { return y(d['@pass']); })
                        .attr("height", function(d) { return height - y(d['@pass']); })
                        .attr("width", x.rangeBand());

                    bar.append("text")
                        .attr("x", x.rangeBand() / 2)
                        .attr("y", function(d) { return y(d['@pass']) + 15; })
                        .attr("dy", ".5em")
                        .text(function(d) { return d['@pass']; })
                        .attr("class", "bar-text");

                    chart.append("g")
                        .attr("class", "x axis")
                        .attr("transform", "translate(0," + height + ")")
                        .call(xAxis);

                    chart.append("g")
                        .attr("class", "y axis")
                        .call(yAxis)
                        .append("text")
                        .attr("transform", "rotate(-90)")
                        .attr("y", 0 - margin.left)
                        .attr("x", 0 - (height / 2))
                        .attr("dy", "1em")
                        .style("text-anchor", "middle")
                        .text("Pass Count");
                };

                scope.$watch('data', function(data) {
                    data = $filter(scope.filtername)(data, scope.filtervalue);
                    scope.render(data);
            }, true);
            }
        };
    }
]);

在正文部分下的 html 模板中,我有如下内容:

<div ng-controller="MyCtrl">
    <bar-graph id="bar1" data="tags" filtername="'filterData'" filterValue="{'#text': 'author-'}"></bar-graph>

    <bar-graph id="bar2" data="tags" filtername="'filterData'" filterValue="{'#text': 'tt-'}"></bar-graph>
</div>

在输出中,bar2 散布在 bar1 的顶部。我想将 bar2 放在 bar1 旁边,但我做不到。请帮我解决这个问题。

有关详细信息,请参阅此 Plunker

好的,所以我找到了问题所在。我将 g 标记附加到 class 属性,其中 class 值为 chart。所以它需要第一个 chart 并一次又一次地附加到同一个图表。所以乱七八糟的。

现在我正在创建一个动态 ID,它将在运行时附加到 svg 元素,从而解决了上述问题。

有关详细信息,请参阅 Plunker