From 83cac7e633de6842b807231f5103cb1e732ef178 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Fri, 4 May 2018 10:15:32 +0200 Subject: [PATCH] Complete Reorganization of Floating Space --- .vs/AAWeb/v15/.suo | Bin 67072 -> 75264 bytes Canvas.js | 50 +- FloatingSpace/BubbleSets.js | 66 +++ FloatingSpace/FloatingLayer.js | 422 ++++++++++++++++ .../FloatingObject.js | 179 ++----- FloatingSpace/ProfileBall.js | 151 ++++++ FloatingSpace/ProfileBalls.js | 78 +++ Project.njsproj | 15 +- Spaces/FloatingSpace.js | 478 +----------------- TimelineChart.js | 13 +- index.html | 7 +- server.js | 8 +- 12 files changed, 849 insertions(+), 618 deletions(-) create mode 100644 FloatingSpace/BubbleSets.js create mode 100644 FloatingSpace/FloatingLayer.js rename FloatingObject.js => FloatingSpace/FloatingObject.js (50%) create mode 100644 FloatingSpace/ProfileBall.js create mode 100644 FloatingSpace/ProfileBalls.js diff --git a/.vs/AAWeb/v15/.suo b/.vs/AAWeb/v15/.suo index 633fd274b31f5cb4a5f36d5b063944e271e6ba26..c983a57061f0373d9ff1c3ccfe1cd6e036aba888 100644 GIT binary patch delta 4167 zcmdT`d2o|O6#w?im*h)HAy*HC9>G$g1==bUL|WRCsRfHIbU2g9HV(aoL!S^EqL>`9T`o@-)>|6evf= z@`kBn;77Ry3iw2M<;FL<&|1aHa7!nP3X~g$0PQrBVhIw=WaSVt65_;R+BjrnBL*R& z5%&hUrMLJF+nt=`;iw zRAVLE8FMBw*tY~8SH-C224_#e3RMcJXqc*(S0ZZ>w5jw0+lPLx+QADu*)FTpN#ZUf zj}`!fMdWZ6-Q82!_?6ue6q+=NEcLv?iocQb1BObX|DvRnpq={$0-k& zq86qx|J{XPLd-)f4$M-9M5LK7S?b-5XhzWb=q~biv?@vK;CzwhXYVK8WVO5&_gddD zb=bf!`y74)f`>d$d~NnPV2MxTHidW2kFR9f7u!daBR* zfp|=bH1V!8#G5O6lFZOikw#tFb;Mf`;T_L=XDOJQW})VvbyGz#b5fQpH`)8^* z%QJ=&Xv@e4aYd}0&6YBmI15+AE#@k?1zaiT;Oty3XT`6B8_AV%PUu)MLm?Fn2X9xW z5Dsc11W0Z3w=Q*)koB-<+0=eXn9J!PWxQA@}3H+-!s9bx+bz+ z;&e8Oy5dUfJiDc6am9jChdtNoa5&+MeJSL%kbqngfRFZ#Bi;~C+e=B(c{Q}I53J`o zDy**3@`VM~XY7k5iF!%mm7@_*(PknoA$d(eKDWwdbJ&aRuD}(xNy}F@$3W?3=8t)> zZ*V+~U%n_9SA&InFc`HmjMzNRh0y|SSE}b_<(4nyWGIw8_aKyfkPZhtCD7cS2;aPK zK-wF>iI~e-T)9dq=4IT!mK~u)DB=TA2W!jYp+E?cocWe6(`kBmab%fu0;F#?0){T8 z4=;zW2cs0G52PjQEh3OZEbFq3Qf|d^gy*oBzK8}K8Ehd`Tepo46Vs%3Lt`s=%;&yoDNQ6@7tHpn_Oz=0&hr%OjIQ`OY zIJZv4sc@oi8^)(;vY}q%O-w z5ADn$klh$Fdd+pYA-hj*|B2!GpFB$3W$wdQwEmx7TDLpWP9)Jez*nw2tp9 zq3P+DjJ)TdI*`6p+dP)sI$?JIhn_yHgm2H~!Hm=WV+uJNwikhx#2IKIF-%iv+j+kX zbXT%y*0FX%JzrMKK=|4mm&;Y5f=%i>i&4#mor%Wsq23(gSI{<~OXDVzU4M delta 2362 zcmcJQdrVVT7{L48-nRGFDlKI^l(&FH7~Ud?7?f8>d~`v(`It^A4(DS`Bo>!|j5>`o zS+ht#6)<7q{bO0wh;m|B+%gf=>B59L-P~e~k|onDTZmRSmrVAZrd@F8G$uREFX#Kt zIrp6Jbxu9~qQ@&9a|r0rC+d2l9=3*It>DByy$uHNp0HimFJQfPo(v<@rf4)8v^dlC zt4Me=7XQ?yS!R$}O6Ul_#)>v^K~gSh$wWGlLu3#(qKpV5mSek^kop(@fSQR$5{M)s zpO{5t6KO;W-V_sH7lO`enM-;e!M~YD{Q^wYO;3Nw)lqE)&5RGO;=@%Wy9o5?6!~ou zHWFK#7v(l8~SqZoAn=p6j>&%WH1gKVH|8!o4;m!&HourdYCQpoo}6L=thh zSW18iSSL-%tsy;%$RuKj2x2;sN)!{^vKN9qm$~nD{6?ANe5Pcswmz#VsVUtMVs;7}#ZpDMjK!Ksjde^5xT5 z_4o+*k9n*P`(6g1oy-K!KODw7a}ylGd**UHQ=vcy)>*z4A2Zzq9jwm!f#8dFDWQXT zw76e!L_EPWpGfcs@S2%S@U?7r^dLOXSDQeM7rJ8SO5!-$iW`jXlmYA$Y|NeNHR<@~ z6~`BKLh~j^S56zrRfO%c=*Np%UT!|02&i$=b%Sjp5o zNyrPw`pDq*2oIg+k6b8KlEN!J5U+_?7uBTWWgxHzOAUHofnAbFGXxhfcYzmtRk5Q@ zQ`FT0nbB3<2Uwaj+c%@MWw#C_wqV@}?c=|Xbn8oK!+=TiB_8HSEF!N*Mq5qlMwI4vwQ3>}QwSkXDGSppyZ^wC&`_F^V{B9GV zZEp^C^d@3LTLdmIOk+x`7O?%Z8gL;jEW=xOC$h>94`{Krbt<1nrF9m%F4%CzK@}c3 zRg^XM(7}axVvtdzmRepYDqou66rqaEB_~EbZdU&~hgR;#vIG+UHMIfrS@PsPQ+PB6_xp0@HzmKjz@EPfb|Ve>g^= z_iF5queR04JZq}q+4GD=y`C|d#JI2X@yP8uOXaBeY$myc9r>Xco}O6?&n(zyDfDZY z{!*FEhP9`n5?>AZPyKp=KUw^5K}+z)@^)STEN*k+s`jx3Q40TOrjxi4c-)i0vOabS zhGhf%zH0D&Z$9?yNoTjb(SX04V^j~Xf$oX<0|$d^BY@3&rlHbl!j*??bT!%@srzPh z?bYGMD`p(mmdrcLa4%cuMTM{AU2O?-x8%JaM=`2e02QeL^0)H%eeO z;LynM(|zZT{nlsb&X&MoU_&F91#sfQyQSSOD_qr{xCB2zU|>@B%osQ??n{QxTT&*& mP>YZZC%JT!f$tQUuWdLi&z|$gNqh12@5+Avc?XskDt`mNM*|4} diff --git a/Canvas.js b/Canvas.js index a5625b2f8..50b50300c 100644 --- a/Canvas.js +++ b/Canvas.js @@ -45,7 +45,7 @@ function newCanvas() { /* Mouse event related variables. */ let containerDragStarted = false; - let ballDragStarted = false; + let floatingObjectDragStarted = false; let floatingObjectBeingDragged; let containerBeingDragged; let viewPortBeingDragged = false; @@ -114,7 +114,7 @@ function newCanvas() { /* Here we add all the functions that will be called during the animation cycle. */ animation.addCallBackFunction("Chart Space", thisObject.chartSpace.draw, onFunctionAdded); - animation.addCallBackFunction("Floating Space", thisObject.floatingSpace.physicsLoop, onFunctionAdded); + animation.addCallBackFunction("Floating Space", thisObject.floatingSpace.floatingLayer.physicsLoop, onFunctionAdded); animation.addCallBackFunction("Panels Space", thisObject.panelsSpace.draw, onFunctionAdded); animation.addCallBackFunction("Splash Screen", splashScreen.draw, onFunctionAdded); animation.addCallBackFunction("ViewPort Animate", viewPort.animate, onFunctionAdded); @@ -239,12 +239,12 @@ function newCanvas() { return; } - /* We check first if the mouse is over a ball/ */ + /* We check first if the mouse is over a floatingObject/ */ - floatingObjectBeingDragged = thisObject.floatingSpace.isInside(event.pageX, event.pageY); + floatingObjectBeingDragged = thisObject.floatingSpace.floatingLayer.isInside(event.pageX, event.pageY); if (floatingObjectBeingDragged >= 0) { - ballDragStarted = true; + floatingObjectDragStarted = true; return; } @@ -283,11 +283,11 @@ function newCanvas() { return; } - /* We check first if the mouse is over a ball/ */ + /* We check first if the mouse is over a floatingObject/ */ - let ballBeingClicked = thisObject.floatingSpace.isInside(event.pageX, event.pageY); + let floatingObjectBeingClicked = thisObject.floatingSpace.floatingLayer.isInside(event.pageX, event.pageY); - if (ballBeingClicked >= 0) { + if (floatingObjectBeingClicked >= 0) { /* Right now we do nothing with this. */ return; @@ -309,7 +309,7 @@ function newCanvas() { if (INFO_LOG === true) { logger.write("[INFO] onMouseUp -> Entering function."); } - if (containerDragStarted || viewPortBeingDragged || ballDragStarted) { + if (containerDragStarted || viewPortBeingDragged || floatingObjectDragStarted) { thisObject.eventHandler.raiseEvent("Drag Finished", undefined); @@ -318,7 +318,7 @@ function newCanvas() { /* Turn off all the possible things that can be dragged. */ containerDragStarted = false; - ballDragStarted = false; + floatingObjectDragStarted = false; viewPortBeingDragged = false; containerBeingDragged = undefined; @@ -334,16 +334,16 @@ function newCanvas() { viewPort.mousePosition.x = event.pageX; viewPort.mousePosition.y = event.pageY; - if (containerDragStarted === true || ballDragStarted === true || viewPortBeingDragged === true) { + if (containerDragStarted === true || floatingObjectDragStarted === true || viewPortBeingDragged === true) { - if (ballDragStarted === true) { + if (floatingObjectDragStarted === true) { - if (thisObject.floatingSpace.isInsideFloatingObject(floatingObjectBeingDragged, event.pageX, event.pageY) === false) { + if (thisObject.floatingSpace.floatingLayer.isInsideFloatingObject(floatingObjectBeingDragged, event.pageX, event.pageY) === false) { - /* This means that the user stop moving the mouse and the ball ball out of the pointer. + /* This means that the user stop moving the mouse and the floatingObject floatingObject out of the pointer. In this case we cancell the drag operation . */ - ballDragStarted = false; + floatingObjectDragStarted = false; browserCanvas.style.cursor = "auto"; return; } @@ -374,24 +374,24 @@ function newCanvas() { if (INFO_LOG === true) { logger.write("[INFO] checkDrag -> Entering function."); } - if (containerDragStarted === true || ballDragStarted === true || viewPortBeingDragged === true) { + if (containerDragStarted === true || floatingObjectDragStarted === true || viewPortBeingDragged === true) { browserCanvas.style.cursor = "grabbing"; thisObject.eventHandler.raiseEvent("Dragging", undefined); - let targetFloatingObject = thisObject.floatingSpace.isInside(event.pageX, event.pageY); + let targetFloatingObject = thisObject.floatingSpace.floatingLayer.isInside(event.pageX, event.pageY); - if (ballDragStarted) { + if (floatingObjectDragStarted) { - let ball = thisObject.floatingSpace.floatingObjects[floatingObjectBeingDragged]; + let floatingObject = thisObject.floatingSpace.floatingLayer.floatingObjects[floatingObjectBeingDragged]; - ball.currentPosition.x = dragVector.upX; - ball.currentPosition.y = dragVector.upY; + floatingObject.currentPosition.x = dragVector.upX; + floatingObject.currentPosition.y = dragVector.upY; - /* Now we estimate if the drag was towards the Target Point of the ball or not. */ + /* Now we estimate if the drag was towards the Target Point of the floatingObject or not. */ - let distDown = distance(dragVector.downX, dragVector.downY, ball.targetPosition.x, ball.targetPosition.y); - let distUp = distance(dragVector.upX, dragVector.upY, ball.targetPosition.x, ball.targetPosition.y); + let distDown = distance(dragVector.downX, dragVector.downY, floatingObject.targetPosition.x, floatingObject.targetPosition.y); + let distUp = distance(dragVector.upX, dragVector.upY, floatingObject.targetPosition.x, floatingObject.targetPosition.y); let mZoomValue; @@ -402,7 +402,7 @@ function newCanvas() { mZoomValue = -1; } - //ball.container.zoom.mZoom(mZoomValue); // Zoom is applied to ball mass of all balls in the same container. + //floatingObject.container.zoom.mZoom(mZoomValue); // Zoom is applied to floatingObject mass of all floatingObjects in the same container. } if (containerDragStarted || viewPortBeingDragged) { diff --git a/FloatingSpace/BubbleSets.js b/FloatingSpace/BubbleSets.js new file mode 100644 index 000000000..a43fcb350 --- /dev/null +++ b/FloatingSpace/BubbleSets.js @@ -0,0 +1,66 @@ + +function newBubbleSets() { + + const MODULE_NAME = "Bubble Sets"; + const INFO_LOG = false; + const ERROR_LOG = true; + const logger = newDebugLog(); + logger.fileName = MODULE_NAME; + + let thisObject = { + createBubbleSet: createBubbleSet, + destroyBubbleSet: destroyBubbleSet, + initialize: initialize + }; + + let bubbleSets = []; + + let floatingLayer; + + return thisObject; + + function initialize(pFloatingLayer, callBackFunction) { + + try { + + if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); } + + floatingLayer = pFloatingLayer; + + callBackFunction(GLOBAL.CUSTOM_OK_RESPONSE); + + } catch (err) { + + if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err); } + callBackFunction(GLOBAL.CUSTOM_FAIL_RESPONSE); + } + } + + function createBubbleSet(pPlotterBubbles) { + + let bubbleSet = { + floatingBubbles: [], + plotterBubbles: pPlotterBubbles, + handle: Math.floor((Math.random() * 10000000) + 1) + }; + + bubbleSets.push(bubbleSet); + + return bubbleSet.handle; + } + + function destroyBubbleSet(pHandle) { + + for (let i = 0; i < bubbleSets.length; i++) { + + let bubbleSet = bubbleSets[i]; + + if (bubbleSet.handle === pHandle) { + bubbleSets.splice(i, 1); // Delete item from array. + return; + } + } + } +} + + diff --git a/FloatingSpace/FloatingLayer.js b/FloatingSpace/FloatingLayer.js new file mode 100644 index 000000000..cbe088afa --- /dev/null +++ b/FloatingSpace/FloatingLayer.js @@ -0,0 +1,422 @@ + +function newFloatingLayer() { + + let thisObject = { + floatingObjects: undefined, // This is the array of floatingObjects being displayed + addFloatingObject: addFloatingObject, + removeFloatingObject: removeFloatingObject, + physicsLoop: physicsLoop, + isInside: isInside, + isInsideFloatingObject: isInsideFloatingObject, + initialize: initialize + }; + + innactiveFloatingObjects = []; + + return thisObject; + + function initialize(callBackFunction) { + + thisObject.floatingObjects = []; // We initialize this in order to start the calculations in a clean way. + + callBackFunction(); + } + + function addFloatingObject(pFloatingObject) { + + innactiveFloatingObjects.push(pFloatingObject); + + pFloatingObject.handle = Math.floor((Math.random() * 10000000) + 1); + + } + + function removeFloatingObject(pFloatingObjectHandle) { + + for (let i = 0; i < innactiveFloatingObjects.length; i++) { + + let floatingObject = innactiveFloatingObjects[i]; + + if (floatingObject.handle === pFloatingObjectHandle) { + innactiveFloatingObjects.splice(i, 1); // Delete item from array. + return; + } + } + + for (let i = 0; i < thisObject.floatingObjects.length; i++) { + + let floatingObject = thisObject.floatingObjects[i]; + + if (floatingObject.handle === pFloatingObjectHandle) { + thisObject.floatingObjects.splice(i, 1); // Delete item from array. + return; + } + } + } + + /******************************************/ + /* */ + /* Physics Engine Follows */ + /* */ + /******************************************/ + + function physicsLoop() { + + /* This function makes all the calculations to apply phisycs on all floatingObjects in this space. */ + + for (let i = 0; i < thisObject.floatingObjects.length; i++) { + + let floatingObject = thisObject.floatingObjects[i]; + + /* Change position based on speed */ + + floatingObject.currentPosition.x = floatingObject.currentPosition.x + floatingObject.currentSpeed.x; + floatingObject.currentPosition.y = floatingObject.currentPosition.y + floatingObject.currentSpeed.y; + + /* Apply some friction to desacelerate */ + + floatingObject.currentSpeed.x = floatingObject.currentSpeed.x * floatingObject.friction; // Desaceleration factor. + floatingObject.currentSpeed.y = floatingObject.currentSpeed.y * floatingObject.friction; // Desaceleration factor. + + // Gives a minimun speed towards their taget. + + if (floatingObject.currentPosition.x < floatingObject.input.position.x) { + floatingObject.currentSpeed.x = floatingObject.currentSpeed.x + .005; + } else { + floatingObject.currentSpeed.x = floatingObject.currentSpeed.x - .005; + } + + if (floatingObject.currentPosition.y < floatingObject.input.position.y) { + floatingObject.currentSpeed.y = floatingObject.currentSpeed.y + .005; + } else { + floatingObject.currentSpeed.y = floatingObject.currentSpeed.y - .005; + } + + // Lets put a maximun speed also. + + const MAX_SPEED = 50; + + if (floatingObject.currentSpeed.x > MAX_SPEED) { + floatingObject.currentSpeed.x = MAX_SPEED; + } + + if (floatingObject.currentSpeed.y > MAX_SPEED) { + floatingObject.currentSpeed.y = MAX_SPEED; + } + + if (floatingObject.currentSpeed.x < -MAX_SPEED) { + floatingObject.currentSpeed.x = -MAX_SPEED; + } + + if (floatingObject.currentSpeed.y < -MAX_SPEED) { + floatingObject.currentSpeed.y = -MAX_SPEED; + } + + // The radius also have a target. + + if (floatingObject.currentRadius < floatingObject.targetRadius) { + floatingObject.currentRadius = floatingObject.currentRadius + .5; + } else { + floatingObject.currentRadius = floatingObject.currentRadius - .5; + } + + // The imageSize also have a target. + + if (floatingObject.currentImageSize < floatingObject.targetImageSize) { + floatingObject.currentImageSize = floatingObject.currentImageSize + 1; + } else { + floatingObject.currentImageSize = floatingObject.currentImageSize - 1; + } + + /* Collision Control */ + + for (let k = i + 1; k < thisObject.floatingObjects.length; k++) { + + if (colliding(thisObject.floatingObjects[i], thisObject.floatingObjects[k])) { + + resolveCollision(thisObject.floatingObjects[k], thisObject.floatingObjects[i]); + + } + } + + /* Calculate repulsion force produced by all other floatingObjects */ + + repulsionForce(i); + + gravityForce(floatingObject); + + } + + /* We draw all the thisObject.floatingObjects. */ + + for (let i = 0; i < thisObject.floatingObjects.length; i++) { + let floatingObject = thisObject.floatingObjects[i]; + floatingObject.drawBackground(); + } + + for (let i = 0; i < thisObject.floatingObjects.length; i++) { + let floatingObject = thisObject.floatingObjects[thisObject.floatingObjects.length - i - 1]; + floatingObject.drawForeground(); + } + + /* Finally we check if any of the created FloatingObjects where enabled to run under the Physics Engine. */ + + for (let i = 0; i < innactiveFloatingObjects.length; i++) { + + let floatingObject = innactiveFloatingObjects[i]; + + if (floatingObject.input.visible === true) { + + /* The first time that the floatingObject becomes visible, we need to do this. */ + + floatingObject.radomizeCurrentPosition(floatingObject.input.position); + floatingObject.radomizeCurrentSpeed(); + + thisObject.floatingObjects.push(floatingObject); + innactiveFloatingObjects.splice(i, 1); // Delete item from array. + return; // Only one at the time. + + } + } + } + + function gravityForce(floatingObject) { + + /* We simulate a kind of gravity towards the target point of each floatingObject. This force will make the floatingObject to keep pushing to reach that point. */ + + const coulomb = .00001; + const minForce = 0.01; + + var d = Math.sqrt(Math.pow(floatingObject.input.position.x - floatingObject.currentPosition.x, 2) + Math.pow(floatingObject.input.position.y - floatingObject.currentPosition.y, 2)); // ... we calculate the distance ... + + var force = coulomb * d * d / floatingObject.currentMass; // In this case the mass of the floatingObject affects the gravity force that it receives, that gives priority to target position to bigger floatingObjects. + + if (force < minForce) { // We need this attraction force to overcome the friction we imposed to the system. + force = minForce; + } + + var pos1 = { + x: floatingObject.currentPosition.x, + y: floatingObject.currentPosition.y + }; + + var pos2 = { + x: floatingObject.input.position.x, + y: floatingObject.input.position.y + }; + + var posDiff = { // Next we need the vector resulting from the 2 positions. + x: pos2.x - pos1.x, + y: pos2.y - pos1.y + }; + + var unitVector = { // To find the unit vector, we divide each component by the magnitude of the vector. + x: posDiff.x / d, + y: posDiff.y / d + }; + + var forceVector = { + x: unitVector.x * force, + y: unitVector.y * force + }; + + /* We add the force vector to the speed vector */ + + floatingObject.currentSpeed.x = floatingObject.currentSpeed.x + forceVector.x; + floatingObject.currentSpeed.y = floatingObject.currentSpeed.y + forceVector.y; + + } + + function repulsionForce(currentFloatingObject) { + + /* We generate a repulsion force between floatingObjects, that prevents them to be collisioning so often. */ + + const coulomb = 2; + + var floatingObject1 = thisObject.floatingObjects[currentFloatingObject]; + + for (var i = 0; i < thisObject.floatingObjects.length; i++) { // The force to be applied is considering all other floatingObjects... + + if (i !== currentFloatingObject) { // ... except for the current one. + + var floatingObject2 = thisObject.floatingObjects[i]; // So, for each floatingObject... + + var d = Math.sqrt(Math.pow(floatingObject2.currentPosition.x - floatingObject1.currentPosition.x, 2) + Math.pow(floatingObject2.currentPosition.y - floatingObject1.currentPosition.y, 2)); // ... we calculate the distance ... + + var force = coulomb * floatingObject2.currentMass / (d * d); // ... and with it the repulsion force. + + /* We need to put a hard limit to this force, in order to to eject very little floatingObjects to the infinite and beyond. */ + + if (force > 1) { + force = 1; + } + + var pos1 = { + x: floatingObject1.currentPosition.x, + y: floatingObject1.currentPosition.y + }; + + var pos2 = { + x: floatingObject2.currentPosition.x, + y: floatingObject2.currentPosition.y + }; + + var posDiff = { // Next we need the vector resulting from the 2 positions. + x: pos2.x - pos1.x, + y: pos2.y - pos1.y + }; + + var unitVector = { // To find the unit vector, we divide each component by the magnitude of the vector. + x: posDiff.x / d, + y: posDiff.y / d + }; + + var forceVector = { + x: unitVector.x * force, + y: unitVector.y * force + }; + + /* We substract the force vector to the speed vector of the current floatingObject */ + + floatingObject1.currentSpeed.x = floatingObject1.currentSpeed.x - forceVector.x; + floatingObject1.currentSpeed.y = floatingObject1.currentSpeed.y - forceVector.y; + + } + + } + + } + + function colliding(floatingObject1, floatingObject2) { + /* This function detects weather 2 floatingObjects collide with each other. */ + + var r1 = floatingObject1.currentRadius; + var r2 = floatingObject2.currentRadius; + + var distance = Math.sqrt(Math.pow(floatingObject2.currentPosition.x - floatingObject1.currentPosition.x, 2) + Math.pow(floatingObject2.currentPosition.y - floatingObject1.currentPosition.y, 2)); + + if (distance > (r1 + r2)) { + // No solutions, the circles are too far apart. + return false; + } + else if (distance <= r1 + r2) { + // One circle contains the other. + return true; + } + else if ((distance === 0) && (r1 === r2)) { + // the circles coincide. + return true; + } + else return true; + } + + function isInside(x, y) { + + /* This function detects weather the point x,y is inside any of the floatingObjects. */ + + for (var i = 0; i < thisObject.floatingObjects.length; i++) { + var floatingObject = thisObject.floatingObjects[i]; + var distance = Math.sqrt(Math.pow(floatingObject.currentPosition.x - x, 2) + Math.pow(floatingObject.currentPosition.y - y, 2)); + + if (distance < floatingObject.currentRadius) { + return i; + } + } + return -1; + + } + + function isInsideFloatingObject(floatingObjectIndex, x, y) { + + /* This function detects weather the point x,y is inside one particular floatingObjects. */ + + + var floatingObject = thisObject.floatingObjects[floatingObjectIndex]; + var distance = Math.sqrt(Math.pow(floatingObject.currentPosition.x - x, 2) + Math.pow(floatingObject.currentPosition.y - y, 2)); + + if (distance < floatingObject.currentRadius) { + return true; + } + + return false; + + } + + function distance(x1, y1, x2, y2) { + return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); + } + + function resolveCollision(floatingObject1, floatingObject2) { + + /* This function changes speed and position of floatingObjects that are in collision */ + + var collisionision_angle = Math.atan2((floatingObject2.currentPosition.y - floatingObject1.currentPosition.y), (floatingObject2.currentPosition.x - floatingObject1.currentPosition.x)); + + var speed1 = Math.sqrt(floatingObject1.currentSpeed.x * floatingObject1.currentSpeed.x + floatingObject1.currentSpeed.y * floatingObject1.currentSpeed.y); // Magnitude of Speed Vector for floatingObject 1 + var speed2 = Math.sqrt(floatingObject2.currentSpeed.x * floatingObject2.currentSpeed.x + floatingObject2.currentSpeed.y * floatingObject2.currentSpeed.y); // Magnitude of Speed Vector for floatingObject 2 + + var direction_1 = Math.atan2(floatingObject1.currentSpeed.y, floatingObject1.currentSpeed.x); + var direction_2 = Math.atan2(floatingObject2.currentSpeed.y, floatingObject2.currentSpeed.x); + + var new_xspeed_1 = speed1 * Math.cos(direction_1 - collisionision_angle); + var new_yspeed_1 = speed1 * Math.sin(direction_1 - collisionision_angle); + var new_xspeed_2 = speed2 * Math.cos(direction_2 - collisionision_angle); + var new_yspeed_2 = speed2 * Math.sin(direction_2 - collisionision_angle); + + var final_xspeed_1 = ((floatingObject1.currentMass - floatingObject2.currentMass) * new_xspeed_1 + (floatingObject2.currentMass + floatingObject2.currentMass) * new_xspeed_2) / (floatingObject1.currentMass + floatingObject2.currentMass); + var final_xspeed_2 = ((floatingObject1.currentMass + floatingObject1.currentMass) * new_xspeed_1 + (floatingObject2.currentMass - floatingObject1.currentMass) * new_xspeed_2) / (floatingObject1.currentMass + floatingObject2.currentMass); + var final_yspeed_1 = new_yspeed_1; + var final_yspeed_2 = new_yspeed_2; + + var cosAngle = Math.cos(collisionision_angle); + var sinAngle = Math.sin(collisionision_angle); + + floatingObject1.currentSpeed.x = cosAngle * final_xspeed_1 - sinAngle * final_yspeed_1; + floatingObject1.currentSpeed.y = sinAngle * final_xspeed_1 + cosAngle * final_yspeed_1; + + floatingObject2.currentSpeed.x = cosAngle * final_xspeed_2 - sinAngle * final_yspeed_2; + floatingObject2.currentSpeed.y = sinAngle * final_xspeed_2 + cosAngle * final_yspeed_2; + + var pos1 = { + x: floatingObject1.currentPosition.x, + y: floatingObject1.currentPosition.y + }; + + var pos2 = { + x: floatingObject2.currentPosition.x, + y: floatingObject2.currentPosition.y + }; + + // get the mtd + var posDiff = { + x: pos1.x - pos2.x, + y: pos1.y - pos2.y + }; + + var d = Math.sqrt(Math.pow(floatingObject2.currentPosition.x - floatingObject1.currentPosition.x, 2) + Math.pow(floatingObject2.currentPosition.y - floatingObject1.currentPosition.y, 2)); + + // minimum translation distance to push floatingObjects apart after intersecting + var scalar = (((floatingObject1.currentRadius + floatingObject2.currentRadius) - d) / d); + + var minTD = { + x: posDiff.x * scalar, + y: posDiff.y * scalar + }; + + // resolve intersection -- + // computing inverse mass quantities + var im1 = 1 / floatingObject1.currentMass; + var im2 = 1 / floatingObject2.currentMass; + + // push-pull them apart based off their mass + + pos1.x = pos1.x + minTD.x * (im1 / (im1 + im2)); + pos1.y = pos1.y + minTD.y * (im1 / (im1 + im2)); + pos2.x = pos2.x - minTD.x * (im2 / (im1 + im2)); + pos2.y = pos2.y - minTD.y * (im2 / (im1 + im2)); + + floatingObject1.currentPosition = pos1; + floatingObject2.currentPosition = pos2; + } +} + + diff --git a/FloatingObject.js b/FloatingSpace/FloatingObject.js similarity index 50% rename from FloatingObject.js rename to FloatingSpace/FloatingObject.js index c276acee8..433375ed7 100644 --- a/FloatingObject.js +++ b/FloatingSpace/FloatingObject.js @@ -31,8 +31,8 @@ function newFloatingObject() { radomizeCurrentPosition: radomizeCurrentPosition, radomizeCurrentSpeed: radomizeCurrentSpeed, - drawBackground: drawBackgrond, // Function to draw the floating object elements on the canvas layer. - drawForeground: drawForeground, // Function to draw the floating object elements on the floating objects layer. + drawBackground: drawBackground, + drawForeground: drawForeground, updateMass: updateMass, // Function to update the mass when the zoom level changed. updateRadius: updateRadius, // Function to update the radius when the zoom level changed. @@ -40,11 +40,55 @@ function newFloatingObject() { linkedObject: undefined, // This is a reference to the object that this floating object is representing. linkedObjectType: "", // Since there might be floating objects for different types of objects, here we store the type of object we are linking to. - container: undefined // This is a pointer to the object where the floating object belongs to. + container: undefined, // This is a pointer to the object where the floating object belongs to. + initialize: initialize + }; + let underlayingObject; + return thisObject; + function initialize(pType, callBackFunction) { + + switch (pType) { + + case "Profile Ball": { + + underlayingObject = newProfileBall(); + underlayingObject.initialize(onInitialized); + + function onInitialized(err) { + + + } + + break; + } + case "Bubble": { + + break; + } + default: { + + break; + } + } + + callBackFunction(); + } + + function drawBackground() { + + underlayingObject.drawBackground(thisObject); + + } + + function drawForeground() { + + underlayingObject.drawForeground(thisObject); + + } function initializeMass(suggestedValue) { @@ -131,135 +175,6 @@ function newFloatingObject() { //thisObject.targetRadius = thisObject.rawRadius + thisObject.rawRadius * thisObject.container.zoom.incrementR * thisObject.container.zoom.levelR; } - - function drawBackgrond() { - - if (thisObject.currentRadius > 1) { - - /* Target Line */ - - browserCanvasContext.beginPath(); - browserCanvasContext.moveTo(thisObject.currentPosition.x, thisObject.currentPosition.y); - browserCanvasContext.lineTo(thisObject.input.position.x, thisObject.input.position.y); - browserCanvasContext.strokeStyle = 'rgba(204, 204, 204, 0.5)'; - browserCanvasContext.setLineDash([4, 2]); - browserCanvasContext.lineWidth = 1; - browserCanvasContext.stroke(); - browserCanvasContext.setLineDash([0, 0]); - - } - - if (thisObject.currentRadius > 0.5) { - - /* Target Spot */ - - var radius = 1; - - browserCanvasContext.beginPath(); - browserCanvasContext.arc(thisObject.input.position.x, thisObject.input.position.y, radius, 0, Math.PI * 2, true); - browserCanvasContext.closePath(); - browserCanvasContext.fillStyle = 'rgba(30, 30, 30, 1)'; - browserCanvasContext.fill(); - - } - } - - function drawForeground() { - - if (thisObject.currentRadius > 5) { - - /* Contourn */ - - browserCanvasContext.beginPath(); - browserCanvasContext.arc(thisObject.currentPosition.x, thisObject.currentPosition.y, thisObject.currentRadius, 0, Math.PI * 2, true); - browserCanvasContext.closePath(); - browserCanvasContext.strokeStyle = 'rgba(30, 30, 30, 0.75)'; - browserCanvasContext.lineWidth = 1; - browserCanvasContext.stroke(); - - } - - if (thisObject.currentRadius > 0.5) { - - /* Main FloatingObject */ - - var alphaA; - - if (thisObject.currentRadius < 3) { - alphaA = 1; - } else { - alphaA = 0.75; - } - - alphaA = 0.75; - - browserCanvasContext.beginPath(); - browserCanvasContext.arc(thisObject.currentPosition.x, thisObject.currentPosition.y, thisObject.currentRadius, 0, Math.PI * 2, true); - browserCanvasContext.closePath(); - - browserCanvasContext.fillStyle = thisObject.fillStyle; - - browserCanvasContext.fill(); - - } - - /* Image */ - - if (thisObject.input.imageId !== undefined) { - - let image = document.getElementById(thisObject.input.imageId); - - if (image !== null) { - - browserCanvasContext.drawImage(image, thisObject.currentPosition.x - thisObject.currentImageSize / 2, thisObject.currentPosition.y - thisObject.currentImageSize / 2, thisObject.currentImageSize, thisObject.currentImageSize); - - } - } - - /* Label Text */ - - if (thisObject.currentRadius > 6) { - - browserCanvasContext.strokeStyle = thisObject.labelStrokeStyle; - - let labelPoint; - let fontSize = 10; - - browserCanvasContext.font = fontSize + 'px Courier New'; - - let label; - - label = thisObject.input.upLabel; - - if (label !== undefined) { - - labelPoint = { - x: thisObject.currentPosition.x - label.length / 2 * fontSize * 0.60, - y: thisObject.currentPosition.y - thisObject.currentImageSize / 2 - fontSize * 0.60 - 5 - }; - - browserCanvasContext.font = fontSize + 'px Courier New'; - browserCanvasContext.fillStyle = thisObject.labelStrokeStyle; - browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y); - - } - - label = thisObject.input.downLabel; - - if (label !== undefined) { - - labelPoint = { - x: thisObject.currentPosition.x - label.length / 2 * fontSize * 0.60, - y: thisObject.currentPosition.y + thisObject.currentImageSize / 2 + fontSize * 0.60 + 10 - }; - - browserCanvasContext.font = fontSize + 'px Courier New'; - browserCanvasContext.fillStyle = thisObject.labelStrokeStyle; - browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y); - - } - } - } } diff --git a/FloatingSpace/ProfileBall.js b/FloatingSpace/ProfileBall.js new file mode 100644 index 000000000..dbfa706b5 --- /dev/null +++ b/FloatingSpace/ProfileBall.js @@ -0,0 +1,151 @@ + +function newProfileBall() { + + var thisObject = { + + drawBackground: drawBackground, + drawForeground: drawForeground, + initialize: initialize + + }; + + return thisObject; + + function initialize(callBackFunction) { + + callBackFunction(); + + } + + function drawBackground(pFloatingObject) { + + if (pFloatingObject.currentRadius > 1) { + + /* Target Line */ + + browserCanvasContext.beginPath(); + browserCanvasContext.moveTo(pFloatingObject.currentPosition.x, pFloatingObject.currentPosition.y); + browserCanvasContext.lineTo(pFloatingObject.input.position.x, pFloatingObject.input.position.y); + browserCanvasContext.strokeStyle = 'rgba(204, 204, 204, 0.5)'; + browserCanvasContext.setLineDash([4, 2]); + browserCanvasContext.lineWidth = 1; + browserCanvasContext.stroke(); + browserCanvasContext.setLineDash([0, 0]); + + } + + if (pFloatingObject.currentRadius > 0.5) { + + /* Target Spot */ + + var radius = 1; + + browserCanvasContext.beginPath(); + browserCanvasContext.arc(pFloatingObject.input.position.x, pFloatingObject.input.position.y, radius, 0, Math.PI * 2, true); + browserCanvasContext.closePath(); + browserCanvasContext.fillStyle = 'rgba(30, 30, 30, 1)'; + browserCanvasContext.fill(); + + } + } + + function drawForeground(pFloatingObject) { + + if (pFloatingObject.currentRadius > 5) { + + /* Contourn */ + + browserCanvasContext.beginPath(); + browserCanvasContext.arc(pFloatingObject.currentPosition.x, pFloatingObject.currentPosition.y, pFloatingObject.currentRadius, 0, Math.PI * 2, true); + browserCanvasContext.closePath(); + browserCanvasContext.strokeStyle = 'rgba(30, 30, 30, 0.75)'; + browserCanvasContext.lineWidth = 1; + browserCanvasContext.stroke(); + + } + + if (pFloatingObject.currentRadius > 0.5) { + + /* Main FloatingObject */ + + var alphaA; + + if (pFloatingObject.currentRadius < 3) { + alphaA = 1; + } else { + alphaA = 0.75; + } + + alphaA = 0.75; + + browserCanvasContext.beginPath(); + browserCanvasContext.arc(pFloatingObject.currentPosition.x, pFloatingObject.currentPosition.y, pFloatingObject.currentRadius, 0, Math.PI * 2, true); + browserCanvasContext.closePath(); + + browserCanvasContext.fillStyle = pFloatingObject.fillStyle; + + browserCanvasContext.fill(); + + } + + /* Image */ + + if (pFloatingObject.input.imageId !== undefined) { + + let image = document.getElementById(pFloatingObject.input.imageId); + + if (image !== null) { + + browserCanvasContext.drawImage(image, pFloatingObject.currentPosition.x - pFloatingObject.currentImageSize / 2, pFloatingObject.currentPosition.y - pFloatingObject.currentImageSize / 2, pFloatingObject.currentImageSize, pFloatingObject.currentImageSize); + + } + } + + /* Label Text */ + + if (pFloatingObject.currentRadius > 6) { + + browserCanvasContext.strokeStyle = pFloatingObject.labelStrokeStyle; + + let labelPoint; + let fontSize = 10; + + browserCanvasContext.font = fontSize + 'px Courier New'; + + let label; + + label = pFloatingObject.input.upLabel; + + if (label !== undefined) { + + labelPoint = { + x: pFloatingObject.currentPosition.x - label.length / 2 * fontSize * 0.60, + y: pFloatingObject.currentPosition.y - pFloatingObject.currentImageSize / 2 - fontSize * 0.60 - 5 + }; + + browserCanvasContext.font = fontSize + 'px Courier New'; + browserCanvasContext.fillStyle = pFloatingObject.labelStrokeStyle; + browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y); + + } + + label = pFloatingObject.input.downLabel; + + if (label !== undefined) { + + labelPoint = { + x: pFloatingObject.currentPosition.x - label.length / 2 * fontSize * 0.60, + y: pFloatingObject.currentPosition.y + pFloatingObject.currentImageSize / 2 + fontSize * 0.60 + 10 + }; + + browserCanvasContext.font = fontSize + 'px Courier New'; + browserCanvasContext.fillStyle = pFloatingObject.labelStrokeStyle; + browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y); + + } + } + } +} + + + diff --git a/FloatingSpace/ProfileBalls.js b/FloatingSpace/ProfileBalls.js new file mode 100644 index 000000000..205a535fc --- /dev/null +++ b/FloatingSpace/ProfileBalls.js @@ -0,0 +1,78 @@ + +function newProfileBalls() { + + const MODULE_NAME = "Profile Balls"; + const INFO_LOG = false; + const ERROR_LOG = true; + const logger = newDebugLog(); + logger.fileName = MODULE_NAME; + + /* + + This object deals with Profile Balls, a type of Floating Object that shows profile info in a floating ball. + + */ + + let thisObject = { + + createNewProfileBall: createNewProfileBall, + destroyProfileBall: destroyProfileBall, + initialize: initialize + + } + + let floatingLayer; + + return thisObject; + + function initialize(pFloatingLayer, callBackFunction) { + + try { + + if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); } + + floatingLayer = pFloatingLayer; + + callBackFunction(GLOBAL.CUSTOM_OK_RESPONSE); + + } catch (err) { + + if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err); } + callBackFunction(GLOBAL.CUSTOM_FAIL_RESPONSE); + } + } + + function createNewProfileBall(pInput, pContainer, callBackFunction) { + + let floatingObject = newFloatingObject(); + floatingObject.initialize("Profile Ball", onInitialized); + + function onInitialized(err) { + + floatingObject.input = pInput; + + floatingObject.container = pContainer; + + floatingObject.friction = .995; + + floatingObject.initializeMass(100); + floatingObject.initializeRadius(30); + floatingObject.initializeImageSize(50); + + floatingObject.fillStyle = 'rgba(255, 255, 255, 0.5)'; + floatingObject.labelStrokeStyle = 'rgba(60, 60, 60, 0.50)'; + + floatingLayer.addFloatingObject(floatingObject); + + callBackFunction(GLOBAL.CUSTOM_OK_RESPONSE, floatingObject.handle); + + } + } + + function destroyProfileBall(pFloatingObjectHandle) { + + floatingLayer.removeFloatingObject(pFloatingObjectHandle); + + } +} + diff --git a/Project.njsproj b/Project.njsproj index 311261be0..b3022b5c5 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -32,19 +32,31 @@ - + + Code + + Code Code + + Code + Code Code + + Code + + + Code + Code @@ -112,6 +124,7 @@ + diff --git a/Spaces/FloatingSpace.js b/Spaces/FloatingSpace.js index bcb82a779..cba37e7c2 100644 --- a/Spaces/FloatingSpace.js +++ b/Spaces/FloatingSpace.js @@ -1,473 +1,43 @@ -/* -The Floating Space is the place where floating elements like floatingObjects, live and are rendered. -This space has its own physics which helps with the animation of these objects and also preventing them to overlap. -*/ - + function newFloatingSpace() { + /* + The Floating Space is the place where floating elements like floatingObjects, live and are rendered. + This space has its own physics which helps with the animation of these objects and also preventing them to overlap. + */ + let thisObject = { - floatingObjects: undefined, // This is the array of floatingObjects being displayed - createNewFloatingObject: createNewFloatingObject, - destroyFloatingObject: destroyFloatingObject, - createBubbleSet: createBubbleSet, - destroyBubbleSet: destroyBubbleSet, - physicsLoop: physicsLoop, - isInside: isInside, - isInsideFloatingObject: isInsideFloatingObject, + floatingLayer: undefined, // This is the array of floatingObjects being displayed + profileBalls: undefined, + bubbleSets: undefined, initialize: initialize }; - let createdFloatingObjects = []; - let bubbleSets = []; - return thisObject; - function initialize() { + function initialize(callBackFunction) { - thisObject.floatingObjects = []; // We initialize this in order to start the calculations in a clean way. - - } + thisObject.floatingLayer = newFloatingLayer(); + thisObject.floatingLayer.initialize(onFloatingLayerInitialized); + + function onFloatingLayerInitialized(err) { + + thisObject.profileBalls = newProfileBalls(); + thisObject.profileBalls.initialize(thisObject.floatingLayer, onProfileBallsInitialized); + + function onProfileBallsInitialized(err) { + + thisObject.bubbleSets = newBubbleSets(); + thisObject.bubbleSets.initialize(thisObject.floatingLayer, onBubbleSetsInitialized); + + function onBubbleSetsInitialized(err) { - function createNewFloatingObject(pInput, pContainer) { - /* This function is used to create new floatingObjects */ - - var floatingObject = newFloatingObject(); - - floatingObject.input = pInput; - - floatingObject.container = pContainer; - - floatingObject.friction = .995; - - floatingObject.initializeMass(150); - floatingObject.initializeRadius(30); - floatingObject.initializeImageSize(50); - - floatingObject.fillStyle = 'rgba(255, 255, 255, 0.5)'; - floatingObject.labelStrokeStyle = 'rgba(60, 60, 60, 0.50)'; - - createdFloatingObjects.push(floatingObject); - - floatingObject.handle = Math.floor((Math.random() * 10000000) + 1); - - return floatingObject.handle; - } - - function destroyFloatingObject(pFloatingObjectHandle) { - - for (let i = 0; i < createdFloatingObjects.length; i++) { - - let floatingObject = createdFloatingObjects[i]; - - if (floatingObject.handle === pFloatingObjectHandle) { - createdFloatingObjects.splice(i, 1); // Delete item from array. - return; - } - } - - for (let i = 0; i < thisObject.floatingObjects.length; i++) { - - let floatingObject = thisObject.floatingObjects[i]; - - if (floatingObject.handle === pFloatingObjectHandle) { - thisObject.floatingObjects.splice(i, 1); // Delete item from array. - return; - } - } - } - - - function createBubbleSet(pPlotterBubbles) { - - let bubbleSet = { - floatingBubbles: [], - plotterBubbles: pPlotterBubbles, - handle: Math.floor((Math.random() * 10000000) + 1) - }; - - bubbleSets.push(bubbleSet); - - return bubbleSet.handle; - } - - function destroyBubbleSet(pHandle) { - - for (let i = 0; i < bubbleSets.length; i++) { - - let bubbleSet = bubbleSets[i]; - - if (bubbleSet.handle === pHandle) { - bubbleSets.splice(i, 1); // Delete item from array. - return; - } - } - } - - /******************************************/ - /* */ - /* Physics Engine Follows */ - /* */ - /******************************************/ - - function physicsLoop() { - - /* This function makes all the calculations to apply phisycs on all floatingObjects in this space. */ - - for (let i = 0; i < thisObject.floatingObjects.length; i++) { - - let floatingObject = thisObject.floatingObjects[i]; - - /* Change position based on speed */ - - floatingObject.currentPosition.x = floatingObject.currentPosition.x + floatingObject.currentSpeed.x; - floatingObject.currentPosition.y = floatingObject.currentPosition.y + floatingObject.currentSpeed.y; - - /* Apply some friction to desacelerate */ - - floatingObject.currentSpeed.x = floatingObject.currentSpeed.x * floatingObject.friction; // Desaceleration factor. - floatingObject.currentSpeed.y = floatingObject.currentSpeed.y * floatingObject.friction; // Desaceleration factor. - - // Gives a minimun speed towards their taget. - - if (floatingObject.currentPosition.x < floatingObject.input.position.x) { - floatingObject.currentSpeed.x = floatingObject.currentSpeed.x + .005; - } else { - floatingObject.currentSpeed.x = floatingObject.currentSpeed.x - .005; - } - - if (floatingObject.currentPosition.y < floatingObject.input.position.y) { - floatingObject.currentSpeed.y = floatingObject.currentSpeed.y + .005; - } else { - floatingObject.currentSpeed.y = floatingObject.currentSpeed.y - .005; - } - - // Lets put a maximun speed also. - - const MAX_SPEED = 50; - - if (floatingObject.currentSpeed.x > MAX_SPEED) { - floatingObject.currentSpeed.x = MAX_SPEED; - } - - if (floatingObject.currentSpeed.y > MAX_SPEED) { - floatingObject.currentSpeed.y = MAX_SPEED; - } - - if (floatingObject.currentSpeed.x < -MAX_SPEED) { - floatingObject.currentSpeed.x = -MAX_SPEED; - } - - if (floatingObject.currentSpeed.y < -MAX_SPEED) { - floatingObject.currentSpeed.y = -MAX_SPEED; - } - - // The radius also have a target. - - if (floatingObject.currentRadius < floatingObject.targetRadius) { - floatingObject.currentRadius = floatingObject.currentRadius + .5; - } else { - floatingObject.currentRadius = floatingObject.currentRadius - .5; - } - - // The imageSize also have a target. - - if (floatingObject.currentImageSize < floatingObject.targetImageSize) { - floatingObject.currentImageSize = floatingObject.currentImageSize + 1; - } else { - floatingObject.currentImageSize = floatingObject.currentImageSize - 1; - } - - /* Collision Control */ - - for (let k = i + 1; k < thisObject.floatingObjects.length; k++) { - - if (colliding(thisObject.floatingObjects[i], thisObject.floatingObjects[k])) { - - resolveCollision(thisObject.floatingObjects[k], thisObject.floatingObjects[i]); } } - - /* Calculate repulsion force produced by all other floatingObjects */ - - repulsionForce(i); - - gravityForce(floatingObject); - } - - /* We draw all the thisObject.floatingObjects. */ - - for (let i = 0; i < thisObject.floatingObjects.length; i++) { - let floatingObject = thisObject.floatingObjects[i]; - floatingObject.drawBackground(); - } - - for (let i = 0; i < thisObject.floatingObjects.length; i++) { - let floatingObject = thisObject.floatingObjects[thisObject.floatingObjects.length - i - 1]; - floatingObject.drawForeground(); - } - - /* Finally we check if any of the created FloatingObjects where enabled to run under the Physics Engine. */ - - for (let i = 0; i < createdFloatingObjects.length; i++) { - - let floatingObject = createdFloatingObjects[i]; - - if (floatingObject.input.visible === true) { - - /* The first time that the floatingObject becomes visible, we need to do this. */ - - floatingObject.radomizeCurrentPosition(floatingObject.input.position); - floatingObject.radomizeCurrentSpeed(); - - thisObject.floatingObjects.push(floatingObject); - createdFloatingObjects.splice(i, 1); // Delete item from array. - return; // Only one at the time. - - } - } - } - - function gravityForce(floatingObject) { - - /* We simulate a kind of gravity towards the target point of each floatingObject. This force will make the floatingObject to keep pushing to reach that point. */ - - const coulomb = .00001; - const minForce = 0.01; - - var d = Math.sqrt(Math.pow(floatingObject.input.position.x - floatingObject.currentPosition.x, 2) + Math.pow(floatingObject.input.position.y - floatingObject.currentPosition.y, 2)); // ... we calculate the distance ... - - var force = coulomb * d * d / floatingObject.currentMass; // In this case the mass of the floatingObject affects the gravity force that it receives, that gives priority to target position to bigger floatingObjects. - - if (force < minForce) { // We need this attraction force to overcome the friction we imposed to the system. - force = minForce; - } - - var pos1 = { - x: floatingObject.currentPosition.x, - y: floatingObject.currentPosition.y - }; - - var pos2 = { - x: floatingObject.input.position.x, - y: floatingObject.input.position.y - }; - - var posDiff = { // Next we need the vector resulting from the 2 positions. - x: pos2.x - pos1.x, - y: pos2.y - pos1.y - }; - - var unitVector = { // To find the unit vector, we divide each component by the magnitude of the vector. - x: posDiff.x / d, - y: posDiff.y / d - }; - - var forceVector = { - x: unitVector.x * force, - y: unitVector.y * force - }; - - /* We add the force vector to the speed vector */ - - floatingObject.currentSpeed.x = floatingObject.currentSpeed.x + forceVector.x; - floatingObject.currentSpeed.y = floatingObject.currentSpeed.y + forceVector.y; - - } - - function repulsionForce(currentFloatingObject) { - - /* We generate a repulsion force between floatingObjects, that prevents them to be collisioning so often. */ - - const coulomb = 2; - - var floatingObject1 = thisObject.floatingObjects[currentFloatingObject]; - - for (var i = 0; i < thisObject.floatingObjects.length; i++) { // The force to be applied is considering all other floatingObjects... - - if (i !== currentFloatingObject) { // ... except for the current one. - - var floatingObject2 = thisObject.floatingObjects[i]; // So, for each floatingObject... - - var d = Math.sqrt(Math.pow(floatingObject2.currentPosition.x - floatingObject1.currentPosition.x, 2) + Math.pow(floatingObject2.currentPosition.y - floatingObject1.currentPosition.y, 2)); // ... we calculate the distance ... - - var force = coulomb * floatingObject2.currentMass / (d * d); // ... and with it the repulsion force. - - /* We need to put a hard limit to this force, in order to to eject very little floatingObjects to the infinite and beyond. */ - - if (force > 1) { - force = 1; - } - - var pos1 = { - x: floatingObject1.currentPosition.x, - y: floatingObject1.currentPosition.y - }; - - var pos2 = { - x: floatingObject2.currentPosition.x, - y: floatingObject2.currentPosition.y - }; - - var posDiff = { // Next we need the vector resulting from the 2 positions. - x: pos2.x - pos1.x, - y: pos2.y - pos1.y - }; - - var unitVector = { // To find the unit vector, we divide each component by the magnitude of the vector. - x: posDiff.x / d, - y: posDiff.y / d - }; - - var forceVector = { - x: unitVector.x * force, - y: unitVector.y * force - }; - - /* We substract the force vector to the speed vector of the current floatingObject */ - - floatingObject1.currentSpeed.x = floatingObject1.currentSpeed.x - forceVector.x; - floatingObject1.currentSpeed.y = floatingObject1.currentSpeed.y - forceVector.y; - - } - - } - - } - - function colliding(floatingObject1, floatingObject2) { - /* This function detects weather 2 floatingObjects collide with each other. */ - - var r1 = floatingObject1.currentRadius; - var r2 = floatingObject2.currentRadius; - - var distance = Math.sqrt(Math.pow(floatingObject2.currentPosition.x - floatingObject1.currentPosition.x, 2) + Math.pow(floatingObject2.currentPosition.y - floatingObject1.currentPosition.y, 2)); - - if (distance > (r1 + r2)) { - // No solutions, the circles are too far apart. - return false; - } - else if (distance <= r1 + r2) { - // One circle contains the other. - return true; - } - else if ((distance === 0) && (r1 === r2)) { - // the circles coincide. - return true; - } - else return true; - } - - function isInside(x, y) { - - /* This function detects weather the point x,y is inside any of the floatingObjects. */ - - for (var i = 0; i < thisObject.floatingObjects.length; i++) { - var floatingObject = thisObject.floatingObjects[i]; - var distance = Math.sqrt(Math.pow(floatingObject.currentPosition.x - x, 2) + Math.pow(floatingObject.currentPosition.y - y, 2)); - - if (distance < floatingObject.currentRadius) { - return i; - } - } - return -1; - - } - - function isInsideFloatingObject(floatingObjectIndex, x, y) { - - /* This function detects weather the point x,y is inside one particular floatingObjects. */ - - - var floatingObject = thisObject.floatingObjects[floatingObjectIndex]; - var distance = Math.sqrt(Math.pow(floatingObject.currentPosition.x - x, 2) + Math.pow(floatingObject.currentPosition.y - y, 2)); - - if (distance < floatingObject.currentRadius) { - return true; - } - - return false; - - } - - function distance(x1, y1, x2, y2) { - return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); - } - - function resolveCollision(floatingObject1, floatingObject2) { - - /* This function changes speed and position of floatingObjects that are in collision */ - - var collisionision_angle = Math.atan2((floatingObject2.currentPosition.y - floatingObject1.currentPosition.y), (floatingObject2.currentPosition.x - floatingObject1.currentPosition.x)); - - var speed1 = Math.sqrt(floatingObject1.currentSpeed.x * floatingObject1.currentSpeed.x + floatingObject1.currentSpeed.y * floatingObject1.currentSpeed.y); // Magnitude of Speed Vector for floatingObject 1 - var speed2 = Math.sqrt(floatingObject2.currentSpeed.x * floatingObject2.currentSpeed.x + floatingObject2.currentSpeed.y * floatingObject2.currentSpeed.y); // Magnitude of Speed Vector for floatingObject 2 - - var direction_1 = Math.atan2(floatingObject1.currentSpeed.y, floatingObject1.currentSpeed.x); - var direction_2 = Math.atan2(floatingObject2.currentSpeed.y, floatingObject2.currentSpeed.x); - - var new_xspeed_1 = speed1 * Math.cos(direction_1 - collisionision_angle); - var new_yspeed_1 = speed1 * Math.sin(direction_1 - collisionision_angle); - var new_xspeed_2 = speed2 * Math.cos(direction_2 - collisionision_angle); - var new_yspeed_2 = speed2 * Math.sin(direction_2 - collisionision_angle); - - var final_xspeed_1 = ((floatingObject1.currentMass - floatingObject2.currentMass) * new_xspeed_1 + (floatingObject2.currentMass + floatingObject2.currentMass) * new_xspeed_2) / (floatingObject1.currentMass + floatingObject2.currentMass); - var final_xspeed_2 = ((floatingObject1.currentMass + floatingObject1.currentMass) * new_xspeed_1 + (floatingObject2.currentMass - floatingObject1.currentMass) * new_xspeed_2) / (floatingObject1.currentMass + floatingObject2.currentMass); - var final_yspeed_1 = new_yspeed_1; - var final_yspeed_2 = new_yspeed_2; - - var cosAngle = Math.cos(collisionision_angle); - var sinAngle = Math.sin(collisionision_angle); - - floatingObject1.currentSpeed.x = cosAngle * final_xspeed_1 - sinAngle * final_yspeed_1; - floatingObject1.currentSpeed.y = sinAngle * final_xspeed_1 + cosAngle * final_yspeed_1; - - floatingObject2.currentSpeed.x = cosAngle * final_xspeed_2 - sinAngle * final_yspeed_2; - floatingObject2.currentSpeed.y = sinAngle * final_xspeed_2 + cosAngle * final_yspeed_2; - - var pos1 = { - x: floatingObject1.currentPosition.x, - y: floatingObject1.currentPosition.y - }; - - var pos2 = { - x: floatingObject2.currentPosition.x, - y: floatingObject2.currentPosition.y - }; - - // get the mtd - var posDiff = { - x: pos1.x - pos2.x, - y: pos1.y - pos2.y - }; - - var d = Math.sqrt(Math.pow(floatingObject2.currentPosition.x - floatingObject1.currentPosition.x, 2) + Math.pow(floatingObject2.currentPosition.y - floatingObject1.currentPosition.y, 2)); - - // minimum translation distance to push floatingObjects apart after intersecting - var scalar = (((floatingObject1.currentRadius + floatingObject2.currentRadius) - d) / d); - - var minTD = { - x: posDiff.x * scalar, - y: posDiff.y * scalar - }; - - // resolve intersection -- - // computing inverse mass quantities - var im1 = 1 / floatingObject1.currentMass; - var im2 = 1 / floatingObject2.currentMass; - - // push-pull them apart based off their mass - - pos1.x = pos1.x + minTD.x * (im1 / (im1 + im2)); - pos1.y = pos1.y + minTD.y * (im1 / (im1 + im2)); - pos2.x = pos2.x - minTD.x * (im2 / (im1 + im2)); - pos2.y = pos2.y - minTD.y * (im2 / (im1 + im2)); - - floatingObject1.currentPosition = pos1; - floatingObject2.currentPosition = pos2; } } diff --git a/TimelineChart.js b/TimelineChart.js index 9cbdf41e6..e02aac988 100644 --- a/TimelineChart.js +++ b/TimelineChart.js @@ -315,13 +315,18 @@ productPlotter.plotter.profile.downLabel = pProductCard.bot.displayName; productPlotter.plotter.profile.imageId = imageId; - productPlotter.profile = canvas.floatingSpace.createNewFloatingObject(productPlotter.plotter.profile, thisObject.container) + canvas.floatingSpace.profileBalls.createNewProfileBall(productPlotter.plotter.profile, thisObject.container, onProfileBallCreated) + function onProfileBallCreated(err, pProfileHandle) { + + productPlotter.profile = pProfileHandle; + + } } /* Create the Text Bubbles */ - productPlotter.bubbleSet = canvas.floatingSpace.createBubbleSet(productPlotter.plotter.bubbles); + productPlotter.bubbleSet = canvas.floatingSpace.bubbleSets.createBubbleSet(productPlotter.plotter.bubbles); /* Add the new Active Protter to the Array */ @@ -369,13 +374,13 @@ if (productPlotters[i].profile !== undefined) { - canvas.floatingSpace.destroyFloatingObject(productPlotters[i].profile); + canvas.floatingSpace.profileBalls.destroyProfileBall(productPlotters[i].profile); } /* Destroyd the Bubble Set */ - canvas.floatingSpace.destroyBubbleSet(productPlotters[i].bubbleSet); + canvas.floatingSpace.bubbleSets.destroyBubbleSet(productPlotters[i].bubbleSet); /* Finally the panels. */ diff --git a/index.html b/index.html index 12c98c8c1..e26d9397b 100644 --- a/index.html +++ b/index.html @@ -27,7 +27,6 @@ - @@ -44,6 +43,12 @@ + + + + + + diff --git a/server.js b/server.js index 1cf8bb361..626140bfd 100644 --- a/server.js +++ b/server.js @@ -6,7 +6,7 @@ if (CONSOLE_LOG === true) { } -const DEBUG_MODE = false; // This forces the server to read Plotters from the local drive. +const DEBUG_MODE = true; // This forces the server to read Plotters from the local drive. if (CONSOLE_LOG === true && DEBUG_MODE === true) { @@ -851,6 +851,12 @@ function onBrowserRequest(request, response) { } break; + case "FloatingSpace": + { + respondWithFile('./' + requestParameters[1] + '/' + requestParameters[2], response); + } + break; + default: if (requestParameters[1] === "") {