Angular Directives - Line Chart

Line chart with linear regression

HTML

<script src="http://code.angularjs.org/angular-1.0.1.js"></script>
<link rel="stylesheet" href="http://cdn.wijmo.com/themes/metro/jquery-wijmo.css">
<link rel="stylesheet" href="http://cdn.wijmo.com/jquery.wijmo-complete.all.2.3.1.min.css">
<script src="http://cdn.wijmo.com/jquery.wijmo-open.all.2.3.1.min.js"></script>
<script src="http://cdn.wijmo.com/jquery.wijmo-complete.all.2.3.1.min.js"></script>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css">
<body ng-app="app" ng-controller="appCtrl">

<h3>Wijmo Line Chart</h3>

<p>This chart directive includes a linear regression with {{data.length}} points:</p>

<app-chart 
    data="data" x="x" y="y" 
    reg-parms="reg"
    color="blue" >
</app-chart>

<p>The linear regression equation is:
  <b>Y =
    {{reg.a | number:2}}
    <span ng-show="reg.b >= 0"> + </span>
    <span ng-show="reg.b < 0"> - </span>
    {{Math.abs(reg.b) | number:2}} * X</b></p>
<p>The coefficient of determination is:
  <b>r<sup>2</sup> = 
    {{reg.r2 | number:2}}</b></p>
    
<button ng-click="generateData()">Randomize Data</button>

</body>

CSS

/* change Wijmo widgets font to match bootstrap */
 .ui-widget {
    font-family:'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button {
    font-family:'Helvetica Neue', Helvetica, Arial, sans-serif;
}
/* use auto-width for Wijmo menu items */
 .wijmo-wijmenu .wijmo-wijmenu-parent .wijmo-wijmenu-child {
    width: auto;
    min-width: 150px;
}
/* custom back color for Wijmo tooltips*/
 .wijmo-wijtooltip {
    background-color: #fff9d1;
}

JavaScript

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

app.controller("appCtrl", function ($scope) {

    // generate the data
    $scope.generateData = function () {

        // generate some random points
        $scope.data = [];
        var a = Math.random() * 10 - 5;
        var b = Math.random() * 10 - 5;
        for (var i = 0; i < 250; i++) {
            var x = Math.random() * 100;
            var y = a + b * x;
            for (var j = 0; j < 10; j++)
                y += Math.random() * 40 - 20;
            $scope.data.push({ x: x, y: y });
        }

        // compute linear regression
        $scope.reg = linReg($scope.data, "x", "y");
    };

    // initialize the data
    $scope.generateData();
    
    // allow expressions to use javaScript Math functions
    $scope.Math = window.Math;

    // calculates a linear regression on the values provided
    function linReg(data, xProp, yProp) {

        // compute sums and sums of squares
        var n = 0, sx = 0, sy = 0, sxx = 0, syy = 0, sxy = 0;
        for (var i = 0; i < data.length; i++) {
            var x = data[i][xProp];
            var y = data[i][yProp];
            n++;
            sx += x;
            sy += y;
            sxx += x * x;
            syy += y * y;
            sxy += x * y;
        }

        // return regression coefficients and r2
        var b = (n * sxy - sx * sy) / (n * sxx - sx * sx);
        var a = sy / n - sx / n * b;  
        var r2 = (n * sxy - sx * sy) * (n * sxy - sx * sy) / ((n * sxx - sx * sx) * (n * syy - sy * sy)); 
        return { a: a, b: b, r2: r2 };
    }
});

app.directive("appChart", function (appUtil) {
    return {
        restrict: "E",
        replace: true,
        scope: {
            data: "=",      // array that contains the data for the chart.
            x: "@",         // property that contains the X values.
            y: "@",         // property that contains the Y values.
            regParms: "=",  // regression parameters (a and b coefficients)
       ...