Gantt Chart. Find Critical Path v2

__REFACTORING__

by Ivan Gerasimenko

HTML

<div ng-app='app'>
    <div id="logger"></div>
    <h4>Gantt Chart</h4>
    <div class="gantt-box" ng-controller="GanttCtrl">
        
        <div class="cell" ng-repeat="task in tasks">
            <div class="bar" 
                style="width: {{task.duration * 20}}px;
                        margin-left: {{task.startTime * 20}}px;"
                ng-class="{true:'critical'}[task.isCritical]">
                <div class="bar-arrow">
                    <div class="arrow-connector" 
                        ng-repeat="pred in task.predecessors" 
                        style="height: {{pred.height}}px; 
                               width: {{pred.width}}px"
                        ng-class="{true:'critical'}[pred.isCritical]"
                               ></div>
                </div>
                {{task.name}}
            </div>
        </div>
        
    </div>
</div>

CSS

.cell {
    border: 1px dashed #cccccc;
    width: 300px;
    height: 16px;
    padding: 7px;
}
.bar {
    position: relative;
    height: 16px;
    background: #cccccc;
    text-align: center;
    font-size: 12px;
    font-weight: bold;
}
.bar.critical {
    background: #ffcccc;
}

/*************** arrow connectors *****************/
.arrow-connector {
    /* four params to position respectively parent element */
    bottom: 11px;    
    right: -7px;     
    width: 5px;    
    height: 10px;  
    /******************************/
    position: absolute;
    border-top: 2px solid #8cc;
    border-right: 2px solid #8cc;
    border-top-right-radius: 4px;
}
.arrow-connector:before {
    content: "";
    display: inline-block;
    position: absolute;
    bottom: -12px;
    right: -6px;
    width: 0;
    height: 0;
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    border-top: 12px solid #8cc;
}
.arrow-connector { border-color: #8cc }
.arrow-connector:before { border-top-color: #8cc }
.arrow-connector.critical { border-color: #ff8888; z-index: 1000;}
.arrow-connector.critical:before { border-top-color: #ff8888; }

/*****************************************************/
.bar-arrow {
    position: absolute;
    width: 0;
    height: 0;
    top: 0;
    bottom: 0;
}

JavaScript

angular.module('app',[]).controller('GanttCtrl', function($scope) {
    gc.init(ganttChart);
    
    $scope.tasks = gc.get().tasks;
    console.log(gc.get().tasks);
});    

console.clear();

var ganttChart = {
    startDate: "Jul 23, 2006",
    tasks: [
        /*{ name: "task E", 
            predecessors: [
                {name: "task B", height: 0, width: 0, isCritical: true}, 
                {name: "task C"}], duration: 2.17, startTime: 8.5 },*/
        { name: "task A", predecessors: [], duration: 4},
        { name: "task B", predecessors: [], duration: 5.33},
        { name: "task C", predecessors: [{name: "task A"}], 
         duration: 4.5},
        { name: "task D", predecessors: [{name: "task A"}], 
         duration: 3},
        { name: "task E", predecessors: [{name: "task B"}, {name: "task C"}], 
         duration: 2.17},
        { name: "task F", predecessors: [{name: "task D"}, {name: "task E"}], 
         duration: 3}
]};

/* Finding critical path */


/****** module ****/
function GanttChart() {
    var chartData;
    var pathes;
    
    function init(params) { 
        // check for isNaN, expected properties.
        if(checkChartData(params)){
            chartData = params;
            // compute pathes
            pathes = getPathes();
            // compute critical start time startTime:
            for(var i=0; i<chartData.tasks.length; i++) {
                setTaskStartTime({ i: i, name: chartData.tasks[i].name });
            }
            // setCriticalPathMark
            setCriticalPathMark();
            // add connectors
            AddConnectors();
            console.log("Init complete."); 
        } else {
            console.log("Incorrect input data.");
        }
    };
    function checkChartData(params) {
        if(typeof params === 'object' &&
           typeof params.tasks === 'object' &&
           typeof params.tasks.slice === 'function') {
            return true;
        }
        else {
            return...