Running with Profile Balls, Bubbles Implemented but not tested
This commit is contained in:
1 parent
83cac7e633
commit
22e193a045
10 files changed
+358
-31
No files matched your search
Binary file not shown.
@@ -0,0 +1,148 @@
|
||||
|
||||
function newBubble() {
|
||||
|
||||
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.payload.bubbles[pFloatingObject.payload.bubbleIndex].position.x, pFloatingObject.payload.bubbles[pFloatingObject.payload.bubbleIndex].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.payload.bubbles[pFloatingObject.payload.bubbleIndex].position.x, pFloatingObject.payload.bubbles[pFloatingObject.payload.bubbleIndex].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.payload.profile.imageId !== undefined) {
|
||||
|
||||
let image = document.getElementById(pFloatingObject.payload.profile.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.payload.bubbles[pFloatingObject.payload.bubbleIndex].title;
|
||||
|
||||
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.payload.bubbles[pFloatingObject.payload.bubbleIndex].body;
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+112
-4
@@ -14,7 +14,6 @@ function newBubbleSets() {
|
||||
};
|
||||
|
||||
let bubbleSets = [];
|
||||
|
||||
let floatingLayer;
|
||||
|
||||
return thisObject;
|
||||
@@ -36,17 +35,118 @@ function newBubbleSets() {
|
||||
}
|
||||
}
|
||||
|
||||
function createBubbleSet(pPlotterBubbles) {
|
||||
function createBubbleSet(pPayload, pEventHandler, callBackFunction) {
|
||||
|
||||
let bubbleSet = {
|
||||
imageId: pPayload.profile.imageId,
|
||||
floatingBubbles: [],
|
||||
plotterBubbles: pPlotterBubbles,
|
||||
payload: pPayload,
|
||||
handle: Math.floor((Math.random() * 10000000) + 1)
|
||||
};
|
||||
|
||||
bubbleSets.push(bubbleSet);
|
||||
|
||||
return bubbleSet.handle;
|
||||
pEventHandler.listenToEvent("Bubbles Changed", onBubblesChanged, bubbleSets.length - 1)
|
||||
|
||||
callBackFunction(GLOBAL.CUSTOM_OK_RESPONSE, bubbleSet.handle);
|
||||
|
||||
function onBubblesChanged(pEvent, pBubbleSetIndex) {
|
||||
|
||||
let bubbleSet = bubbleSets[pBubbleSetIndex];
|
||||
|
||||
/* First we add the new bubbles. */
|
||||
|
||||
let newFloatingBubbles = []; // We will create a new array of Floating Bubbles as a result of this operation.
|
||||
|
||||
for (let i = 0; i < bubbleSet.payload.bubbles.length; i++) {
|
||||
|
||||
let plotterBubble = bubbleSet.payload.bubbles[i];
|
||||
let plotterBubbleKey = plotterBubble.date.toString() + plotterBubble.rate.toString();
|
||||
let found = false;
|
||||
|
||||
for (let j = 0; j < bubbleSet.floatingBubbles.length; j++) {
|
||||
|
||||
let floatingBubble = bubbleSet.floatingBubbles[j];
|
||||
let floatingBubbleKey = floatingBubble.date.toString() + floatingBubble.rate.toString();
|
||||
|
||||
if (plotterBubbleKey === floatingBubbleKey) {
|
||||
|
||||
found = true;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (found === false) {
|
||||
|
||||
let floatingObject = newFloatingObject();
|
||||
floatingObject.initialize("Bubble", onInitialized);
|
||||
|
||||
function onInitialized(err) {
|
||||
|
||||
floatingObject.payload = bubbleSet.payload;
|
||||
floatingObject.payload.bubbleIndex = i;
|
||||
floatingObject.payload.profile.imageId = bubbleSet.imageId;
|
||||
|
||||
//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);
|
||||
plotterBubble.floatingHandle = floatingObject.handle;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
newFloatingBubbles.push(plotterBubble);
|
||||
|
||||
}
|
||||
|
||||
bubbleSet.floatingBubbles = newFloatingBubbles;
|
||||
|
||||
/* Second we remove the old bubbles. */
|
||||
|
||||
newFloatingBubbles = []; // We will create a new array of Floating Bubbles as a result of this operation.
|
||||
|
||||
for (let j = 0; j < bubbleSet.floatingBubbles.length; j++) {
|
||||
|
||||
let floatingBubble = bubbleSet.floatingBubbles[j];
|
||||
let floatingBubbleKey = floatingBubble.date.toString() + floatingBubble.rate.toString();
|
||||
|
||||
for (let i = 0; i < bubbleSet.payload.bubbles.length; i++) {
|
||||
|
||||
let plotterBubble = bubbleSet.payload.bubbles[i];
|
||||
let plotterBubbleKey = plotterBubble.date.toString() + plotterBubble.rate.toString();
|
||||
let found = false;
|
||||
|
||||
if (plotterBubbleKey === floatingBubbleKey) {
|
||||
|
||||
found = true;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (found === false) {
|
||||
|
||||
floatingLayer.removeFloatingObject(floatingBubble.floatingHandle);
|
||||
|
||||
} else {
|
||||
|
||||
newFloatingBubbles.push(floatingBubble);
|
||||
}
|
||||
}
|
||||
|
||||
bubbleSet.floatingBubbles = newFloatingBubbles;
|
||||
}
|
||||
}
|
||||
|
||||
function destroyBubbleSet(pHandle) {
|
||||
@@ -56,6 +156,14 @@ function newBubbleSets() {
|
||||
let bubbleSet = bubbleSets[i];
|
||||
|
||||
if (bubbleSet.handle === pHandle) {
|
||||
|
||||
for (let j = 0; j < bubbleSet.floatingBubbles.length; j++) {
|
||||
|
||||
let floatingBubble = bubbleSet.floatingBubbles[j];
|
||||
|
||||
floatingLayer.removeFloatingObject(floatingBubble.floatingHandle);
|
||||
}
|
||||
|
||||
bubbleSets.splice(i, 1); // Delete item from array.
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -79,13 +79,38 @@ function newFloatingLayer() {
|
||||
|
||||
// Gives a minimun speed towards their taget.
|
||||
|
||||
if (floatingObject.currentPosition.x < floatingObject.input.position.x) {
|
||||
let payload = {
|
||||
position: undefined,
|
||||
visible: false
|
||||
};
|
||||
|
||||
switch (floatingObject.type) {
|
||||
|
||||
case "Profile Ball": {
|
||||
|
||||
payload.position = floatingObject.payload.profile.position;
|
||||
payload.visible = floatingObject.payload.profile.visible;
|
||||
break;
|
||||
}
|
||||
case "Bubble": {
|
||||
|
||||
payload.position = floatingObject.payload.bubbles[floatingObject.payload.bubbleIndex].position;
|
||||
payload.visible = floatingObject.payload.bubbles[floatingObject.payload.bubbleIndex].visible;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (floatingObject.currentPosition.x < payload.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) {
|
||||
if (floatingObject.currentPosition.y < payload.position.y) {
|
||||
floatingObject.currentSpeed.y = floatingObject.currentSpeed.y + .005;
|
||||
} else {
|
||||
floatingObject.currentSpeed.y = floatingObject.currentSpeed.y - .005;
|
||||
@@ -142,7 +167,7 @@ function newFloatingLayer() {
|
||||
|
||||
repulsionForce(i);
|
||||
|
||||
gravityForce(floatingObject);
|
||||
gravityForce(floatingObject, payload);
|
||||
|
||||
}
|
||||
|
||||
@@ -164,11 +189,36 @@ function newFloatingLayer() {
|
||||
|
||||
let floatingObject = innactiveFloatingObjects[i];
|
||||
|
||||
if (floatingObject.input.visible === true) {
|
||||
let payload = {
|
||||
position: undefined,
|
||||
visible: false
|
||||
};
|
||||
|
||||
switch (floatingObject.type) {
|
||||
|
||||
case "Profile Ball": {
|
||||
|
||||
payload.position = floatingObject.payload.profile.position;
|
||||
payload.visible = floatingObject.payload.profile.visible;
|
||||
break;
|
||||
}
|
||||
case "Bubble": {
|
||||
|
||||
payload.position = floatingObject.payload.bubbles[floatingObject.payload.bubbleIndex].position;
|
||||
payload.visible = floatingObject.payload.bubbles[floatingObject.payload.bubbleIndex].visible;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (payload.visible === true) {
|
||||
|
||||
/* The first time that the floatingObject becomes visible, we need to do this. */
|
||||
|
||||
floatingObject.radomizeCurrentPosition(floatingObject.input.position);
|
||||
floatingObject.radomizeCurrentPosition(payload.position);
|
||||
floatingObject.radomizeCurrentSpeed();
|
||||
|
||||
thisObject.floatingObjects.push(floatingObject);
|
||||
@@ -179,14 +229,14 @@ function newFloatingLayer() {
|
||||
}
|
||||
}
|
||||
|
||||
function gravityForce(floatingObject) {
|
||||
function gravityForce(floatingObject, payload) {
|
||||
|
||||
/* 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 d = Math.sqrt(Math.pow(payload.position.x - floatingObject.currentPosition.x, 2) + Math.pow(payload.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.
|
||||
|
||||
@@ -200,8 +250,8 @@ function newFloatingLayer() {
|
||||
};
|
||||
|
||||
var pos2 = {
|
||||
x: floatingObject.input.position.x,
|
||||
y: floatingObject.input.position.y
|
||||
x: payload.position.x,
|
||||
y: payload.position.y
|
||||
};
|
||||
|
||||
var posDiff = { // Next we need the vector resulting from the 2 positions.
|
||||
|
||||
@@ -3,7 +3,9 @@ function newFloatingObject() {
|
||||
|
||||
var thisObject = {
|
||||
|
||||
input: undefined, // This object contains information needed to draw the floating object, but also referenced from outside, so as to have control of the basics of the floating object.
|
||||
payload: undefined, // This is a reference to an object controlled by a Plotter. The plotter can change its internal value and we will see them from here.
|
||||
type: undefined, // Currently there are two types of Floating Objects: Profile Balls, and Bubbles.
|
||||
|
||||
physicsEnabled: false,
|
||||
|
||||
initializeMass: initializeMass,
|
||||
@@ -67,6 +69,13 @@ function newFloatingObject() {
|
||||
}
|
||||
case "Bubble": {
|
||||
|
||||
underlayingObject = newBubble();
|
||||
underlayingObject.initialize(onInitialized);
|
||||
|
||||
function onInitialized(err) {
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -75,6 +84,8 @@ function newFloatingObject() {
|
||||
}
|
||||
}
|
||||
|
||||
thisObject.type = pType;
|
||||
|
||||
callBackFunction();
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ function newProfileBall() {
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
browserCanvasContext.moveTo(pFloatingObject.currentPosition.x, pFloatingObject.currentPosition.y);
|
||||
browserCanvasContext.lineTo(pFloatingObject.input.position.x, pFloatingObject.input.position.y);
|
||||
browserCanvasContext.lineTo(pFloatingObject.payload.profile.position.x, pFloatingObject.payload.profile.position.y);
|
||||
browserCanvasContext.strokeStyle = 'rgba(204, 204, 204, 0.5)';
|
||||
browserCanvasContext.setLineDash([4, 2]);
|
||||
browserCanvasContext.lineWidth = 1;
|
||||
@@ -41,7 +41,7 @@ function newProfileBall() {
|
||||
var radius = 1;
|
||||
|
||||
browserCanvasContext.beginPath();
|
||||
browserCanvasContext.arc(pFloatingObject.input.position.x, pFloatingObject.input.position.y, radius, 0, Math.PI * 2, true);
|
||||
browserCanvasContext.arc(pFloatingObject.payload.profile.position.x, pFloatingObject.payload.profile.position.y, radius, 0, Math.PI * 2, true);
|
||||
browserCanvasContext.closePath();
|
||||
browserCanvasContext.fillStyle = 'rgba(30, 30, 30, 1)';
|
||||
browserCanvasContext.fill();
|
||||
@@ -90,9 +90,9 @@ function newProfileBall() {
|
||||
|
||||
/* Image */
|
||||
|
||||
if (pFloatingObject.input.imageId !== undefined) {
|
||||
if (pFloatingObject.payload.profile.imageId !== undefined) {
|
||||
|
||||
let image = document.getElementById(pFloatingObject.input.imageId);
|
||||
let image = document.getElementById(pFloatingObject.payload.profile.imageId);
|
||||
|
||||
if (image !== null) {
|
||||
|
||||
@@ -114,7 +114,7 @@ function newProfileBall() {
|
||||
|
||||
let label;
|
||||
|
||||
label = pFloatingObject.input.upLabel;
|
||||
label = pFloatingObject.payload.profile.upLabel;
|
||||
|
||||
if (label !== undefined) {
|
||||
|
||||
@@ -129,7 +129,7 @@ function newProfileBall() {
|
||||
|
||||
}
|
||||
|
||||
label = pFloatingObject.input.downLabel;
|
||||
label = pFloatingObject.payload.profile.downLabel;
|
||||
|
||||
if (label !== undefined) {
|
||||
|
||||
|
||||
@@ -42,14 +42,14 @@ function newProfileBalls() {
|
||||
}
|
||||
}
|
||||
|
||||
function createNewProfileBall(pInput, pContainer, callBackFunction) {
|
||||
function createNewProfileBall(pPayload, pContainer, callBackFunction) {
|
||||
|
||||
let floatingObject = newFloatingObject();
|
||||
floatingObject.initialize("Profile Ball", onInitialized);
|
||||
|
||||
function onInitialized(err) {
|
||||
|
||||
floatingObject.input = pInput;
|
||||
floatingObject.payload = pPayload;
|
||||
|
||||
floatingObject.container = pContainer;
|
||||
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
<Compile Include="AccumulatedVolumeBar.js" />
|
||||
<Compile Include="Animation.js" />
|
||||
<Compile Include="Azure\azure-storage.blob.js" />
|
||||
<Compile Include="FloatingSpace\Bubble.js">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="FloatingSpace\BubbleSets.js">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
|
||||
+15
-9
@@ -307,27 +307,33 @@
|
||||
|
||||
/* Create The Profie Picture FloatingObject */
|
||||
|
||||
if (productPlotter.plotter.profile !== undefined) {
|
||||
if (productPlotter.plotter.payload !== undefined) {
|
||||
|
||||
let imageId = pProductCard.bot.devTeam + "." + pProductCard.bot.profilePicture;
|
||||
|
||||
productPlotter.plotter.profile.upLabel = pProductCard.product.shortDisplayName;
|
||||
productPlotter.plotter.profile.downLabel = pProductCard.bot.displayName;
|
||||
productPlotter.plotter.profile.imageId = imageId;
|
||||
productPlotter.plotter.payload.profile.upLabel = pProductCard.product.shortDisplayName;
|
||||
productPlotter.plotter.payload.profile.downLabel = pProductCard.bot.displayName;
|
||||
productPlotter.plotter.payload.profile.imageId = imageId;
|
||||
|
||||
canvas.floatingSpace.profileBalls.createNewProfileBall(productPlotter.plotter.profile, thisObject.container, onProfileBallCreated)
|
||||
canvas.floatingSpace.profileBalls.createNewProfileBall(productPlotter.plotter.payload, thisObject.container, onProfileBallCreated)
|
||||
|
||||
function onProfileBallCreated(err, pProfileHandle) {
|
||||
|
||||
productPlotter.profile = pProfileHandle;
|
||||
|
||||
}
|
||||
|
||||
/* Create the Text Bubbles */
|
||||
|
||||
canvas.floatingSpace.bubbleSets.createBubbleSet(productPlotter.plotter.payload, productPlotter.plotter.container.eventHandler, onBubbleSetCreated);
|
||||
|
||||
function onBubbleSetCreated(err, pBubbleSetHandle) {
|
||||
|
||||
productPlotter.bubbleSet = pBubbleSetHandle;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the Text Bubbles */
|
||||
|
||||
productPlotter.bubbleSet = canvas.floatingSpace.bubbleSets.createBubbleSet(productPlotter.plotter.bubbles);
|
||||
|
||||
/* Add the new Active Protter to the Array */
|
||||
|
||||
productPlotters.push(productPlotter);
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
<script type="text/javascript" src="Azure/azure-storage.blob.js"></script>
|
||||
|
||||
<script type="text/javascript" src="FloatingSpace/BubbleSets.js"></script>
|
||||
<script type="text/javascript" src="FloatingSpace/Bubble.js"></script>
|
||||
<script type="text/javascript" src="FloatingSpace/ProfileBalls.js"></script>
|
||||
<script type="text/javascript" src="FloatingSpace/ProfileBall.js"></script>
|
||||
<script type="text/javascript" src="FloatingSpace/FloatingObject.js"></script>
|
||||
|
||||
Reference in new issue
Block a user