API Docs for:
Show:

File: script.js

var canvasWidth;
var canvasHeight; 
var mapScale = 43;
var c;
var ct;
var offset = 0;
var animationId;
var map = new SubwayMap();
var timer;

/**
 * Subway Map Object constructor
 * @class SubwayMap
 */
function SubwayMap(){
    
    /**
    * @property that
    */
    var that = this;
    
    /**
    * Array of subway stations, represents a route
    * @property route
    */
    this.route = [];
    
    /**
    * Array of subway lines
    * @property subwayLines
    */
    this.subwayLines = [];
    
    /**
     * Calculates subway line relative width
     * @method getLineWidth
     * @private
     * @return {number} width of the subway line
     */
    getLineWidth = function() {
        return canvasWidth * 0.005;
    }

    /**
     * Calculates subway station relative radiues
     * @method getStationRadius
     * @private
     * @return {number} radius of the subway station
     */
    getStationRadius = function() {
        return canvasWidth * 0.01;
    }

    /**
     * Calculates X coordinate on the canvas plane
     * @method getCanvasX
     * @private
     * @param {number} X relative X coordinate
     * @return {number} X coordinate on the canvas plane
     */
    getCanvasX = function(X) {
        return (canvasWidth * X)/mapScale;
    }

    /**
     * Calculates Y coordinate on the canvas plane
     * @method getCanvasY
     * @private
     * @param {number} Y relative Y coordinate
     * @return {number} Y coordinate on the canvas plane
     */
    getCanvasY = function(Y) {
        return (canvasHeight * Y)/mapScale;
    };
    
    /**
     * Calculates an array of station between station of origin to closest intersection with passed subway line
     * @method getStationsToLine
     * @private
     * @param {Object} stationfrom station of origin
     * @param {number} lineTo subway line id
     * @return {Object[]} an array of stations
     */
    getStationsToLine = function (stationfrom, lineTo) {
        var lineStations = getStationsByLineId(stationfrom.line_id);
        var indexOfOrigin = lineStations.indexOf(stationfrom);
        
        var candidateOne = [], candidateTwo = [];
        
        var candidateOneFound = false;
        var candidateTwoFound = false;
        
        var i = indexOfOrigin;
        var j = indexOfOrigin;
        
        parentLoop:
        for(var i = indexOfOrigin; i < lineStations.length; i++) {
            candidateOne.push(lineStations[i]);
            if(lineStations[i].intersection_id != -1) {
                var sts1 = getStationsByIntersectionId(lineStations[i].intersection_id);
                childLoop:
                for(var k = 0; k < sts1.length; k++) {
                    if(sts1[k].line_id == lineTo) {
                        candidateOneFound = true;
                        break parentLoop;
                    }
                }
            }
        }
        
        parentLoop:
        for(var i = indexOfOrigin; i >= 0; i--) {
            candidateTwo.push(lineStations[i]);
            if(lineStations[i].intersection_id != -1) {
                var sts1 = getStationsByIntersectionId(lineStations[i].intersection_id);
                childLoop:
                for(var k = 0; k < sts1.length; k++) {
                    if(sts1[k].line_id == lineTo) {
                        candidateTwoFound = true;
                        break parentLoop;
                    }
                }
            }
        }
        
        
        var candidateOneTrueStations = [];
        var candidateTwoTrueStations = [];
        for(var i = 0; i < candidateOne.length; i++) {
            if(candidateOne[i].name != "not-a-station") {
                candidateOneTrueStations.push(candidateOne[i]);
            }
        }
        
        for(var i = 0; i < candidateTwo.length; i++) {
            if(candidateTwo[i].name != "not-a-station") {
                candidateTwoTrueStations.push(candidateTwo[i]);
            }
        }
        
        if(!candidateOneFound) return candidateTwo;
        if(!candidateTwoFound) return candidateOne;
        
        if(candidateOneTrueStations.length >= candidateTwoTrueStations.length) return candidateTwo;
        if(candidateOneTrueStations.length <= candidateTwoTrueStations.length) return candidateOne;
    }
    
    /**
     * Calculates an array of subway stations with a passed intersection ID
     * @method getStationsByIntersectionId
     * @private
     * @param {number} intersection_id intersection ID
     * @return {Object[]} an array of subway stations
     */
    getStationsByIntersectionId = function(intersection_id) {
        var intersections = [];
        for(var i = 0; i < that.subwayLines.length; i++) {
            var curLine = that.subwayLines[i];
            for(var j = 0; j < curLine.stations.length; j++) {
                if(curLine.stations[j].intersection_id == intersection_id) {
                    intersections.push(curLine.stations[j]);
                }
            }
        }
        
        return intersections;
    }
    
    /**
     * Calculates an array of subway lines which intersects two given lines
     * @method getSharedLines
     * @private
     * @param {number} lineOne first subway line ID
     * @param {number} lineTwo second subway line ID
     * @return {Object[]} an aray of subway lines
     */
    getSharedLines = function(lineOne, lineTwo) {
        var lineOneIntersections = getIntersectionsByLineId(lineOne);
        var lineTwoIntersections = getIntersectionsByLineId(lineTwo);
        
        var lineOneIntersectionLines = []
        for(var i = 0; i < lineOneIntersections.length; i++) {
            var stns = getStationsByIntersectionId(lineOneIntersections[i].intersection_id)
            for(var j = 0; j < stns.length; j++) {
                if(stns[j].line_id != lineOne) lineOneIntersectionLines.push(stns[j].line_id)
            }
        }
        
        var lineTwoIntersectionLines = []
        for(var i = 0; i < lineTwoIntersections.length; i++) {
            var stns = getStationsByIntersectionId(lineTwoIntersections[i].intersection_id)
            for(var j = 0; j < stns.length; j++) {
                if(stns[j].line_id != lineTwo) lineTwoIntersectionLines.push(stns[j].line_id)
            }
        }
        
        var sharedLines = [];
        for(var i = 0; i < lineOneIntersectionLines.length; i++) {
            for(var j = 0; j < lineTwoIntersectionLines.length; j++) {
                if(lineOneIntersectionLines[i] == lineTwoIntersectionLines[j]) {
                    sharedLines.push(lineOneIntersectionLines[i]);
                }
            }
        }
        
        var uniqueSharedLines = sharedLines.filter(function(elem, pos) {
            return sharedLines.indexOf(elem) == pos;
        });
        
        return uniqueSharedLines;
    };
    
    /**
     * Calculates an array of subway stations on a given subway line which intersects with other subway lines
     * @method getIntersectionsByLineId
     * @private
     * @param {number} line_id subway line ID
     * @return {Object[]} an array of subway stations
     */
    getIntersectionsByLineId = function(line_id) {
        var line = getStationsByLineId(line_id).slice();
        
        var i = line.length;
        while(i--) {
            if(line[i].intersection_id == -1) 
                line.splice(i, 1);
        };
        
        return line;
    }
    
    /**
     * Calculates an array of colors for a given station
     * @method getStationColors
     * @private
     * @param {Object} station a subway station
     * @return {String[]} an array of string which represents subway station color to be paint
     */
    getStationColors = function(station) {
        
        var colors = [];
        intersectionId = station.intersection_id;
        
        if(intersectionId == -1) {
            for(var i = 0; i < that.subwayLines.length; i++) {
                if(station.line_id == that.subwayLines[i].id) {
                    colors.push(that.subwayLines[i].color);
                    break;
                }
            }
        } else {
            for(var i = 0; i < that.subwayLines.length; i++) {
                var curLine = that.subwayLines[i];
                for(var j = 0; j < curLine.stations.length; j++) {
                    var curStation = that.subwayLines[i].stations[j];
                    if(curStation.intersection_id == intersectionId) {
                        colors.push(curLine.color);
                    }
                }
            }
        }
        
        return colors;
    }
    
    /**
     * Gets a station object on a given line which has shared intersection with a given station
     * @method getStationOnIntersectedLine
     * @private
     * @param {number} lineId subway line ID
     * @param {Object} station subway station
     * @return {Object} a subway station
     */
    getStationOnIntersectedLine = function (lineId, station) {
        var intersections = getIntersectionsByLineId(lineId);
        for(var i = 0; i < intersections.length; i++) {
            if(station.intersection_id == intersections[i].intersection_id) {
                return intersections[i];
            }
        }
    }
    
    /**
     * Gets a subway line object by subway line name
     * @method getLineByName
     * @private
     * @param {string} name subway line name
     * @return {Object} a subway line
     */
    getLineByName = function(name){
        for(var i = 0; i < that.subwayLines.length; i++) {
            if(that.subwayLines[i].name == name) {
                return that.subwayLines[i];
            }
        }
    };
    
    /**
     * Gets an array of subway stations by subway line ID
     * @method getStationsByLineId
     * @private
     * @param {number} id subway line ID
     * @return {Object[]} an array of subway stations
     */
    getStationsByLineId = function(id){
        for(var i = 0; i < that.subwayLines.length; i++) {
            if(that.subwayLines[i].id == id) {
                return that.subwayLines[i].stations;
            }
        }
    };
    
    /**
     * Gets a subway station with by subway station ID
     * @method getStationById
     * @private
     * @param {number} id subway station ID
     * @return {Object} a subway station
     */
    getStationById = function(id){
        for(var i = 0; i < that.subwayLines.length; i++) {
            var line = that.subwayLines[i];
            for(j = 0; j < line.stations.length; j++) {
                var station = line.stations[j];
                if(station.station_id == id) {
                    return station;
                }
            }
        }
    };    
    
    /**
     * Draws subway lines on canvas
     * @method drawSubwayLines
     * @private
     */
    drawSubwayLines = function(){
        for(var i = 0; i < that.subwayLines.length; i++) {
            for(var j = 0; j < that.subwayLines[i].stations.length; j++) {
                if(j == 0) continue;

                var curStation = that.subwayLines[i].stations[j];
                var prevStation = that.subwayLines[i].stations[j - 1];

                if(curStation.name == "Biblioteka Imeni Lenina" && that.subwayLines[i].name == "Sokolnicheskaya"){
                    ct.beginPath();
                    ct.moveTo(getCanvasX(prevStation.X),getCanvasY(prevStation.Y) + 1.25 * getLineWidth());
                    ct.lineTo(getCanvasX(curStation.X),getCanvasX(curStation.Y) + 1.25 * getLineWidth());
                    ct.strokeStyle = that.subwayLines[i].color;
                    ct.lineWidth = getLineWidth();
                    ct.stroke();
                    
                    continue;
                }
                
                if(curStation.name == "Ploshad' revolutcii" && that.subwayLines[i].name == "Arbatskaya"){
                    ct.beginPath();
                    ct.moveTo(getCanvasX(prevStation.X),getCanvasY(prevStation.Y) - 1.25 * getLineWidth());
                    ct.lineTo(getCanvasX(curStation.X),getCanvasX(curStation.Y) - 1.25 * getLineWidth());
                    ct.strokeStyle = that.subwayLines[i].color;
                    ct.lineWidth = getLineWidth();
                    ct.stroke();
                    
                    continue;
                }
                
                
                ct.beginPath();
                ct.moveTo(getCanvasX(prevStation.X),getCanvasY(prevStation.Y));
                ct.lineTo(getCanvasX(curStation.X),getCanvasX(curStation.Y));
                ct.strokeStyle = that.subwayLines[i].color;
                ct.lineWidth = getLineWidth();
                ct.stroke();
            }
        }
    };

    /**
     * Draws subway stations on canvas
     * @method drawSubwayStations
     * @private
     */
    drawSubwayStations = function(){
        for(var i = 0; i < that.subwayLines.length; i++) {
            for(var j = 0; j < that.subwayLines[i].stations.length; j++) {
                
                var curStation = that.subwayLines[i].stations[j];
                if(curStation.name == "not-a-station") continue;
                ct.beginPath();
                ct.arc(getCanvasX(curStation.X),getCanvasY(curStation.Y),getStationRadius() + 1,0,2*Math.PI);
                ct.fillStyle = 'black';
                ct.fill();
                
                var colors = getStationColors(curStation);
                var tau = Math.PI * 2;
                var frac = tau/colors.length;
                
                for(var k = 0; k < colors.length; k++) {
                    ct.beginPath();
                    ct.moveTo(getCanvasX(curStation.X), getCanvasY(curStation.Y));
                    ct.arc(getCanvasX(curStation.X),getCanvasY(curStation.Y),getStationRadius(), k * frac, (k + 1) * frac);
                    ct.fillStyle = colors[k];
                    ct.fill();
                }
            }
        }
    };
    
    /**
     * Draws subway station labels on canvas
     * @method drawLabels
     * @private
     */
    drawLabels = function() {
        
        var names = [];
        
        for(var i = 0; i < that.subwayLines.length; i++) {
            for(var j = 0; j < that.subwayLines[i].stations.length; j++) {
                var curStation = that.subwayLines[i].stations[j];
                
                if(curStation.name == "not-a-station") continue;
                
                
                if(curStation.name != "Arbatskaya" && curStation.name != "Smolenskaya") {
                    if(names.indexOf(curStation.name) > -1) {
                        continue;
                    }
                }
                
                names.push(curStation.name);
                
                var xOffset, yOffset;
                
                if(curStation.labelposition == "top-right") {
                    xOffset = 5;
                    yOffset = getStationRadius() * -3.2;
                }
                
                if(curStation.labelposition == "right") {
                    xOffset = getStationRadius() * 2;
                    yOffset = -7.5;
                }
                
                if(curStation.labelposition == "bottom-right") {
                    xOffset = 5;
                    yOffset = getStationRadius() * 1.5;
                }
                
                if(curStation.labelposition == "left") {
                    xOffset = -1 * ct.measureText(curStation.name).width - getStationRadius() * 2;
                    yOffset = -7.5;
                }
                
                if(curStation.labelposition == "bottom-left") {
                    xOffset = -1 * ct.measureText(curStation.name).width - getStationRadius() * 1.5;
                    yOffset = getStationRadius() * 1.5;
                }
                
                ct.lineWidth = 1;
                ct.strokeStyle = "rgba(0, 0, 0, 0.3)";
                ct.fillStyle = "rgba(200, 200, 200, 0.3)";
                
                roundRect(
                    ct, 
                    getCanvasX(curStation.X) + xOffset - 5,
                    getCanvasY(curStation.Y) + yOffset,
                    ct.measureText(curStation.name).width + 10, 
                    15, 
                    3, 
                    true
                );
                
                
                ct.textBaseline = 'top';
                ct.fillStyle = "black";
                ct.font = "10px sans-serif";
                ct.fillText(curStation.name, getCanvasX(curStation.X) + xOffset, getCanvasY(curStation.Y) + yOffset);
            }
        }
    }
    
    /**
     * Gets an array of subway stations between station of origin and station of destination on the same subway line
     * @method getStationsBetween
     * @private
     * @param {Object} from station of origin
     * @param {Object} to station of destination
     * @return {Object[]} an array of subway stations 
     */
    getStationsBetween = function(from, to) {
        if(from.station_id == to.station_id) {
            return [];
        }
        
        var lineStations = getStationsByLineId(from.line_id);
        var candidateOne = [], candidateTwo = [], stationsBetween = [];
        
        var indexOfOrigin = lineStations.indexOf(from);
        var indexOfDestination = lineStations.indexOf(to);

        var i = indexOfOrigin;
        var j = indexOfOrigin;
        
        candidateOne.push(lineStations[i]);
        candidateTwo.push(lineStations[j]);
        
        do {
            i++;
            j--;

            if(from.line_id == 1) {
                if(i == lineStations.length) i = 0;
                if(j == -1) j = lineStations.length-1;

                if(lineStations[i].name != 'not-a-station') candidateOne.push(lineStations[i]);
                if(lineStations[j].name != 'not-a-station') candidateTwo.push(lineStations[j]);
            } else {
                if(i == lineStations.length) i = lineStations.length - 1;
                if(j == -1) j = 0;

                candidateOne.push(lineStations[i]);
                candidateTwo.push(lineStations[j]);
            }
        } while(i!=indexOfDestination && j!=indexOfDestination);

        if(candidateOne[candidateOne.length - 1] == to) return candidateOne;
        else return candidateTwo;
    }
    
    /**
     * A method to test the subway map
     * @method testMap
     */
    this.testMap = function() {
        var origins = map.subwayLines;
        var destinations = map.subwayLines;
        
        for(var i = 0; i < origins.length; i++) {
            var originLine = origins[i];
            for(var j = 0; j < originLine.stations.length; j++) {
                var originStation = origins[i].stations[j];
                
                for(var k = 0; k < destinations.length; k++) {
                    var destinationLine = destinations[k];
                    for(var m = 0; m < destinations[k].stations.length; m++) {
                        var destinationStation = destinations[k].stations[m];
                        if(originStation.station_id == destinationStation.station_id) continue;
                        if(originStation.name == "not-a-station") continue;
                        if(destinationStation.name == "not-a-station") continue;
                        
                        var sts = [];
                        that.setRoute(originStation.station_id, destinationStation.station_id);
                        
                        console.log("From: " + originStation.name + "(" + originLine.name + ") To: " + destinationStation.name + "(" +destinationLine.name+ ") Total stations between: " + that.route.length);
                    }
                }
            }
        }
    }
    
    /**
     * Calculates most optimal route between two given stations
     * @method setRoute
     * @param {number} StationIdfrom ID of the station of origin
     * @param {number} StationIdto ID of the station of destination
     * @return {Object[]} an array of stations
     */
    this.setRoute = function(StationIdfrom, StationIdto){
        that.route = [];
        
        var tempRoute = [];
        var dirtyCandidates = [];
        
        from = getStationById(StationIdfrom);
        to = getStationById(StationIdto);
        
        if(from.line_id == to.line_id) {
            that.route = getStationsBetween(from, to);
        }
        else {
            var fromLineIntersections   = getIntersectionsByLineId(from.line_id);
            var toLineIntersections     = getIntersectionsByLineId(to.line_id);

            var froms = [];
            if(from.intersection_id != -1) {
                froms = getStationsByIntersectionId(from.intersection_id);
            } else {
                froms.push(from);
            }
            
            for(var j = 0; j < froms.length; j++) {
                var sharedLines = getSharedLines(froms[j].line_id, to.line_id);

                for(var i = 0; i < sharedLines.length; i++) {
                    var originLineStations = getStationsToLine(froms[j], sharedLines[i]);
                    var destinationLineStations = getStationsToLine(to, sharedLines[i]);

                    var stn1 = getStationOnIntersectedLine(sharedLines[i],originLineStations[originLineStations.length - 1]);
                    var stn2 = getStationOnIntersectedLine(sharedLines[i],destinationLineStations[destinationLineStations.length - 1]);

                    var stationBetween = getStationsBetween(stn1, stn2);
                    destinationLineStations.reverse();

                    var dirtyCandidate = originLineStations.concat(stationBetween, destinationLineStations);
                    dirtyCandidates.push(dirtyCandidate);
                }      
            }
            
            var sharedIntersections = [];
            for(var i = 0; i < fromLineIntersections.length; i++) {
                for(var j = 0; j < toLineIntersections.length; j++) {
                    if(fromLineIntersections[i].intersection_id == toLineIntersections[j].intersection_id) {
                        sharedIntersections.push({
                            "from"  : fromLineIntersections[i],
                            "to"    : toLineIntersections[j]
                        });
                    }
                }
            }
            
            for(var i = 0; i < sharedIntersections.length; i++) {
                var arr1 = getStationsBetween(from, sharedIntersections[i].from);
                var arr2 = getStationsBetween(sharedIntersections[i].to, to);
                dirtyCandidate = arr1.concat(arr2);
                dirtyCandidates.push(dirtyCandidate);
            }
            
            var cleanCandidates = [];
            for(var i = 0; i < dirtyCandidates.length; i++) {
                var dirtyCandidate = dirtyCandidates[i];
                var cleanCandidate = [];
                
                parentLoop:
                for(var j = 0; j < dirtyCandidate.length; j++) {
                    if(dirtyCandidate[j].name != "not-a-station") {
                        for(var k = 0; k < cleanCandidate.length; k++){
                            if(dirtyCandidate[j].X == cleanCandidate[k].X && dirtyCandidate[j].Y == cleanCandidate[k].Y) {
                                continue parentLoop; 
                            }
                        }
                        
                        cleanCandidate.push(dirtyCandidate[j]);
                    }
                }
                cleanCandidates.push(cleanCandidate);
            }

            var candidateCount = 100;
            for(var i = 0; i < cleanCandidates.length; i++) {
                if(cleanCandidates[i].length < candidateCount) {
                    candidateCount = cleanCandidates[i].length;
                    tempRoute = dirtyCandidates[i];
                }
            }
            
            that.route = tempRoute;
        }
    };
    
    /**
     * Draws the route
     * @method drawRoute
     * @private
     */
    drawRoute = function() {
        
        offset++;
        if (offset > 1000) {
            offset = 0;
        }
        
        for(var i = 0; i < that.route.length; i++) {
            if(i == 0) continue;

            var curStation = that.route[i];
            var prevStation = that.route[i - 1];

            ct.beginPath();
            ct.moveTo(getCanvasX(prevStation.X),getCanvasY(prevStation.Y));
            ct.lineTo(getCanvasX(curStation.X),getCanvasX(curStation.Y));
            ct.strokeStyle = "black";
            ct.setLineDash([10]);
            ct.lineDashOffset = -offset;
            ct.lineWidth = 10;
            ct.stroke();
        }
    }
    
    /**
     * Description
     * @method drawSubwayMap
     * @return 
     */
    this.drawSubwayMap = function(){
        c.attr('width', $(c).parent().width()); 
        c.attr('height', $(c).parent().width());
        
        canvasWidth = c.width();
        canvasHeight = c.height();  			
        
        drawSubwayLines();
        drawLabels();
        if(map.route.length > 0) {
            drawRoute(route);
        }
        drawSubwayStations();
    }
}

/**
 * Draws rounded rectangle on a canvas
 * @method roundRect
 * @param {Object} ctx a canvas context
 * @param {number} x coordinate
 * @param {number} y coordinate
 * @param {number} width
 * @param {number} height
 * @param {number} radius
 * @param {boolean} fill
 * @param {boolean} stroke
 */
function roundRect(ctx, x, y, width, height, radius, fill, stroke) {
    if (typeof stroke == 'undefined') {
        stroke = true;
    }
    if (typeof radius === 'undefined') {
        radius = 5;
    }
    if (typeof radius === 'number') {
        radius = {tl: radius, tr: radius, br: radius, bl: radius};
    } else {
        var defaultRadius = {tl: 0, tr: 0, br: 0, bl: 0};
        for (var side in defaultRadius) {
            radius[side] = radius[side] || defaultRadius[side];
        }
    }
    
    ctx.beginPath();
    ctx.moveTo(x + radius.tl, y);
    ctx.lineTo(x + width - radius.tr, y);
    ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr);
    ctx.lineTo(x + width, y + height - radius.br);
    ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height);
    ctx.lineTo(x + radius.bl, y + height);
    ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl);
    ctx.lineTo(x, y + radius.tl);
    ctx.quadraticCurveTo(x, y, x + radius.tl, y);
    ctx.closePath();
    if (fill) {
        ctx.fill();
    }
    if (stroke) {
        ctx.stroke();
    }
}

/**
 * Fills dropdown menus with stations data
 * @method fillDropDown
 * @param {Object[]} data an array of stations
 * @param {string} id id of the select element
 */
var fillDropDown = function(data, id) {
    var select = $(id);
    var searchItems = [];
    var icon;
    
    for(var i = 0; i < data.length; i++) {
        var curLine = data[i];
        for(var j = 0; j < curLine.stations.length; j++) {
            var curStation = curLine.stations[j];
            
            if(curStation.name == "not-a-station") continue;
            
            var icon;
            switch(curLine.id) {
                case "1": 
                    icon = "images/lines/brown.png";
                    break;
                case "2": 
                    icon = "images/lines/green.png";
                    break;
                case "3": 
                    icon = "images/lines/orange.png";
                    break;
                case "4": 
                    icon = "images/lines/red.png";
                    break;
                case "5": 
                    icon = "images/lines/darkblue.png";
                    break;
                case "6": 
                    icon = "images/lines/lightblue.png";
                    break;
                case "7": 
                    icon = "images/lines/pink.png";
                    break;
                case "8": 
                    icon = "images/lines/yellow.png";
                    break;
            }
            
            searchItems.push({
                value:  curStation.station_id,
                label:  curStation.name,
                icon:   icon
            });   
        }
    }
    
    $(id).autocomplete({
        source: searchItems
    });
}

$("#clear").click(function() {
    map.drawSubwayMap();
});

/**
 * Renders canvas
 * @method render
 */
function render() {
    if(map.route.length > 0) {
        timer = setTimeout(function() {
            animationId = requestAnimationFrame(render);
            map.drawSubwayMap();
        }, 1000 / 100);
    } else {
        map.drawSubwayMap();
    }
}

$(document).ready( function(){

    $("#route").click(function() {
        cancelAnimationFrame(animationId);
        clearTimeout(timer);
        map.setRoute($("#originHidden").val(), $("#destinationHidden").val());
        render();
    });
    
    $("#test").click(function() {
        var origins = map.testMap();
    });
    
    var req = $.get( "get-data.php")
    .fail(function() {
    })
    .done(function(data) {
        map.subwayLines = data;
        fillDropDown(data, "#origin");
        fillDropDown(data, "#destination");
        map.drawSubwayMap();
    });
    
    c = $('#canvas');
    ct = c.get(0).getContext('2d');

    $(window).resize(render);
    
    render();
});