<commit_before>var Graph = Class.create({

    initialize: function() {
        this.hoverModeZones = editor.getPaper().set();
        this._placeHolderNodes = [];
        this._partnershipNodes = [];
        this._pregnancyNodes = [];
        this._personGroupNodes = [];
        this._personNodes = [];
        this.idCount = 1;
        this._nodeMap = {};
        this._currentHoveredNode = null;
        this._currentDraggable = null;
    },

    getNodeMap: function() {
        return this._nodeMap;
    },

    getCurrentHoveredNode: function() {
        return this._currentHoveredNode;
    },

    setCurrentHoveredNode: function(node) {
        this._currentHoveredNode = node;
    },

    getCurrentDraggable: function() {
        return this._currentDraggable;
    },

    setCurrentDraggable: function(draggable) {
        this._currentDraggable = draggable;
    },

    generateID: function() {
        return this.idCount++;
    },

    getProband: function() {
        return this.getNodeMap()[1];
    },

    addPartnership : function(x, y, node1, node2, id) {
        var partnership = new Partnership(x, y, node1, node2, id);
        this.getNodeMap()[partnership.getID()] = partnership;
        editor.getNodeIndex()._addNode(partnership, true);
        this._partnershipNodes.push(partnership);
        return partnership;
    },

    removePartnership: function(partnership) {
        delete this.getNodeMap()[partnership.getID()];
        this._partnershipNodes = this._partnershipNodes.without(partnership);
    },

    getPregnancyNodes: function() {
        return this._pregnancyNodes;
    },

    getPersonNodes: function() {
        return this._personNodes;
    },

    getPlaceHolderNodes: function() {
        return this._placeHolderNodes;
    },

    getPartnershipNodes: function() {
        return this._partnershipNodes;
    },

    getPersonGroupNodes: function() {
        return this._personGroupNodes;
    },

    addPerson: function(x, y, gender, id) {
        var isProband = this.getPersonNodes().length == 0;
        if(!isProband) {
        }
        var node = new Person(x, y, gender, id, isProband);
        this.getPersonNodes().push(node);
        this.getNodeMap()[node.getID()] = node;
        editor.getNodeIndex()._addNode(node, true);
        return node;
    },

    removePerson: function(person) {
        delete this.getNodeMap()[person.getID()];
        this._personNodes = this._personNodes.without(person);
    },

    addPlaceHolder: function(x, y, gender, id) {
        var node = new PlaceHolder(x, y, gender, id);
        this.getPlaceHolderNodes().push(node);
        this.getNodeMap()[node.getID()] = node;
        editor.getNodeIndex()._addNode(node, true);
        return node;
    },

    removePlaceHolder: function(placeholder) {
        delete this.getNodeMap()[placeholder.getID()];
        this._placeHolderNodes = this._placeHolderNodes.without(placeholder);
    },

    addPersonGroup: function(x, y, gender, id) {
        var node = new PersonGroup(x, y, gender, id);
        this.getPersonGroupNodes().push(node);
        this.getNodeMap()[node.getID()] = node;
        editor.getNodeIndex()._addNode(node, true);
        return node;
    },

    removePersonGroup: function(groupNode) {
        delete this.getNodeMap()[groupNode.getID()];
        this._personGroupNodes = this._personGroupNodes.without(groupNode);
    },

    addPregnancy: function(x, y, partnership, id) {
        var node = new Pregnancy(x, y, partnership, id);
        this.getPregnancyNodes().push(node);
        this.getNodeMap()[node.getID()] = node;
        editor.getNodeIndex()._addNode(node, true);
        return node;
    },

    removePregnancy: function(pregnancy) {
        delete this.getNodeMap()[pregnancy.getID()];
        this._pregnancyNodes = this._pregnancyNodes.without(pregnancy);
    },

    // HOVER MODE
    enterHoverMode: function(sourceNode, hoverTypes) {
        if(this.getCurrentDraggable().getType() == "parent") {
            this.getPartnershipNodes().each(function(partnershipBubble) {
                partnershipBubble.getGraphics().grow();
            })
        }
        var me = this,
            color,
            hoverNodes = [];
        hoverTypes.each(function(type) {
            hoverNodes = hoverNodes.concat(me["get" + type + "Nodes"]())
        });
        hoverNodes.without(sourceNode).each(function(node) {
            var hoverModeZone = node.getGraphics().getHoverBox().getHoverZoneMask().clone().toFront();
            hoverModeZone.attr("cursor", "pointer");
            hoverModeZone.hover(
                function() {
                    me._currentHoveredNode = node;
                    node.getGraphics().getHoverBox().setHovered(true);
                    node.getGraphics().getHoverBox().getBoxOnHover().attr(editor.attributes.boxOnHover);

                    if(me.getCurrentDraggable().getType() == 'PlaceHolder' && me.getCurrentDraggable().canMergeWith(node)) {
                        me.getCurrentDraggable().validHoveredNode = node;
                        color = "green";
                    }
                    else if(me.getCurrentDraggable().getType() == "partner" && sourceNode.canPartnerWith(node)) {
                        node.validPartnerSelected = true;
                        color = "green";
                    }
                    else if(me.getCurrentDraggable().getType() == "child" && sourceNode.canBeParentOf(node)) {
                        node.validChildSelected = true;
                        color = "green";
                    }
                    else if(me.getCurrentDraggable().getType() == "parent" && node.canBeParentOf(sourceNode)) {
                        if(node.getType() == 'Person') {
                            node.validParentSelected = true;
                        }
                        else {
                            node.validParentsSelected = true;
                        }
                        color = "green";
                    }
                    else {
                        color = "red";
                    }
                    node.getGraphics().getHoverBox().getBoxOnHover().attr("fill", color);
                },
                function() {
                    me.getCurrentDraggable() && (me.getCurrentDraggable().validHoveredNode = null);
                    node.getGraphics().getHoverBox().setHovered(false);
                    node.getGraphics().getHoverBox().getBoxOnHover().attr(editor.attributes.boxOnHover).attr('opacity', 0);
                    me._currentHoveredNode = null;
                    node.validPartnerSelected = node.validChildSelected =  node.validParentSelected = node.validParentsSelected = false;
                });
            me.hoverModeZones.push(hoverModeZone);
        });
    },

    exitHoverMode: function() {
        this.hoverModeZones.remove();
        this.getPartnershipNodes().each(function(partnership) {
            partnership.getGraphics().area && partnership.getGraphics().area.remove();
        });
    }
});<commit_msg>Added getters and setter for idCount<commit_after>var Graph = Class.create({

    initialize: function() {
        this.hoverModeZones = editor.getPaper().set();
        this._placeHolderNodes = [];
        this._partnershipNodes = [];
        this._pregnancyNodes = [];
        this._personGroupNodes = [];
        this._personNodes = [];
        this._idCount = 1;
        this._nodeMap = {};
        this._currentHoveredNode = null;
        this._currentDraggable = null;
    },

    getNodeMap: function() {
        return this._nodeMap;
    },

    getCurrentHoveredNode: function() {
        return this._currentHoveredNode;
    },

    setCurrentHoveredNode: function(node) {
        this._currentHoveredNode = node;
    },

    getCurrentDraggable: function() {
        return this._currentDraggable;
    },

    setCurrentDraggable: function(draggable) {
        this._currentDraggable = draggable;
    },

    generateID: function() {
        return this._idCount++;
    },

    getIdCount: function() {
        return this._idCount
    },

    setIdCount: function(maxID) {
        this._idCount = maxID;
    },

    getProband: function() {
        return this.getNodeMap()[1];
    },

    addPartnership : function(x, y, node1, node2, id) {
        var partnership = new Partnership(x, y, node1, node2, id);
        this.getNodeMap()[partnership.getID()] = partnership;
        editor.getNodeIndex()._addNode(partnership, true);
        this._partnershipNodes.push(partnership);
        return partnership;
    },

    removePartnership: function(partnership) {
        delete this.getNodeMap()[partnership.getID()];
        this._partnershipNodes = this._partnershipNodes.without(partnership);
    },

    getPregnancyNodes: function() {
        return this._pregnancyNodes;
    },

    getPersonNodes: function() {
        return this._personNodes;
    },

    getPlaceHolderNodes: function() {
        return this._placeHolderNodes;
    },

    getPartnershipNodes: function() {
        return this._partnershipNodes;
    },

    getPersonGroupNodes: function() {
        return this._personGroupNodes;
    },

    addPerson: function(x, y, gender, id) {
        var isProband = this.getPersonNodes().length == 0;
        if(!isProband) {
        }
        var node = new Person(x, y, gender, id, isProband);
        this.getPersonNodes().push(node);
        this.getNodeMap()[node.getID()] = node;
        editor.getNodeIndex()._addNode(node, true);
        return node;
    },

    removePerson: function(person) {
        delete this.getNodeMap()[person.getID()];
        this._personNodes = this._personNodes.without(person);
    },

    addPlaceHolder: function(x, y, gender, id) {
        var node = new PlaceHolder(x, y, gender, id);
        this.getPlaceHolderNodes().push(node);
        this.getNodeMap()[node.getID()] = node;
        editor.getNodeIndex()._addNode(node, true);
        return node;
    },

    removePlaceHolder: function(placeholder) {
        delete this.getNodeMap()[placeholder.getID()];
        this._placeHolderNodes = this._placeHolderNodes.without(placeholder);
    },

    addPersonGroup: function(x, y, gender, id) {
        var node = new PersonGroup(x, y, gender, id);
        this.getPersonGroupNodes().push(node);
        this.getNodeMap()[node.getID()] = node;
        editor.getNodeIndex()._addNode(node, true);
        return node;
    },

    removePersonGroup: function(groupNode) {
        delete this.getNodeMap()[groupNode.getID()];
        this._personGroupNodes = this._personGroupNodes.without(groupNode);
    },

    addPregnancy: function(x, y, partnership, id) {
        var node = new Pregnancy(x, y, partnership, id);
        this.getPregnancyNodes().push(node);
        this.getNodeMap()[node.getID()] = node;
        editor.getNodeIndex()._addNode(node, true);
        return node;
    },

    removePregnancy: function(pregnancy) {
        delete this.getNodeMap()[pregnancy.getID()];
        this._pregnancyNodes = this._pregnancyNodes.without(pregnancy);
    },

    // HOVER MODE
    enterHoverMode: function(sourceNode, hoverTypes) {
        if(this.getCurrentDraggable().getType() == "parent") {
            this.getPartnershipNodes().each(function(partnershipBubble) {
                partnershipBubble.getGraphics().grow();
            })
        }
        var me = this,
            color,
            hoverNodes = [];
        hoverTypes.each(function(type) {
            hoverNodes = hoverNodes.concat(me["get" + type + "Nodes"]())
        });
        hoverNodes.without(sourceNode).each(function(node) {
            var hoverModeZone = node.getGraphics().getHoverBox().getHoverZoneMask().clone().toFront();
            hoverModeZone.attr("cursor", "pointer");
            hoverModeZone.hover(
                function() {
                    me._currentHoveredNode = node;
                    node.getGraphics().getHoverBox().setHovered(true);
                    node.getGraphics().getHoverBox().getBoxOnHover().attr(editor.attributes.boxOnHover);

                    if(me.getCurrentDraggable().getType() == 'PlaceHolder' && me.getCurrentDraggable().canMergeWith(node)) {
                        me.getCurrentDraggable().validHoveredNode = node;
                        color = "green";
                    }
                    else if(me.getCurrentDraggable().getType() == "partner" && sourceNode.canPartnerWith(node)) {
                        node.validPartnerSelected = true;
                        color = "green";
                    }
                    else if(me.getCurrentDraggable().getType() == "child" && sourceNode.canBeParentOf(node)) {
                        node.validChildSelected = true;
                        color = "green";
                    }
                    else if(me.getCurrentDraggable().getType() == "parent" && node.canBeParentOf(sourceNode)) {
                        if(node.getType() == 'Person') {
                            node.validParentSelected = true;
                        }
                        else {
                            node.validParentsSelected = true;
                        }
                        color = "green";
                    }
                    else {
                        color = "red";
                    }
                    node.getGraphics().getHoverBox().getBoxOnHover().attr("fill", color);
                },
                function() {
                    me.getCurrentDraggable() && (me.getCurrentDraggable().validHoveredNode = null);
                    node.getGraphics().getHoverBox().setHovered(false);
                    node.getGraphics().getHoverBox().getBoxOnHover().attr(editor.attributes.boxOnHover).attr('opacity', 0);
                    me._currentHoveredNode = null;
                    node.validPartnerSelected = node.validChildSelected =  node.validParentSelected = node.validParentsSelected = false;
                });
            me.hoverModeZones.push(hoverModeZone);
        });
    },

    exitHoverMode: function() {
        this.hoverModeZones.remove();
        this.getPartnershipNodes().each(function(partnership) {
            partnership.getGraphics().area && partnership.getGraphics().area.remove();
        });
    }
});<|endoftext|>


<commit_before>/*!
 * Copyright (c) 2016 Naufal Rabbani (http://github.com/BosNaufal),
 * ,Licensed Under MIT (http://opensource.org/licenses/MIT),
 * ,
 * ,Vue 2 Autocomplete @ Version 0.0.3,
 *
 */
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Vue2Autocomplete=e():t.Vue2Autocomplete=e()}(this,function(){return function(t){function e(n){if(s[n])return s[n].exports;var o=s[n]={exports:{},id:n,loaded:!1};return t[n].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var s={};return e.m=t,e.c=s,e.p="../dist/",e(0)}([function(t,e,s){"use strict";function n(t){return t&&t.__esModule?t:{default:t}}var o=s(2),i=n(o);t.exports=i.default},function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),/*! Copyright (c) 2016 Naufal Rabbani (http://github.com/BosNaufal)
	* Licensed Under MIT (http://opensource.org/licenses/MIT)
	*
	* Vue 2 Autocomplete @ Version 0.0.1
	*
	*/
e.default={props:{id:String,className:String,placeholder:String,initValue:{type:String,default:""},anchor:{type:String,required:!0},label:String,url:{type:String,required:!0},param:{type:String,default:"q"},customParams:Object,min:{type:Number,default:0},onInput:Function,onShow:Function,onBlur:Function,onHide:Function,onFocus:Function,onSelect:Function,onBeforeAjax:Function,onAjaxProgress:Function,onAjaxLoaded:Function},data:function(){return{showList:!1,type:"",json:[],focusList:""}},methods:{clearInput:function(){this.showList=!1,this.type="",this.json=[],this.focusList=""},cleanUp:function(t){return JSON.parse(JSON.stringify(t))},input:function(t){this.showList=!0,this.onInput?this.onInput(t):null,this.getData(t)},showAll:function(){this.json=[],this.getData(""),this.onShow?this.onShow():null,this.showList=!0},hideAll:function(t){var e=this;this.onBlur?this.onBlur(t):null,setTimeout(function(){e.onHide?e.onHide():null,e.showList=!1},250)},focus:function(t){this.focusList=0,this.onFocus?this.onFocus(t):null},mousemove:function(t){this.focusList=t},keydown:function(t){var e=t.keyCode;if(this.showList){switch(e){case 40:this.focusList++;break;case 38:this.focusList--;break;case 13:this.selectList(this.json[this.focusList]),this.showList=!1;break;case 27:this.showList=!1}var s=this.json.length-1;this.focusList=this.focusList>s?0:this.focusList<0?s:this.focusList}},activeClass:function(t){return{"focus-list":t==this.focusList}},selectList:function(t){var e=this.cleanUp(t);this.type=e[this.anchor],this.showList=!1,this.onSelect?this.onSelect(e):null},getData:function(t){var e=this,s=this;if(!(t.length<this.min)&&null!=this.url){this.onBeforeAjax?this.onBeforeAjax(t):null;var n=new XMLHttpRequest,o="";this.customParams&&Object.keys(this.customParams).forEach(function(t){o+="&"+t+"="+e.customParams[t]}),n.open("GET",this.url+"?"+this.param+"="+t+o,!0),n.send(),n.addEventListener("progress",function(t){t.lengthComputable&&(this.onAjaxProgress?this.onAjaxProgress(t):null)}),n.addEventListener("loadend",function(t){var e=JSON.parse(this.responseText);this.onAjaxLoaded?this.onAjaxLoaded(e):null,s.json=e})}},setValue:function(t){this.type=t}},created:function(){this.type=this.initValue?this.initValue:null}}},function(t,e,s){var n,o;n=s(1);var i=s(3);o=n=n||{},"object"!=typeof n.default&&"function"!=typeof n.default||(o=n=n.default),"function"==typeof o&&(o=o.options),o.render=i.render,o.staticRenderFns=i.staticRenderFns,t.exports=n},function(t,e){t.exports={render:function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("div",{class:(t.className?t.className+"-wrapper ":"")+"autocomplete-wrapper"},[s("input",{directives:[{name:"model",rawName:"v-model",value:t.type,expression:"type"}],class:(t.className?t.className+"-input ":"")+"autocomplete-input",attrs:{type:"text",id:t.id,placeholder:t.placeholder,autocomplete:"off"},domProps:{value:t._s(t.type)},on:{input:[function(e){e.target.composing||(t.type=e.target.value)},function(e){t.input(t.type)}],dblclick:t.showAll,blur:t.hideAll,keydown:t.keydown,focus:t.focus}}),t._v(" "),s("div",{directives:[{name:"show",rawName:"v-show",value:t.showList,expression:"showList"}],class:(t.className?t.className+"-list ":"")+"autocomplete transition autocomplete-list"},[s("ul",t._l(t.json,function(e,n){return s("li",{class:t.activeClass(n),attrs:{transition:"showAll"}},[s("a",{attrs:{href:"#"},on:{click:function(s){s.preventDefault(),t.selectList(e)},mousemove:function(e){t.mousemove(n)}}},[s("b",[t._v(t._s(e[t.anchor]))]),t._v(" "),s("span",[t._v(t._s(e[t.label]))])])])}))])])},staticRenderFns:[]}}])});<commit_msg>syncing dist files<commit_after>/*!
 * Copyright (c) 2016 Naufal Rabbani (http://github.com/BosNaufal),
 * ,Licensed Under MIT (http://opensource.org/licenses/MIT),
 * ,
 * ,Vue 2 Autocomplete @ Version 0.0.3,
 *
 */
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Vue2Autocomplete=e():t.Vue2Autocomplete=e()}(this,function(){return function(t){function e(o){if(s[o])return s[o].exports;var n=s[o]={exports:{},id:o,loaded:!1};return t[o].call(n.exports,n,n.exports,e),n.loaded=!0,n.exports}var s={};return e.m=t,e.c=s,e.p="../dist/",e(0)}([function(t,e,s){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}var n=s(2),i=o(n);t.exports=i.default},function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0});/*! Copyright (c) 2016 Naufal Rabbani (http://github.com/BosNaufal)
	* Licensed Under MIT (http://opensource.org/licenses/MIT)
	*
	* Vue 2 Autocomplete @ Version 0.0.1
	*
	*/
/*!
	*  javascript-debounce 1.0.0
	*
	*  A lightweight, dependency-free JavaScript module for debouncing functions based on David Walsh's debounce function.
	*
	*  Source code available at: https://github.com/jgarber623/javascript-debounce
	*
	*  (c) 2015-present Jason Garber (http://sixtwothree.org)
	*
	*  javascript-debounce may be freely distributed under the MIT license.
	*/
var s=function(t,e){var s;return function(){var o=this,n=arguments;clearTimeout(s),s=setTimeout(function(){t.apply(o,n)},e)}};e.default={props:{id:String,className:String,placeholder:String,initValue:{type:String,default:""},anchor:{type:String,required:!0},label:String,debounce:Number,url:{type:String,required:!0},param:{type:String,default:"q"},customParams:Object,customHeaders:Object,min:{type:Number,default:0},process:Function,onInput:Function,onShow:Function,onBlur:Function,onHide:Function,onFocus:Function,onSelect:Function,onBeforeAjax:Function,onAjaxProgress:Function,onAjaxLoaded:Function},data:function(){return{showList:!1,type:"",json:[],focusList:""}},methods:{clearInput:function(){this.showList=!1,this.type="",this.json=[],this.focusList=""},cleanUp:function(t){return JSON.parse(JSON.stringify(t))},input:function(t){this.showList=!0,this.onInput?this.onInput(t):null,this.debouncedGetData&&this.debounce===this.oldDebounce||(this.oldDebounce=this.debounce,this.debouncedGetData=this.debounce?s(this.getData.bind(this),this.debounce):this.getData),this.debouncedGetData(t)},showAll:function(){this.json=[],this.getData(""),this.onShow?this.onShow():null,this.showList=!0},hideAll:function(t){var e=this;this.onBlur?this.onBlur(t):null,setTimeout(function(){e.onHide?e.onHide():null,e.showList=!1},250)},focus:function(t){this.focusList=0,this.onFocus?this.onFocus(t):null},mousemove:function(t){this.focusList=t},keydown:function(t){var e=t.keyCode;if(this.showList){switch(e){case 40:this.focusList++;break;case 38:this.focusList--;break;case 13:this.selectList(this.json[this.focusList]),this.showList=!1;break;case 27:this.showList=!1}var s=this.json.length-1;this.focusList=this.focusList>s?0:this.focusList<0?s:this.focusList}},activeClass:function(t){return{"focus-list":t==this.focusList}},selectList:function(t){var e=this.cleanUp(t);this.type=e[this.anchor],this.showList=!1,this.onSelect?this.onSelect(e):null},getData:function(t){var e=this,s=this;if(!(t.length<this.min)&&null!=this.url){this.onBeforeAjax?this.onBeforeAjax(t):null;var o=new XMLHttpRequest,n="";this.customParams&&Object.keys(this.customParams).forEach(function(t){n+="&"+t+"="+e.customParams[t]}),o.open("GET",this.url+"?"+this.param+"="+t+n,!0),this.customHeaders&&Object.keys(this.customHeaders).forEach(function(t){o.setRequestHeader(t,e.customHeaders[t])}),o.send(),o.addEventListener("progress",function(t){t.lengthComputable&&(this.onAjaxProgress?this.onAjaxProgress(t):null)}),o.addEventListener("loadend",function(t){var e=JSON.parse(this.responseText);this.onAjaxLoaded?this.onAjaxLoaded(e):null,s.json=s.process?s.process(e):e})}},setValue:function(t){this.type=t}},created:function(){this.type=this.initValue?this.initValue:null}}},function(t,e,s){var o=s(3)(s(1),s(4),null,null);t.exports=o.exports},function(t,e){t.exports=function(t,e,s,o){var n,i=t=t||{},u=typeof t.default;"object"!==u&&"function"!==u||(n=t,i=t.default);var c="function"==typeof i?i.options:i;if(e&&(c.render=e.render,c.staticRenderFns=e.staticRenderFns),s&&(c._scopeId=s),o){var a=Object.create(c.computed||null);Object.keys(o).forEach(function(t){var e=o[t];a[t]=function(){return e}}),c.computed=a}return{esModule:n,exports:i,options:c}}},function(t,e){t.exports={render:function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("div",{class:(t.className?t.className+"-wrapper ":"")+"autocomplete-wrapper"},[s("input",{directives:[{name:"model",rawName:"v-model",value:t.type,expression:"type"}],class:(t.className?t.className:"")+" autocomplete-input",attrs:{type:"text",id:t.id,placeholder:t.placeholder,autocomplete:"off"},domProps:{value:t._s(t.type)},on:{input:[function(e){e.target.composing||(t.type=e.target.value)},function(e){t.input(t.type)}],dblclick:t.showAll,blur:t.hideAll,keydown:t.keydown,focus:t.focus}}),t._v(" "),s("div",{directives:[{name:"show",rawName:"v-show",value:t.showList,expression:"showList"}],class:(t.className?t.className+"-list ":"")+"autocomplete transition autocomplete-list"},[s("ul",t._l(t.json,function(e,o){return s("li",{class:t.activeClass(o),attrs:{transition:"showAll"}},[s("a",{attrs:{href:"#"},on:{click:function(s){s.preventDefault(),t.selectList(e)},mousemove:function(e){t.mousemove(o)}}},[s("b",[t._v(t._s(e[t.anchor]))]),t._v(" "),s("span",[t._v(t._s(e[t.label]))])])])}))])])},staticRenderFns:[]}}])});<|endoftext|>


<commit_before>import config from './config';
import assert from 'assert';
import memdown from 'memdown';

let leveldb;
if (config.platform.isNode())
    leveldb = require('pouchdb-adapter-leveldb');

import * as RxDB from '../../dist/lib/index';
import * as util from '../../dist/lib/util';
import AsyncTestUtil from 'async-test-util';

config.parallel('pouch-db-integration.test.js', () => {
    describe('init', () => {
        it('should export the pouchDB-module', async () => {
            assert.equal(typeof RxDB.PouchDB, 'function');
        });
    });
    describe('memdown', () => {
        it('should not allow leveldown-adapters without the plugin', async () => {
            await AsyncTestUtil.assertThrows(
                () => RxDB.create({
                    name: util.randomCouchString(10),
                    adapter: memdown
                }),
                'RxError',
                'leveldb-plugin'
            );
        });
        it('should work after adding the leveldb-plugin', async () => {
            if (!config.platform.isNode()) return;
            RxDB.PouchDB.plugin(leveldb);
            const db = await RxDB.create({
                name: util.randomCouchString(10),
                adapter: memdown
            });
            assert.equal(db.constructor.name, 'RxDatabase');
            db.destroy();
        });
    });
    describe('pouchdb-adapter-memory', () => {
        it('should not create a db without adding the adapter', async () => {
            await AsyncTestUtil.assertThrows(
                () => RxDB.create({
                    name: util.randomCouchString(10),
                    adapter: 'memory'
                }),
                'RxError',
                'Adapter'
            );
        });
        it('should work when adapter was added', async () => {
            RxDB.plugin(require('pouchdb-adapter-memory'));
            const db = await RxDB.create({
                name: util.randomCouchString(10),
                adapter: 'memory'
            });
            assert.equal(db.constructor.name, 'RxDatabase');
            db.destroy();
        });
    });
    describe('localstorage', () => {
        it('should crash because nodejs has no localstorage', async () => {
            if (!config.platform.isNode()) return;
            RxDB.PouchDB.plugin(require('pouchdb-adapter-localstorage'));
            await AsyncTestUtil.assertThrows(
                () => RxDB.create({
                    name: util.randomCouchString(10),
                    adapter: 'localstorage'
                }),
                'RxError',
                'Adapter'
            );
        });
    });
    describe('websql', () => {
        describe('negative', () => {
            it('should fail when no adapter was added', async () => {
                await AsyncTestUtil.assertThrows(
                    () => RxDB.create({
                        name: util.randomCouchString(10),
                        adapter: 'websql'
                    }),
                    'RxError',
                    'Adapter'
                );
            });
        });
        describe('positive', () => {
            it('should work after adding the adapter', async () => {
                // test websql on chrome only
                if (config.platform.name !== 'chrome') return;

                RxDB.plugin(require('pouchdb-adapter-websql'));
                const db = await RxDB.create({
                    name: util.randomCouchString(10),
                    adapter: 'websql'
                });
                assert.equal(db.constructor.name, 'RxDatabase');
                await util.promiseWait(10);
                db.destroy();
            });
        });
    });
    describe('own pouchdb functions', () => {
        describe('.countAllUndeleted()', () => {
            it('should return 0', async () => {
                const name = util.randomCouchString(10);
                const pouchdb = new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }
                );
                const count = await RxDB.PouchDB.countAllUndeleted(pouchdb);
                assert.deepEqual(count, 0);
            });
            it('should return 1', async () => {
                const name = util.randomCouchString(10);
                const pouchdb = new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }
                );
                await pouchdb.put({
                    _id: util.randomCouchString(10)
                });
                const count = await RxDB.PouchDB.countAllUndeleted(pouchdb);
                assert.deepEqual(count, 1);
            });
            it('should not count deleted docs', async () => {
                const name = util.randomCouchString(10);
                const pouchdb = new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }
                );
                const _id = util.randomCouchString(10);
                await pouchdb.put({
                    _id,
                    x: 1
                });

                const countBefore = await RxDB.PouchDB.countAllUndeleted(pouchdb);
                assert.deepEqual(countBefore, 1);

                const doc = await pouchdb.get(_id);
                await pouchdb.remove(doc);
                const count = await RxDB.PouchDB.countAllUndeleted(pouchdb);
                assert.deepEqual(count, 0);
            });
            it('should count a big amount with one deleted doc', async () => {
                const name = util.randomCouchString(10);
                const pouchdb = new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }
                );

                const _id = util.randomCouchString(10);
                await pouchdb.put({
                    _id,
                    x: 1
                });
                const countBefore = await RxDB.PouchDB.countAllUndeleted(pouchdb);
                assert.deepEqual(countBefore, 1);
                const doc = await pouchdb.get(_id);
                await pouchdb.remove(doc);

                let t = 42;
                while (t > 0) {
                    await pouchdb.put({
                        _id: util.randomCouchString(10),
                        x: 1
                    });
                    t--;
                }
                const count = await RxDB.PouchDB.countAllUndeleted(pouchdb);
                assert.deepEqual(count, 42);
            });
        });
        describe('.getBatch()', () => {
            it('should return empty array', async () => {
                const name = util.randomCouchString(10);
                const pouchdb = new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }
                );
                const docs = await RxDB.PouchDB.getBatch(pouchdb, 10);
                assert.deepEqual(docs, []);
            });
            it('should not return deleted', async () => {
                const name = util.randomCouchString(10);
                const pouchdb = new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }
                );

                const _id = util.randomCouchString(10);
                await pouchdb.put({
                    _id,
                    x: 1
                });

                const countBefore = await RxDB.PouchDB.countAllUndeleted(pouchdb);
                assert.deepEqual(countBefore, 1);

                const doc = await pouchdb.get(_id);
                await pouchdb.remove(doc);

                const docs = await RxDB.PouchDB.getBatch(pouchdb, 10);
                assert.deepEqual(docs, []);
            });
            it('should return one document in array', async () => {
                const name = util.randomCouchString(10);
                const pouchdb = new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }
                );
                const _id = util.randomCouchString(10);
                await pouchdb.put({
                    _id,
                    x: 1
                });
                const docs = await RxDB.PouchDB.getBatch(pouchdb, 10);
                assert.equal(docs.length, 1);
                assert.equal(docs[0].x, 1);
                assert.equal(docs[0]._id, _id);
            });

            it('should max return batchSize', async () => {
                const name = util.randomCouchString(10);
                const pouchdb = new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }
                );

                let t = 42;
                while (t > 0) {
                    await pouchdb.put({
                        _id: util.randomCouchString(10),
                        x: 1
                    });
                    t--;
                }
                const batchSize = 13;
                const docs = await RxDB.PouchDB.getBatch(pouchdb, batchSize);
                assert.equal(docs.length, batchSize);
                docs.forEach(doc => {
                    assert.equal(doc.x, 1);
                });
            });
        });
    });
    describe('BUGS: pouchdb', () => {
        it('_local documents should not be cached by pouchdb', async () => {
            const name = util.randomCouchString(10);
            const _id = '_local/foobar';
            const createPouch = () => {
                return new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }, {
                        auto_compaction: true,
                        revs_limit: 1
                    }
                );
            };
            const pouch1 = createPouch();
            const pouch2 = createPouch();
            await AsyncTestUtil.assertThrows(
                () => pouch2.get(_id),
                'PouchError'
            );
            // insert
            await pouch1.put({
                _id,
                value: 'foo'
            });
            const doc2 = await pouch2.get(_id);
            assert.equal(doc2.value, 'foo');

            pouch1.destroy();
            pouch2.destroy();
        });
        /**
         * @link https://github.com/pouchdb/pouchdb/issues/6733
         */
        it('pouchdb.find() should not return design-docs', async () => {
            const pouch = new RxDB.PouchDB(
                util.randomCouchString(10), {
                    adapter: 'memory'
                }, {
                    auto_compaction: true,
                    revs_limit: 1
                }
            );

            await pouch.createIndex({
                index: {
                    fields: ['foo']
                }
            });

            // add one doc
            await pouch.put({
                _id: 'asdf',
                foo: 'bar'
            });

            // get docs
            const docs = await pouch.find({
                selector: {
                    foo: {
                        $gt: null
                    }
                },
                sort: ['foo']
            });

            assert.equal(docs.docs.length, 1);

            pouch.destroy();
        });
        it('removing via bulkDocs does not work', async () => {
            const pouch = new RxDB.PouchDB(
                util.randomCouchString(10), {
                    adapter: 'memory'
                }, {
                    auto_compaction: true,
                    revs_limit: 1
                }
            );

            // add one doc
            await pouch.put({
                _id: 'foobar',
                foo: 'bar'
            });

            // overwrite via bulkDocs
            await pouch.bulkDocs([{
                _id: 'foobar',
                foo: 'bar',
                _rev: '2-6c5d4399ffe848f395069eab42630eee'
            }], {
                new_edits: false
            });

            // find again
            const foundAfter = await pouch.find({
                selector: {}
            });
            assert.ok(foundAfter.docs[0]._rev.startsWith('2-')); // ok

            // delete via bulkDocs
            const x = await pouch.put({
                _id: 'foobar',
                foo: 'bar',
                _rev: '3-13af8c9a835820969a8a273b18783a70',
                _deleted: true
            }, {
                new_edits: false
            });
            assert.equal(x.length, 0);

            /**
             * If this test ever throws, it means we can remove the hacky workarround in
             * src/plugins/in-memory.js
             * Where we add the rxdb_originInMemory-flag
             */
            await AsyncTestUtil.assertThrows(
                async () => {
                    const foundAfter2 = await pouch.find({
                        selector: {}
                    });
                    assert.ok(foundAfter2.docs[0]._rev.startsWith('3-'));
                },
                'AssertionError'
            );

            pouch.destroy();
        });
    });
});
<commit_msg>ADD test for pouchdb<commit_after>import config from './config';
import assert from 'assert';
import memdown from 'memdown';

let leveldb;
if (config.platform.isNode())
    leveldb = require('pouchdb-adapter-leveldb');

import * as RxDB from '../../dist/lib/index';
import * as util from '../../dist/lib/util';
import AsyncTestUtil from 'async-test-util';

config.parallel('pouch-db-integration.test.js', () => {
    describe('init', () => {
        it('should export the pouchDB-module', async () => {
            assert.equal(typeof RxDB.PouchDB, 'function');
        });
    });
    describe('memdown', () => {
        it('should not allow leveldown-adapters without the plugin', async () => {
            await AsyncTestUtil.assertThrows(
                () => RxDB.create({
                    name: util.randomCouchString(10),
                    adapter: memdown
                }),
                'RxError',
                'leveldb-plugin'
            );
        });
        it('should work after adding the leveldb-plugin', async () => {
            if (!config.platform.isNode()) return;
            RxDB.PouchDB.plugin(leveldb);
            const db = await RxDB.create({
                name: util.randomCouchString(10),
                adapter: memdown
            });
            assert.equal(db.constructor.name, 'RxDatabase');
            db.destroy();
        });
    });
    describe('pouchdb-adapter-memory', () => {
        it('should not create a db without adding the adapter', async () => {
            await AsyncTestUtil.assertThrows(
                () => RxDB.create({
                    name: util.randomCouchString(10),
                    adapter: 'memory'
                }),
                'RxError',
                'Adapter'
            );
        });
        it('should work when adapter was added', async () => {
            RxDB.plugin(require('pouchdb-adapter-memory'));
            const db = await RxDB.create({
                name: util.randomCouchString(10),
                adapter: 'memory'
            });
            assert.equal(db.constructor.name, 'RxDatabase');
            db.destroy();
        });
    });
    describe('localstorage', () => {
        it('should crash because nodejs has no localstorage', async () => {
            if (!config.platform.isNode()) return;
            RxDB.PouchDB.plugin(require('pouchdb-adapter-localstorage'));
            await AsyncTestUtil.assertThrows(
                () => RxDB.create({
                    name: util.randomCouchString(10),
                    adapter: 'localstorage'
                }),
                'RxError',
                'Adapter'
            );
        });
    });
    describe('websql', () => {
        describe('negative', () => {
            it('should fail when no adapter was added', async () => {
                await AsyncTestUtil.assertThrows(
                    () => RxDB.create({
                        name: util.randomCouchString(10),
                        adapter: 'websql'
                    }),
                    'RxError',
                    'Adapter'
                );
            });
        });
        describe('positive', () => {
            it('should work after adding the adapter', async () => {
                // test websql on chrome only
                if (config.platform.name !== 'chrome') return;

                RxDB.plugin(require('pouchdb-adapter-websql'));
                const db = await RxDB.create({
                    name: util.randomCouchString(10),
                    adapter: 'websql'
                });
                assert.equal(db.constructor.name, 'RxDatabase');
                await util.promiseWait(10);
                db.destroy();
            });
        });
    });
    describe('own pouchdb functions', () => {
        describe('.countAllUndeleted()', () => {
            it('should return 0', async () => {
                const name = util.randomCouchString(10);
                const pouchdb = new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }
                );
                const count = await RxDB.PouchDB.countAllUndeleted(pouchdb);
                assert.deepEqual(count, 0);
            });
            it('should return 1', async () => {
                const name = util.randomCouchString(10);
                const pouchdb = new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }
                );
                await pouchdb.put({
                    _id: util.randomCouchString(10)
                });
                const count = await RxDB.PouchDB.countAllUndeleted(pouchdb);
                assert.deepEqual(count, 1);
            });
            it('should not count deleted docs', async () => {
                const name = util.randomCouchString(10);
                const pouchdb = new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }
                );
                const _id = util.randomCouchString(10);
                await pouchdb.put({
                    _id,
                    x: 1
                });

                const countBefore = await RxDB.PouchDB.countAllUndeleted(pouchdb);
                assert.deepEqual(countBefore, 1);

                const doc = await pouchdb.get(_id);
                await pouchdb.remove(doc);
                const count = await RxDB.PouchDB.countAllUndeleted(pouchdb);
                assert.deepEqual(count, 0);
            });
            it('should count a big amount with one deleted doc', async () => {
                const name = util.randomCouchString(10);
                const pouchdb = new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }
                );

                const _id = util.randomCouchString(10);
                await pouchdb.put({
                    _id,
                    x: 1
                });
                const countBefore = await RxDB.PouchDB.countAllUndeleted(pouchdb);
                assert.deepEqual(countBefore, 1);
                const doc = await pouchdb.get(_id);
                await pouchdb.remove(doc);

                let t = 42;
                while (t > 0) {
                    await pouchdb.put({
                        _id: util.randomCouchString(10),
                        x: 1
                    });
                    t--;
                }
                const count = await RxDB.PouchDB.countAllUndeleted(pouchdb);
                assert.deepEqual(count, 42);
            });
        });
        describe('.getBatch()', () => {
            it('should return empty array', async () => {
                const name = util.randomCouchString(10);
                const pouchdb = new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }
                );
                const docs = await RxDB.PouchDB.getBatch(pouchdb, 10);
                assert.deepEqual(docs, []);
            });
            it('should not return deleted', async () => {
                const name = util.randomCouchString(10);
                const pouchdb = new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }
                );

                const _id = util.randomCouchString(10);
                await pouchdb.put({
                    _id,
                    x: 1
                });

                const countBefore = await RxDB.PouchDB.countAllUndeleted(pouchdb);
                assert.deepEqual(countBefore, 1);

                const doc = await pouchdb.get(_id);
                await pouchdb.remove(doc);

                const docs = await RxDB.PouchDB.getBatch(pouchdb, 10);
                assert.deepEqual(docs, []);
            });
            it('should return one document in array', async () => {
                const name = util.randomCouchString(10);
                const pouchdb = new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }
                );
                const _id = util.randomCouchString(10);
                await pouchdb.put({
                    _id,
                    x: 1
                });
                const docs = await RxDB.PouchDB.getBatch(pouchdb, 10);
                assert.equal(docs.length, 1);
                assert.equal(docs[0].x, 1);
                assert.equal(docs[0]._id, _id);
            });

            it('should max return batchSize', async () => {
                const name = util.randomCouchString(10);
                const pouchdb = new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }
                );

                let t = 42;
                while (t > 0) {
                    await pouchdb.put({
                        _id: util.randomCouchString(10),
                        x: 1
                    });
                    t--;
                }
                const batchSize = 13;
                const docs = await RxDB.PouchDB.getBatch(pouchdb, batchSize);
                assert.equal(docs.length, batchSize);
                docs.forEach(doc => {
                    assert.equal(doc.x, 1);
                });
            });
        });
    });
    describe('BUGS: pouchdb', () => {
        it('_local documents should not be cached by pouchdb', async () => {
            const name = util.randomCouchString(10);
            const _id = '_local/foobar';
            const createPouch = () => {
                return new RxDB.PouchDB(
                    name, {
                        adapter: 'memory'
                    }, {
                        auto_compaction: true,
                        revs_limit: 1
                    }
                );
            };
            const pouch1 = createPouch();
            const pouch2 = createPouch();
            await AsyncTestUtil.assertThrows(
                () => pouch2.get(_id),
                'PouchError'
            );
            // insert
            await pouch1.put({
                _id,
                value: 'foo'
            });
            const doc2 = await pouch2.get(_id);
            assert.equal(doc2.value, 'foo');

            pouch1.destroy();
            pouch2.destroy();
        });
        /**
         * @link https://github.com/pouchdb/pouchdb/issues/6733
         */
        it('pouchdb.find() should not return design-docs', async () => {
            const pouch = new RxDB.PouchDB(
                util.randomCouchString(10), {
                    adapter: 'memory'
                }, {
                    auto_compaction: true,
                    revs_limit: 1
                }
            );

            await pouch.createIndex({
                index: {
                    fields: ['foo']
                }
            });

            // add one doc
            await pouch.put({
                _id: 'asdf',
                foo: 'bar'
            });

            // get docs
            const docs = await pouch.find({
                selector: {
                    foo: {
                        $gt: null
                    }
                },
                sort: ['foo']
            });

            assert.equal(docs.docs.length, 1);

            pouch.destroy();
        });
        it('removing via bulkDocs does not work', async () => {
            const pouch = new RxDB.PouchDB(
                util.randomCouchString(10), {
                    adapter: 'memory'
                }, {
                    auto_compaction: true,
                    revs_limit: 1
                }
            );

            // add one doc
            await pouch.put({
                _id: 'foobar',
                foo: 'bar'
            });

            // overwrite via bulkDocs
            await pouch.bulkDocs([{
                _id: 'foobar',
                foo: 'bar',
                _rev: '2-6c5d4399ffe848f395069eab42630eee'
            }], {
                new_edits: false
            });

            // find again
            const foundAfter = await pouch.find({
                selector: {}
            });
            assert.ok(foundAfter.docs[0]._rev.startsWith('2-')); // ok

            // delete via bulkDocs
            const x = await pouch.put({
                _id: 'foobar',
                foo: 'bar',
                _rev: '3-13af8c9a835820969a8a273b18783a70',
                _deleted: true
            }, {
                new_edits: false
            });
            assert.equal(x.length, 0);

            /**
             * If this test ever throws, it means we can remove the hacky workarround in
             * src/plugins/in-memory.js
             * Where we add the rxdb_originInMemory-flag
             */
            await AsyncTestUtil.assertThrows(
                async () => {
                    const foundAfter2 = await pouch.find({
                        selector: {}
                    });
                    assert.ok(foundAfter2.docs[0]._rev.startsWith('3-'));
                },
                'AssertionError'
            );

            pouch.destroy();
        });
        it('putting with _deleted does not work', async () => {
            const pouch = new RxDB.PouchDB(
                util.randomCouchString(10), {
                    adapter: 'memory'
                }, {
                    auto_compaction: true,
                    revs_limit: 1
                }
            );
            const bulkOptions = {
                new_edits: false
            };

            // subscribe to changes 2 times
            pouch.changes({
                since: 'now',
                live: true,
                include_docs: true
            });
            pouch.changes({
                since: 'now',
                live: true,
                include_docs: true
            });

            // insert doc via bulkDocs
            await pouch.bulkDocs({
                docs: [{
                    '|c': '0waqyh2xjwtu',
                    '|a': 'foo123',
                    '|b': 'King',
                    age: 1,
                    _id: 'myid',
                    _rev: '1-62080c42d471e3d2625e49dcca3b8e3e'
                }]
            }, bulkOptions);

            let foundAfter = await pouch.find({
                selector: {}
            });
            assert.equal(foundAfter.docs.length, 1);

            // update via bulkDocs
            const updateMe = foundAfter.docs[0];
            updateMe.firstName = 'foobar';
            await pouch.bulkDocs({
                docs: [updateMe]
            }, bulkOptions);

            // remove
            foundAfter = await pouch.find({
                selector: {}
            });
            const removeMe = foundAfter.docs[0];
            removeMe._deleted = true;
            await pouch.get('myid').catch(() => null);
            await pouch.put(removeMe);

            foundAfter = await pouch.find({
                selector: {}
            });
            assert.equal(foundAfter.docs.length, 0);

            pouch.destroy();
        });
    });
});
<|endoftext|>


<commit_before>var burndownDataToList = function (burndownData) {
    var days = [];

    for (var day in burndownData) {
        days.push({
            day: d3.time.format('%Y-%m-%d').parse(day),
            points: burndownData[day]
        });
    }

    return days;
};

var $burndownData = $('#burndown-data'),
    totalPoints = $burndownData.data('total'),
    closedBefore = $burndownData.data('before'),
    closedPerDay = burndownDataToList($.parseJSON($burndownData.text()));

var dayAfter = function (date) {
    var next = new Date(date);
    next.setDate(date.getDate() + 1);

    return next;
};

var sprintData = function () {
    var remaining = totalPoints - closedBefore;

    return closedPerDay.map(function (day) {
            remaining -= day.points;

            return {
                day: day.day,
                points: remaining + day.points // adding the points again so the progress will not show for the previous day
            };
        }).concat([{ // adding another "day" so that the progress of the last day is not hidden
            day: dayAfter(closedPerDay[closedPerDay.length - 1].day),
            points: remaining
        }]);
};

var isWeekend = function (date) {
    return date.getDay() % 6 === 0;
};

var countWeekendDays = function (data) {
    var count = 0;

    data.forEach(function (data) {
        if (isWeekend(data.day)) count++;
    });

    return count;
};

var calculateIdealGraph = function (data) {
    var averagePointsPerDay = totalPoints / (data.length - countWeekendDays(data) - 1),
        idealData = [],
        remaining = totalPoints;

    data.forEach(function (day) {
        idealData.push({ day: day.day, points: remaining });
        if (!isWeekend(day.day)) remaining -= averagePointsPerDay;
    });

    return idealData;
};

var actualGraphData = sprintData(),
    idealGraphData = calculateIdealGraph(actualGraphData),

    margin = { top: 10, right: 10, bottom: 50, left: 30 },
    width = 600 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom,

    x = d3.time.scale().range([0, width]),
    y = d3.scale.linear().range([height, 0]),

    xOfDay = function (d) { return x(d.day); },
    yOfPoints = function (d) { return y(d.points); };

var xAxis = d3.svg.axis().scale(x)
                .orient('bottom')
                .ticks(actualGraphData.length)
                    .tickFormat(d3.time.format('%b %e'));

var yAxis = d3.svg.axis().scale(y)
                .orient('left').ticks(5);

var line = d3.svg.line()
                .x(xOfDay)
                .y(yOfPoints);

var svg = d3.select('#burndown')
            .append('svg')
                .attr('width', width + margin.left + margin.right)
                .attr('height', height + margin.top + margin.bottom)
            .append('g')
                .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

x.domain(d3.extent(actualGraphData, function (d) { return d.day; }));
y.domain([0, totalPoints]);

svg.append('path')
    .attr('class', 'graph ideal')
    .attr('d', line(idealGraphData));

svg.append('path')
    .attr('class', 'graph actual')
    .attr('d', line(actualGraphData.filter(function (data) {
        return data.day <= new Date();
    })));

svg.append('g')
    .attr('class', 'x axis')
    .attr('transform', 'translate(0,' + height + ')')
    .call(xAxis)
    .selectAll("text") // aligns the labels on the x-axis for the rotation
        .style("text-anchor", "end")
        .attr("dx", "-.8em")
        .attr("dy", ".15em");

svg.append('g')
    .attr('class', 'y axis')
    .call(yAxis);

svg.append('path')
    .datum(actualGraphData)
    .attr('class', 'graph-area')
    .attr('d', d3.svg.area()
        .x(xOfDay)
        .y0(y(0))
        .y1(yOfPoints));

svg.selectAll('.daily-points')
    .data(closedPerDay)
    .enter().append('line')
        .attr('class', 'daily-points')
        .attr('x1', xOfDay)
        .attr('y1', y(0))
        .attr('x2', xOfDay)
        .attr('y2', yOfPoints);
<commit_msg>Restructure burndown.js.<commit_after>(function () {
    var burndownChart = (function () {
        var sprintData,
            dimensions,

            svg,

            x, y;

        var setSVG = function (svgElementID) {
            svg = d3.select(svgElementID)
                .append('svg')
                .attr('width', dimensions.width + dimensions.margin.left + dimensions.margin.right)
                .attr('height', dimensions.height + dimensions.margin.top + dimensions.margin.bottom)
                .append('g')
                .attr('transform', 'translate(' + dimensions.margin.left + ',' + dimensions.margin.top + ')');
        };

        var addAxes = function () {
            var xAxis = d3.svg.axis().scale(x)
                .orient('bottom')
                .ticks(sprintData.getBurndownData().length)
                .tickFormat(d3.time.format('%b %e'));

            var yAxis = d3.svg.axis().scale(y)
                .orient('left').ticks(5);

            svg.append('g')
                .attr('class', 'x axis')
                .attr('transform', 'translate(0,' + dimensions.height + ')')
                .call(xAxis)
                .selectAll('text') // aligns the labels on the x-axis for the rotation
                    .style('text-anchor', 'end')
                    .attr('dx', '-.8em')
                    .attr('dy', '.15em');

            svg.append('g')
                .attr('class', 'y axis')
                .call(yAxis);
        };

        var addActualProgressLine = function () {
            svg.append('path')
                .attr('class', 'graph actual')
                .attr('d', line(sprintData.getBurndownData().filter(function (data) {
                    return data.day <= new Date();
                })));

            svg.append('path')
                .datum(sprintData.getBurndownData())
                .attr('class', 'graph-area')
                .attr('d', d3.svg.area()
                    .x(xOfDay)
                    .y0(y(0))
                    .y1(yOfPoints));
        };

        var addIdealProgressLine = function () {
            svg.append('path')
                .attr('class', 'graph ideal')
                .attr('d', line(sprintData.getIdealGraphData()));
        };

        var xOfDay = function (d) { return x(d.day); },
            yOfPoints = function (d) { return y(d.points); };

        var line = d3.svg.line()
            .x(xOfDay)
            .y(yOfPoints);

        var addClosedTasksPerDayBars = function () {
            svg.selectAll('.daily-points')
                .data(sprintData.getPointsClosedPerDay())
                .enter().append('line')
                .attr('class', 'daily-points')
                .attr('x1', xOfDay)
                .attr('y1', y(0))
                .attr('x2', xOfDay)
                .attr('y2', yOfPoints);
        };

        var setDomain = function () {
            x = d3.time.scale().range([0, dimensions.width]);
            y = d3.scale.linear().range([dimensions.height, 0]);

            x.domain(d3.extent(sprintData.getBurndownData(), function (d) { return d.day; }));
            y.domain([0, sprintData.getTotalPoints()]);
        };

        return {
            /**
             * @param {Object} data - A burndownData Object containing information for the graphs
             */
            init: function (data) {
                sprintData = data;
            },

            /**
             * @param {string} id - The ID of the element where the burndown chart will be shown
             * @param {Object} chartDimensions - An object containing height, width, margin.top, margin.right, margin.bottom, margin.left
             */
            render: function (id, chartDimensions) {
                dimensions = chartDimensions;

                setSVG(id);
                setDomain();

                addAxes();
                addActualProgressLine();
                addClosedTasksPerDayBars();
                addIdealProgressLine();
            }
        };
    })();

    var burndownData = function () {
        var pointsClosedPerDay,
            remainingPointsPerDay,
            pointsClosedBeforeSprint,
            totalPoints;

        var dataToList = function (dataObject) {
            var days = [];

            for (var date in dataObject) {
                days.push({
                    day: d3.time.format('%Y-%m-%d').parse(date),
                    points: dataObject[date]
                });
            }

            return days;
        };

        var dayAfter = function (date) {
            var next = new Date(date);
            next.setDate(date.getDate() + 1);

            return next;
        };

        var calculateActualProgressData = function (closedPerDay) {
            var remaining = totalPoints - pointsClosedBeforeSprint;

            return closedPerDay.map(function (day) {
                remaining -= day.points;

                return {
                    day: day.day,
                    points: remaining + day.points // adding the points again so the progress will not show for the previous day
                };
            }).concat([{ // adding another "day" so that the progress of the last day is not hidden
                day: dayAfter(closedPerDay[closedPerDay.length - 1].day),
                points: remaining
            }]);
        };

        var isWeekend = function (date) {
            return date.getDay() % 6 === 0;
        };

        var countWeekendDays = function (data) {
            var count = 0;

            data.forEach(function (data) {
                if (isWeekend(data.day)) count++;
            });

            return count;
        };

        var calculateIdealGraph = function (actualProgress) {
            var averagePointsPerDay = totalPoints / (actualProgress.length - countWeekendDays(actualProgress) - 1),
                idealData = [],
                remaining = totalPoints;

            actualProgress.forEach(function (day) {
                idealData.push({ day: day.day, points: remaining });
                if (!isWeekend(day.day)) remaining -= averagePointsPerDay;
            });

            return idealData;
        };

        return {
            /**
             * @param {Object} closedPerDate - An object with date strings as its keys and number of closed points as values
             * @param {number} closedBeforeSprint - Number of story points that were closed before the sprint start
             * @param {number} pointsInSprint - Total number of story points in this sprint
             */
            init: function (closedPerDate, closedBeforeSprint, pointsInSprint) {
                totalPoints = pointsInSprint;
                pointsClosedBeforeSprint = closedBeforeSprint;
                pointsClosedPerDay = dataToList(closedPerDate);
                remainingPointsPerDay = calculateActualProgressData(pointsClosedPerDay);
            },

            /**
             * @returns {number} Total number of story points in this sprint
             */
            getTotalPoints: function () {
                return totalPoints;
            },

            /**
             * The data represented by the line in the burndown chart.
             * It returns a list of the days of the sprint as well as the number of unclosed points at that day.
             * @returns {Object[]} List of Objects of the form { day: 'yyyy-mm-dd', points: numberOfRemainingPoints }
             */
            getBurndownData: function () {
                return remainingPointsPerDay;
            },

            /**
             * The data represented by bar charts in the diagram.
             * It returns a list of the days of the sprint as well as the number of points closed on that day.
             * @returns {Object[]} List of Objects of the form { day: 'yyyy-mm-dd', points: numberOfClosedPoints }
             */
            getPointsClosedPerDay: function () {
                return pointsClosedPerDay;
            },

            /**
             * The data represented by the dashed green line.
             * It contains the days of the sprint as well as the ideal number of points (= total points / (number of days - weekend days)) to be closed on a day.
             * @returns {Object[]}
             */
            getIdealGraphData: function () {
                return calculateIdealGraph(remainingPointsPerDay);
            }
        }
    }();

    var $burndownData = $('#burndown-data');

    burndownData.init(
        $.parseJSON($burndownData.text()),
        +$burndownData.data('before'),
        +$burndownData.data('total')
    );

    burndownChart.init(burndownData);
    burndownChart.render(
        '#burndown',
        {
            height: 400,
            width: 600,

            margin: { top: 10, right: 10, bottom: 50, left: 30 }
        }
    );
})();
<|endoftext|>


<commit_before>girder.App = girder.View.extend({
    initialize: function (settings) {
        girder.restRequest({
            path: 'user/me'
        }).done(_.bind(function (user) {
            girder.eventStream = new girder.EventStream({
                timeout: girder.sseTimeout || null
            });

            this.headerView = new girder.views.LayoutHeaderView({
                parentView: this
            });

            this.globalNavView = new girder.views.LayoutGlobalNavView({
                parentView: this
            });

            this.footerView = new girder.views.LayoutFooterView({
                parentView: this
            });

            this.progressListView = new girder.views.ProgressListView({
                eventStream: girder.eventStream,
                parentView: this
            });

            if (user) {
                girder.currentUser = new girder.models.UserModel(user);
                girder.eventStream.open();
            }
            this._initLayoutRenderMap();
            this.render();

            // Once we've rendered the layout, we can start up the routing.
            Backbone.history.start({
                pushState: false
            });
        }, this));

        girder.events.on('g:navigateTo', this.navigateTo, this);
        girder.events.on('g:loginUi', this.loginDialog, this);
        girder.events.on('g:registerUi', this.registerDialog, this);
        girder.events.on('g:resetPasswordUi', this.resetPasswordDialog, this);
        girder.events.on('g:alert', this.alert, this);
        girder.events.on('g:login', this.login, this);
    },

    _initLayoutRenderMap: function () {
        var hide_on_empty = ['#g-app-header-container', '#g-global-nav-container', '#g-app-footer-container'],
            css_empty = {
                '#g-app-body-container': {
                    'margin-left': '0px',
                    'padding-top': '10px'
                }
            },
            css_restore = {},
            _this = this, // more readable than _.bind-ing this through three nested functions
            toEmpty = function () {
                _.each(hide_on_empty, function (element) {
                    _this.$(element).hide();
                });
                _.each(css_empty, function (properties, element) {
                    var restored_element = {};
                    _.each(properties, function (value, property) {
                        restored_element[property] = _this.$(element).css(property);
                        _this.$(element).css(property, value);
                    });
                    css_restore[element] = restored_element;
                });
            },
            toDefault = function () {
                _.each(hide_on_empty, function (element) {
                    _this.$(element).show();
                });
                _.each(css_restore, function (properties, element) {
                    _.each(properties, function (value, property) {
                        _this.$(element).css(property, value);
                    });
                });
                css_restore = {};
            };
        this.layoutRenderMap = {};
        this.layoutRenderMap[girder.Layout.DEFAULT] = toDefault;
        this.layoutRenderMap[girder.Layout.EMPTY] = toEmpty;
    },

    render: function () {
        this.$el.html(girder.templates.layout());

        this.globalNavView.setElement(this.$('#g-global-nav-container')).render();
        this.headerView.setElement(this.$('#g-app-header-container')).render();
        this.footerView.setElement(this.$('#g-app-footer-container')).render();
        this.progressListView.setElement(this.$('#g-app-progress-container')).render();

        return this;
    },

    /**
     * Changes the current body view to the view class specified by view.
     * @param view The view to display in the body.
     * @param [settings={}] Settings to pass to the view initialize() method.
     * @param opts Additional options for navigateTo, if any.
     */
    navigateTo: function (view, settings, opts) {
        var container = this.$('#g-app-body-container');

        this.globalNavView.deactivateAll();

        settings = settings || {};

        if (opts && opts.layout) {
            if (girder.layout !== opts.layout) {
                if (_.has(this.layoutRenderMap, opts.layout)) {
                    // set a layout if opts specifies one different from current
                    girder.layout = opts.layout;
                    this.layoutRenderMap[girder.layout]();
                } else {
                    console.error('Attempting to set unknown layout type: ' + opts.layout);
                }
            }
        } else if (girder.layout !== girder.Layout.DEFAULT) {
            // reset to default as needed when nothing specified in opts
            girder.layout = girder.Layout.DEFAULT;
            this.layoutRenderMap[girder.layout]();
        }

        if (view) {
            if (this.bodyView) {
                this.bodyView.destroy();
            }

            settings = _.extend(settings, {
                el: this.$('#g-app-body-container'),
                parentView: this
            });

            /* We let the view be created in this way even though it is
             * normally against convention.
             */
            /*jshint -W055 */
            // jscs:disable requireCapitalizedConstructors
            this.bodyView = new view(settings);
            // jscs:enable requireCapitalizedConstructors
        } else {
            console.error('Undefined page.');
        }
        return this;
    },

    /**
     * Close any open dialog if we are already logged in.
     * :returns: true if we have a current user.
     */
    closeDialogIfUser: function () {
        if (girder.currentUser) {
            $('.modal').girderModal('close');
            return true;
        }
        return false;
    },

    /**
     * Show a dialog allowing a user to login or register.
     */
    loginDialog: function () {
        if (this.closeDialogIfUser()) {
            return;
        }
        if (!this.loginView) {
            this.loginView = new girder.views.LoginView({
                el: this.$('#g-dialog-container'),
                parentView: this
            });
        }
        this.loginView.render();
    },

    registerDialog: function () {
        if (this.closeDialogIfUser()) {
            return;
        }
        if (!this.registerView) {
            this.registerView = new girder.views.RegisterView({
                el: this.$('#g-dialog-container'),
                parentView: this
            });
        }
        this.registerView.render();
    },

    resetPasswordDialog: function () {
        if (this.closeDialogIfUser()) {
            return;
        }
        if (!this.resetPasswordView) {
            this.resetPasswordView = new girder.views.ResetPasswordView({
                el: this.$('#g-dialog-container'),
                parentView: this
            });
        }
        this.resetPasswordView.render();
    },

    /**
     * Display a brief alert on the screen with the following options:
     *   - text: The text to be displayed
     *   - [type]: The alert class ('info', 'warning', 'success', 'danger').
     *             Default is 'info'.
     *   - [icon]: An optional icon to display in the alert.
     *   - [timeout]: How long before the alert should automatically disappear.
     *                Default is 6000ms. Set to <= 0 to have no timeout.
     */
    alert: function (options) {
        var el = $(girder.templates.alert({
            text: options.text,
            type: options.type || 'info',
            icon: options.icon
        }));
        $('#g-alerts-container').append(el);
        el.fadeIn(500);

        if (options.timeout === undefined) {
            options.timeout = 6000;
        }
        if (options.timeout > 0) {
            window.setTimeout(function () {
                el.fadeOut(750, function () {
                    $(this).remove();
                });
            }, options.timeout);
        }
    },

    /**
     * On login or logout, we re-render the current body view.
     */
    login: function () {
        var route = girder.dialogs.splitRoute(Backbone.history.fragment).base;
        Backbone.history.fragment = null;
        girder.router.navigate(route, {trigger: true});

        if (girder.currentUser) {
            girder.eventStream.close();
            girder.eventStream.open();
        } else {
            girder.eventStream.close();
        }
    }
});
<commit_msg>Use .call(this, opts) on layout handlers<commit_after>girder.App = girder.View.extend({
    initialize: function (settings) {
        girder.restRequest({
            path: 'user/me'
        }).done(_.bind(function (user) {
            girder.eventStream = new girder.EventStream({
                timeout: girder.sseTimeout || null
            });

            this.headerView = new girder.views.LayoutHeaderView({
                parentView: this
            });

            this.globalNavView = new girder.views.LayoutGlobalNavView({
                parentView: this
            });

            this.footerView = new girder.views.LayoutFooterView({
                parentView: this
            });

            this.progressListView = new girder.views.ProgressListView({
                eventStream: girder.eventStream,
                parentView: this
            });

            if (user) {
                girder.currentUser = new girder.models.UserModel(user);
                girder.eventStream.open();
            }
            this._initLayoutRenderMap();
            this.render();

            // Once we've rendered the layout, we can start up the routing.
            Backbone.history.start({
                pushState: false
            });
        }, this));

        girder.events.on('g:navigateTo', this.navigateTo, this);
        girder.events.on('g:loginUi', this.loginDialog, this);
        girder.events.on('g:registerUi', this.registerDialog, this);
        girder.events.on('g:resetPasswordUi', this.resetPasswordDialog, this);
        girder.events.on('g:alert', this.alert, this);
        girder.events.on('g:login', this.login, this);
    },

    _initLayoutRenderMap: function () {
        var hideOnEmpty = ['#g-app-header-container', '#g-global-nav-container', '#g-app-footer-container'],
            css_empty = {
                '#g-app-body-container': {
                    'margin-left': '0px',
                    'padding-top': '10px'
                }
            },
            cssRestore = {},
            toEmpty = function () {
                _.each(hideOnEmpty, _.bind(function (element) {
                    this.$(element).hide();
                }, this));
                _.each(css_empty, _.bind(function (properties, element) {
                    var restored_element = {};
                    _.each(properties, _.bind(function (value, property) {
                        restored_element[property] = this.$(element).css(property);
                        this.$(element).css(property, value);
                    }, this));
                    cssRestore[element] = restored_element;
                }, this));
            },
            toDefault = function () {
                _.each(hideOnEmpty, _.bind(function (element) {
                    this.$(element).show();
                }, this));
                _.each(cssRestore, _.bind(function (properties, element) {
                    _.each(properties, _.bind(function (value, property) {
                        this.$(element).css(property, value);
                    }, this));
                }, this));
                cssRestore = {};
            };
        this.layoutRenderMap = {};
        this.layoutRenderMap[girder.Layout.DEFAULT] = toDefault;
        this.layoutRenderMap[girder.Layout.EMPTY] = toEmpty;
    },

    render: function () {
        this.$el.html(girder.templates.layout());

        this.globalNavView.setElement(this.$('#g-global-nav-container')).render();
        this.headerView.setElement(this.$('#g-app-header-container')).render();
        this.footerView.setElement(this.$('#g-app-footer-container')).render();
        this.progressListView.setElement(this.$('#g-app-progress-container')).render();

        return this;
    },

    /**
     * Changes the current body view to the view class specified by view.
     * @param view The view to display in the body.
     * @param [settings={}] Settings to pass to the view initialize() method.
     * @param opts Additional options for navigateTo, if any.
     */
    navigateTo: function (view, settings, opts) {
        var container = this.$('#g-app-body-container');

        this.globalNavView.deactivateAll();

        settings = settings || {};
        opts = opts || {};

        if (opts.layout) {
            if (girder.layout !== opts.layout) {
                if (_.has(this.layoutRenderMap, opts.layout)) {
                    // set a layout if opts specifies one different from current
                    girder.layout = opts.layout;
                    this.layoutRenderMap[girder.layout].call(this, opts);
                } else {
                    console.error('Attempting to set unknown layout type: ' + opts.layout);
                }
            }
        } else if (girder.layout !== girder.Layout.DEFAULT) {
            // reset to default as needed when nothing specified in opts
            girder.layout = girder.Layout.DEFAULT;
            this.layoutRenderMap[girder.layout].call(this, opts);
        }

        if (view) {
            if (this.bodyView) {
                this.bodyView.destroy();
            }

            settings = _.extend(settings, {
                el: this.$('#g-app-body-container'),
                parentView: this
            });

            /* We let the view be created in this way even though it is
             * normally against convention.
             */
            /*jshint -W055 */
            // jscs:disable requireCapitalizedConstructors
            this.bodyView = new view(settings);
            // jscs:enable requireCapitalizedConstructors
        } else {
            console.error('Undefined page.');
        }
        return this;
    },

    /**
     * Close any open dialog if we are already logged in.
     * :returns: true if we have a current user.
     */
    closeDialogIfUser: function () {
        if (girder.currentUser) {
            $('.modal').girderModal('close');
            return true;
        }
        return false;
    },

    /**
     * Show a dialog allowing a user to login or register.
     */
    loginDialog: function () {
        if (this.closeDialogIfUser()) {
            return;
        }
        if (!this.loginView) {
            this.loginView = new girder.views.LoginView({
                el: this.$('#g-dialog-container'),
                parentView: this
            });
        }
        this.loginView.render();
    },

    registerDialog: function () {
        if (this.closeDialogIfUser()) {
            return;
        }
        if (!this.registerView) {
            this.registerView = new girder.views.RegisterView({
                el: this.$('#g-dialog-container'),
                parentView: this
            });
        }
        this.registerView.render();
    },

    resetPasswordDialog: function () {
        if (this.closeDialogIfUser()) {
            return;
        }
        if (!this.resetPasswordView) {
            this.resetPasswordView = new girder.views.ResetPasswordView({
                el: this.$('#g-dialog-container'),
                parentView: this
            });
        }
        this.resetPasswordView.render();
    },

    /**
     * Display a brief alert on the screen with the following options:
     *   - text: The text to be displayed
     *   - [type]: The alert class ('info', 'warning', 'success', 'danger').
     *             Default is 'info'.
     *   - [icon]: An optional icon to display in the alert.
     *   - [timeout]: How long before the alert should automatically disappear.
     *                Default is 6000ms. Set to <= 0 to have no timeout.
     */
    alert: function (options) {
        var el = $(girder.templates.alert({
            text: options.text,
            type: options.type || 'info',
            icon: options.icon
        }));
        $('#g-alerts-container').append(el);
        el.fadeIn(500);

        if (options.timeout === undefined) {
            options.timeout = 6000;
        }
        if (options.timeout > 0) {
            window.setTimeout(function () {
                el.fadeOut(750, function () {
                    $(this).remove();
                });
            }, options.timeout);
        }
    },

    /**
     * On login or logout, we re-render the current body view.
     */
    login: function () {
        var route = girder.dialogs.splitRoute(Backbone.history.fragment).base;
        Backbone.history.fragment = null;
        girder.router.navigate(route, {trigger: true});

        if (girder.currentUser) {
            girder.eventStream.close();
            girder.eventStream.open();
        } else {
            girder.eventStream.close();
        }
    }
});
<|endoftext|>


<commit_before>var particleCount = (($(document).width() * $(document).height()) / (1920 * 1080)) * baseParticleCount;

//TODO: split main system into foreground and background particles
var particles = new THREE.Geometry();
var flecks = new THREE.Geometry();
var bokeh = new THREE.Geometry();

textureLoader = new THREE.TextureLoader();

var stdTexure = textureLoader.load(
	'./img/particle.png'
)
stdTexure.minFilter = THREE.LinearFilter;

var fleckTexture = textureLoader.load(
	'./img/fleck.png'
)
fleckTexture.minFilter = THREE.LinearFilter;

var bokehTexture = textureLoader.load(
	'./img/bokeh.png'
)
bokehTexture.minFilter = THREE.LinearFilter;

var pMaterial = new THREE.PointsMaterial({
	color: song.getGenre() === 'BTC' ? 0x000000 : 0xFFFFFF,
	opacity: particleOpacity,
	size: 5,
	map: stdTexure,
	blending: THREE.AdditiveBlending,
	transparent: true
});

var fleckMaterial = new THREE.PointsMaterial({
	color: color,
	opacity: particleOpacity,
	size: 4,
	map: fleckTexture,
	blending: THREE.AdditiveBlending,
	transparent: true
});

var bokehMaterial = new THREE.PointsMaterial({
	color: 0xFFFFFF,
	opacity: bokehOpacity,
	size: 100,
	map: bokehTexture,
	blending: THREE.AdditiveBlending,
	transparent: true
});

var velocityResScale = Math.pow(resRatio, 5);
var fleckVelocity = maxParticleVelocity * fleckVelocityScalar;

for (var p = 0; p < particleCount; p++) {
	var z = biasedRandom(zPosRange, zPosBias) + zModifier;
	var xRange = Math.abs(camera.position.z - z) * Math.tan(toRads(VIEW_ANGLE)) * 2; // maximum range on the x-axis at this z-value
	var yRange = Math.abs(camera.position.z - z) * Math.tan(toRads(VIEW_ANGLE / ASPECT)) * 2; // maximum range on the y-axis at this z-value
	var pX = Math.random() * xRange - xRange / 2,
		pY = centerBiasedRandom(yRange, xPosBias),
		pZ = z,
		particle = new THREE.Vector3(pX, pY, pZ);

	  // create a velocity vector
	particle.velocity = new THREE.Vector3(
		velocityResScale * (Math.random() * (maxParticleVelocity - minParticleVelocity) + minParticleVelocity),
		velocityResScale * centerBiasedRandom(yVelRange, velBias),
		0
	);

	// add it to the geometry
	particles.vertices.push(particle);
}

fleckYVelScalar *= fleckVelocity;

var fleckZ = 150;

for (var p = 0; p < fleckCount; p++) {
	var z = fleckZ;
	var xRange = Math.abs(camera.position.z - z) * Math.tan(toRads(VIEW_ANGLE)) * 2; // maximum range on the x-axis at this z-value
	var yRange = Math.abs(camera.position.z - z) * Math.tan(toRads(VIEW_ANGLE / ASPECT)) * 2; // maximum range on the y-axis at this z-value
	var pX = Math.random() * xRange - xRange / 2,
		pY = Math.floor(Math.random() * yRange) - yRange / 2,
		pZ = z,
		fleck = new THREE.Vector3(pX, pY, pZ);
	fleck.fleck = true;

	  // create a velocity vector
	fleck.velocity = new THREE.Vector3(
		velocityResScale * fleckVelocity,
		velocityResScale * centerBiasedRandom(fleckYVelScalar, velBias),
		0
	);

	// add it to the geometry
	flecks.vertices.push(fleck);
}

var bokehYVelRange = ((bokehMinVelocity + bokehMaxVelocity) * 0.5) * 2;

var bokehZ = 200;

for (var p = 0; p < bokehCount; p++) {
	var z = bokehZ;
    //var z = Math.random() * zPosRange - (zPosRange / 2);
	var xRange = Math.abs(camera.position.z - z) * Math.tan(toRads(VIEW_ANGLE)) * 2; // maximum range on the x-axis at this z-value
	var yRange = Math.abs(camera.position.z - z) * Math.tan(toRads(VIEW_ANGLE / ASPECT)) * 2; // maximum range on the y-axis at this z-value
	var pX = Math.random() * xRange - xRange / 2,
		pY = Math.random() * yRange - yRange / 2,
		pZ = z,
		b = new THREE.Vector3(pX, pY, pZ);
	b.bokeh = true;

	  // create a velocity vector
	b.velocity = new THREE.Vector3(
		velocityResScale * (Math.random() * (bokehMaxVelocity - bokehMinVelocity) + bokehMinVelocity),
		velocityResScale * (Math.random() * bokehYVelRange - bokehYVelRange / 2),
		0
	);

	// add it to the geometry
	bokeh.vertices.push(b);
}

// create the particle systems
var particleSystem = new THREE.Points(particles, pMaterial);
var fleckSystem = new THREE.Points(flecks, fleckMaterial);
var bokehSystem = new THREE.Points(bokeh, bokehMaterial);

particleSystem.sortParticles = true;
particleSystem.geometry.dynamic = true;

fleckSystem.sortParticles = true;
fleckSystem.geometry.dynamic = true;

bokehSystem.sortParticles = true;
bokehSystem.geometry.dynamic = true;

// add it to the scene
scene.add(particleSystem);
if (song.getGenre() != 'BTC' && song.getGenre() != 'Mirai Sekai') {
	scene.add(fleckSystem);
	scene.add(bokehSystem);
}
<commit_msg>Sightly theme colored bokeh<commit_after>var particleCount = (($(document).width() * $(document).height()) / (1920 * 1080)) * baseParticleCount;

//TODO: split main system into foreground and background particles
var particles = new THREE.Geometry();
var flecks = new THREE.Geometry();
var bokeh = new THREE.Geometry();

textureLoader = new THREE.TextureLoader();

var stdTexure = textureLoader.load(
	'./img/particle.png'
)
stdTexure.minFilter = THREE.LinearFilter;

var fleckTexture = textureLoader.load(
	'./img/fleck.png'
)
fleckTexture.minFilter = THREE.LinearFilter;

var bokehTexture = textureLoader.load(
	'./img/bokeh.png'
)
bokehTexture.minFilter = THREE.LinearFilter;

var pMaterial = new THREE.PointsMaterial({
	color: song.getGenre() === 'BTC' ? 0x000000 : 0xFFFFFF,
	opacity: particleOpacity,
	size: 5,
	map: stdTexure,
	blending: THREE.AdditiveBlending,
	transparent: true
});

var fleckMaterial = new THREE.PointsMaterial({
	color: color,
	opacity: particleOpacity,
	size: 4,
	map: fleckTexture,
	blending: THREE.AdditiveBlending,
	transparent: true
});

var bokehMaterial = new THREE.PointsMaterial({
	color: brighten(color, 2.5),
	opacity: bokehOpacity,
	size: 100,
	map: bokehTexture,
	blending: THREE.AdditiveBlending,
	transparent: true
});

var velocityResScale = Math.pow(resRatio, 5);
var fleckVelocity = maxParticleVelocity * fleckVelocityScalar;

for (var p = 0; p < particleCount; p++) {
	var z = biasedRandom(zPosRange, zPosBias) + zModifier;
	var xRange = Math.abs(camera.position.z - z) * Math.tan(toRads(VIEW_ANGLE)) * 2; // maximum range on the x-axis at this z-value
	var yRange = Math.abs(camera.position.z - z) * Math.tan(toRads(VIEW_ANGLE / ASPECT)) * 2; // maximum range on the y-axis at this z-value
	var pX = Math.random() * xRange - xRange / 2,
		pY = centerBiasedRandom(yRange, xPosBias),
		pZ = z,
		particle = new THREE.Vector3(pX, pY, pZ);

	  // create a velocity vector
	particle.velocity = new THREE.Vector3(
		velocityResScale * (Math.random() * (maxParticleVelocity - minParticleVelocity) + minParticleVelocity),
		velocityResScale * centerBiasedRandom(yVelRange, velBias),
		0
	);

	// add it to the geometry
	particles.vertices.push(particle);
}

fleckYVelScalar *= fleckVelocity;

var fleckZ = 150;

for (var p = 0; p < fleckCount; p++) {
	var z = fleckZ;
	var xRange = Math.abs(camera.position.z - z) * Math.tan(toRads(VIEW_ANGLE)) * 2; // maximum range on the x-axis at this z-value
	var yRange = Math.abs(camera.position.z - z) * Math.tan(toRads(VIEW_ANGLE / ASPECT)) * 2; // maximum range on the y-axis at this z-value
	var pX = Math.random() * xRange - xRange / 2,
		pY = Math.floor(Math.random() * yRange) - yRange / 2,
		pZ = z,
		fleck = new THREE.Vector3(pX, pY, pZ);
	fleck.fleck = true;

	  // create a velocity vector
	fleck.velocity = new THREE.Vector3(
		velocityResScale * fleckVelocity,
		velocityResScale * centerBiasedRandom(fleckYVelScalar, velBias),
		0
	);

	// add it to the geometry
	flecks.vertices.push(fleck);
}

var bokehYVelRange = ((bokehMinVelocity + bokehMaxVelocity) * 0.5) * 2;

var bokehZ = 200;

for (var p = 0; p < bokehCount; p++) {
	var z = bokehZ;
    //var z = Math.random() * zPosRange - (zPosRange / 2);
	var xRange = Math.abs(camera.position.z - z) * Math.tan(toRads(VIEW_ANGLE)) * 2; // maximum range on the x-axis at this z-value
	var yRange = Math.abs(camera.position.z - z) * Math.tan(toRads(VIEW_ANGLE / ASPECT)) * 2; // maximum range on the y-axis at this z-value
	var pX = Math.random() * xRange - xRange / 2,
		pY = Math.random() * yRange - yRange / 2,
		pZ = z,
		b = new THREE.Vector3(pX, pY, pZ);
	b.bokeh = true;

	  // create a velocity vector
	b.velocity = new THREE.Vector3(
		velocityResScale * (Math.random() * (bokehMaxVelocity - bokehMinVelocity) + bokehMinVelocity),
		velocityResScale * (Math.random() * bokehYVelRange - bokehYVelRange / 2),
		0
	);

	// add it to the geometry
	bokeh.vertices.push(b);
}

// create the particle systems
var particleSystem = new THREE.Points(particles, pMaterial);
var fleckSystem = new THREE.Points(flecks, fleckMaterial);
var bokehSystem = new THREE.Points(bokeh, bokehMaterial);

particleSystem.sortParticles = true;
particleSystem.geometry.dynamic = true;

fleckSystem.sortParticles = true;
fleckSystem.geometry.dynamic = true;

bokehSystem.sortParticles = true;
bokehSystem.geometry.dynamic = true;

// add it to the scene
scene.add(particleSystem);
if (song.getGenre() != 'BTC' && song.getGenre() != 'Mirai Sekai') {
	scene.add(fleckSystem);
	scene.add(bokehSystem);
}
<|endoftext|>