Ankit Gupta Ankit Gupta - 6 months ago 42
AngularJS Question

svg is loading inside a single div even after putting it in different divs

I am a newbie in d3.js data visualization . I have created a angular directive for area chart . I am trying to put the Area chart with different datasets into different div panel but it is resulting into svg being loaded inside single div panel .

Here is my plunkr link https://plnkr.co/edit/rEYclx6RSfEpuuL3X2z0?p=preview .

<html>

<head>
<script data-require="angular.js@2.0.0" data-semver="2.0.0" src="https://code.angularjs.org/2.0.0-beta.6/angular2.min.js"></script>
<link rel="stylesheet" href="style.css" type="text/css" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" type="text/css" />
</head>

<body>
<script src="angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script src="moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-moment/0.10.3/angular-moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="report.js"></script>
<div ng-app="myApp">
<div class="panel panel-default">
<div class="panel-heading">Monthly User Report</div>
<div class="panel-body" ng-controller="monthlyDataReport">
<weekly-user-report data="monthlyData2"></weekly-user-report>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">WeeklyUserReport</div>
<div class="panel-body" ng-controller="weeklyData">
<weekly-user-report data="weeklyData2"></weekly-user-report>
</div>
</div>
</div>
</body>

</html>


Thanks in advance .

Answer

The issue was in the directive...The D3 code was configured as following: d3.select('div.panel-body')...This instructs D3 to find the first element that matches that description and use it in both instances......Now the directive's LINK property is being configured to use an anonymous function that contains an element param which is the actual weekly-user-report html element...SO if we need to select that element as such:

var el = element[0] var chart = d3.select(el)

angular.module('myApp', [])

    .controller('weeklyData',function($scope){

        $scope.weeklyData=[{"week":66,"count":0},{"week":67,"count":0},{"week":68,"count":0},{"week":69,"count":0},{"week":70,"count":0},{"week":71,"count":0}];
        function getDateOfISOWeek(w, y) {
            var simple = new Date(y, 0, 1 + (w - 1) * 7);
            var dow = simple.getDay();
            var ISOweekStart = simple;
            if (dow <= 4)
                ISOweekStart.setDate(simple.getDate() - simple.getDay() + 1);
            else
                ISOweekStart.setDate(simple.getDate() + 8 - simple.getDay());
            return ISOweekStart;
        }
        $scope.weeklyData2=[];
        for(var i=0;i<$scope.weeklyData.length;i++){
            console.log($scope.weeklyData[i].week);
            var weekStart=getDateOfISOWeek($scope.weeklyData[i].week,2015);
            $scope.weeklyData2.push({"date":weekStart,"usage":Math.floor(Math.random() * (2)) });
        }

        console.log($scope.weeklyData2);
    })


    .controller('monthlyDataReport',function($scope){

        console.log("inside controller");



        $scope.monthlyData=[{"month":15,"count":0},{"month":16,"count":0},{"month":17,"count":0}];




        $scope.monthlyData2=[];
        for(var i=0;i< $scope.monthlyData.length;i++){
            console.log("inside for loop");


            if($scope.monthlyData[i].month < 12){
                console.log("inside if");
                var date = new Date(2015,$scope.monthlyData[i].month ,1);
                var firstDate = date.toISOString();
                $scope.monthlyData2.push({"date":firstDate,"usage":Math.floor(Math.random() * (2)) });

            }

            else{
                console.log("inside else");
                var monthOfTheYear = ($scope.monthlyData[i].month)%12;
                var dateCalculated = new Date(2016,monthOfTheYear,1);
                var firstDateCalc =dateCalculated.toISOString();
                $scope.monthlyData2.push({"date":firstDateCalc,"usage":Math.floor(Math.random() * (2)) });

            }
        }


    })



    .directive('weeklyUserReport', function () {

        var directiveDefinitionObject = {

            restrict: 'E',

            replace: false,

            scope: {data: '=data'},
            link: function (scope, element, attrs) {


                scope.$watch('data',function(data) {

                    if (data) {

                        var parseDate = d3.time.format("%Y%m%d").parse;

                        var generateData = function (data) {
                            var newData = [];
                            data.forEach(function (d) {
                                var newDataPoint;
                                if (d.date) {
                                    newDataPoint = {
                                        date: d.date,
                                        usage: d.usage
                                    };
                                    newData.push(newDataPoint);
                                }
                            });
                            return newData;
                        };

                        var data = generateData(scope.data);


                        var margin = {
                            top: 20,
                            right: 20,
                            bottom: 20,
                            left: 45
                        };

                        var width = 400 - margin.left - margin.right;
                        var height = 150 - margin.top - margin.bottom;

                        var x = d3.time.scale()
                            .domain(d3.extent(data, function (d) {
                                return d.date;
                            }))
                            .range([0, width]);

                        var y = d3.scale.linear()
                            .domain(d3.extent(data, function (d) {
                                return d.usage;
                            }))
                            .range([height, 0]);

                        var line = d3.svg.line()
                            .x(function (d) {
                                return x(d.date);
                            })
                            .y(function (d) {
                                return y(d.usage);
                            });

                        var area = d3.svg.area()
                            .x(function (d) {
                                return x(d.date);
                            })
                            .y0(height)
                            .y1(function (d) {
                                return y(d.usage);
                            });

                        var zoom = d3.behavior.zoom()
                            .x(x)
                            .y(y)
                            .on("zoom", zoomed);
                            var el=element[0];

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


                        var make_x_axis = function () {
                            return d3.svg.axis()
                                .scale(x)
                                .orient("bottom")
                                .ticks(5);
                        };

                        var make_y_axis = function () {
                            return d3.svg.axis()
                                .scale(y)
                                .orient("left")
                                .ticks(5);
                        };

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

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

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

                        chart.append("g")
                            .attr("class", "y axis")
                            .call(yAxis);

                        chart.append("g")
                            .attr("class", "x grid")
                            .attr("transform", "translate(0," + height + ")")
                            .call(make_x_axis()
                                .tickSize(-height, 0, 0)
                                .tickFormat(""));

                        chart.append("g")
                            .attr("class", "y grid")
                            .call(make_y_axis()
                                .tickSize(-width, 0, 0)
                                .tickFormat(""));

                        chart.append("path")
                            .datum(data)
                            .attr("class", "area")
                            .attr("d", area);


                        chart.append("g")
                            .attr("class", "points")
                            .selectAll(".point")
                            .data(data)
                            .enter().append("circle")
                            .attr("class", "point")
                            .attr("cx", function (d) {
                                return x(d.date)
                            })
                            .attr("cy", function (d) {
                                return y(d.usage)
                            })
                            .attr("r", 3)

                    }

                    function zoomed() {
                        console.log(d3.event.translate);
                        console.log(d3.event.scale);
                        chart.select(".x.axis").call(xAxis);
                        chart.select(".y.axis").call(yAxis);
                        chart.select(".x.grid")
                            .call(make_x_axis()
                                .tickSize(-height, 0, 0)
                                .tickFormat(""));
                        chart.select(".y.grid")
                            .call(make_y_axis()
                                .tickSize(-width, 0, 0)
                                .tickFormat(""));
                        chart.select(".area")
                            .attr("class", "area")
                            .attr("d", area);
                    }

                    function responsivefy(svg) {
                        // get container + svg aspect ratio
                        var container = d3.select(svg.node().parentNode),
                            width = parseInt(svg.style("width")),
                            height = parseInt(svg.style("height")),
                            aspect = width / height;

                        // add viewBox and preserveAspectRatio properties,
                        // and call resize so that svg resizes on inital page load
                        svg.attr("viewBox", "0 0 " + width + " " + height)
                            .attr("perserveAspectRatio", "xMinYMid")
                            .call(resize);

                        // to register multiple listeners for same event type,
                        // you need to add namespace, i.e., 'click.foo'
                        // necessary if you call invoke this function for multiple svgs
                        // api docs: https://github.com/mbostock/d3/wiki/Selections#on
                        d3.select(window).on("resize." + container.attr("id"), resize);

                        // get width of container and resize svg to fit it
                        function resize() {
                            var targetWidth = parseInt(container.style("width"));
                            svg.attr("width", targetWidth);
                            svg.attr("height", Math.round(targetWidth / aspect));
                        }
                    };
                })

            }
        };
        return directiveDefinitionObject;
    })
/* Styles go here */

body {
    font: 10px sans-serif;
}
.plot {
    fill: rgba(250, 250, 255, 0.6);
}
.grid .tick {
    stroke: lightgrey;
    opacity: 0.7;
}
.grid path {
    stroke-width: 0;
}
.axis path, .axis line {
    fill: none;
    stroke: #000;
    shape-rendering: crispEdges;
}
.x.axis path {
    display: none;
}
.line {
    fill: none;
    stroke: steelblue;
    stroke-width: 1.5px;
}



.axis path {
    fill: transparent;
    stroke: black;
}
.axis.y .tick line {
    stroke: #e2e1e6;
}
.axis.y .tick:first-child line {
    stroke: black;
}
.area {
    fill: rgba(52, 151, 219, 0.4);
}

.points .point:first-child {
    fill: transparent;
}
.point {
    fill: #3497db;
    stroke: transparent;
}
svg {
    background-color: #f5f5f5;
    display: block;
    margin: 1em auto;
}



.buttons a
{
    font-size: 16px;
}
.buttons a:hover
{
    cursor:pointer;
    font-size: 16px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.10/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<html>

  <head>
    <script data-require="angular.js@2.0.0" data-semver="2.0.0" src="https://code.angularjs.org/2.0.0-beta.6/angular2.min.js"></script>
    <link rel="stylesheet" href="style.css" type="text/css" />
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" type="text/css" />
  </head>

  <body>
    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.11.2/locale/en-gb.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-moment/0.10.3/angular-moment.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <script src="report.js"></script>
    <div ng-app="myApp">
      <div class="panel panel-default">
        <div class="panel-heading">Monthly User Report</div>
        <div class="panel-body" ng-controller="monthlyDataReport">
          <weekly-user-report data="monthlyData2"></weekly-user-report>
        </div>
      </div>
      <div class="panel panel-default">
        <div class="panel-heading">WeeklyUserReport</div>
        <div class="panel-body" ng-controller="weeklyData">
          <weekly-user-report data="weeklyData2"></weekly-user-report>
        </div>
      </div>
    </div>
  </body>

</html>