Angular Ad-hoc brackets drawing

by anup1986

HTML

<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<script src="http://underscorejs.org/underscore-min.js"></script>
<div class="container" ng-app="myApp">
    <div ng-controller="drawController">
        <div class="row">
            <div class="col-md-12">
                <div class="btn-group">
                <button class="btn btn-primary" ng-click="addCompetitor(name); name=''" type="button">
                    + Lägg till tävlande
                </button>
                    <button class="btn btn-success" ng-click="drawBrackets()" type="button">
                        <- -> Lotta
                    </button>
                </div>
                    <input class="form-control" ng-model="name" type="text" placeholder="Namn" />
                <table class="table" ng-hide="draw">
                    <thead>
                        <tr>
                            <th>Namn</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr ng-repeat="competitor in competitors">
                            <td>
                                <span>{{competitor.name}}<span/>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
        <div class="row" ng-show="draw">
            <div class="col-md-12">
                <div mc-render-brackets list="competitors"></div>
            </div>
        </div>
    </div>
</div>

CSS

html, body, .brackets {
    width: 100%;
    min-height: 100%;
    font-family:"Arial", sans-serif;
}
.metroBtn {
    background-color: #2E7BCC;
    color: #fff;
    font-size: 1.1em;
    padding: 10px;
    display: inline-block;
    margin-bottom: 30px;
    cursor: pointer;
}
.brackets > div {
    vertical-align: top;
    clear: both;
}
.brackets > div > div {
    float: left;
    height: 100%;
}
.brackets > div > div > div {
    margin: 50px 0;
}
.brackets div.bracketbox {
    position: relative;
    width: 100%;
    height: 100%;
    border-top: 1px solid #555;
    border-right: 1px solid #555;
    border-bottom: 1px solid #555;
}
.brackets div.r1 .bracketbox > span.info {
    position: absolute;
    top: 0;
    right: 0;
    font-size: 0.8em;
    color: #000;
    background: rgba(204, 204, 204, 0.32);
    height: 100%;
    padding-top: 20px;
    margin-left: 85%;
    text-align: center;
    border-left: 1px solid #000;
}
.brackets div.r2 .bracketbox > span.info {
    position: absolute;
    top: 0;
    right: 0;
    font-size: 0.8em;
    color: #000;
    background: rgba(204, 204, 204, 0.32);
    height: 100%;
    padding-top: 45px;
    margin-left: 85%;
    text-align: center;
    border-left: 1px solid #000;
}
.brackets div.r3 .bracketbox > span.info {
    position: absolute;
    top: 0;
    right: 0;
    font-size: 0.8em;
    color: #000;
    background: rgba(204, 204, 204, 0.32);
    height: 100%;
    padding-top: 108px;
    margin-left: 85%;
    text-align: center;
    border-left: 1px solid #000;
}
.brackets div.r4 .bracketbox > span.info {
    position: absolute;
    top: 0;
    right: 0;
    font-size: 0.8em;
    color: #000;
    background: rgba(204, 204, 204, 0.32);
    height: 100%;
    padding-top: 202px;
    margin-left: 85%;
    text-align: center;
    border-left: 1px solid #000;
}

.brackets div.bracketbox > span {
    position: absolute;
    left: 5px;
    font-size: 0.85em;
}
.brackets div.bracketbox > span.teama {
    top: -20px;
   ...

JavaScript

var myApp = angular.module('myApp', []);

myApp.filter('range', function () {
    return function (input, total) {
        var total = parseInt(total);
        for (var i = 0; i < total; i++)
        input.push(i);
        return input;
    };
});

myApp.directive('mcRenderBrackets', [

function () {
    return {
        restrict: 'AE',
        scope: {
            list: '='
        },
        template:
            '<div class="brackets">' +
            '<div class="group{{groupCount +1}}">' +
            '<div class="r{{round}}" ng-repeat="round in [] | range: groupCount +1">' +
            '<div ng-repeat="match in matches[round]">' +
            '<div class="bracketbox">' +
            '<span class="info">{{match.bracketNo}}</span>' +
            '<span class="teama" ng-click="matchWinner(match.compA, match)">{{match.compA.name}}</span>' +
            '<span class="teamb" ng-click="matchWinner(match.compB, match)">{{match.compB.name}}</span>' +
            '</div>' +
            '</div>' +
            '</div>' +
            '<div class="r{{groupCount +1}}">' +
            '<div class="final">' +
            '<div class="bracketbox">' +
            '<span class="winner">{{winner.name}}</span>' +
            '</div>' +
            '</div>' +
            '</div>' +
            '</div' +
            '</div>',
        link: function (scope, element, attrs, controller) {
            var knownBrackets = [2, 4, 8, 16, 32]; // brackets with "perfect" proportions (full fields, no walk overs)
            var shuffledCompetitors = _.shuffle(angular.copy(scope.list)),
                brackets = [];
            
            console.log(scope.list);
            
            scope.matchWinner = function(competitor, match){
                var nextMatch = _.findWhere(brackets, {
                    bracketNo: match.nextGame
                });
                
                // The final
                if (!nextMatch){
                    scope.winner = competitor;
         ...