!function(f){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=f();else if("function"==typeof define&&define.amd)define([],f);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).ngraphCreateLayout=f()}}((function(){return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,(function(e){var n=t[o][1][e];return s(n||e)}),l,l.exports,e,t,n,r)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o max_{var}) max_{var} = bodyPos.{var};",{indent:6})}\n }\n\n ${pattern("boundingBox.min_{var} = min_{var};",{indent:4})}\n ${pattern("boundingBox.max_{var} = max_{var};",{indent:4})}\n }\n\n function resetBoundingBox() {\n ${pattern("boundingBox.min_{var} = boundingBox.max_{var} = 0;",{indent:4})}\n }\n`}},{"./createPatternBuilder":2}],4:[function(require,module,exports){const createPatternBuilder=require("./createPatternBuilder");function generateCreateBodyFunctionBody(dimension,debugSetters){return`\n${getVectorCode(dimension,debugSetters)}\n${getBodyCode(dimension)}\nreturn {Body: Body, Vector: Vector};\n`}function getBodyCode(dimension){let pattern=createPatternBuilder(dimension),variableList=pattern("{var}",{join:", "});return`\nfunction Body(${variableList}) {\n this.isPinned = false;\n this.pos = new Vector(${variableList});\n this.force = new Vector();\n this.velocity = new Vector();\n this.mass = 1;\n\n this.springCount = 0;\n this.springLength = 0;\n}\n\nBody.prototype.reset = function() {\n this.force.reset();\n this.springCount = 0;\n this.springLength = 0;\n}\n\nBody.prototype.setPosition = function (${variableList}) {\n ${pattern("this.pos.{var} = {var} || 0;",{indent:2})}\n};`}function getVectorCode(dimension,debugSetters){let pattern=createPatternBuilder(dimension),setters="";return debugSetters&&(setters=""+pattern("\n var v{var};\nObject.defineProperty(this, '{var}', {\n set: function(v) { \n if (!Number.isFinite(v)) throw new Error('Cannot set non-numbers to {var}');\n v{var} = v; \n },\n get: function() { return v{var}; }\n});")),`function Vector(${pattern("{var}",{join:", "})}) {\n ${setters}\n if (typeof arguments[0] === 'object') {\n // could be another vector\n let v = arguments[0];\n ${pattern('if (!Number.isFinite(v.{var})) throw new Error("Expected value is not a finite number at Vector constructor ({var})");',{indent:4})}\n ${pattern("this.{var} = v.{var};",{indent:4})}\n } else {\n ${pattern('this.{var} = typeof {var} === "number" ? {var} : 0;',{indent:4})}\n }\n }\n \n Vector.prototype.reset = function () {\n ${pattern("this.{var} = ",{join:""})}0;\n };`}module.exports=function(dimension,debugSetters){let code=generateCreateBodyFunctionBody(dimension,debugSetters),{Body:Body}=new Function(code)();return Body},module.exports.generateCreateBodyFunctionBody=generateCreateBodyFunctionBody,module.exports.getVectorCode=getVectorCode,module.exports.getBodyCode=getBodyCode},{"./createPatternBuilder":2}],5:[function(require,module,exports){const createPatternBuilder=require("./createPatternBuilder");function generateCreateDragForceFunctionBody(dimension){return`\n if (!Number.isFinite(options.dragCoefficient)) throw new Error('dragCoefficient is not a finite number');\n\n return {\n update: function(body) {\n ${createPatternBuilder(dimension)("body.force.{var} -= options.dragCoefficient * body.velocity.{var};",{indent:6})}\n }\n };\n`}module.exports=function(dimension){let code=generateCreateDragForceFunctionBody(dimension);return new Function("options",code)},module.exports.generateCreateDragForceFunctionBody=generateCreateDragForceFunctionBody},{"./createPatternBuilder":2}],6:[function(require,module,exports){const createPatternBuilder=require("./createPatternBuilder");function generateCreateSpringForceFunctionBody(dimension){let pattern=createPatternBuilder(dimension);return`\n if (!Number.isFinite(options.springCoefficient)) throw new Error('Spring coefficient is not a number');\n if (!Number.isFinite(options.springLength)) throw new Error('Spring length is not a number');\n\n return {\n /**\n * Updates forces acting on a spring\n */\n update: function (spring) {\n var body1 = spring.from;\n var body2 = spring.to;\n var length = spring.length < 0 ? options.springLength : spring.length;\n ${pattern("var d{var} = body2.pos.{var} - body1.pos.{var};",{indent:6})}\n var r = Math.sqrt(${pattern("d{var} * d{var}",{join:" + "})});\n\n if (r === 0) {\n ${pattern("d{var} = (random.nextDouble() - 0.5) / 50;",{indent:8})}\n r = Math.sqrt(${pattern("d{var} * d{var}",{join:" + "})});\n }\n\n var d = r - length;\n var coefficient = ((spring.coefficient > 0) ? spring.coefficient : options.springCoefficient) * d / r;\n\n ${pattern("body1.force.{var} += coefficient * d{var}",{indent:6})};\n body1.springCount += 1;\n body1.springLength += r;\n\n ${pattern("body2.force.{var} -= coefficient * d{var}",{indent:6})};\n body2.springCount += 1;\n body2.springLength += r;\n }\n };\n`}module.exports=function(dimension){let code=generateCreateSpringForceFunctionBody(dimension);return new Function("options","random",code)},module.exports.generateCreateSpringForceFunctionBody=generateCreateSpringForceFunctionBody},{"./createPatternBuilder":2}],7:[function(require,module,exports){const createPatternBuilder=require("./createPatternBuilder");function generateIntegratorFunctionBody(dimension){let pattern=createPatternBuilder(dimension);return`\n var length = bodies.length;\n if (length === 0) return 0;\n\n ${pattern("var d{var} = 0, t{var} = 0;",{indent:2})}\n\n for (var i = 0; i < length; ++i) {\n var body = bodies[i];\n if (body.isPinned) continue;\n\n if (adaptiveTimeStepWeight && body.springCount) {\n timeStep = (adaptiveTimeStepWeight * body.springLength/body.springCount);\n }\n\n var coeff = timeStep / body.mass;\n\n ${pattern("body.velocity.{var} += coeff * body.force.{var};",{indent:4})}\n ${pattern("var v{var} = body.velocity.{var};",{indent:4})}\n var v = Math.sqrt(${pattern("v{var} * v{var}",{join:" + "})});\n\n if (v > 1) {\n // We normalize it so that we move within timeStep range. \n // for the case when v <= 1 - we let velocity to fade out.\n ${pattern("body.velocity.{var} = v{var} / v;",{indent:6})}\n }\n\n ${pattern("d{var} = timeStep * body.velocity.{var};",{indent:4})}\n\n ${pattern("body.pos.{var} += d{var};",{indent:4})}\n\n ${pattern("t{var} += Math.abs(d{var});",{indent:4})}\n }\n\n return (${pattern("t{var} * t{var}",{join:" + "})})/length;\n`}module.exports=function(dimension){let code=generateIntegratorFunctionBody(dimension);return new Function("bodies","timeStep","adaptiveTimeStepWeight",code)},module.exports.generateIntegratorFunctionBody=generateIntegratorFunctionBody},{"./createPatternBuilder":2}],8:[function(require,module,exports){const createPatternBuilder=require("./createPatternBuilder"),getVariableName=require("./getVariableName");function generateQuadTreeFunctionBody(dimension){let pattern=createPatternBuilder(dimension),quadCount=Math.pow(2,dimension);return`\n${getInsertStackCode()}\n${getQuadNodeCode(dimension)}\n${isSamePosition(dimension)}\n${getChildBodyCode(dimension)}\n${setChildBodyCode(dimension)}\n\nfunction createQuadTree(options, random) {\n options = options || {};\n options.gravity = typeof options.gravity === 'number' ? options.gravity : -1;\n options.theta = typeof options.theta === 'number' ? options.theta : 0.8;\n\n var gravity = options.gravity;\n var updateQueue = [];\n var insertStack = new InsertStack();\n var theta = options.theta;\n\n var nodesCache = [];\n var currentInCache = 0;\n var root = newNode();\n\n return {\n insertBodies: insertBodies,\n\n /**\n * Gets root node if it is present\n */\n getRoot: function() {\n return root;\n },\n\n updateBodyForce: update,\n\n options: function(newOptions) {\n if (newOptions) {\n if (typeof newOptions.gravity === 'number') {\n gravity = newOptions.gravity;\n }\n if (typeof newOptions.theta === 'number') {\n theta = newOptions.theta;\n }\n\n return this;\n }\n\n return {\n gravity: gravity,\n theta: theta\n };\n }\n };\n\n function newNode() {\n // To avoid pressure on GC we reuse nodes.\n var node = nodesCache[currentInCache];\n if (node) {\n${function(indent){let quads=[];for(let i=0;i {var}max) {var}max = pos.{var};",{indent:6})}\n }\n\n // Makes the bounds square.\n var maxSideLength = -Infinity;\n ${pattern("if ({var}max - {var}min > maxSideLength) maxSideLength = {var}max - {var}min ;",{indent:4})}\n\n currentInCache = 0;\n root = newNode();\n ${pattern("root.min_{var} = {var}min;",{indent:4})}\n ${pattern("root.max_{var} = {var}min + maxSideLength;",{indent:4})}\n\n i = bodies.length - 1;\n if (i >= 0) {\n root.body = bodies[i];\n }\n while (i--) {\n insert(bodies[i], root);\n }\n }\n\n function insert(newBody) {\n insertStack.reset();\n insertStack.push(root, newBody);\n\n while (!insertStack.isEmpty()) {\n var stackItem = insertStack.pop();\n var node = stackItem.node;\n var body = stackItem.body;\n\n if (!node.body) {\n // This is internal node. Update the total mass of the node and center-of-mass.\n ${pattern("var {var} = body.pos.{var};",{indent:8})}\n node.mass += body.mass;\n ${pattern("node.mass_{var} += body.mass * {var};",{indent:8})}\n\n // Recursively insert the body in the appropriate quadrant.\n // But first find the appropriate quadrant.\n var quadIdx = 0; // Assume we are in the 0's quad.\n ${pattern("var min_{var} = node.min_{var};",{indent:8})}\n ${pattern("var max_{var} = (min_{var} + node.max_{var}) / 2;",{indent:8})}\n\n${function(indentCount){let insertionCode=[],indent=Array(indentCount+1).join(" ");for(let i=0;i max_${getVariableName(i)}) {`),insertionCode.push(indent+` quadIdx = quadIdx + ${Math.pow(2,i)};`),insertionCode.push(indent+` min_${getVariableName(i)} = max_${getVariableName(i)};`),insertionCode.push(indent+` max_${getVariableName(i)} = node.max_${getVariableName(i)};`),insertionCode.push(indent+"}");return insertionCode.join("\n")}(8)}\n\n var child = getChild(node, quadIdx);\n\n if (!child) {\n // The node is internal but this quadrant is not taken. Add\n // subnode to it.\n child = newNode();\n ${pattern("child.min_{var} = min_{var};",{indent:10})}\n ${pattern("child.max_{var} = max_{var};",{indent:10})}\n child.body = body;\n\n setChild(node, quadIdx, child);\n } else {\n // continue searching in this quadrant.\n insertStack.push(child, body);\n }\n } else {\n // We are trying to add to the leaf node.\n // We have to convert current leaf into internal node\n // and continue adding two nodes.\n var oldBody = node.body;\n node.body = null; // internal nodes do not cary bodies\n\n if (isSamePosition(oldBody.pos, body.pos)) {\n // Prevent infinite subdivision by bumping one node\n // anywhere in this quadrant\n var retriesCount = 3;\n do {\n var offset = random.nextDouble();\n ${pattern("var d{var} = (node.max_{var} - node.min_{var}) * offset;",{indent:12})}\n\n ${pattern("oldBody.pos.{var} = node.min_{var} + d{var};",{indent:12})}\n retriesCount -= 1;\n // Make sure we don't bump it out of the box. If we do, next iteration should fix it\n } while (retriesCount > 0 && isSamePosition(oldBody.pos, body.pos));\n\n if (retriesCount === 0 && isSamePosition(oldBody.pos, body.pos)) {\n // This is very bad, we ran out of precision.\n // if we do not return from the method we'll get into\n // infinite loop here. So we sacrifice correctness of layout, and keep the app running\n // Next layout iteration should get larger bounding box in the first step and fix this\n return;\n }\n }\n // Next iteration should subdivide node further.\n insertStack.push(node, oldBody);\n insertStack.push(node, body);\n }\n }\n }\n}\nreturn createQuadTree;\n\n`}function isSamePosition(dimension){let pattern=createPatternBuilder(dimension);return`\n function isSamePosition(point1, point2) {\n ${pattern("var d{var} = Math.abs(point1.{var} - point2.{var});",{indent:2})}\n \n return ${pattern("d{var} < 1e-8",{join:" && "})};\n } \n`}function setChildBodyCode(dimension){var quadCount=Math.pow(2,dimension);return`\nfunction setChild(node, idx, child) {\n ${function(){let childBody=[];for(let i=0;i 0) {\n return this.stack[--this.popIdx];\n }\n },\n reset: function () {\n this.popIdx = 0;\n }\n};\n\nfunction InsertStackElement(node, body) {\n this.node = node; // QuadTree node\n this.body = body; // physical body which needs to be inserted to node\n}\n"}module.exports=function(dimension){let code=generateQuadTreeFunctionBody(dimension);return new Function(code)()},module.exports.generateQuadTreeFunctionBody=generateQuadTreeFunctionBody,module.exports.getInsertStackCode=getInsertStackCode,module.exports.getQuadNodeCode=getQuadNodeCode,module.exports.isSamePosition=isSamePosition,module.exports.getChildBodyCode=getChildBodyCode,module.exports.setChildBodyCode=setChildBodyCode},{"./createPatternBuilder":2,"./getVariableName":9}],9:[function(require,module,exports){module.exports=function(index){return 0===index?"x":1===index?"y":2===index?"z":"c"+(index+1)}},{}],10:[function(require,module,exports){module.exports=function(settings){var Spring=require("./spring"),merge=require("ngraph.merge"),eventify=require("ngraph.events");if(settings){if(void 0!==settings.springCoeff)throw new Error("springCoeff was renamed to springCoefficient");if(void 0!==settings.dragCoeff)throw new Error("dragCoeff was renamed to dragCoefficient")}settings=merge(settings,{springLength:10,springCoefficient:.8,gravity:-12,theta:.8,dragCoefficient:.9,timeStep:.5,adaptiveTimeStepWeight:0,dimensions:2,debug:!1});var factory=dimensionalCache[settings.dimensions];if(!factory){var dimensions=settings.dimensions;factory={Body:generateCreateBodyFunction(dimensions,settings.debug),createQuadTree:generateQuadTreeFunction(dimensions),createBounds:generateBoundsFunction(dimensions),createDragForce:generateCreateDragForceFunction(dimensions),createSpringForce:generateCreateSpringForceFunction(dimensions),integrate:generateIntegratorFunction(dimensions)},dimensionalCache[dimensions]=factory}var Body=factory.Body,createQuadTree=factory.createQuadTree,createBounds=factory.createBounds,createDragForce=factory.createDragForce,createSpringForce=factory.createSpringForce,integrate=factory.integrate,random=require("ngraph.random").random(42),bodies=[],springs=[],quadTree=createQuadTree(settings,random),bounds=createBounds(bodies,settings,random),springForce=createSpringForce(settings,random),dragForce=createDragForce(settings),forces=[],forceMap=new Map,iterationNumber=0;addForce("nbody",(function(){if(0===bodies.length)return;quadTree.insertBodies(bodies);var i=bodies.length;for(;i--;){var body=bodies[i];body.isPinned||(body.reset(),quadTree.updateBodyForce(body),dragForce.update(body))}})),addForce("spring",(function(){var i=springs.length;for(;i--;)springForce.update(springs[i])}));var publicApi={bodies:bodies,quadTree:quadTree,springs:springs,settings:settings,addForce:addForce,removeForce:function(forceName){var forceIndex=forces.indexOf(forceMap.get(forceName));if(forceIndex<0)return;forces.splice(forceIndex,1),forceMap.delete(forceName)},getForces:function(){return forceMap},step:function(){for(var i=0;inew Body(pos))(pos);return bodies.push(body),body},removeBody:function(body){if(body){var idx=bodies.indexOf(body);if(!(idx<0))return bodies.splice(idx,1),0===bodies.length&&bounds.reset(),!0}},addSpring:function(body1,body2,springLength,springCoefficient){if(!body1||!body2)throw new Error("Cannot add null spring to force simulator");"number"!=typeof springLength&&(springLength=-1);var spring=new Spring(body1,body2,springLength,springCoefficient>=0?springCoefficient:-1);return springs.push(spring),spring},getTotalMovement:function(){return 0},removeSpring:function(spring){if(spring){var idx=springs.indexOf(spring);return idx>-1?(springs.splice(idx,1),!0):void 0}},getBestNewBodyPosition:function(neighbors){return bounds.getBestNewPosition(neighbors)},getBBox:getBoundingBox,getBoundingBox:getBoundingBox,invalidateBBox:function(){console.warn("invalidateBBox() is deprecated, bounds always recomputed on `getBBox()` call")},gravity:function(value){return void 0!==value?(settings.gravity=value,quadTree.options({gravity:value}),this):settings.gravity},theta:function(value){return void 0!==value?(settings.theta=value,quadTree.options({theta:value}),this):settings.theta},random:random};return function(settings,target){for(var key in settings)augment(settings,target,key)}(settings,publicApi),eventify(publicApi),publicApi;function getBoundingBox(){return bounds.update(),bounds.box}function addForce(forceName,forceFunction){if(forceMap.has(forceName))throw new Error("Force "+forceName+" is already added");forceMap.set(forceName,forceFunction),forces.push(forceFunction)}};var generateCreateBodyFunction=require("./codeGenerators/generateCreateBody"),generateQuadTreeFunction=require("./codeGenerators/generateQuadTree"),generateBoundsFunction=require("./codeGenerators/generateBounds"),generateCreateDragForceFunction=require("./codeGenerators/generateCreateDragForce"),generateCreateSpringForceFunction=require("./codeGenerators/generateCreateSpringForce"),generateIntegratorFunction=require("./codeGenerators/generateIntegrator"),dimensionalCache={};function augment(source,target,key){if(source.hasOwnProperty(key)&&"function"!=typeof target[key]){var sourceIsNumber=Number.isFinite(source[key]);target[key]=sourceIsNumber?function(value){if(void 0!==value){if(!Number.isFinite(value))throw new Error("Value of "+key+" should be a valid number.");return source[key]=value,target}return source[key]}:function(value){return void 0!==value?(source[key]=value,target):source[key]}}}},{"./codeGenerators/generateBounds":3,"./codeGenerators/generateCreateBody":4,"./codeGenerators/generateCreateDragForce":5,"./codeGenerators/generateCreateSpringForce":6,"./codeGenerators/generateIntegrator":7,"./codeGenerators/generateQuadTree":8,"./spring":11,"ngraph.events":12,"ngraph.merge":13,"ngraph.random":14}],11:[function(require,module,exports){module.exports=function(fromBody,toBody,length,springCoefficient){this.from=fromBody,this.to=toBody,this.length=length,this.coefficient=springCoefficient}},{}],12:[function(require,module,exports){module.exports=function(subject){!function(subject){if(!subject)throw new Error("Eventify cannot use falsy object as events subject");for(var reservedWords=["on","fire","off"],i=0;i1&&(fireArguments=Array.prototype.splice.call(arguments,1));for(var i=0;i>>19))+374761393+(seed<<5)&4294967295)+3550635116^seed<<9))+4251993797+(seed<<3)&4294967295)^seed>>>16),this.seed=seed,(268435455&seed)/268435456}module.exports=random,module.exports.random=random,module.exports.randomIterator=function(array,customRandom){var localRandom=customRandom||random();if("function"!=typeof localRandom.next)throw new Error("customRandom does not match expected API: next() function is missing");return{forEach:function(callback){var i,j,t;for(i=array.length-1;i>0;--i)j=localRandom.next(i+1),t=array[j],array[j]=array[i],array[i]=t,callback(t);array.length&&callback(array[0])},shuffle:function(){var i,j,t;for(i=array.length-1;i>0;--i)j=localRandom.next(i+1),t=array[j],array[j]=array[i],array[i]=t;return array}}},Generator.prototype.next=function(maxValue){return Math.floor(this.nextDouble()*maxValue)},Generator.prototype.nextDouble=nextDouble,Generator.prototype.uniform=nextDouble,Generator.prototype.gaussian=function(){var r,x,y;do{x=2*this.nextDouble()-1,y=2*this.nextDouble()-1,r=x*x+y*y}while(r>=1||0===r);return x*Math.sqrt(-2*Math.log(r)/r)}},{}]},{},[1])(1)}));