<commit_before>window.tronament = new function() {
    // some constant enums
    this.Direction = Object.freeze({
        UP: 1,
        DOWN: 2,
        LEFT: 3,
        RIGHT: 4
    });
    this.Space = Object.freeze({
        EMPTY: 0,
        TRAIL: 1,
        OPPONENT: 2,
        WALL: 4,
        OUT_OF_BOUNDS: 8
    });

    // game options
    this.options = {
        playerCount: 2,
        fastMovement: false
    }

    // some debug options
    this.debug = {
        // indicates if the framerate should be displayed on the canvas
        showFps: false,
        // the current frame rate
        fps: 0,
        maxFps: 60
    };

    // times used for scheduling, keeping track of frame rate, etc...
    var lastDrawTime, lastSecondTime, lastTickTime;

    // variables used for drawing to the canvas
    var canvas, ctx;

    // a map of all loaded AI classes
    this.aiModules = [];
    // an array of currently active players
    var players = [];
    // an array containing the coordinates of each player
    var playerCoordinates = [];
    // the dimensions of the board grid
    var boardWidth, boardHeight;
    // a 2d array that stores a collision map for each position on the grid
    var collisionMap = [[]];
    var squareWidth, squareHeight;
    var timer;
    var running = false;
    var lastLoadedModule;
    var alivePlayerCount = 0;

    /**
     * Initializes the Tronament game engine.
     *
     * @param Element canvasElement The canvas element to be used for drawing.
     */
    this.init = function() {
        canvas = document.getElementById("canvas");
        ctx = canvas.getContext("2d");
        this.setBoardSize(48, 48);
    }

    /**
     * Gets the dimensions of the board.
     *
     * @return Object An object whose "width" property is the width of the board
     *                and "height" property is the height of the board.
     */
    this.getBoardSize = function() {
        return {
            width: boardWidth,
            height: boardHeight
        };
    }

    /**
     * Sets the dimensions of the board.
     *
     * @param Number width  The new board width.
     * @param Number height The new board height.
     */
    this.setBoardSize = function(width, height) {
        boardWidth = width;
        boardHeight = height;

        // do some calculations ahead of time for rendering performance
        squareWidth = Math.round(canvas.width / boardWidth);
        squareHeight = Math.round(canvas.height / boardHeight);
    }

    /**
     * Bootstraps an AI module prototype.
     *
     * Here there be dragons. This method uses some meta-programming
     * techniques, so be sure to remember who's who and what's what.
     *
     * @param String   name        The module name.
     * @param Function constructor An object constructor.
     */
    this.aiModule = function(name, constructor) {
        constructor.prototype.name = name;

        // next, define some useful methods for the module to use...

        /**
         * Queries the game for what is at an absolute location.
         *
         * @param  Number  x The x-coordinate of the position.
         * @param  Number  y The y-coordinate of the position.
         * @return Number    A Space value indicating what is in the space.
         */
        constructor.prototype.queryAbsolute = function(x, y) {
            var playerIndex = players.indexOf(this);
            var result = tronament.query(x, y);

            // do an additional check for opponent trail
            if (result == tronament.Space.TRAIL && collisionMap[x][y] != playerIndex) {
                result = result | tronament.Space.OPPONENT;
            }

            return result;
        }

        /**
         * Queries the game for what is at a location relative to the player's current position.
         *
         * @param  Number  x The x-coordinate offset of the position.
         * @param  Number  y The y-coordinate offset of the position.
         * @return Number    A Space value indicating what is in the space.
         */
        constructor.prototype.queryRelative = function(x, y) {
            var playerIndex = players.indexOf(this);
            return this.queryAbsolute(playerCoordinates[playerIndex].x + x, playerCoordinates[playerIndex].y + y);
        }

        /**
         * Displays a fun message in the Tronament UI.
         *
         * @param String message The message to display.
         */
        constructor.prototype.message = function(message) {
            var playerIndex = players.indexOf(this);
            var messageBox = document.getElementById("player-" + (playerIndex + 1) + "-message");
            messageBox.value = message;
        }

        this.aiModules[name] = constructor;
        lastLoadedModule = name;
    }

    /**
     * Loads a module from file.
     */
    this.loadModule = function() {
        // open the file chooser
        this.ui.openFilePicker(function(files) {
            // get the chosen file
            var file = files[0];
            var objectURL = window.URL.createObjectURL(file);

            // load the script
            var script = document.createElement("script");
            script.src = objectURL;
            document.body.appendChild(script);

            // update the player widgets after the module is loaded
            script.onload = function() {
                this.ui.updatePlayerWidgets();
            }.bind(this);
        }.bind(this));
    }

    /**
     * Sets the resolution of the canvas.
     *
     * @param Number width  The new canvas width.
     * @param Number height The new canvas height.
     */
    this.setResolution = function(width, height) {
        canvas.width = width;
        canvas.height = height;
    }

    /**
     * Queries the game for what is at a given location.
     *
     * @param  Number  x The x-coordinate of the position.
     * @param  Number  y The y-coordinate of the position.
     * @return Number    A Space value indicating what is in the space.
     */
    this.query = function(x, y) {
        if (x < 0 || x >= boardWidth || y < 0 || y >= boardHeight) {
            return this.Space.OUT_OF_BOUNDS;
        }
        if (collisionMap[x] != undefined && collisionMap[x][y] != undefined) {
            return this.Space.TRAIL;
        }
        return this.Space.EMPTY;
    }

    /**
     * Resets all the game variables and starts a new game running.
     */
    this.start = function() {
        players = [];
        collisionMap = [[]];
        playerCoordinates = [
            { x: Math.floor(boardWidth * 0.1), y: Math.floor(boardHeight * 0.1) },
            { x: Math.floor(boardWidth * 0.9), y: Math.floor(boardHeight * 0.9) },
            { x: Math.floor(boardWidth * 0.1), y: Math.floor(boardHeight * 0.9) },
            { x: Math.floor(boardWidth * 0.9), y: Math.floor(boardHeight * 0.1) }
        ];

        // create player objects
        for (var i = 0; i < this.options.playerCount; i++) {
            // get the desired a.i. module for this player
            var name = document.getElementById("player-ai-" + (i + 1)).value;

            // initialize an a.i. module instance
            try {
                var instance = new this.aiModules[name]();
            } catch(e) {
                tronament.ui.showDialog("Error", "The A.I. \"" + name + "\" created the following exception: " + e.message);
                return;
            }

            // set player's color as requested
            instance.color = document.getElementById("player-color-" + (i + 1)).value;

            // let the a.i. know we are ready
            players[i] = instance;
            if (typeof instance.onReady === "function") {
                instance.onReady();
            }
        }

        alivePlayerCount = players.length;
        running = true;
        mainLoop();
    }

    /**
     * Ends the game.
     */
    this.end = function(player) {
        terminateLoop();
        tronament.ui.showDialog("Game Over", "Player " + (players.indexOf(player) + 1) + " (" + player.name + ") Wins!", true);
        tronament.ui.playAudio("sound2");
    }

    var terminateLoop = function() {
        running = false;
        cancelAnimationFrame(timer);
    }

    /**
     * The main game loop that gets called repeatedly.
     */
    var mainLoop = function() {
        if (!running) {
            return;
        }

        // schedule the main loop to be called again
        timer = requestAnimationFrame(mainLoop);

        // initialize timers
        if (!lastDrawTime || !lastSecondTime || !lastTickTime) {
            lastDrawTime = lastSecondTime = lastTickTime = timestamp();
        }

        var now = timestamp();
        // update fps every second
        if (now - lastSecondTime > 1000) {
            var delta = (now - lastDrawTime) / 1000;
            this.debug.fps = 1 / delta;
            lastSecondTime = now;
        }

        // check if it is time to run the next game tick based on speed setting
        if (this.options.fastMovement || now - lastTickTime > 100) {
            tick();
            lastTickTime = now; // update tick time since we just called it
        }

        // render the display canvas
        draw();
        lastDrawTime = now;
    }.bind(this);

    var timestamp = function() {
        return window.performance && window.performance.now ? window.performance.now() : new Date().getTime();
    }

    /**
     * Executes a single tick of the game loop.
     */
    var tick = function() {
        // ask each player to respond with their move
        for (var i = 0; i < players.length; i++) {
            // ignore dead players :(
            if (players[i].__dead)
                continue;

            // tell the player to move
            try {
                var move = players[i].move(this);
            } catch(e) {
                tronament.ui.showDialog("Error", "The A.I. \"" + players[i].name + "\" created the following exception: " + e.message);
                terminateLoop();
                return;
            }

            // adjust the player position based on the direction
            if (move == this.Direction.RIGHT) {
                playerCoordinates[i].x++;
            } else if (move == this.Direction.DOWN) {
                playerCoordinates[i].y++;
            } else if (move == this.Direction.LEFT) {
                playerCoordinates[i].x--;
            } else if (move == this.Direction.UP) {
                playerCoordinates[i].y--;
            }

            if (this.query(playerCoordinates[i].x, playerCoordinates[i].y)) {
                playerDeath(i);
            } else {
                fill(i, playerCoordinates[i].x, playerCoordinates[i].y);
            }
        }
    }.bind(this);

    /**
     * Fills a player's position into the collision map.
     *
     * @param Number x The x-coordinate of the position.
     * @param Number y The y-coordinate of the position.
     */
    var fill = function(playerIndex, x, y) {
        if (collisionMap[x] == undefined) {
            collisionMap[x] = [];
        }
        collisionMap[x][y] = playerIndex;
    }.bind(this);

    /**
     * Removes a player from the game.
     */
    var playerDeath = function(i) {
        // tell the a.i. that it died
        if (typeof players[i].onDeath === "function") {
            players[i].onDeath();
        }

        // remove player from game
        alivePlayerCount--;
        players[i].__dead = true;

        if (alivePlayerCount <= 1) {
            for (var i = 0; i < players.length; i++) {
                if (!players[i].__dead) {
                    this.end(players[i]);
                }
            }
        }
    }.bind(this);

    /**
     * Renders the game screen to the canvas.
     */
    var draw = function() {
        // wipe the canvas clean
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // calculate the size of the trails

        // draw the grid
        ctx.strokeStyle = "#334";
        ctx.beginPath();
        for (var i = 0; i < boardWidth; i++) {
            ctx.moveTo(i * squareWidth, 0);
            ctx.lineTo(i * squareWidth, canvas.height);
        }
        for (var i = 0; i < boardHeight; i++) {
            ctx.moveTo(0, i * squareHeight);
            ctx.lineTo(canvas.width, i * squareHeight);
        }
        ctx.stroke();

        // render all trails
        for (var x = 0; x < collisionMap.length; x++) {
            if (collisionMap[x] != undefined) {
                for (var y = 0; y < collisionMap[x].length; y++) {
                    if (collisionMap[x][y] != undefined) {
                        var player = players[collisionMap[x][y]];
                        ctx.fillStyle = player.color;
                        ctx.fillRect(x * squareWidth, y * squareHeight, squareWidth, squareHeight);
                    }
                }
            }
        }

        // render debug info
        if (this.debug.showFps) {
            ctx.fillStyle = "white";
            ctx.font = "24px Silkscreen";
            ctx.textAlign = "end";
            ctx.textBaseline = "bottom";
            ctx.fillText("FPS: " + this.debug.fps.toFixed(2), canvas.width - 10, canvas.height - 10);
        }
    }.bind(this);
};
<commit_msg>60FPS!<commit_after>window.tronament = new function() {
    // some constants
    this.NORTH = 1;
    this.SOUTH = 2;
    this.WEST = 3;
    this.EAST = 4;

    this.EMPTY = 0;
    this.TRAIL = 1;
    this.OPPONENT = 2;
    this.WALL = 4;
    this.OUT_OF_BOUNDS = 8;

    // game options
    this.options = {
        playerCount: 2,
        fastMovement: false
    }

    // some debug options
    this.debug = {
        // indicates if the framerate should be displayed on the canvas
        showFps: false,
        // the current frame rate
        fps: 0,
        maxFps: 60
    };

    // times used for scheduling, keeping track of frame rate, etc...
    var lastDrawTime, lastSecondTime, lastTickTime;

    // variables used for drawing to the canvas
    var canvas, ctx;

    // a map of all loaded AI classes
    this.aiModules = [];
    // an array of currently active players
    var players = [];
    // an array containing the coordinates of each player
    var playerCoordinates = [];
    // the dimensions of the board grid
    var boardWidth, boardHeight;
    // a 2d array that stores a collision map for each position on the grid
    var collisionMap = [[]];
    var squareWidth, squareHeight;
    var timer;
    var running = false;
    var lastLoadedModule;
    var alivePlayerCount = 0;

    /**
     * Initializes the Tronament game engine.
     *
     * @param Element canvasElement The canvas element to be used for drawing.
     */
    this.init = function() {
        canvas = document.getElementById("canvas");
        ctx = canvas.getContext("2d");
        this.setBoardSize(48, 48);
    }

    /**
     * Gets the dimensions of the board.
     *
     * @return Object An object whose "width" property is the width of the board
     *                and "height" property is the height of the board.
     */
    this.getBoardSize = function() {
        return {
            width: boardWidth,
            height: boardHeight
        };
    }

    /**
     * Sets the dimensions of the board.
     *
     * @param Number width  The new board width.
     * @param Number height The new board height.
     */
    this.setBoardSize = function(width, height) {
        boardWidth = width;
        boardHeight = height;

        // do some calculations ahead of time for rendering performance
        squareWidth = Math.round(canvas.width / boardWidth);
        squareHeight = Math.round(canvas.height / boardHeight);
    }

    /**
     * Bootstraps an AI module prototype.
     *
     * Here there be dragons. This method uses some meta-programming
     * techniques, so be sure to remember who's who and what's what.
     *
     * @param String   name        The module name.
     * @param Function constructor An object constructor.
     */
    this.aiModule = function(name, constructor) {
        constructor.prototype.name = name;

        // next, define some useful methods for the module to use...

        /**
         * Queries the game for what is at an absolute location.
         *
         * @param  Number  x The x-coordinate of the position.
         * @param  Number  y The y-coordinate of the position.
         * @return Number    A Space value indicating what is in the space.
         */
        constructor.prototype.queryAbsolute = function(x, y) {
            var playerIndex = players.indexOf(this);
            var result = tronament.query(x, y);

            // do an additional check for opponent trail
            if (result == tronament.TRAIL && collisionMap[x][y] != playerIndex) {
                result = result | tronament.OPPONENT;
            }

            return result;
        }

        /**
         * Queries the game for what is at a location relative to the player's current position.
         *
         * @param  Number  x The x-coordinate offset of the position.
         * @param  Number  y The y-coordinate offset of the position.
         * @return Number    A Space value indicating what is in the space.
         */
        constructor.prototype.queryRelative = function(x, y) {
            var playerIndex = players.indexOf(this);
            return this.queryAbsolute(playerCoordinates[playerIndex].x + x, playerCoordinates[playerIndex].y + y);
        }

        /**
         * Displays a fun message in the Tronament UI.
         *
         * @param String message The message to display.
         */
        constructor.prototype.message = function(message) {
            var playerIndex = players.indexOf(this);
            var messageBox = document.getElementById("player-" + (playerIndex + 1) + "-message");
            messageBox.value = message;
        }

        this.aiModules[name] = constructor;
        lastLoadedModule = name;
    }

    /**
     * Loads a module from file.
     */
    this.loadModule = function() {
        // open the file chooser
        this.ui.openFilePicker(function(files) {
            // get the chosen file
            var file = files[0];
            var objectURL = window.URL.createObjectURL(file);

            // load the script
            var script = document.createElement("script");
            script.src = objectURL;
            document.body.appendChild(script);

            // update the player widgets after the module is loaded
            script.onload = function() {
                this.ui.updatePlayerWidgets();
            }.bind(this);
        }.bind(this));
    }

    /**
     * Sets the resolution of the canvas.
     *
     * @param Number width  The new canvas width.
     * @param Number height The new canvas height.
     */
    this.setResolution = function(width, height) {
        canvas.width = width;
        canvas.height = height;
    }

    /**
     * Queries the game for what is at a given location.
     *
     * @param  Number  x The x-coordinate of the position.
     * @param  Number  y The y-coordinate of the position.
     * @return Number    A Space value indicating what is in the space.
     */
    this.query = function(x, y) {
        if (x < 0 || x >= boardWidth || y < 0 || y >= boardHeight) {
            return this.OUT_OF_BOUNDS;
        }
        if (collisionMap[x] != undefined && collisionMap[x][y] != undefined) {
            return this.TRAIL;
        }
        return this.EMPTY;
    }

    /**
     * Resets all the game variables and starts a new game running.
     */
    this.start = function() {
        players = [];
        collisionMap = [[]];
        playerCoordinates = [
            { x: Math.floor(boardWidth * 0.1), y: Math.floor(boardHeight * 0.1) },
            { x: Math.floor(boardWidth * 0.9), y: Math.floor(boardHeight * 0.9) },
            { x: Math.floor(boardWidth * 0.1), y: Math.floor(boardHeight * 0.9) },
            { x: Math.floor(boardWidth * 0.9), y: Math.floor(boardHeight * 0.1) }
        ];

        // create player objects
        for (var i = 0; i < this.options.playerCount; i++) {
            // get the desired a.i. module for this player
            var name = document.getElementById("player-ai-" + (i + 1)).value;

            // initialize an a.i. module instance
            try {
                var instance = new this.aiModules[name]();
            } catch(e) {
                tronament.ui.showDialog("Error", "The A.I. \"" + name + "\" created the following exception: " + e.message);
                return;
            }

            // set player's color as requested
            instance.color = document.getElementById("player-color-" + (i + 1)).value;

            // let the a.i. know we are ready
            players[i] = instance;
            if (typeof instance.onReady === "function") {
                instance.onReady();
            }
        }

        alivePlayerCount = players.length;
        running = true;
        mainLoop();
    }

    /**
     * Ends the game.
     */
    this.end = function(player) {
        terminateLoop();
        tronament.ui.showDialog("Game Over", "Player " + (players.indexOf(player) + 1) + " (" + player.name + ") Wins!", true);
        tronament.ui.playAudio("sound2");
    }

    var terminateLoop = function() {
        running = false;
        cancelAnimationFrame(timer);
    }

    /**
     * The main game loop that gets called repeatedly.
     */
    var mainLoop = function() {
        if (!running) {
            return;
        }

        // schedule the main loop to be called again
        timer = requestAnimationFrame(mainLoop);

        // initialize timers
        if (!lastDrawTime || !lastSecondTime || !lastTickTime) {
            lastDrawTime = lastSecondTime = lastTickTime = timestamp();
        }

        var now = timestamp();
        // update fps every second
        if (now - lastSecondTime > 1000) {
            var delta = (now - lastDrawTime) / 1000;
            this.debug.fps = 1 / delta;
            lastSecondTime = now;
        }

        // check if it is time to run the next game tick based on speed setting
        if (this.options.fastMovement || now - lastTickTime > 100) {
            tick();
            lastTickTime = now; // update tick time since we just called it
        }

        // render the display canvas
        draw();
        lastDrawTime = now;
    }.bind(this);

    var timestamp = function() {
        return window.performance && window.performance.now ? window.performance.now() : new Date().getTime();
    }

    /**
     * Executes a single tick of the game loop.
     */
    var tick = function() {
        // ask each player to respond with their move
        for (var i = 0; i < players.length; i++) {
            // ignore dead players :(
            if (players[i].__dead)
                continue;

            // tell the player to move
            try {
                var move = players[i].move(this);
            } catch(e) {
                tronament.ui.showDialog("Error", "The A.I. \"" + players[i].name + "\" created the following exception: " + e.message);
                terminateLoop();
                return;
            }

            // adjust the player position based on the direction
            if (move == this.EAST) {
                playerCoordinates[i].x++;
            } else if (move == this.SOUTH) {
                playerCoordinates[i].y++;
            } else if (move == this.WEST) {
                playerCoordinates[i].x--;
            } else if (move == this.NORTH) {
                playerCoordinates[i].y--;
            }

            if (this.query(playerCoordinates[i].x, playerCoordinates[i].y)) {
                playerDeath(i);
            } else {
                fill(i, playerCoordinates[i].x, playerCoordinates[i].y);
            }
        }
    }.bind(this);

    /**
     * Fills a player's position into the collision map.
     *
     * @param Number x The x-coordinate of the position.
     * @param Number y The y-coordinate of the position.
     */
    var fill = function(playerIndex, x, y) {
        if (collisionMap[x] == undefined) {
            collisionMap[x] = [];
        }
        collisionMap[x][y] = playerIndex;
    }.bind(this);

    /**
     * Removes a player from the game.
     */
    var playerDeath = function(i) {
        // tell the a.i. that it died
        if (typeof players[i].onDeath === "function") {
            players[i].onDeath();
        }

        // remove player from game
        alivePlayerCount--;
        players[i].__dead = true;

        if (alivePlayerCount <= 1) {
            for (var i = 0; i < players.length; i++) {
                if (!players[i].__dead) {
                    this.end(players[i]);
                }
            }
        }
    }.bind(this);

    /**
     * Renders the game screen to the canvas.
     */
    var draw = function() {
        // wipe the canvas clean
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // calculate the size of the trails

        // render all trails
        for (var x = 0; x < collisionMap.length; x++) {
            if (collisionMap[x] != undefined) {
                for (var y = 0; y < collisionMap[x].length; y++) {
                    if (collisionMap[x][y] != undefined) {
                        var player = players[collisionMap[x][y]];
                        ctx.fillStyle = player.color;
                        ctx.fillRect(x * squareWidth, y * squareHeight, squareWidth, squareHeight);
                    }
                }
            }
        }

        // draw the grid
        ctx.strokeStyle = "#334";
        ctx.beginPath();
        for (var i = 0; i < boardWidth; i++) {
            ctx.moveTo(i * squareWidth, 0);
            ctx.lineTo(i * squareWidth, canvas.height);
        }
        for (var i = 0; i < boardHeight; i++) {
            ctx.moveTo(0, i * squareHeight);
            ctx.lineTo(canvas.width, i * squareHeight);
        }
        ctx.stroke();

        // render debug info
        if (this.debug.showFps) {
            ctx.fillStyle = "white";
            ctx.font = "24px Silkscreen";
            ctx.textAlign = "end";
            ctx.textBaseline = "bottom";
            ctx.fillText("FPS: " + this.debug.fps.toFixed(2), canvas.width - 10, canvas.height - 10);
        }
    }.bind(this);
};
<|endoftext|>


<commit_before>/**
 * Created by ilinca on 05/12/2016.
 */
/** Initialize var mpTopLevelTerms if you want it filtered **/

var drawChords = function (openNewPage, mpTopLevelTerms) {

    console.log(mpTopLevelTerms);
    var jsonSource = (mpTopLevelTerms && mpTopLevelTerms.length > 0) ? baseUrl + "/chordDiagram.json?phenotype_name=" + mpTopLevelTerms.join("&phenotype_name=") : baseUrl+ "/chordDiagram.json";
    console.log(jsonSource);

    var url = (window.location.href.indexOf("chordDiagram?") >= 0) ? baseUrl + "/chordDiagram?" : window.location.href.replace("chordDiagram", "chordDiagram?");

    // Attach download action
    if (mpTopLevelTerms && mpTopLevelTerms.length > 0) {
        $('#chordContainer').html("
Genes with at least on phenotype association in each of the following systems: " + mpTopLevelTerms.join(",") + "

Get gene list
");
    }

    queue().defer(d3.json, jsonSource)
        .await(ready);

    function ready(error, json) {

        if (error) throw error;

        else {
            var labels = json.labels;

            var matrix = json.matrix;

            d3.select("#chordDiagramSvg").selectAll("*").remove(); // clear svg for in-place filters
            var svg = d3.select("#chordDiagramSvg"),
                width = +svg.attr("width"),
                height = +svg.attr("height"),
                outerRadius = Math.min(width, height) * 0.5 - 200,
                innerRadius = outerRadius - 30;

            var chord = d3.chord()
                .padAngle(0.05)
                .sortSubgroups(d3.descending);

            var arc = d3.arc()
                .innerRadius(innerRadius)
                .outerRadius(outerRadius);

            var ribbon = d3.ribbon()
                .radius(innerRadius);

            var color = d3.scaleOrdinal()
                .domain(d3.range(4))
                .range(["rgb(239, 123, 11)", "rgb(9, 120, 161)", "rgb(119, 119, 119)", "rgb(238, 238, 180)", "rgb(36, 139, 75)", "rgb(191, 75, 50)", "rgb(255, 201, 67)", "rgb(191, 151, 50)", "rgb(239, 123, 11)", "rgb(247, 157, 70)", "rgb(247, 181, 117)", "rgb(191, 75, 50)", "rgb(151, 51, 51)", "rgb(144, 195, 212)"]);

            var g = svg.append("g")
                .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
                .datum(chord(matrix));

            var group = g.append("g")
                .attr("class", "groups")
                .selectAll("g")
                .data(function (chords) {
                    return chords.groups;
                })
                .enter().append("g")
                .attr("class", "group")
                .on("mouseover", fade(.02))
                .on("mouseout", fade(.80))
                .on("click", function (d) {
                    if (mpTopLevelTerms.indexOf(labels[d.index].name) < 0) { // top level is not already selected
                        if (openNewPage) {
                            window.open(url + "&phenotype_name=" + labels[d.index].name, "_self");
                        }
                        else {
                            mpTopLevelTerms.push(labels[d.index].name);
                            drawChords(openNewPage, mpTopLevelTerms);
                        }
                    }
                });

            group.append("path")
                .style("fill", function (d) {
                    return color(d.index);
                })
                .style("stroke", function (d) {
                    return d3.rgb(color(d.index)).darker();
                })
                .attr("d", arc);

            var groupTick = group.selectAll(".group-tick")
                .data(function (d) {
                    return groupTicks(d, 1e3);
                })
                .enter().append("g")
                .attr("class", "group-tick")
                .attr("transform", function (d) {
                    return "rotate(" + (d.angle * 180 / Math.PI - 90) + ") translate(" + outerRadius + ",0)";
                });

            groupTick.append("line")
                .attr("x2", 6);

            groupTick
                .filter(function (d) {
                    return d.value % 5e3 === 0;
                })
                .append("text")
                .attr("x", 8)
                .attr("dy", ".35em")
                .attr("transform", function (d) {
                    return d.angle > Math.PI ? "rotate(180) translate(-16)" : null;
                })
                .style("text-anchor", function (d) {
                    return d.angle > Math.PI ? "end" : null;
                })
                .text(function (d) {
                    return labels[d.index].name.replace("phenotype", "");
                });

            g.append("g")
                .attr("class", "ribbons")
                .selectAll("path")
                .data(function (chords) {
                    return chords;
                })
                .enter().append("path")
                .attr("d", ribbon)
                .attr("class", "chord")
                .style("fill", function (d) {
                    return color(d.target.index);
                })
                .style("stroke", function (d) {
                    return d3.rgb(color(d.target.index)).darker();
                })
                .style("visibility", function (d) {
                    if (mpTopLevelTerms && mpTopLevelTerms.length > 0) {
                        if (mpTopLevelTerms.indexOf(labels[d.source.index].name) < 0 && mpTopLevelTerms.indexOf(labels[d.target.index].name) < 0) {
                            return "hidden";
                        } else {
                            return "visible";
                        }
                    } else {
                        return "visible";
                    }
                })
                .append("title").text(function (d) {
                return d.source.value + " genes present " + labels[d.source.index].name + " and " + labels[d.target.index].name + ", " + mpTopLevelTerms.join(", ");
            });

            // Returns an array of tick angles and values for a given group and step.
            function groupTicks(d, step) {
                var k = (d.endAngle - d.startAngle) / d.value;
                return d3.range(0, d.value, step).map(function (value) {
                    return {value: value, angle: value * k + d.startAngle, index: d.index};
                });
            }

            // Returns an event handler for fading a given chord group.
            // Display parameter for the group hovering over
            function fade(opacity) {
                return function (d, i) {
                    // hide other chords on mose over
                    svg.selectAll("path.chord")
                        .filter(function (d) {
                            return d.source.index != i && d.target.index != i;
                        })
                        .transition()
                        .style("stroke-opacity", opacity)
                        .style("fill-opacity", opacity);

                };
            }
        }
    }
} ;
<commit_msg>Chord diagram fixed download link<commit_after>/**
 * Created by ilinca on 05/12/2016.
 */
/** Initialize var mpTopLevelTerms if you want it filtered **/

var drawChords = function (openNewPage, mpTopLevelTerms) {

    console.log(mpTopLevelTerms);
    var jsonSource = (mpTopLevelTerms && mpTopLevelTerms.length > 0) ? baseUrl + "/chordDiagram.json?phenotype_name=" + mpTopLevelTerms.join("&phenotype_name=") : baseUrl+ "/chordDiagram.json";
    console.log(jsonSource);

    var url = (mpTopLevelTerms && mpTopLevelTerms.length > 0) ? baseUrl + "/chordDiagram?phenotype_name=" + mpTopLevelTerms.join("&phenotype_name=") : baseUrl+ "/chordDiagram";

    // Attach download action
    if (mpTopLevelTerms && mpTopLevelTerms.length > 0) {
        $('#chordContainer').html("
Genes with at least on phenotype association in each of the following systems: " + mpTopLevelTerms.join(",") + "

Get gene list
");
    }

    queue().defer(d3.json, jsonSource)
        .await(ready);

    function ready(error, json) {

        if (error) throw error;

        else {
            var labels = json.labels;

            var matrix = json.matrix;

            d3.select("#chordDiagramSvg").selectAll("*").remove(); // clear svg for in-place filters
            var svg = d3.select("#chordDiagramSvg"),
                width = +svg.attr("width"),
                height = +svg.attr("height"),
                outerRadius = Math.min(width, height) * 0.5 - 200,
                innerRadius = outerRadius - 30;

            var chord = d3.chord()
                .padAngle(0.05)
                .sortSubgroups(d3.descending);

            var arc = d3.arc()
                .innerRadius(innerRadius)
                .outerRadius(outerRadius);

            var ribbon = d3.ribbon()
                .radius(innerRadius);

            var color = d3.scaleOrdinal()
                .domain(d3.range(4))
                .range(["rgb(239, 123, 11)", "rgb(9, 120, 161)", "rgb(119, 119, 119)", "rgb(238, 238, 180)", "rgb(36, 139, 75)", "rgb(191, 75, 50)", "rgb(255, 201, 67)", "rgb(191, 151, 50)", "rgb(239, 123, 11)", "rgb(247, 157, 70)", "rgb(247, 181, 117)", "rgb(191, 75, 50)", "rgb(151, 51, 51)", "rgb(144, 195, 212)"]);

            var g = svg.append("g")
                .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
                .datum(chord(matrix));

            var group = g.append("g")
                .attr("class", "groups")
                .selectAll("g")
                .data(function (chords) {
                    return chords.groups;
                })
                .enter().append("g")
                .attr("class", "group")
                .on("mouseover", fade(.02))
                .on("mouseout", fade(.80))
                .on("click", function (d) {
                    if (mpTopLevelTerms.indexOf(labels[d.index].name) < 0) { // top level is not already selected
                        if (openNewPage) {
                            window.open(url + "&phenotype_name=" + labels[d.index].name, "_self");
                        }
                        else {
                            mpTopLevelTerms.push(labels[d.index].name);
                            drawChords(openNewPage, mpTopLevelTerms);
                        }
                    }
                });

            group.append("path")
                .style("fill", function (d) {
                    return color(d.index);
                })
                .style("stroke", function (d) {
                    return d3.rgb(color(d.index)).darker();
                })
                .attr("d", arc);

            var groupTick = group.selectAll(".group-tick")
                .data(function (d) {
                    return groupTicks(d, 1e3);
                })
                .enter().append("g")
                .attr("class", "group-tick")
                .attr("transform", function (d) {
                    return "rotate(" + (d.angle * 180 / Math.PI - 90) + ") translate(" + outerRadius + ",0)";
                });

            groupTick.append("line")
                .attr("x2", 6);

            groupTick
                .filter(function (d) {
                    return d.value % 5e3 === 0;
                })
                .append("text")
                .attr("x", 8)
                .attr("dy", ".35em")
                .attr("transform", function (d) {
                    return d.angle > Math.PI ? "rotate(180) translate(-16)" : null;
                })
                .style("text-anchor", function (d) {
                    return d.angle > Math.PI ? "end" : null;
                })
                .text(function (d) {
                    return labels[d.index].name.replace("phenotype", "");
                });

            g.append("g")
                .attr("class", "ribbons")
                .selectAll("path")
                .data(function (chords) {
                    return chords;
                })
                .enter().append("path")
                .attr("d", ribbon)
                .attr("class", "chord")
                .style("fill", function (d) {
                    return color(d.target.index);
                })
                .style("stroke", function (d) {
                    return d3.rgb(color(d.target.index)).darker();
                })
                .style("visibility", function (d) {
                    if (mpTopLevelTerms && mpTopLevelTerms.length > 0) {
                        if (mpTopLevelTerms.indexOf(labels[d.source.index].name) < 0 && mpTopLevelTerms.indexOf(labels[d.target.index].name) < 0) {
                            return "hidden";
                        } else {
                            return "visible";
                        }
                    } else {
                        return "visible";
                    }
                })
                .append("title").text(function (d) {
                return d.source.value + " genes present " + labels[d.source.index].name + " and " + labels[d.target.index].name + ", " + mpTopLevelTerms.join(", ");
            });

            // Returns an array of tick angles and values for a given group and step.
            function groupTicks(d, step) {
                var k = (d.endAngle - d.startAngle) / d.value;
                return d3.range(0, d.value, step).map(function (value) {
                    return {value: value, angle: value * k + d.startAngle, index: d.index};
                });
            }

            // Returns an event handler for fading a given chord group.
            // Display parameter for the group hovering over
            function fade(opacity) {
                return function (d, i) {
                    // hide other chords on mose over
                    svg.selectAll("path.chord")
                        .filter(function (d) {
                            return d.source.index != i && d.target.index != i;
                        })
                        .transition()
                        .style("stroke-opacity", opacity)
                        .style("fill-opacity", opacity);

                };
            }
        }
    }
} ;
<|endoftext|>


<commit_before>/*
Copyright 2018 New Vector Ltd.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import {throttle} from "lodash";
import ResizeObserver from 'resize-observer-polyfill';

import dis from '../../../dispatcher/dispatcher';

// Shamelessly ripped off Modal.js.  There's probably a better way
// of doing reusable widgets like dialog boxes & menus where we go and
// pass in a custom control as the actual body.

function getContainer(containerId) {
    return document.getElementById(containerId);
}

function getOrCreateContainer(containerId) {
    let container = getContainer(containerId);

    if (!container) {
        container = document.createElement("div");
        container.id = containerId;
        document.body.appendChild(container);
    }

    return container;
}

/*
 * Class of component that renders its children in a separate ReactDOM virtual tree
 * in a container element appended to document.body.
 *
 * This prevents the children from being unmounted when the parent of PersistedElement
 * unmounts, allowing them to persist.
 *
 * When PE is unmounted, it hides the children using CSS. When mounted or updated, the
 * children are made visible and are positioned into a div that is given the same
 * bounding rect as the parent of PE.
 */
export default class PersistedElement extends React.Component {
    static propTypes = {
        // Unique identifier for this PersistedElement instance
        // Any PersistedElements with the same persistKey will use
        // the same DOM container.
        persistKey: PropTypes.string.isRequired,
    };

    constructor() {
        super();
        this.collectChildContainer = this.collectChildContainer.bind(this);
        this.collectChild = this.collectChild.bind(this);
        this._repositionChild = this._repositionChild.bind(this);
        this._onAction = this._onAction.bind(this);

        this.resizeObserver = new ResizeObserver(this._repositionChild);
        // Annoyingly, a resize observer is insufficient, since we also care
        // about when the element moves on the screen without changing its
        // dimensions. Doesn't look like there's a ResizeObserver equivalent
        // for this, so we bodge it by listening for document resize and
        // the timeline_resize action.
        window.addEventListener('resize', this._repositionChild);
        this._dispatcherRef = dis.register(this._onAction);
    }

    /**
     * Removes the DOM elements created when a PersistedElement with the given
     * persistKey was mounted. The DOM elements will be re-added if another
     * PeristedElement is mounted in the future.
     *
     * @param {string} persistKey Key used to uniquely identify this PersistedElement
     */
    static destroyElement(persistKey) {
        const container = getContainer('mx_persistedElement_' + persistKey);
        if (container) {
            container.remove();
        }
    }

    static isMounted(persistKey) {
        return Boolean(getContainer('mx_persistedElement_' + persistKey));
    }

    collectChildContainer(ref) {
        if (this.childContainer) {
            this.resizeObserver.unobserve(this.childContainer);
        }
        this.childContainer = ref;
        if (ref) {
            this.resizeObserver.observe(ref);
        }
    }

    collectChild(ref) {
        this.child = ref;
        this.updateChild();
    }

    componentDidMount() {
        this.updateChild();
        this.renderApp();
    }

    componentDidUpdate() {
        this.updateChild();
        this.renderApp();
    }

    componentWillUnmount() {
        this.updateChildVisibility(this.child, false);
        this.resizeObserver.disconnect();
        window.removeEventListener('resize', this._repositionChild);
        dis.unregister(this._dispatcherRef);
    }

    _onAction(payload) {
        if (payload.action === 'timeline_resize') {
            this._repositionChild();
        }
    }

    _repositionChild() {
        this.updateChildPosition(this.child, this.childContainer);
    }

    updateChild() {
        this.updateChildPosition(this.child, this.childContainer);
        this.updateChildVisibility(this.child, true);
    }

    renderApp() {
        const content =

            {this.props.children}

;

        ReactDOM.render(content, getOrCreateContainer('mx_persistedElement_'+this.props.persistKey));
    }

    updateChildVisibility(child, visible) {
        if (!child) return;
        child.style.display = visible ? 'block' : 'none';
    }

    updateChildPosition = throttle((child, parent) => {
        if (!child || !parent) return;

        const parentRect = parent.getBoundingClientRect();
        Object.assign(child.style, {
            position: 'absolute',
            top: parentRect.top + 'px',
            left: parentRect.left + 'px',
            width: parentRect.width + 'px',
            height: parentRect.height + 'px',
        });
    }, 100, {trailing: true, leading: true});

    render() {
        return
;
    }
}

export const getPersistKey = (appId: string) => 'widget_' + appId;
<commit_msg>Fix stickerpicker not having correct contexts<commit_after>/*
Copyright 2018 New Vector Ltd.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import {throttle} from "lodash";
import ResizeObserver from 'resize-observer-polyfill';

import dis from '../../../dispatcher/dispatcher';
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import {MatrixClientPeg} from "../../../MatrixClientPeg";

// Shamelessly ripped off Modal.js.  There's probably a better way
// of doing reusable widgets like dialog boxes & menus where we go and
// pass in a custom control as the actual body.

function getContainer(containerId) {
    return document.getElementById(containerId);
}

function getOrCreateContainer(containerId) {
    let container = getContainer(containerId);

    if (!container) {
        container = document.createElement("div");
        container.id = containerId;
        document.body.appendChild(container);
    }

    return container;
}

/*
 * Class of component that renders its children in a separate ReactDOM virtual tree
 * in a container element appended to document.body.
 *
 * This prevents the children from being unmounted when the parent of PersistedElement
 * unmounts, allowing them to persist.
 *
 * When PE is unmounted, it hides the children using CSS. When mounted or updated, the
 * children are made visible and are positioned into a div that is given the same
 * bounding rect as the parent of PE.
 */
export default class PersistedElement extends React.Component {
    static propTypes = {
        // Unique identifier for this PersistedElement instance
        // Any PersistedElements with the same persistKey will use
        // the same DOM container.
        persistKey: PropTypes.string.isRequired,
    };

    constructor() {
        super();
        this.collectChildContainer = this.collectChildContainer.bind(this);
        this.collectChild = this.collectChild.bind(this);
        this._repositionChild = this._repositionChild.bind(this);
        this._onAction = this._onAction.bind(this);

        this.resizeObserver = new ResizeObserver(this._repositionChild);
        // Annoyingly, a resize observer is insufficient, since we also care
        // about when the element moves on the screen without changing its
        // dimensions. Doesn't look like there's a ResizeObserver equivalent
        // for this, so we bodge it by listening for document resize and
        // the timeline_resize action.
        window.addEventListener('resize', this._repositionChild);
        this._dispatcherRef = dis.register(this._onAction);
    }

    /**
     * Removes the DOM elements created when a PersistedElement with the given
     * persistKey was mounted. The DOM elements will be re-added if another
     * PeristedElement is mounted in the future.
     *
     * @param {string} persistKey Key used to uniquely identify this PersistedElement
     */
    static destroyElement(persistKey) {
        const container = getContainer('mx_persistedElement_' + persistKey);
        if (container) {
            container.remove();
        }
    }

    static isMounted(persistKey) {
        return Boolean(getContainer('mx_persistedElement_' + persistKey));
    }

    collectChildContainer(ref) {
        if (this.childContainer) {
            this.resizeObserver.unobserve(this.childContainer);
        }
        this.childContainer = ref;
        if (ref) {
            this.resizeObserver.observe(ref);
        }
    }

    collectChild(ref) {
        this.child = ref;
        this.updateChild();
    }

    componentDidMount() {
        this.updateChild();
        this.renderApp();
    }

    componentDidUpdate() {
        this.updateChild();
        this.renderApp();
    }

    componentWillUnmount() {
        this.updateChildVisibility(this.child, false);
        this.resizeObserver.disconnect();
        window.removeEventListener('resize', this._repositionChild);
        dis.unregister(this._dispatcherRef);
    }

    _onAction(payload) {
        if (payload.action === 'timeline_resize') {
            this._repositionChild();
        }
    }

    _repositionChild() {
        this.updateChildPosition(this.child, this.childContainer);
    }

    updateChild() {
        this.updateChildPosition(this.child, this.childContainer);
        this.updateChildVisibility(this.child, true);
    }

    renderApp() {
        const content = <MatrixClientContext.Provider value={MatrixClientPeg.get()}>

                {this.props.children}

        </MatrixClientContext.Provider>;

        ReactDOM.render(content, getOrCreateContainer('mx_persistedElement_'+this.props.persistKey));
    }

    updateChildVisibility(child, visible) {
        if (!child) return;
        child.style.display = visible ? 'block' : 'none';
    }

    updateChildPosition = throttle((child, parent) => {
        if (!child || !parent) return;

        const parentRect = parent.getBoundingClientRect();
        Object.assign(child.style, {
            position: 'absolute',
            top: parentRect.top + 'px',
            left: parentRect.left + 'px',
            width: parentRect.width + 'px',
            height: parentRect.height + 'px',
        });
    }, 100, {trailing: true, leading: true});

    render() {
        return
;
    }
}

export const getPersistKey = (appId: string) => 'widget_' + appId;
<|endoftext|>


<commit_before>/**
 * Created by lilu on 2017/9/23.
 */

import React from 'react';
import {withRouter} from 'react-router'
import {connect} from 'react-redux';
import {Row, Col, Input, Select, Button, Form, InputNumber, message} from 'antd';
import {stationAction, stationSelector} from './redux';
import DivisionCascader from '../../component/DivisionCascader'
import {action , selector} from '../../util/auth'
import LoadActivity, {loadAction} from '../../component/loadActivity'
import {ROLE_CODE} from '../../util/rolePermission'
import mathjs from 'mathjs'

const Option = Select.Option;
const FormItem = Form.Item
const formItemLayout = {
  labelCol: {
    span: 6
  },
  wrapperCol: {
    span: 18
  }
}
const formItemLayout2 = {
  labelCol: {
    span: 3
  },
  wrapperCol: {
    span: 21
  }
}

class AddStation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      curUserId: -1,
      selectedRowId: undefined,
      selectedRowData: undefined,
      status: undefined,
      province: undefined,
      city: undefined,
      area: undefined,
      addr: undefined,
      name: undefined,
      createModalVisible: false,
      updateModalVisible: false,
      modalKey: -1,
      partnerList: []
    }
  }

  selectDivision(value, label) {
    console.log('vauelsas', value, label)
    if (label.length == 3) {
      this.setState({
        province: {label: label[0].label, value: label[0].value},
        city: {label: label[1].label, value: label[1].value},
        area: {label: label[2].label, value: label[2].value},
      })
    } else if (label.length == 2) {
      this.setState({
        province: {label: label[0].label, value: label[0].value},
        city: {label: label[1].label, value: label[1].value},
      })
    } else if (label.length == 1) {
      this.setState({
        province: {label: label[0].label, value: label[0].value},
      })
    }
  }

  componentWillMount() {
    this.props.fetchAdminsByRole({
      roleCode: ROLE_CODE.STATION_MANAGER,
      onFailure: (e)=>{console.log(e.message)}
    })
  }

  userList() {
    if (this.props.userList && this.props.userList.length > 0) {
      // console.log('this.props.userList',this.props.userList)
      let userList = this.props.userList.map((item, key)=> {
        return <Option key={key} value={item.id}>{item.nickname+ ' '+item.mobilePhoneNumber}</Option>
      })
      return userList
    } else {
      return null
    }
  }

  submitStation() {
    this.props.form.validateFields((errors) => {
      if (errors) {
        return
      }
      this.props.updateLoadingState({isLoading: true})
      let data = this.props.form.getFieldsValue()
      data.platformProp = mathjs.chain(data.platformProp).multiply(1/100).done()
      let payload = {
        ...data,
        province: this.state.province,
        city: this.state.city,
        area: this.state.area,
        success: (stationId)=> {
          this.props.updateLoadingState({isLoading: false})
          this.props.history.push({pathname: '/site_list/showStation/' + stationId})
        },
        error: (err)=> {
          console.log(err.message)
          message.error('提交失败')
          this.props.updateLoadingState({isLoading: false})
        }
      }
      console.log('data====>',data.platformProp)
      // console.log('typeOf====>',typeof(data.powerUnitPrice))

      this.props.createStation(payload)
    })
  }

  hasErrors(fieldsError, values, balance) {
    if (Object.keys(fieldsError).some(field => fieldsError[field])) {
      return true
    }
    let isValid = values['name'] && values['adminId'] &&  values['division'] && values['addr'] &&values['platformProp'] >= 0 && values['platformProp'] <= 100 && values['unitPrice'] >= 0 && values['powerUnitPrice'] >= 0 && values['deposit'] >= 0
    return !isValid
  }

  render() {
    let station = this.props.station
    const { getFieldDecorator, getFieldsValue, getFieldsError } = this.props.form

    // console.log('[DEBUG] ---> SysUser props: ', this.state.partnerList);
    // let plate = {id:'platform',shareholderName:'平台', royalty: this.props.station?this.props.station.platformProp:0}
    // let partnerList = this.state.partnerList.splice(0,0,plate)
    return (

        <Form  hideRequiredMark={ true}>
          <Row gutter={24}>
            <Col span={14}>
              <FormItem label='服务点名称'  {...formItemLayout2}>
                {this.props.form.getFieldDecorator('name', {

                  rules: [
                    {
                      required: false,
                      message: '服务点名称未填写'
                    }
                  ]
                })(
                  <Input  />
                )}
              </FormItem>
            </Col>
            <Col span={10}>
              <FormItem label='选择管理员'  {...formItemLayout}>
                {this.props.form.getFieldDecorator('adminId', {
                  rules: [
                    {
                      required: false,
                      message: '管理员未选择'
                    }
                  ]
                })(
                  <Select allowClear={true}  >
                    {this.userList()}
                  </Select>
                )}
              </FormItem>
            </Col>
          </Row>
          <Row gutter={24}>
            <Col span={14}>
              <Row>
                <Col span={12}>
                  <FormItem label='服务点地址'  {...formItemLayout}>
                    {this.props.form.getFieldDecorator('division', {
                      rules: [
                        {
                          required: false,
                          message: '省市区未选择'
                        }
                      ]
                    })(
                      <DivisionCascader onChange={(value, label)=> {
                        this.selectDivision(value, label)
                      }} cascaderSize="large" />
                    )}
                  </FormItem>
                </Col>
                <Col span={12}>
                  <FormItem  >
                    {this.props.form.getFieldDecorator('addr', {
                      rules: [
                        {
                          required: false,
                          message: '服务点地址未填写'
                        }
                      ]
                    })(
                      <Input placeholder="服务点地址"/>
                    )}
                  </FormItem>
                </Col>
              </Row>

            </Col>
            <Col span={10}>
              <FormItem label='平台分成比例'  {...formItemLayout}>
                {this.props.form.getFieldDecorator('platformProp', {
                  rules: [
                    {
                      required: false,
                      message: '平台分成比例未填写'
                    }
                  ]
                })(<InputNumber
                                max={100}
                                min={0}
                />)}
                %
              </FormItem>

            </Col>
          </Row>
          <Row gutter={24}>
            <Col span={7}>
              <FormItem label='使用单价'  {...formItemLayout}>
                {this.props.form.getFieldDecorator('unitPrice', {
                  rules: [
                    {
                      required: false,
                      message: '干衣柜单价未填写'
                    }
                  ]
                })(<InputNumber  min={0}
                />)}
                元/分钟
              </FormItem>
            </Col>

            <Col span={7}>
              <FormItem label='电费单价'  {...formItemLayout}>
                {this.props.form.getFieldDecorator('powerUnitPrice', {
                  rules: [
                    {
                      required: false,
                      message: '电费单价未填写'
                    }
                  ]
                })(<InputNumber  min={0}
                />)}
                元/度
              </FormItem>
            </Col>
            <Col span={10}>
              <FormItem label='干衣柜押金'  {...formItemLayout}>
                {this.props.form.getFieldDecorator('deposit', {
                  rules: [
                    {
                      required: false,
                      message: '干衣柜押金未填写'
                    }
                  ]
                })(<InputNumber min={0}
                />)}
                元

              </FormItem>
            </Col>
          </Row>
          <LoadActivity tip="正在提交..."/>
        </Form>
        <Row gutter={24} style={{flexDirection:'row',marginTop:20,marginBottom:20,justifyContent:' center'}}>
          <Col span={8}></Col>
          <Col span={4}>
            <Button onClick={()=> {
              this.props.history.push({
                pathname: '/site_list'
              })
            }} type="primary">返回</Button>
          </Col>
          <Col span={4}>
            <Button disabled={this.hasErrors(getFieldsError(), getFieldsValue())} onClick={()=> {
              this.submitStation()
            }} type="primary">提交</Button>
          </Col>
        </Row>

    )

  };
}

const mapStateToProps = (state, ownProps) => {
  let station = stationSelector.selectStation(state, ownProps.match.params.id)
  let partners = stationSelector.selectPartners(state)
  let userList = selector.selectAdminsByRole(state, ROLE_CODE.STATION_MANAGER)
  return {
    station: station,
    partners: partners,
    userList: userList

  };
};

const mapDispatchToProps = {
  ...stationAction,
  ...action,
  ...loadAction,

};

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Form.create()(AddStation)));

export {saga, reducer} from './redux';
<commit_msg>message error<commit_after>/**
 * Created by lilu on 2017/9/23.
 */

import React from 'react';
import {withRouter} from 'react-router'
import {connect} from 'react-redux';
import {Row, Col, Input, Select, Button, Form, InputNumber, message} from 'antd';
import {stationAction, stationSelector} from './redux';
import DivisionCascader from '../../component/DivisionCascader'
import {action , selector} from '../../util/auth'
import LoadActivity, {loadAction} from '../../component/loadActivity'
import {ROLE_CODE} from '../../util/rolePermission'
import mathjs from 'mathjs'

const Option = Select.Option;
const FormItem = Form.Item
const formItemLayout = {
  labelCol: {
    span: 6
  },
  wrapperCol: {
    span: 18
  }
}
const formItemLayout2 = {
  labelCol: {
    span: 3
  },
  wrapperCol: {
    span: 21
  }
}

class AddStation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      curUserId: -1,
      selectedRowId: undefined,
      selectedRowData: undefined,
      status: undefined,
      province: undefined,
      city: undefined,
      area: undefined,
      addr: undefined,
      name: undefined,
      createModalVisible: false,
      updateModalVisible: false,
      modalKey: -1,
      partnerList: []
    }
  }

  selectDivision(value, label) {
    console.log('vauelsas', value, label)
    if (label.length == 3) {
      this.setState({
        province: {label: label[0].label, value: label[0].value},
        city: {label: label[1].label, value: label[1].value},
        area: {label: label[2].label, value: label[2].value},
      })
    } else if (label.length == 2) {
      this.setState({
        province: {label: label[0].label, value: label[0].value},
        city: {label: label[1].label, value: label[1].value},
      })
    } else if (label.length == 1) {
      this.setState({
        province: {label: label[0].label, value: label[0].value},
      })
    }
  }

  componentWillMount() {
    this.props.fetchAdminsByRole({
      roleCode: ROLE_CODE.STATION_MANAGER,
      onFailure: (e)=>{console.log(e.message)}
    })
  }

  userList() {
    if (this.props.userList && this.props.userList.length > 0) {
      // console.log('this.props.userList',this.props.userList)
      let userList = this.props.userList.map((item, key)=> {
        return <Option key={key} value={item.id}>{item.nickname+ ' '+item.mobilePhoneNumber}</Option>
      })
      return userList
    } else {
      return null
    }
  }

  submitStation() {
    this.props.form.validateFields((errors) => {
      if (errors) {
        return
      }
      this.props.updateLoadingState({isLoading: true})
      let data = this.props.form.getFieldsValue()
      data.platformProp = mathjs.chain(data.platformProp).multiply(1/100).done()
      let payload = {
        ...data,
        province: this.state.province,
        city: this.state.city,
        area: this.state.area,
        success: (stationId)=> {
          this.props.updateLoadingState({isLoading: false})
          this.props.history.push({pathname: '/site_list/showStation/' + stationId})
        },
        error: (err)=> {
          console.log(err.message)
          message.error(err.message)
          this.props.updateLoadingState({isLoading: false})
        }
      }
      console.log('data====>',data.platformProp)
      // console.log('typeOf====>',typeof(data.powerUnitPrice))

      this.props.createStation(payload)
    })
  }

  hasErrors(fieldsError, values, balance) {
    if (Object.keys(fieldsError).some(field => fieldsError[field])) {
      return true
    }
    let isValid = values['name'] && values['adminId'] &&  values['division'] && values['addr'] &&values['platformProp'] >= 0 && values['platformProp'] <= 100 && values['unitPrice'] >= 0 && values['powerUnitPrice'] >= 0 && values['deposit'] >= 0
    return !isValid
  }

  render() {
    let station = this.props.station
    const { getFieldDecorator, getFieldsValue, getFieldsError } = this.props.form

    // console.log('[DEBUG] ---> SysUser props: ', this.state.partnerList);
    // let plate = {id:'platform',shareholderName:'平台', royalty: this.props.station?this.props.station.platformProp:0}
    // let partnerList = this.state.partnerList.splice(0,0,plate)
    return (

        <Form  hideRequiredMark={ true}>
          <Row gutter={24}>
            <Col span={14}>
              <FormItem label='服务点名称'  {...formItemLayout2}>
                {this.props.form.getFieldDecorator('name', {

                  rules: [
                    {
                      required: false,
                      message: '服务点名称未填写'
                    }
                  ]
                })(
                  <Input  />
                )}
              </FormItem>
            </Col>
            <Col span={10}>
              <FormItem label='选择管理员'  {...formItemLayout}>
                {this.props.form.getFieldDecorator('adminId', {
                  rules: [
                    {
                      required: false,
                      message: '管理员未选择'
                    }
                  ]
                })(
                  <Select allowClear={true}  >
                    {this.userList()}
                  </Select>
                )}
              </FormItem>
            </Col>
          </Row>
          <Row gutter={24}>
            <Col span={14}>
              <Row>
                <Col span={12}>
                  <FormItem label='服务点地址'  {...formItemLayout}>
                    {this.props.form.getFieldDecorator('division', {
                      rules: [
                        {
                          required: false,
                          message: '省市区未选择'
                        }
                      ]
                    })(
                      <DivisionCascader onChange={(value, label)=> {
                        this.selectDivision(value, label)
                      }} cascaderSize="large" />
                    )}
                  </FormItem>
                </Col>
                <Col span={12}>
                  <FormItem  >
                    {this.props.form.getFieldDecorator('addr', {
                      rules: [
                        {
                          required: false,
                          message: '服务点地址未填写'
                        }
                      ]
                    })(
                      <Input placeholder="服务点地址"/>
                    )}
                  </FormItem>
                </Col>
              </Row>

            </Col>
            <Col span={10}>
              <FormItem label='平台分成比例'  {...formItemLayout}>
                {this.props.form.getFieldDecorator('platformProp', {
                  rules: [
                    {
                      required: false,
                      message: '平台分成比例未填写'
                    }
                  ]
                })(<InputNumber
                                max={100}
                                min={0}
                />)}
                %
              </FormItem>

            </Col>
          </Row>
          <Row gutter={24}>
            <Col span={7}>
              <FormItem label='使用单价'  {...formItemLayout}>
                {this.props.form.getFieldDecorator('unitPrice', {
                  rules: [
                    {
                      required: false,
                      message: '干衣柜单价未填写'
                    }
                  ]
                })(<InputNumber  min={0}
                />)}
                元/分钟
              </FormItem>
            </Col>

            <Col span={7}>
              <FormItem label='电费单价'  {...formItemLayout}>
                {this.props.form.getFieldDecorator('powerUnitPrice', {
                  rules: [
                    {
                      required: false,
                      message: '电费单价未填写'
                    }
                  ]
                })(<InputNumber  min={0}
                />)}
                元/度
              </FormItem>
            </Col>
            <Col span={10}>
              <FormItem label='干衣柜押金'  {...formItemLayout}>
                {this.props.form.getFieldDecorator('deposit', {
                  rules: [
                    {
                      required: false,
                      message: '干衣柜押金未填写'
                    }
                  ]
                })(<InputNumber min={0}
                />)}
                元

              </FormItem>
            </Col>
          </Row>
          <LoadActivity tip="正在提交..."/>
        </Form>
        <Row gutter={24} style={{flexDirection:'row',marginTop:20,marginBottom:20,justifyContent:' center'}}>
          <Col span={8}></Col>
          <Col span={4}>
            <Button onClick={()=> {
              this.props.history.push({
                pathname: '/site_list'
              })
            }} type="primary">返回</Button>
          </Col>
          <Col span={4}>
            <Button disabled={this.hasErrors(getFieldsError(), getFieldsValue())} onClick={()=> {
              this.submitStation()
            }} type="primary">提交</Button>
          </Col>
        </Row>

    )

  };
}

const mapStateToProps = (state, ownProps) => {
  let station = stationSelector.selectStation(state, ownProps.match.params.id)
  let partners = stationSelector.selectPartners(state)
  let userList = selector.selectAdminsByRole(state, ROLE_CODE.STATION_MANAGER)
  return {
    station: station,
    partners: partners,
    userList: userList

  };
};

const mapDispatchToProps = {
  ...stationAction,
  ...action,
  ...loadAction,

};

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Form.create()(AddStation)));

export {saga, reducer} from './redux';
<|endoftext|>


<commit_before>L.Icon.Default.imagePath = 'images';

var map = L.map('map').setView([41.88, -87.63], 10);

L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
    attribution: '© OpenStreetMap contributors'
}).addTo(map);

var markerLayer = L.geoJson().addTo(map);

var mapzen_key = "search-F2Xk0nk";
var auto_url = 'https://search.mapzen.com/v1/autocomplete';
var search_url = 'https://search.mapzen.com/v1/search';
var inputElement = document.getElementsByTagName('input')[0];
var dataListEl = document.getElementsByTagName('datalist')[0];
var API_RATE_LIMIT = 500;

inputElement.disabled = true;
inputElement.placeholder = "Getting location...";

// Load geojson into variable to be used later,
// async being false will be deprecated later, but works for now
var chi_json = (function () {
    var chi_json = null;
    $.ajax({
        'async': false,
        'global': false,
        'url': "chi_neighborhoods.geojson",
        'dataType': "json",
        'success': function (data) {
            chi_json = data;
        }
    });
    return chi_json;
})();

// use HTML5 geolocation on page load, otherwise throw error
window.onload = function() {
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(function(position) {
      var pos = [position.coords.latitude, position.coords.longitude];
      searchNeighborhoods(pos, chi_json);
      // Make input usable and change placeholder, included twice so that it waits for function completion
      inputElement.placeholder = "Enter an address.";
      inputElement.disabled = false;
    });
  }
  else {
    console.log("Geolocation is not supported");
    inputElement.placeholder = "Enter an address.";
    inputElement.disabled = false;
  }
};

// Use existing throttle function to load autocomplete Mapzen results on keyup
inputElement.addEventListener('keyup', throttle(searchAddress, API_RATE_LIMIT));

function searchAddress(submitAddr) {
  var params = {
    api_key: mapzen_key,
    "focus.point.lon": -87.63,
    "focus.point.lat": 41.88,
    text: inputElement.value
  };
  // if optional argument supplied, call search endpoint
  if (submitAddr === true) {
    callPelias(search_url, params);
  }
  else if (inputElement.value.length > 0) {
    callPelias(auto_url, params);
  }
};

function callPelias(url, search_params) {
  AJAX.request(url, search_params, function (err, results) {
    if (err) {
      console.log(err);
    }
    // if autocomplete url provided
    if (url === auto_url) {
      if (results && results.features) {
        // remove all children of datalist until empty, fast way of emptying
        while (dataListEl.firstChild) {
          dataListEl.removeChild(dataListEl.firstChild);
        };
        var optionLength = 5;
        if (results.features.length < 5) {
          optionLength = results.features.length;
        }
        // Loop through first five results (or fewer) and add to options
        // TO-DO: Figure out how to display options that aren't datalist exact matches
        for (var i = 0; i < optionLength; ++i) {
          var option = document.createElement('option');
          option.value = results.features[i].properties.label;
          option.text = results.features[i].properties.label;
          dataListEl.appendChild(option);
        };
      }
    }
    // If search url provided
    else if (url === search_url) {
      if (results && results.features) {
        var pos = [results.features[0].geometry.coordinates[1], results.features[0].geometry.coordinates[0]];
        searchNeighborhoods(pos, chi_json);
      }
    }
  });
};

function searchNeighborhoods(position, neighborhoods) {
  // create arbitrary geoJSON point to submit to turfjs function
  var pt = {
    "type": "Feature",
    "properties": {
      "marker-color": "#0f0"
    },
    "geometry": {
      "type": "Point",
      "coordinates": []
    }
  };

  pt["geometry"]["coordinates"] = [position[1], position[0]];

  // Get var of p tag that will hold neighborhood answer
  var answerElement = document.getElementsByTagName('p')[0];
  answerElement.style.display = 'block';

  // Clear any existing GeoJSON and add marker GeoJSON to existing layer
  markerLayer.clearLayers();
  markerLayer.addData(pt);
  // marker = L.marker([position[0], position[1]]).addTo(map);
  map.setView([position[0], position[1]], 15);

  // Loop through all GeoJSON features, break if one selected, and change answerElement
  for (var i = 0; i < neighborhoods.features.length; ++i) {
    if (turf.inside(pt, neighborhoods.features[i])) {
      answerElement.innerHTML = "You are in " + '' + neighborhoods.features[i].properties.name + '.';
      break;
    }
    else {
      answerElement.innerHTML = "You are outside Chicago";
    }
  };
};

(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-40976307-2', 'wnaii.com');ga('send', 'pageview');
<commit_msg>added geojson layer with neighborhood name popup<commit_after>L.Icon.Default.imagePath = 'images';

var map = L.map('map').setView([41.88, -87.63], 10);

L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
    attribution: '© OpenStreetMap contributors'
}).addTo(map);

var markerLayer = L.geoJson().addTo(map);

var mapzen_key = "search-F2Xk0nk";
var auto_url = 'https://search.mapzen.com/v1/autocomplete';
var search_url = 'https://search.mapzen.com/v1/search';
var inputElement = document.getElementsByTagName('input')[0];
var dataListEl = document.getElementsByTagName('datalist')[0];
var API_RATE_LIMIT = 500;

inputElement.disabled = true;
inputElement.placeholder = "Getting location...";

var gjStyle = {
    "color": "#ff0000",
    "weight": 5,
    "opacity": 0.65
};

function onEachFeature(feature, layer) {
  layer.bindPopup("Neighborhood: " + feature.properties.name);
};

// Load geojson into variable to be used later,
// async being false will be deprecated later, but works for now
var chi_json = (function () {
    var chi_json = null;
    $.ajax({
        'async': false,
        'global': false,
        'url': "chi_neighborhoods.geojson",
        'dataType': "json",
        'success': function (data) {
            chi_json = data;
            L.geoJson(chi_json, {
              style: gjStyle,
              onEachFeature: onEachFeature
            }).addTo(map);
        }
    });
    return chi_json;
})();

// use HTML5 geolocation on page load, otherwise throw error
window.onload = function() {
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(function(position) {
      var pos = [position.coords.latitude, position.coords.longitude];
      searchNeighborhoods(pos, chi_json);
      // Make input usable and change placeholder, included twice so that it waits for function completion
      inputElement.placeholder = "Enter an address.";
      inputElement.disabled = false;
    });
  }
  else {
    console.log("Geolocation is not supported");
    inputElement.placeholder = "Enter an address.";
    inputElement.disabled = false;
  }
};

// Use existing throttle function to load autocomplete Mapzen results on keyup
inputElement.addEventListener('keyup', throttle(searchAddress, API_RATE_LIMIT));

function searchAddress(submitAddr) {
  var params = {
    api_key: mapzen_key,
    "focus.point.lon": -87.63,
    "focus.point.lat": 41.88,
    text: inputElement.value
  };
  // if optional argument supplied, call search endpoint
  if (submitAddr === true) {
    callPelias(search_url, params);
  }
  else if (inputElement.value.length > 0) {
    callPelias(auto_url, params);
  }
};

function callPelias(url, search_params) {
  AJAX.request(url, search_params, function (err, results) {
    if (err) {
      console.log(err);
    }
    // if autocomplete url provided
    if (url === auto_url) {
      if (results && results.features) {
        // remove all children of datalist until empty, fast way of emptying
        while (dataListEl.firstChild) {
          dataListEl.removeChild(dataListEl.firstChild);
        };
        var optionLength = 5;
        if (results.features.length < 5) {
          optionLength = results.features.length;
        }
        // Loop through first five results (or fewer) and add to options
        // TO-DO: Figure out how to display options that aren't datalist exact matches
        for (var i = 0; i < optionLength; ++i) {
          var option = document.createElement('option');
          option.value = results.features[i].properties.label;
          option.text = results.features[i].properties.label;
          dataListEl.appendChild(option);
        };
      }
    }
    // If search url provided
    else if (url === search_url) {
      if (results && results.features) {
        var pos = [results.features[0].geometry.coordinates[1], results.features[0].geometry.coordinates[0]];
        searchNeighborhoods(pos, chi_json);
      }
    }
  });
};

function searchNeighborhoods(position, neighborhoods) {
  // create arbitrary geoJSON point to submit to turfjs function
  var pt = {
    "type": "Feature",
    "properties": {
      "marker-color": "#0f0"
    },
    "geometry": {
      "type": "Point",
      "coordinates": []
    }
  };

  pt["geometry"]["coordinates"] = [position[1], position[0]];

  // Get var of p tag that will hold neighborhood answer
  var answerElement = document.getElementsByTagName('p')[0];
  answerElement.style.display = 'block';

  // Clear any existing GeoJSON and add marker GeoJSON to existing layer
  markerLayer.clearLayers();
  markerLayer.addData(pt);
  // marker = L.marker([position[0], position[1]]).addTo(map);
  map.setView([position[0], position[1]], 15);

  // Loop through all GeoJSON features, break if one selected, and change answerElement
  for (var i = 0; i < neighborhoods.features.length; ++i) {
    if (turf.inside(pt, neighborhoods.features[i])) {
      answerElement.innerHTML = "You are in " + '' + neighborhoods.features[i].properties.name + '.';
      break;
    }
    else {
      answerElement.innerHTML = "You are outside Chicago";
    }
  };
};

(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-40976307-2', 'wnaii.com');ga('send', 'pageview');
<|endoftext|>


<commit_before>/*!
 * jQuery column freeze plugin
 * @author Jamie Hoeks <j@skeoh.com>
 * @license MIT
 */
(function ($) {

'use strict';

var CONTROLLER_KEY = 'columnfreeze-controller';

/* Controller constructor */

var Controller = function ($table) {
	this.$table = $table;
};

/* Controller static functions */

Controller.getElementController = function (el) {
	var controller = $(el).data(CONTROLLER_KEY);
	return controller || null;
};

Controller.setElementController = function (el, controller) {
	$(el).data(CONTROLLER_KEY, controller);
};

Controller.ensureElementController = function (el) {
	var $el = $(el);
	var controller = Controller.getElementController($el);
	if (!controller) {
		controller = new Controller($el);
		Controller.setElementController($el, controller);
	}
	return controller;
};

/* Controller methods */

var $Controller = Controller.prototype = {
	$table: null,
	$tableFixed: null,
	$tableScroll: null,
	$containerFixed: null,
	$containerScroll: null,
	$wrapper: null
};

$Controller.config = function (key, value) {
	var options;
	if (!this.settings) {
		this.settings = $.extend({}, $.fn.columnFreeze.defaults);
	}
	// no-op
	if (typeof key === 'undefined') {
		return;
	}
	if (typeof key === 'string') {
		// get operation
		if (arguments.length < 2) {
			return this.settings[key];
		}
		// set operation
		else {
			this.settings[key] = value;
			return;
		}
	}
	else if ($.isPlainObject(key)) {
		options = key;
		$.extend(this.settings, options);
	}
	else {
		throw new Error('Unsupported configuration arguments');
	}
};

$Controller.freeze = function () {
	this.unfreeze();
	this.pin();
	this.fixRowHeights();
};

$Controller.unfreeze = function () {
	if (this.$wrapper) {
		this.$table.insertBefore(this.$wrapper);
		this.$wrapper.remove();
		this.$wrapper = null;
	}
};

/*
	DOM tree (replaces original table)

	$wrapper
		$containerFixed
			$tableFixed
		$containerScroll
			$tableScroll
*/

$Controller.pin = function () {
	var index = this.config('index');
	var headerSelector = this.config('headerSelector');
	var tableWidth = 0;
	var $split = this.splitTable(index);
	this.$containerFixed = this.createContainerFixed();
	this.$containerScroll = this.createContainerScroll();
	this.$tableFixed = $split.eq(0).appendTo(this.$containerFixed);
	this.$tableScroll = $split.eq(1).appendTo(this.$containerScroll);
	if (this.config('scrollWidth') !== 'auto') {
		tableWidth = this.copyColumnWidths();
	}
	this.$tableFixed.width(this.config('fixedWidth'))
	this.$tableScroll.width(this.config('scrollWidth') || tableWidth + 1);
	this.$wrapper = this.createWrapper()
		.append(this.$containerFixed)
		.append(this.$containerScroll)
		.insertBefore(this.$table);
	this.$table.detach();
	this.$containerScroll.css('left', this.$containerFixed.width() + 'px');
};

$Controller.createContainerFixed = function () {
	return $(document.createElement('div'))
		.addClass(this.config('containerFixedClass'))
		.css(this.config('containerFixedCSS'));
};

$Controller.createContainerScroll = function () {
	return $(document.createElement('div'))
		.addClass(this.config('containerScrollClass'))
		.css(this.config('containerScrollCSS'));
};

$Controller.createWrapper = function () {
	return $(document.createElement('div'))
		.addClass(this.config('wrapperClass'))
		.css(this.config('wrapperCSS'));
};

$Controller.splitTable = function () {
	var index = this.config('index');
	return this.$table.tableSplit(index);
};

$Controller.copyColumnWidths = function () {
	var index = this.config('index');
	var headerSelector = this.config('headerSelector');
	var $headers = this.$table.find(headerSelector);
	var controller = this;
	var totalWidth = 0;
	$headers.each(function (i) {
		var $table, $clone;
		var $original = $(this);
		var width = $original.outerWidth();
		if (i < index) {
			$table = controller.$tableFixed;
		}
		else {
			$table = controller.$tableScroll;
			i -= index;
			totalWidth += width;
		}
		$clone = $table.find(headerSelector).eq(i);
		$clone.width(width);
	});
	return totalWidth;
};

$Controller.fixRowHeights = function () {
	var rowSelector = this.config('rowSelector');
	var $fixedRows = this.$tableFixed.find(rowSelector);
	var $scrollRows = this.$tableScroll.find(rowSelector);
	this.$table.find(rowSelector).each(function (i) {
		var $fixedRow = $fixedRows.eq(i);
		var $scrollRow = $scrollRows.eq(i);
		var max = Math.max($fixedRow.height(), $scrollRow.height());
		$fixedRow.height(max);
		$scrollRow.height(max);
	});
};

$Controller.isFrozen = function () {
	return this.$wrapper !== null;
};

/* Expose jQuery plugin */

var returnable = {
	isFrozen: true,
	config: true
};

$.fn.columnFreeze = function (action, options) {
	var args = Array.prototype.slice.call(arguments, 1);
	// the default action if none is specified
	if (typeof action !== 'string') {
		options = action;
		args.unshift(options);
		action = 'freeze';
	}
	var results = this.map(function () {
		// get controller if it exists, create otherwise
		var controller = Controller.ensureElementController(this);
		switch (action) {
			case 'init':
				controller.config(options);
				return;
			case 'freeze':
				controller.config(options);
				return controller.freeze();
			case 'unfreeze':
				controller.config(options);
				return controller.unfreeze();
			case 'isFrozen':
				return controller.isFrozen();
			case 'config':
				return $Controller.config.apply(controller, args);
			default:
				throw new Error('Unrecognized action "' + action + '"');
		}
	});
	if (action in returnable) {
		return results[0];
	}
	return this;
};

$.fn.columnFreeze.Controller = Controller;

$.fn.columnFreeze.defaults = {
	// table is split before the column at this index (0-based)
	index: 1,
	// container for fixed portion of table
	containerFixedClass: 'columnfreeze-container columnfreeze-container-fixed',
	containerFixedCSS: {
		display: 'inline-block',
		float: 'left'
	},
	// container for scrollable portion of table
	containerScrollClass: 'columnfreeze-container columnfreeze-container-scroll',
	containerScrollCSS: {
		display: 'inline-block',
		position: 'absolute',
		overflowX: 'scroll',
		right: 0
	},
	// wrapper for above containers
	wrapperClass: 'columnfreeze-wrapper',
	wrapperCSS: {
		position: 'relative',
		overflow: 'hidden',
		paddingBottom: '20px'
	},
	// used to determine rows (when fixing row heights)
	rowSelector: 'tr',
	// used to determine headers (when fixing col widths)
	headerSelector: 'thead tr:last-child th, thead tr:last-child td',
	// width of fixed section
	fixedWidth: null,
	// width of scrollable section
	scrollWidth: null
};

})(jQuery);<commit_msg>Added frozen state<commit_after>/*!
 * jQuery column freeze plugin
 * @author Jamie Hoeks <j@skeoh.com>
 * @license MIT
 */
(function ($) {

'use strict';

var CONTROLLER_KEY = 'columnfreeze-controller';

/* Controller constructor */

var Controller = function ($table) {
	this.$table = $table;
};

/* Controller static functions */

Controller.getElementController = function (el) {
	var controller = $(el).data(CONTROLLER_KEY);
	return controller || null;
};

Controller.setElementController = function (el, controller) {
	$(el).data(CONTROLLER_KEY, controller);
};

Controller.ensureElementController = function (el) {
	var $el = $(el);
	var controller = Controller.getElementController($el);
	if (!controller) {
		controller = new Controller($el);
		Controller.setElementController($el, controller);
	}
	return controller;
};

/* Controller methods */

var $Controller = Controller.prototype = {
	frozen: false,
	$table: null,
	$tableFixed: null,
	$tableScroll: null,
	$containerFixed: null,
	$containerScroll: null,
	$wrapper: null
};

$Controller.config = function (key, value) {
	var options;
	if (!this.settings) {
		this.settings = $.extend({}, $.fn.columnFreeze.defaults);
	}
	// no-op
	if (typeof key === 'undefined') {
		return;
	}
	if (typeof key === 'string') {
		// get operation
		if (arguments.length < 2) {
			return this.settings[key];
		}
		// set operation
		else {
			this.settings[key] = value;
			return;
		}
	}
	else if ($.isPlainObject(key)) {
		options = key;
		$.extend(this.settings, options);
	}
	else {
		throw new Error('Unsupported configuration arguments');
	}
};

$Controller.freeze = function () {
	this.unfreeze();
	this.pin();
	this.fixRowHeights();
	this.frozen = true;
};

$Controller.unfreeze = function () {
	if (this.isFrozen()) {
		this.$table.insertBefore(this.$wrapper);
		this.$wrapper.remove();
		this.$wrapper = null;
		this.frozen = false;
	}
};

/*
	DOM tree (replaces original table)

	$wrapper
		$containerFixed
			$tableFixed
		$containerScroll
			$tableScroll
*/

$Controller.pin = function () {
	var index = this.config('index');
	var headerSelector = this.config('headerSelector');
	var tableWidth = 0;
	var $split = this.splitTable(index);
	this.$containerFixed = this.createContainerFixed();
	this.$containerScroll = this.createContainerScroll();
	this.$tableFixed = $split.eq(0).appendTo(this.$containerFixed);
	this.$tableScroll = $split.eq(1).appendTo(this.$containerScroll);
	if (this.config('scrollWidth') !== 'auto') {
		tableWidth = this.copyColumnWidths();
	}
	this.$tableFixed.width(this.config('fixedWidth'))
	this.$tableScroll.width(this.config('scrollWidth') || tableWidth + 1);
	this.$wrapper = this.createWrapper()
		.append(this.$containerFixed)
		.append(this.$containerScroll)
		.insertBefore(this.$table);
	this.$table.detach();
	this.$containerScroll.css('left', this.$containerFixed.width() + 'px');
};

$Controller.createContainerFixed = function () {
	return $(document.createElement('div'))
		.addClass(this.config('containerFixedClass'))
		.css(this.config('containerFixedCSS'));
};

$Controller.createContainerScroll = function () {
	return $(document.createElement('div'))
		.addClass(this.config('containerScrollClass'))
		.css(this.config('containerScrollCSS'));
};

$Controller.createWrapper = function () {
	return $(document.createElement('div'))
		.addClass(this.config('wrapperClass'))
		.css(this.config('wrapperCSS'));
};

$Controller.splitTable = function () {
	var index = this.config('index');
	return this.$table.tableSplit(index);
};

$Controller.copyColumnWidths = function () {
	var index = this.config('index');
	var headerSelector = this.config('headerSelector');
	var $headers = this.$table.find(headerSelector);
	var controller = this;
	var totalWidth = 0;
	$headers.each(function (i) {
		var $table, $clone;
		var $original = $(this);
		var width = $original.outerWidth();
		if (i < index) {
			$table = controller.$tableFixed;
		}
		else {
			$table = controller.$tableScroll;
			i -= index;
			totalWidth += width;
		}
		$clone = $table.find(headerSelector).eq(i);
		$clone.width(width);
	});
	return totalWidth;
};

$Controller.fixRowHeights = function () {
	var rowSelector = this.config('rowSelector');
	var $fixedRows = this.$tableFixed.find(rowSelector);
	var $scrollRows = this.$tableScroll.find(rowSelector);
	this.$table.find(rowSelector).each(function (i) {
		var $fixedRow = $fixedRows.eq(i);
		var $scrollRow = $scrollRows.eq(i);
		var max = Math.max($fixedRow.height(), $scrollRow.height());
		$fixedRow.height(max);
		$scrollRow.height(max);
	});
};

$Controller.isFrozen = function () {
	return this.frozen;
};

/* Expose jQuery plugin */

var returnable = {
	isFrozen: true,
	config: true
};

$.fn.columnFreeze = function (action, options) {
	var args = Array.prototype.slice.call(arguments, 1);
	// the default action if none is specified
	if (typeof action !== 'string') {
		options = action;
		args.unshift(options);
		action = 'freeze';
	}
	var results = this.map(function () {
		// get controller if it exists, create otherwise
		var controller = Controller.ensureElementController(this);
		switch (action) {
			case 'init':
				controller.config(options);
				return;
			case 'freeze':
				controller.config(options);
				return controller.freeze();
			case 'unfreeze':
				controller.config(options);
				return controller.unfreeze();
			case 'isFrozen':
				return controller.isFrozen();
			case 'config':
				return $Controller.config.apply(controller, args);
			default:
				throw new Error('Unrecognized action "' + action + '"');
		}
	});
	if (action in returnable) {
		return results[0];
	}
	return this;
};

$.fn.columnFreeze.Controller = Controller;

$.fn.columnFreeze.defaults = {
	// table is split before the column at this index (0-based)
	index: 1,
	// container for fixed portion of table
	containerFixedClass: 'columnfreeze-container columnfreeze-container-fixed',
	containerFixedCSS: {
		display: 'inline-block',
		float: 'left'
	},
	// container for scrollable portion of table
	containerScrollClass: 'columnfreeze-container columnfreeze-container-scroll',
	containerScrollCSS: {
		display: 'inline-block',
		position: 'absolute',
		overflowX: 'scroll',
		right: 0
	},
	// wrapper for above containers
	wrapperClass: 'columnfreeze-wrapper',
	wrapperCSS: {
		position: 'relative',
		overflow: 'hidden',
		paddingBottom: '20px'
	},
	// used to determine rows (when fixing row heights)
	rowSelector: 'tr',
	// used to determine headers (when fixing col widths)
	headerSelector: 'thead tr:last-child th, thead tr:last-child td',
	// width of fixed section
	fixedWidth: null,
	// width of scrollable section
	scrollWidth: null
};

})(jQuery);<|endoftext|>


<commit_before><commit_msg>Add z_t file support<commit_after><|endoftext|>