I am using the the forkit jQuery ribbon that drops down a curtain of additional content. I have managed to apply this and it works fine once the ribbon is pulled down as per the fiddle.
I want to modify it such that, the curtain also appears once a button is clicked.
Kindly help.
jQuery:
(function(){
var STATE_CLOSED = 0,
STATE_DETACHED = 1,
STATE_OPENED = 2,
TAG_HEIGHT = 30,
TAG_WIDTH = 200,
MAX_STRAIN = 40,
// Factor of page height that needs to be dragged for the
// curtain to fall
DRAG_THRESHOLD = 0.36;
VENDORS = [ 'Webkit', 'Moz', 'O', 'ms' ];
var dom = {
ribbon: null,
ribbonString: null,
ribbonTag: null,
curtain: null,
closeButton: null
},
// The current state of the ribbon
state = STATE_CLOSED,
// Ribbon text, correlates to states
closedText = '',
detachedText = '',
friction = 1.04;
gravity = 1.5,
// Resting position of the ribbon when curtain is closed
closedX = TAG_WIDTH * 0.4,
closedY = -TAG_HEIGHT * 0.5,
// Resting position of the ribbon when curtain is opened
openedX = TAG_WIDTH * 0.4,
openedY = TAG_HEIGHT,
velocity = 0,
rotation = 45,
curtainTargetY = 0,
curtainCurrentY = 0,
dragging = false,
dragTime = 0,
dragY = 0,
anchorA = new Point( closedX, closedY ),
anchorB = new Point( closedX, closedY ),
mouse = new Point();
function initialize() {
dom.ribbon = document.querySelector( '.forkit' );
dom.curtain = document.querySelector( '.forkit-curtain' );
dom.closeButton = document.querySelector( '.forkit-curtain .close-button' );
if( dom.ribbon ) {
// Fetch label texts from DOM
closedText = dom.ribbon.getAttribute( 'data-text' ) || '';
detachedText = dom.ribbon.getAttribute( 'data-text-detached' ) || closedText;
// Construct the sub-elements required to represent the
// tag and string that it hangs from
dom.ribbon.innerHTML = '<span class="string"></span><span class="tag">' + closedText + '</span>';
dom.ribbonString = dom.ribbon.querySelector( '.string' );
dom.ribbonTag = dom.ribbon.querySelector( '.tag' );
// Bind events
dom.ribbon.addEventListener( 'click', onRibbonClick, false );
document.addEventListener( 'mousemove', onMouseMove, false );
document.addEventListener( 'mousedown', onMouseDown, false );
document.addEventListener( 'mouseup', onMouseUp, false );
window.addEventListener( 'resize', layout, false );
if( dom.closeButton ) {
dom.closeButton.addEventListener( 'click', onCloseClick, false );
}
// Start the animation loop
animate();
}
}
function onMouseDown( event ) {
if( dom.curtain && state === STATE_DETACHED ) {
event.preventDefault();
dragY = event.clientY;
dragTime = Date.now();
dragging = true;
}
}
function onMouseMove( event ) {
mouse.x = event.clientX;
mouse.y = event.clientY;
}
function onMouseUp( event ) {
if( state !== STATE_OPENED ) {
state = STATE_CLOSED;
dragging = false;
}
}
function onRibbonClick( event ) {
if( dom.curtain ) {
event.preventDefault();
if( state === STATE_OPENED ) {
close();
}
else if( Date.now() - dragTime < 300 ) {
open();
}
}
}
function onCloseClick( event ) {
event.preventDefault();
close();
}
function layout() {
if( state === STATE_OPENED ) {
curtainTargetY = window.innerHeight;
curtainCurrentY = curtainTargetY;
}
}
function open() {
dragging = false;
state = STATE_OPENED;
}
function close() {
dragging = false;
state = STATE_CLOSED;
dom.ribbonTag.innerHTML = closedText;
}
function detach() {
state = STATE_DETACHED;
dom.ribbonTag.innerHTML = detachedText;
}
function animate() {
update();
render();
requestAnimFrame( animate );
}
function update() {
// Distance between mouse and top right corner
var distance = distanceBetween( mouse.x, mouse.y, window.innerWidth, 0 );
// If we're OPENED the curtainTargetY should ease towards page bottom
if( state === STATE_OPENED ) {
curtainTargetY = Math.min( curtainTargetY + ( window.innerHeight - curtainTargetY ) * 0.2, window.innerHeight );
}
else {
// Detach the tag when hovering close enough
if( distance < TAG_WIDTH * 1.5 ) {
detach();
}
// Re-attach the tag if the user moved away
else if( !dragging && state === STATE_DETACHED && distance > TAG_WIDTH * 2 ) {
close();
}
if( dragging ) {
// Updat the curtain position while dragging
curtainTargetY = Math.max( mouse.y - dragY, 0 );
// If the threshold is crossed, open the curtain
if( curtainTargetY > window.innerHeight * DRAG_THRESHOLD ) {
open();
}
}
else {
curtainTargetY *= 0.8;
}
}
// Ease towards the target position of the curtain
curtainCurrentY += ( curtainTargetY - curtainCurrentY ) * 0.3;
// If we're dragging or detached we need to simulate
// the physical behavior of the ribbon
if( dragging || state === STATE_DETACHED ) {
// Apply forces
velocity /= friction;
velocity += gravity;
var containerOffsetX = dom.ribbon.offsetLeft;
var offsetX = Math.max( ( ( mouse.x - containerOffsetX ) - closedX ) * 0.2, -MAX_STRAIN );
anchorB.x += ( ( closedX + offsetX ) - anchorB.x ) * 0.1;
anchorB.y += velocity;
var strain = distanceBetween( anchorA.x, anchorA.y, anchorB.x, anchorB.y );
if( strain > MAX_STRAIN ) {
velocity -= Math.abs( strain ) / ( MAX_STRAIN * 1.25 );
}
var dy = Math.max( mouse.y - anchorB.y, 0 ),
dx = mouse.x - ( containerOffsetX + anchorB.x );
// Angle the ribbon towards the mouse but limit it avoid extremes
var angle = Math.min( 130, Math.max( 50, Math.atan2( dy, dx ) * 180 / Math.PI ) );
rotation += ( angle - rotation ) * 0.1;
}
// Ease ribbon towards the OPENED state
else if( state === STATE_OPENED ) {
anchorB.x += ( openedX - anchorB.x ) * 0.2;
anchorB.y += ( openedY - anchorB.y ) * 0.2;
rotation += ( 90 - rotation ) * 0.02;
}
// Ease ribbon towards the CLOSED state
else {
anchorB.x += ( anchorA.x - anchorB.x ) * 0.2;
anchorB.y += ( anchorA.y - anchorB.y ) * 0.2;
rotation += ( 45 - rotation ) * 0.2;
}
}
function render() {
if( dom.curtain ) {
dom.curtain.style.top = - 100 + Math.min( ( curtainCurrentY / window.innerHeight ) * 100, 100 ) + '%';
}
dom.ribbon.style[ prefix( 'transform' ) ] = transform( 0, curtainCurrentY, 0 );
dom.ribbonTag.style[ prefix( 'transform' ) ] = transform( anchorB.x, anchorB.y, rotation );
var dy = anchorB.y - anchorA.y,
dx = anchorB.x - anchorA.x;
var angle = Math.atan2( dy, dx ) * 180 / Math.PI;
dom.ribbonString.style.width = anchorB.y + 'px';
dom.ribbonString.style[ prefix( 'transform' ) ] = transform( anchorA.x, 0, angle );
}
function prefix( property, el ) {
var propertyUC = property.slice( 0, 1 ).toUpperCase() + property.slice( 1 );
for( var i = 0, len = VENDORS.length; i < len; i++ ) {
var vendor = VENDORS[i];
if( typeof ( el || document.body ).style[ vendor + propertyUC ] !== 'undefined' ) {
return vendor + propertyUC;
}
}
return property;
}
function transform( x, y, r ) {
return 'translate('+x+'px,'+y+'px) rotate('+r+'deg)';
}
function distanceBetween( x1, y1, x2, y2 ) {
var dx = x1-x2;
var dy = y1-y2;
return Math.sqrt(dx*dx + dy*dy);
}
/**
* Defines a 2D position.
*/
function Point( x, y ) {
this.x = x || 0;
this.y = y || 0;
}
Point.prototype.distanceTo = function( x, y ) {
var dx = x-this.x;
var dy = y-this.y;
return Math.sqrt(dx*dx + dy*dy);
};
Point.prototype.clone = function() {
return new Point( this.x, this.y );
};
Point.prototype.interpolate = function( x, y, amp ) {
this.x += ( x - this.x ) * amp;
this.y += ( y - this.y ) * amp;
};
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
initialize();
})();
You need to add an event handler to a button that calls the open() method from the forkit plugin, like this:
$('#dropButton').bind('click', function(){
open();
});
Here is a working JSFiddle
Just add this to it - should work.
$('a.forkit').click(function(){
$('.forkit-curtain').slideDown();
});
https://jsfiddle.net/eaj5rvtm/1/
Related
So I am trying to get the clearInterval to work. This is from: https://codepen.io/whqet/pen/Auzch (I modified it a bit to make it more towards what I needed. Essentially, I want the animation to cease after 10000 ms. Excuse the messy coding, I threw in a timer at the bottom so I could see whether or not it would work.. Any assistance would be appreciated. Thanks!
var canvas = document.getElementById( 'canvas' ),
ctx = canvas.getContext( '2d' ),
// full screen dimensions
cw = window.innerWidth,
ch = window.innerHeight,
// firework collection
fireworks = [],
// particle collection
particles = [],
// starting hue
hue = 120,
// when launching fireworks with a click, too many get launched at once without a limiter, one launch per 5 loop ticks
limiterTotal = 5,
limiterTick = 0,
// this will time the auto launches of fireworks, one launch per 60 loop ticks
timerTotal = 60,
timerTick = 0,
mousedown = false,
// mouse x coordinate,
mx,
// mouse y coordinate
my;
// set canvas dimensions
canvas.width = cw;
canvas.height = ch;
// now we are going to setup our function placeholders for the entire demo
// get a random number within a range
function random( min, max ) {
return Math.random() * ( max - min ) + min;
}
// calculate the distance between two points
function calculateDistance( p1x, p1y, p2x, p2y ) {
var xDistance = p1x - p2x,
yDistance = p1y - p2y;
return Math.sqrt( Math.pow( xDistance, 2 ) + Math.pow( yDistance, 2 ) );
}
// create firework
function Firework( sx, sy, tx, ty ) {
// actual coordinates
this.x = sx;
this.y = sy;
// starting coordinates
this.sx = sx;
this.sy = sy;
// target coordinates
this.tx = tx;
this.ty = ty;
// distance from starting point to target
this.distanceToTarget = calculateDistance( sx, sy, tx, ty );
this.distanceTraveled = 0;
// track the past coordinates of each firework to create a trail effect, increase the coordinate count to create more prominent trails
this.coordinates = [];
this.coordinateCount = 3;
// populate initial coordinate collection with the current coordinates
while( this.coordinateCount-- ) {
this.coordinates.push( [ this.x, this.y ] );
}
this.angle = Math.atan2( ty - sy, tx - sx );
this.speed = 2;
this.acceleration = 1.05;
this.brightness = random( 50, 70 );
// circle target indicator radius
this.targetRadius = 1;
}
// update firework
Firework.prototype.update = function( index ) {
// remove last item in coordinates array
this.coordinates.pop();
// add current coordinates to the start of the array
this.coordinates.unshift( [ this.x, this.y ] );
// cycle the circle target indicator radius
if( this.targetRadius < 8 ) {
this.targetRadius += 0.3;
} else {
this.targetRadius = 1;
}
// speed up the firework
this.speed *= this.acceleration;
// get the current velocities based on angle and speed
var vx = Math.cos( this.angle ) * this.speed,
vy = Math.sin( this.angle ) * this.speed;
// how far will the firework have traveled with velocities applied?
this.distanceTraveled = calculateDistance( this.sx, this.sy, this.x + vx, this.y + vy );
// if the distance traveled, including velocities, is greater than the initial distance to the target, then the target has been reached
if( this.distanceTraveled >= this.distanceToTarget ) {
createParticles( this.tx, this.ty );
// remove the firework, use the index passed into the update function to determine which to remove
fireworks.splice( index, 1 );
} else {
// target not reached, keep traveling
this.x += vx;
this.y += vy;
}
}
// draw firework
Firework.prototype.draw = function() {
ctx.beginPath();
// move to the last tracked coordinate in the set, then draw a line to the current x and y
ctx.moveTo( this.coordinates[ this.coordinates.length - 1][ 0 ], this.coordinates[ this.coordinates.length - 1][ 1 ] );
ctx.lineTo( this.x, this.y );
ctx.strokeStyle = 'hsl(' + hue + ', 100%, ' + this.brightness + '%)';
ctx.stroke();
ctx.beginPath();
// draw the target for this firework with a pulsing circle
ctx.arc( this.tx, this.ty, this.targetRadius, 0, Math.PI * 2 );
ctx.stroke();
}
// create particle
function Particle( x, y ) {
this.x = x;
this.y = y;
// track the past coordinates of each particle to create a trail effect, increase the coordinate count to create more prominent trails
this.coordinates = [];
this.coordinateCount = 5;
while( this.coordinateCount-- ) {
this.coordinates.push( [ this.x, this.y ] );
}
// set a random angle in all possible directions, in radians
this.angle = random( 0, Math.PI * 2 );
this.speed = random( 1, 10 );
// friction will slow the particle down
this.friction = 0.95;
// gravity will be applied and pull the particle down
this.gravity = 1;
// set the hue to a random number +-50 of the overall hue variable
this.hue = random( hue - 50, hue + 50 );
this.brightness = random( 50, 80 );
this.alpha = 1;
// set how fast the particle fades out
this.decay = random( 0.015, 0.03 );
}
// update particle
Particle.prototype.update = function( index ) {
// remove last item in coordinates array
this.coordinates.pop();
// add current coordinates to the start of the array
this.coordinates.unshift( [ this.x, this.y ] );
// slow down the particle
this.speed *= this.friction;
// apply velocity
this.x += Math.cos( this.angle ) * this.speed;
this.y += Math.sin( this.angle ) * this.speed + this.gravity;
// fade out the particle
this.alpha -= this.decay;
// remove the particle once the alpha is low enough, based on the passed in index
if( this.alpha <= this.decay ) {
particles.splice( index, 1 );
}
}
// draw particle
Particle.prototype.draw = function() {
ctx. beginPath();
// move to the last tracked coordinates in the set, then draw a line to the current x and y
ctx.moveTo( this.coordinates[ this.coordinates.length - 1 ][ 0 ], this.coordinates[ this.coordinates.length - 1 ][ 1 ] );
ctx.lineTo( this.x, this.y );
ctx.strokeStyle = 'hsla(' + this.hue + ', 100%, ' + this.brightness + '%, ' + this.alpha + ')';
ctx.stroke();
}
// create particle group/explosion
function createParticles( x, y ) {
// increase the particle count for a bigger explosion, beware of the canvas performance hit with the increased particles though
var particleCount = 300;
while( particleCount-- ) {
particles.push( new Particle( x, y ) );
}
}
// main demo loop
function loop() {
// this function will run endlessly with requestAnimationFrame
requestAnimFrame( loop );
// increase the hue to get different colored fireworks over time
//hue += 0.5;
// create random color
hue= random(0, 360 );
// normally, clearRect() would be used to clear the canvas
// we want to create a trailing effect though
// setting the composite operation to destination-out will allow us to clear the canvas at a specific opacity, rather than wiping it entirely
ctx.globalCompositeOperation = 'destination-out';
// decrease the alpha property to create more prominent trails
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
ctx.fillRect( 0, 0, cw, ch );
// change the composite operation back to our main mode
// lighter creates bright highlight points as the fireworks and particles overlap each other
ctx.globalCompositeOperation = 'lighter';
// loop over each firework, draw it, update it
var i = fireworks.length;
while( i-- ) {
fireworks[ i ].draw();
fireworks[ i ].update( i );
}
// loop over each particle, draw it, update it
var i = particles.length;
while( i-- ) {
particles[ i ].draw();
particles[ i ].update( i );
}
// launch fireworks automatically to random coordinates, when the mouse isn't down
if( timerTick >= timerTotal ) {
if( !mousedown ) {
// start the firework at the bottom middle of the screen, then set the random target coordinates, the random y coordinates will be set within the range of the top half of the screen
fireworks.push( new Firework( cw / 2, ch, random( 0, cw ), random( 0, ch / 2 ) ) );
timerTick = 0;
}
} else {
timerTick++;
}
// limit the rate at which fireworks get launched when mouse is down
if( limiterTick >= limiterTotal ) {
if( mousedown ) {
// start the firework at the bottom middle of the screen, then set the current mouse coordinates as the target
fireworks.push( new Firework( cw / 2, ch, mx, my ) );
limiterTick = 0;
}
} else {
limiterTick++;
}
}
// mouse event bindings
// update the mouse coordinates on mousemove
canvas.addEventListener( 'mousemove', function( e ) {
mx = e.pageX - canvas.offsetLeft;
my = e.pageY - canvas.offsetTop;
});
// toggle mousedown state and prevent canvas from being selected
canvas.addEventListener( 'mousedown', function( e ) {
e.preventDefault();
mousedown = true;
});
canvas.addEventListener( 'mouseup', function( e ) {
e.preventDefault();
mousedown = false;
});
// once the window loads, we are ready for some fireworks!
window.onload = loop;
// when animating on canvas, it is best to use requestAnimationFrame instead of setTimeout or setInterval
window.requestAnimFrame = ( function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( ) {
window.setTimeout( timePeriodms );
};
function stopFireworks () {
var timePeriodms = 10000;
window.clearTimeout(timePeriodms);
};
})();
// now we will setup our basic variables for the demo
var minute = 0;
var sec = 00;
var zeroPholder = 0;
var counterIdv2 = setInterval(function(){
countUp2();
}, 1000);
function countUp2 () {
sec++;
if(sec == 60){
sec = 00;
minute = minute + 1;
}
if (minute == 0 && sec == 1) {
document.getElementById('count-up-2').style.color = 'red';
}
if (minute == 0 && sec == 59) {
document.getElementById('count-up-2').style.color = 'blue';
}
if (minute == 10 && sec == 00) {
document.getElementById('count-up-2').style.color = 'red';
}
if(sec == 10){
zeroPholder = '';
}else
if(sec == 00){
zeroPholder = 0;
}
document.getElementById("count-up-2").innerText = minute+':'+zeroPholder+sec;
}
body {
background: #000;
margin: 0;
}
canvas {
display: block;
}
<canvas id="canvas">Canvas is not supported in your browser.</canvas>
<table border="1" style="border-color:black;">
<tbody>
<tr>
<td style="background-color: #fff; padding: 5px;"><span>Time spent on page: </span><span id="count-up-2">0:00</span>
</td>
</tr>
</tbody>
</table>
requestAnimationFrame callback's argument
When requestAnimationFrame calls the callback function it supplies a high precision time in ms. You can use this time to control the timing of your animations.
For example the following animation loop will stop 10 seconds after the first frame is called.
requestAnimationFrame(mainLoop);
var startTime;
const endTime = 10000; // in ms
function mainLoop(time) {
if (startTime === undefined) { startTime = time }
if (time - startTime > endTime) {
console.log("Animation end.");
return;
}
// draw animated content
requestAnimationFrame(mainLoop);
}
This gives you better timing control in animations than using setTimeout especially if you have more than one thing to control the timing of (see demo)
Demo
The demo uses the same method to count down the time and control the fireworks. A few seconds before the end the fireworks are held back and then a second before a group are fired to explode in time with zero (Well there about!!!)
// Code based loosely on OPs code in so far as it animates fireworks.
// There is no control of fireworks via mouse.
// Uses reusable buffers to avoid GC overhead in low end devices.
const ctx = canvas.getContext( '2d' );
const GRAVITY = 0.2; // per frame squared
var cw = canvas.width = innerWidth - 40;
var ch = canvas.height = 500;
const iH = innerHeight;
var startTime;
const DISPLAY_TIME = 10000; // in ms. Time to countdown
const SHELL_X = cw / 2; // Location that shells are fired from in px
const SHELL_Y = ch;
const SHELL_TIME = 100; // in frames
const MAX_SHELLS = 8;
const MAX_PARTICLES = 1000; // Approx max particles.
const SHELL_RANDOM_RATE = 0.01; // cof of shell random fire control
const SHELL_FIRE_CURVE = 3; // Highest power of fire control exponents
var randomFire = 0; // holds the odds of a random shell being fired
Math.TAU = Math.PI * 2;
Math.PI90 = Math.PI / 2;
Math.PI270 = Math.PI + Math.PI90;
Math.rand = (m, M) => Math.random() * (M - m) + m;
Math.distance = (x1, y1, x2, y2) => ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5;
requestAnimationFrame(mainLoop);
function mainLoop(time) {
if (startTime === undefined) { startTime = time }
const timer = DISPLAY_TIME - (time - startTime);
const displayTime = timer / 1000 | 0;
if (timer <= 0) {
countdown.textContent = "HAPPY NEW YEAR 2020";
if(particles.size === 0 && shells.size === 0) {
ctx.clearRect(0,0,cw,ch);
shells.clear();
startTime = undefined;
countdown.textContent = "Click to restart";
canvas.addEventListener("click",() => requestAnimationFrame(mainLoop), {once: true});
return; // ends update
} else {
randomFire = 0; // pervent shells firing after zero time
}
} else {
countdown.textContent !== displayTime && (countdown.textContent = displayTime);
}
ctx.lineCap = "round";
ctx.globalCompositeOperation = 'destination-out';
ctx.globalAlpha = 0.2;
ctx.fillStyle = "#000"
ctx.fillRect( 0, 0, cw, ch );
ctx.globalCompositeOperation = 'lighter';
shells.update();
particles.update();
ctx.lineWidth = 2;
shells.draw();
ctx.lineWidth = 3;
particles.draw();
if (timer < 2500 && timer > 1000) { randomFire = 0 }
else if(timer <= 1000 && timer > 0) { randomFire = 1 }
if(shells.size < MAX_SHELLS && particles.size < MAX_PARTICLES) {
if(Math.random() < randomFire ** SHELL_FIRE_CURVE) {
randomFire = 0;
shells.fire(
Math.rand(cw * (1/3), cw *(2/3)),
Math.rand(iH * (3/4), iH *(4/4)),
SHELL_TIME
);
}
randomFire += SHELL_RANDOM_RATE;
}
requestAnimationFrame(mainLoop);
}
function Trail() {}
function Particle() { }
function Shell( sx, sy, tx, ty ) {
this.trail = new Trail();
this.init(sx, sy,tx,sy);
}
Trail.prototype = {
init(x, y) {
this.x1 = this.x2 = this.x3 = x;
this.y1 = this.y2 = this.y3 = y;
},
update(x, y) {
this.x3 = this.x2
this.y3 = this.y2
this.x2 = this.x1
this.y2 = this.y1
this.x1 = x;
this.y1 = y;
},
draw() {
ctx.moveTo(this.x1, this.y1);
ctx.lineTo(this.x2, this.y2);
ctx.lineTo(this.x3, this.y3);
}
};
Shell.prototype = {
init(x, y, time) {
this.x = SHELL_X;
this.y = SHELL_Y;
this.sx = (x - this.x) / (time / 2);
this.sy = ((y - this.y) * (GRAVITY / ((time) ** 0.5)))* 2;
this.power = (-this.sy * 10) | 0;
this.hue = Math.rand(360, 720) % 360 | 0;
this.active = true;
this.trail.init(this.x, this.y);
this.time = time / 2;
this.life = time / 2;
},
explode() {
this.active = false;
particles.explode(this, this.power);
},
update() {
this.time -= 1;
if (this.time <= 0) { this.explode() }
this.sy += GRAVITY;
this.x += this.sx;
this.y += this.sy;
this.trail.update(this.x, this.y);
return this.active;
},
draw() {
ctx.strokeStyle = `hsl(${this.hue},100%,${(this.time / this.life) * 100}%)`;
ctx.beginPath();
this.trail.draw();
ctx.stroke();
},
};
Particle.prototype = {
init(shell) {
this.x2 = this.x1 = this.x = shell.x;
this.y2 = this.y1 = this.y = shell.y;
this.dx = shell.sx;
this.dy = shell.sy;
this.angle = Math.rand(0, Math.TAU);
const zAng = Math.cos(Math.random() ** 2 * Math.PI)
this.speed = zAng * shell.power / 30;
this.friction = 0.95;
this.gravity = GRAVITY;
this.hue = (Math.rand(shell.hue - 5, shell.hue + 5) + 360) % 360;
this.brightness = Math.rand( 25, 50 );
this.alpha = shell.power / 10;
this.decay = Math.rand( 0.2, 0.5);
this.active = true;
},
update() {
const dx = Math.cos(this.angle);
const dy = Math.sin(this.angle);
this.x2 = this.x1;
this.y2 = this.y1;
this.x1 = this.x - dx;
this.y1 = this.y + dy;
this.speed *= this.friction;
this.x += (this.dx *= 0.9);
this.y += (this.dy *= 0.9);
this.dy += GRAVITY / 100;
this.x += dx * this.speed;
this.y += dy * this.speed;
this.alpha -= this.decay;
if( this.alpha <= 0 || this.x < 0 || this.y < 0 || this.x > cw) {
this.active = false;
}
return this.active;
},
draw() {
const alpha = this.alpha / 5 > 1 ? 1 : this.alpha / 5;
const lum = this.brightness + this.alpha
ctx.strokeStyle = `hsla(${this.hue},100%,${lum<100 ? lum : 100}%,${alpha})`;
ctx. beginPath();
ctx.moveTo( this.x2, this.y2);
ctx.lineTo( this.x, this.y );
ctx.stroke();
}
};
function BubbleArray(extension) {
return Object.assign([], {
size: 0,
update() {
var read = 0, write = 0;
while (read < this.size) {
const item = this[read];
if(read !== write) {
const temp = this[write]
this[write] = item;
this[read] = temp;
}
item.update() === true && (write ++);
read++;
}
this.size = write;
},
draw() {
var i = 0,len = this.size;
while(i < len) { this[i++].draw() }
},
add(item) {
this.size ++;
this.push(item);
},
clear() { this.length = this.size = 0 },
getInactive() { return this.size < this.length ? this[this.size++] : undefined },
},
extension,
);
}
const particles = BubbleArray({
explode(shell, count) {
var item;
while(count-- > 0) {
!(item = this.getInactive()) && this.add(item = new Particle());
item.init(shell);
}
},
});
const shells = BubbleArray({
fire(tx = mx, ty = my) {
var item;
!(item = this.getInactive()) && this.add(item = new Shell());
item.init(tx, ty, 100);
}
});
body {
padding: 0px;
}
canvas {
background: #000;
position: absolute;
top: 0px;
left: 0px;
}
#countdown {
position: absolute;
top: 20px;
left: 20px;
font-family: arial;
font-size: xx-large;
color: white;
}
<canvas id="canvas"></canvas>
<div id="countdown"></div>
Can someone help! I am simulating a cloth attached to their 4 corners. I am trying to re-locate the 4 pins 0, 10, 88, 98 of the Cloth with an 10x10 array. I want to be able to place each Pin at a different position in x,y,z.
For this simulation I am using Three.js and Cloth.js.
Something similar to this example:
[https://threejs.org/examples/#webgl_animation_cloth][1]
Here is my Code and also the Cloth code I am using.
var pinsFormation = [];
pinsFormation.push( pins );
pins = [ 0, 10, 88, 98 ];
var container, stats;
var camera, scene, renderer, clothGeometry, object;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
scene = new THREE.Scene();
scene.background = new THREE.Color( 0xFFFFFF );
camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 1000, 50, 1000 );
// cloth
var material_wire = new THREE.MeshBasicMaterial( { color : 0x000000, side: THREE.DoubleSide, wireframe: true } );
clothGeometry = new THREE.ParametricGeometry( clothFunction, cloth.w, cloth.h );
object = new THREE.Mesh( clothGeometry, material_wire ); // clothMaterial
object.position.set( 0, 0, 0 );
scene.add( object );
// renderer
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.maxPolarAngle = Math.PI * 1.5;
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
var time = Date.now();
var windStrength = Math.cos( time / 7000 ) * 20 + 40;
windForce.set( Math.sin( time / 2000 ), Math.cos( time / 3000 ), Math.sin( time / 1000 ) )
windForce.normalize()
windForce.multiplyScalar( windStrength );
simulate( time );
render();
}
function render() {
var p = cloth.particles;
for ( var i = 0, il = p.length; i < il; i ++ ) {
clothGeometry.vertices[ i ].copy( p[ i ].position );
}
clothGeometry.verticesNeedUpdate = true;
clothGeometry.computeFaceNormals();
clothGeometry.computeVertexNormals();
renderer.render( scene, camera );
}
// cloth.js
var DAMPING = 0.03;
var DRAG = 1 - DAMPING;
var MASS = 0.1;
var restDistance = 25;
var xSegs = 10;
var ySegs = 10;
var clothFunction = plane( restDistance * xSegs, restDistance * ySegs );
var cloth = new Cloth( xSegs, ySegs );
var GRAVITY = 981 * 1.4;
var gravity = new THREE.Vector3( 0, - GRAVITY, 0 ).multiplyScalar( MASS );
var TIMESTEP = 18 / 1000;
var TIMESTEP_SQ = TIMESTEP * TIMESTEP;
var pins = [];
var wind = true;
var windStrength = 2;
var windForce = new THREE.Vector3( 0, 0, 0 );
var tmpForce = new THREE.Vector3();
var lastTime;
function plane( width, height ) {
return function( u, v ) {
var x = ( u - 0.5 ) * width;
var y = ( v - 0.1 ) * height;
var z = 0;
return new THREE.Vector3( x, y, z );
};
}
function Particle( x, y, z, mass ) {
this.position = clothFunction( x, y ); // position
this.previous = clothFunction( x, y ); // previous
this.original = clothFunction( x, y );
this.a = new THREE.Vector3( 0, 0, 0 ); // acceleration
this.mass = mass;
this.invMass = 1 / mass;
this.tmp = new THREE.Vector3();
this.tmp2 = new THREE.Vector3();
}
// Force -> Acceleration
Particle.prototype.addForce = function( force ) {
this.a.add(
this.tmp2.copy( force ).multiplyScalar( this.invMass )
);
};
// Performs Verlet integration
Particle.prototype.integrate = function( timesq ) {
var newPos = this.tmp.subVectors( this.position, this.previous );
newPos.multiplyScalar( DRAG ).add( this.position );
newPos.add( this.a.multiplyScalar( timesq ) );
this.tmp = this.previous;
this.previous = this.position;
this.position = newPos;
this.a.set( 0, 0, 0 );
};
var diff = new THREE.Vector3();
function satisfyConstraints( p1, p2, distance ) {
diff.subVectors( p2.position, p1.position );
var currentDist = diff.length();
if ( currentDist === 0 ) return;
var correction = diff.multiplyScalar( 1 - distance / currentDist );
var correctionHalf = correction.multiplyScalar( 0.5 );
p1.position.add( correctionHalf );
p2.position.sub( correctionHalf );
}
function Cloth( w, h ) {
w = w || 20;
h = h || 20;
this.w = w;
this.h = h;
var particles = [];
var constraints = [];
var u, v;
// Create particles
for ( v = 0; v <= h; v ++ ) {
for ( u = 0; u <= w; u ++ ) {
particles.push(
new Particle( u / w, v / h, 0, MASS )
);
}
}
// Structural
for ( v = 0; v < h; v ++ ) {
for ( u = 0; u < w; u ++ ) {
constraints.push( [
particles[ index( u, v ) ],
particles[ index( u, v + 1 ) ],
restDistance
] );
constraints.push( [
particles[ index( u, v ) ],
particles[ index( u + 1, v ) ],
restDistance
] );
}
}
for ( u = w, v = 0; v < h; v ++ ) {
constraints.push( [
particles[ index( u, v ) ],
particles[ index( u, v + 1 ) ],
restDistance
] );
}
for ( v = h, u = 0; u < w; u ++ ) {
constraints.push( [
particles[ index( u, v ) ],
particles[ index( u + 1, v ) ],
restDistance
] );
}
this.particles = particles;
this.constraints = constraints;
function index( u, v ) {
return u + v * ( w + 1 );
}
this.index = index;
}
function simulate( time ) {
if ( ! lastTime ) {
lastTime = time;
return;
}
var i, il, particles, particle, pt, constraints, constraint;
// Aerodynamics forces
if ( wind ) {
var face, faces = clothGeometry.faces, normal;
particles = cloth.particles;
for ( i = 0, il = faces.length; i < il; i ++ ) {
face = faces[ i ];
normal = face.normal;
tmpForce.copy( normal ).normalize().multiplyScalar( normal.dot( windForce ) );
particles[ face.a ].addForce( tmpForce );
particles[ face.b ].addForce( tmpForce );
particles[ face.c ].addForce( tmpForce );
}
}
for ( particles = cloth.particles, i = 0, il = particles.length; i < il; i ++ ) {
particle = particles[ i ];
particle.addForce( gravity );
particle.integrate( TIMESTEP_SQ );
}
// Start Constraints
constraints = cloth.constraints;
il = constraints.length;
for ( i = 0; i < il; i ++ ) {
constraint = constraints[ i ];
satisfyConstraints( constraint[ 0 ], constraint[ 1 ], constraint[ 2 ] );
}
// Pin Constraints
for ( i = 0, il = pins.length; i < il; i ++ ) {
var xy = pins[ i ];
var p = particles[ xy ];
p.position.copy( particles.original );
p.previous.copy( particles.original );
}
}
The "pin" is just the index of one of the vertices.. so what you'll have to do is identify the vertex corresponding to the spot you want to pin.. you can get that from a raycast when the user clicks the mesh, or figure it our analytically.
I am aiming to attach a slider onto this codepen animation, so the user can edit the speed of the animation.
At the moment, I am not getting any errors, but I am not getting the value from the input slider passed through to the animation.
this.speed = dotSpeed;
I am aiming to take the value from the slider, create a variable and put it through the "function Circle" properties.
var dotArray = [];
function threeDotSliderChangeSpeed (value) {
document.getElementById('threeDotSpeed').innerHTML = value;
dotSpeed = +value; // + will convert the string to number
for (var i = 0; i < dotArray.length; i++) {
dotArray[i].speed = Math.round(1 * dotSpeed);
}
}
var canvas = document.getElementById( 'canvas2' ),
c = canvas.getContext( '2d' ),
i = 0,
rowOne = [],
rowTwo = [],
rowThree = [],
length = canvas.width * 0.4,
origin = [ canvas.width / 2, canvas.height / 2 ],
angle = 90,
dotSpeed = 2,
loop;
function Circle( args ) {
this.position = [ 0, 0 ];
this.angle = 30;
this.speed = dotSpeed;
this.offset = 1;
this.length = 100;
this.size = 5;
this.color = '#fff';
this.direction = 'grow';
if ( 'undefined' !== typeof args.position )
this.position = args.position;
if ( 'undefined' !== typeof args.angle )
this.angle = args.angle;
if ( 'undefined' !== typeof args.speed )
this.speed = args.speed;
if ( 'undefined' !== typeof args.length )
this.length = args.length;
if ( 'undefined' !== typeof args.size )
this.size = args.size;
if ( 'undefined' !== typeof args.color )
this.color = args.color;
if ( 'undefined' !== typeof args.offset ) {
this.offset = args.offset;
this.length = canvas.width * this.offset * 0.03
}
}
Circle.prototype.render = function() {
this.move();
this.draw();
}
Circle.prototype.draw = function() {
c.fillStyle = this.color;
c.beginPath();
c.arc( this.position[0], this.position[1], ( this.size / 2 ), 0, Math.PI * 2, true );
c.closePath();
c.fill();
}
Circle.prototype.move = function() {
this.angle = ( this.angle < 360 ) ? this.angle + this.speed : 0;
if ( 'grow' == this.direction ) {
this.length++;
this.direction = ( 150 >= this.length ) ? 'grow' : 'shrink';
} else {
this.length--;
this.direction = ( 50 <= this.length ) ? 'shrink' : 'grow';
}
this.position[0] = this.length * Math.sin( this.angle * ( Math.PI / 180 ) );
this.position[1] = this.length * Math.cos( this.angle * ( Math.PI / 180 ) );
this.position[0] = this.position[0] + origin[0];
this.position[1] = this.position[1] + origin[1];
}
for ( i = 1; i < 10; i++ ) {
var offset = 1;
rowOne.push( new Circle( {
angle: 0,
offset: i
} ) );
rowTwo.push( new Circle( {
angle: 120,
offset: i
} ) );
rowThree.push( new Circle( {
angle: 240,
offset: i
} ) );
}
function render() {
c.fillStyle = 'rgba( 0, 0, 0, 0.025 )';
c.fillRect( 0, 0, canvas.width, canvas.height );
for ( i = 0; i < 9; i++ ) {
rowOne[i].render();
rowTwo[i].render();
rowThree[i].render();
}
}
(function animate() {
render();
loop = setTimeout( animate, 40 );
})();
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CodePen - 3 dotted-line canvas animation.</title>
<link rel="stylesheet" href="css/style.css">
<script type="text/javascript" src="jquery-2.1.0.min.js"></script>
</head>
<body>
<canvas id="canvas2" width="400" height="400"></canvas>
<p id="attribute">Speed </p>
<span id="threeDotSpeed" class="sliderSpan">5</span>
<input type="range" min="0" max="10" value="5" step="1" onchange="threeDotSliderChangeSpeed(3)"/>
<br /> <br />
<script src="js/index.js"></script>
</body>
</html>
Here is a video of another one I got going, using the same method.
https://www.youtube.com/watch?v=vjZ6CfQ2WrY&feature=youtu.be
To get the value from the slider you need to get the value from the element
by using document.getElementById('rg').value on change event
js:
var dotArray = [];
function threeDotSliderChangeSpeed () {
var value = document.getElementById('rg').value;
alert(value);
document.getElementById('threeDotSpeed').innerHTML = value;
dotSpeed = +value; // + will convert the string to number
for (var i = 0; i < dotArray.length; i++) {
dotArray[i].speed = Math.round(1 * dotSpeed);
}
}
var canvas = document.getElementById( 'canvas2' ),
c = canvas.getContext( '2d' ),
i = 0,
rowOne = [],
rowTwo = [],
rowThree = [],
length = canvas.width * 0.4,
origin = [ canvas.width / 2, canvas.height / 2 ],
angle = 90,
dotSpeed = 2,
loop;
function Circle( args ) {
this.position = [ 0, 0 ];
this.angle = 30;
this.speed = dotSpeed;
this.offset = 1;
this.length = 100;
this.size = 5;
this.color = '#fff';
this.direction = 'grow';
if ( 'undefined' !== typeof args.position )
this.position = args.position;
if ( 'undefined' !== typeof args.angle )
this.angle = args.angle;
if ( 'undefined' !== typeof args.speed )
this.speed = args.speed;
if ( 'undefined' !== typeof args.length )
this.length = args.length;
if ( 'undefined' !== typeof args.size )
this.size = args.size;
if ( 'undefined' !== typeof args.color )
this.color = args.color;
if ( 'undefined' !== typeof args.offset ) {
this.offset = args.offset;
this.length = canvas.width * this.offset * 0.03
}
}
Circle.prototype.render = function() {
this.move();
this.draw();
}
Circle.prototype.draw = function() {
c.fillStyle = this.color;
c.beginPath();
c.arc( this.position[0], this.position[1], ( this.size / 2 ), 0, Math.PI * 2, true );
c.closePath();
c.fill();
}
Circle.prototype.move = function() {
this.angle = ( this.angle < 360 ) ? this.angle + this.speed : 0;
if ( 'grow' == this.direction ) {
this.length++;
this.direction = ( 150 >= this.length ) ? 'grow' : 'shrink';
} else {
this.length--;
this.direction = ( 50 <= this.length ) ? 'shrink' : 'grow';
}
this.position[0] = this.length * Math.sin( this.angle * ( Math.PI / 180 ) );
this.position[1] = this.length * Math.cos( this.angle * ( Math.PI / 180 ) );
this.position[0] = this.position[0] + origin[0];
this.position[1] = this.position[1] + origin[1];
}
for ( i = 1; i < 10; i++ ) {
var offset = 1;
rowOne.push( new Circle( {
angle: 0,
offset: i
} ) );
rowTwo.push( new Circle( {
angle: 120,
offset: i
} ) );
rowThree.push( new Circle( {
angle: 240,
offset: i
} ) );
}
function render() {
c.fillStyle = 'rgba( 0, 0, 0, 0.025 )';
c.fillRect( 0, 0, canvas.width, canvas.height );
for ( i = 0; i < 9; i++ ) {
rowOne[i].render();
rowTwo[i].render();
rowThree[i].render();
}
}
(function animate() {
render();
loop = setTimeout( animate, 40 );
})();
Html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CodePen - 3 dotted-line canvas animation.</title>
<link rel="stylesheet" href="css/style.css">
<script type="text/javascript" src="jquery-2.1.0.min.js"></script>
</head>
<body>
<canvas id="canvas2" width="400" height="400"></canvas>
<p id="attribute">Speed </p>
<span id="threeDotSpeed" class="sliderSpan">5</span>
<input type="range" min="0" max="10" value="5" step="1" id="rg" onchange="threeDotSliderChangeSpeed(3)"/>
<br />
<br />
<script src="js/index.js"></script>
</body>
</html>
i am able to get the slider value on alert
you can see output in codepin
http://codepen.io/anon/pen/aOOjXE
I have a canvas in a PhoneGap app for iPhone and I'm building a lock pattern into it, using something very similar to < How I can create a pattern login like Android in HTML5? >. I rewrote parts to keep jQuery off the app, and also the circles and line are much less detailed.
I am doing desktop testing in Chrome, and also checked in Safari, this code works great and just as expected. My problem, however, is that nothing gets rendered on my iPhone 5 nor the iOS Simulator.
GLOBAL.Swiper = function( element , width , height ) {
var _self = this;
var theCanvas;
var code = '';
var stopDrawing = false;
var dragging=false;
var event = {
start : 'ontouchstart' in window ? 'touchstart' : 'mousedown',
move : 'ontouchstart' in window ? 'touchmove' : 'mousemove',
end : 'ontouchstart' in window ? 'touchend' : 'mouseup'
}
getCode = function() {
return code;
}
resetCode = function() {
code = '';
}
init = function( element , width , height) {
// Mark the Canvas, get its context, and set up the options
theCanvas = {
el: element,
ctx : element.getContext('2d'),
height : height || element.height,
width : width || element.width,
pad : 20 ,
circles : [],
selectedCircles : [],
startPoint : {x:0, y:0}
}
var rad = (theCanvas.width - theCanvas.pad * 4) / 3;
// Set up the circles
for ( var i=0;i<3;i++ ) {
for ( var j=0;j<3;j++ ) {
theCanvas.circles.push ( new Circle ({
x : j * ( theCanvas.pad + rad ) + theCanvas.pad + rad / 2,
y : i * ( theCanvas.pad + rad ) + theCanvas.pad + rad / 2
}, rad / 2) )
}
}
theCanvas.el.addEventListener (event.start , onStart );
theCanvas.el.addEventListener (event.move , onMove );
theCanvas.el.addEventListener (event.end , onEnd );
console.log ("Swiper Initialized");
drawCircles();
}
/**
* Circle
**/
Circle = function (center, radius, fill, stroke, hover, active) {
console.log ("NEW CIRCLE CREATED");
var center = {
x: center.x,
y: center.y
},
radius = radius,
fill = fill || '#482b5a',
hover = hover || '#663d80',
active = active || '#71b644',
stroke = stroke || '';
this.position = function(){
return {x:center.x, y:center.y};
}
this.draw = function(ctx) {
ctx.fillStyle = this.selected ? active : this.hovering ? hover : fill;
if (stroke) ctx.strokeStyle = stroke;
ctx.beginPath();
ctx.arc(center.x, center.y, radius, 0, Math.PI * 2, false);
ctx.closePath();
ctx.fill();
if (stroke) ctx.stroke();
};
this.isPointInPath = function(x, y) {
return Math.sqrt(Math.pow(center.x - x, 2) + Math.pow(center.y - y, 2)) <= radius;
};
this.hovering = false;
this.selected = false;
}
/**
* drawCircles
**/
drawCircles = function() {
var ctx = theCanvas.ctx;
ctx.clearRect(0,0,theCanvas.width,theCanvas.height);
for (var i = 0; i < theCanvas.circles.length; i++) {
theCanvas.circles[i].draw(ctx);
}
// Draw the lines connecting each circle
if (dragging && theCanvas.selectedCircles.length > 1) {
var pos = theCanvas.selectedCircles[0].circ.position();
ctx.beginPath();
ctx.lineWidth = 10;
ctx.strokeStyle = "#251";
ctx.moveTo(pos.x, pos.y);
for (var j = 1; j < theCanvas.selectedCircles.length; j++){
pos = theCanvas.selectedCircles[j].circ.position();
ctx.lineTo(pos.x,pos.y);
}
ctx.stroke();
ctx.closePath();
}
}
/**
* events - onStart, onMove, onEnd
**/
onStart = function() {
dragging = true;
drawCircles();
}
onMove = function(e) {
for (var i = 0; i < theCanvas.circles.length; i++) {
var cir = theCanvas.circles[i];
var pip = cir.isPointInPath(e.offsetX, e.offsetY);
cir.hovering = pip;
if (dragging && pip && !cir.selected) {
theCanvas.selectedCircles.push({circ:cir, index:i});
cir.selected = true;
}
drawCircles();
}
}
onEnd = function() {
dragging = false;
code = '';
while ( theCanvas.selectedCircles.length > 0 ) {
var singleCircle;
theCanvas.selectedCircles[0].circ.selected = false;
singleCircle = theCanvas.selectedCircles.shift();
code += (singleCircle.index + 1).toString();
}
alert (code);
// reset selection
for (var i = 0; i < theCanvas.selectedCircles.length; i++)
theCanvas.selectedCircles[i].circ.selected = false;
theCanvas.selectedCircles = [];
drawCircles();
}
if ( element ) init ( element , width , height);
return {
init : init,
draw : drawCircles,
getCode : getCode,
resetCode : resetCode,
c : theCanvas
}
}
As usual, any help will be appreciated.
this is my situation:
I want to show twitter tweets like this: http://threejs.org/examples/css3d_periodictable.html
This is what I have now:http://nielsvroman.be/twitter/root/index.php
The boxes are tweets from the user: #BachelorGDM.
What I would like now is that there is always one selected and that you can navigate through them with the arrow keys on the keyboard.
This is my javascript code:
// THE TWEETS
var data = loadTweets()
// FUNCTION SHOW THE TWEETS
function ShowTweets(){
// VARS TABLE WITH TWEETS / PLACE IN COLUMN / PLACE IN ROW
var table = [];
var column = 1;
var row = 1;
// LOOP THROUGH DATA AND CREATE TABLE WITH TWEET DETAILS + PLACE
$.each(data, function(i) {
// DETAILS TWEET
var idstring = data[i].id_str;
var screenname = data[i].user.screen_name;
var imageurl = data[i].user.profile_image_url;
// 9 TWEETS NEXT TO EACH OTHER
if(column % 9 == 0)
{
row++
column = 1;
}
var array = [imageurl, idstring, screenname, column, row ]
column++;
table.push(array);
});
// VARIABLES THREE JS
var camera, scene, renderer;
var controls;
var objects = [];
var targets = { table: [], sphere: [], helix: [], grid: [] };
init(); // CALL INIT FUNCTION
animate(); // CALL ANIMATE FUNCTION
function init() {
// INITIALIZE CAMERA
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 5000 );
camera.position.z = 1800;
// INITIALIZE SCENE
scene = new THREE.Scene();
// LOOP THROUGH TABLE ARRAY (ARRAY WITH ARRAYS IN IT)
for ( var i = 0; i < table.length; i ++ ) {
var item = table[i]; // ITEM IS ARRAY WITH [imageurl, idstring, screenname, column, row]
var element = document.createElement( 'div' );
element.className = 'element';
element.id = item[1]; // ITEM IDSTRING
element.style.backgroundColor = 'rgba(0,127,127,' + ( Math.random() * 0.5 + 0.25 ) + ')'; // BG COLOR + OPACITY FROM FRAME
var number = document.createElement( 'div' );
number.className = 'number';
number.textContent = i + 1; // NUMBER IN THE RIGHT TOP
element.appendChild( number );
var symbol = document.createElement( 'div' );
symbol.className = 'symbol';
var img = document.createElement('img');
img.src = item[0]; // IMAGE SOURCE IS LINK TO IMAGE
symbol.appendChild(img);
element.appendChild( symbol );
var details = document.createElement( 'div' );
details.className = 'details';
details.innerHTML = "" + '<br>' + item[2]; // SCREENNAME
element.appendChild( details );
var object = new THREE.CSS3DObject( element );
// POSITION OBJECTS AGAINST EACH OTHER
object.position.x = Math.random() * 4000 - 2000;
object.position.y = Math.random() * 4000 - 2000;
object.position.z = Math.random() * 4000 - 2000;
// ADD OBJECTS TO SCENE
scene.add(object);
// ADD OBJECT TO OBJECTS ARRAY
objects.push(object);
}
// TABLE VIEW
for ( var i = 0; i < objects.length; i ++ ) {
var item = table[i]; // ITEM IS ARRAY WITH [imageurl, idstring, screenname, column, row]
var object = new THREE.Object3D();
object.position.x = ( item[3] * 160 ) - 1540; // X-POSITION (COLUMN)
object.position.y = - ( item[4] * 200 ) + 1100; // Y-POSITION (ROW)
// targets = { table: [], sphere: [], helix: [], grid: [] };
targets.table.push(object); // PUSH OBJECT IN TABLE ARRAY (IN TARGETS ARRAY)
}
// SPHERE VIEW
var vector = new THREE.Vector3();
for ( var i = 0, l = objects.length; i < l; i ++ ) {
var phi = Math.acos( -1 + ( 2 * i ) / l );
var theta = Math.sqrt( l * Math.PI ) * phi;
var object = new THREE.Object3D();
object.position.x = 1000 * Math.cos( theta ) * Math.sin( phi );
object.position.y = 1000 * Math.sin( theta ) * Math.sin( phi );
object.position.z = 1000 * Math.cos( phi );
vector.copy( object.position ).multiplyScalar( 2 );
object.lookAt( vector );
// targets = { table: [], sphere: [], helix: [], grid: [] };
targets.sphere.push( object ); // PUSH OBJECT IN SPHERES ARRAY (IN TARGETS ARRAY)
}
// HELIX VIEW
var vector = new THREE.Vector3();
for ( var i = 0, l = objects.length; i < l; i ++ ) {
var phi = i * 0.175 + Math.PI;
var object = new THREE.Object3D();
object.position.x = 1100 * Math.sin( phi );
object.position.y = - ( i * 8 ) + 450;
object.position.z = 1100 * Math.cos( phi );
vector.copy( object.position );
vector.x *= 2;
vector.z *= 2;
object.lookAt( vector );
// targets = { table: [], sphere: [], helix: [], grid: [] };
targets.helix.push( object ); // PUSH OBJECT IN HELIX ARRAY (IN TARGETS ARRAY)
}
// GRID VIEW
for ( var i = 0; i < objects.length; i ++ ) {
var object = new THREE.Object3D();
object.position.x = ( ( i % 5 ) * 400 ) - 800;
object.position.y = ( - ( Math.floor( i / 5 ) % 5 ) * 400 ) + 800;
object.position.z = ( Math.floor( i / 25 ) ) * 1000 - 2000;
// targets = { table: [], sphere: [], helix: [], grid: [] };
targets.grid.push( object ); // PUSH OBJECT IN GRID ARRAY (IN TARGETS ARRAY)
}
renderer = new THREE.CSS3DRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.domElement.style.position = 'absolute';
// ADD RENDERER TO CONTAINER
document.getElementById( 'container' ).appendChild( renderer.domElement );
// TRACKBALLCONTROLS => WHEN YOU HOLD DOWN MOUSECLICK
controls = new THREE.TrackballControls( camera, renderer.domElement );
controls.rotateSpeed = 0.5;
//controls.minDistance = 500; // MAX ZOOM IN => MIN DISTANCE
controls.maxDistance = 2500; // MAX ZOOM OUT => MAX DISTANCE
controls.zoomSpeed = 1; // STANDARD IS 1.2
controls.keys = [ 37 /*LEFT*/, 38 /*UP*/, 39 /*RIGHT*/, 40 /*DOWN*/ ];
controls.addEventListener( 'change', render ); // RENDER ON CHANGE
var button = document.getElementById( 'table' );
button.addEventListener( 'click', function ( event ) {
transform( targets.table, 2000 );
}, false );
var button = document.getElementById( 'sphere' );
button.addEventListener( 'click', function ( event ) {
transform( targets.sphere, 2000 );
}, false );
var button = document.getElementById( 'helix' );
button.addEventListener( 'click', function ( event ) {
transform( targets.helix, 2000 );
}, false );
var button = document.getElementById( 'grid' );
button.addEventListener( 'click', function ( event ) {
transform( targets.grid, 2000 );
}, false );
transform( targets.table, 5000 );
//
window.addEventListener( 'resize', onWindowResize, false );
// WHEN PRESSED ON KEY
window.addEventListener( 'keydown', keydown, false );
function keydown( event ) {
};
}
function transform( targets, duration ) {
TWEEN.removeAll();
for ( var i = 0; i < objects.length; i ++ ) {
var object = objects[ i ];
var target = targets[ i ];
new TWEEN.Tween( object.position )
.to( { x: target.position.x, y: target.position.y, z: target.position.z }, Math.random() * duration + duration )
.easing( TWEEN.Easing.Exponential.InOut )
.start();
new TWEEN.Tween( object.rotation )
.to( { x: target.rotation.x, y: target.rotation.y, z: target.rotation.z }, Math.random() * duration + duration )
.easing( TWEEN.Easing.Exponential.InOut )
.start();
}
new TWEEN.Tween( this )
.to( {}, duration * 2 )
.onUpdate( render )
.start();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
TWEEN.update();
controls.update();
}
// RENDER SCENE/CAMERA
function render() {
renderer.render( scene, camera );
}
}
My tweets are initially in the variable data.
I now have added this to my code:
controls.keys = [ 37 /*LEFT*/, 38 /*UP*/, 39 /*RIGHT*/, 40 /*DOWN*/ ];
window.addEventListener( 'keydown', keydown, false );
function keydown( event ) {};
But now how can I navigate through the tweets (boxes) with my arrows on the keyboard?
I want to change the css of the selected box and open an overlay of the associated tweet. (You can see this when you click on a box on the link)
I have no clue on how to start with this. Can somebody help me?
You could make a stylesheet with a "selected" class, which when you click one of the elements, it removes all other instances of the class "selected" and adds ".selected" to that specific element that was clicked. Then with keyboard input, you do the same thing, but move to the next element. It could be simplified a bit with jQuery, though done without as well.
.element .selected {
background-color: #cccccc;
}
javascript:
document.addEventListener("click", function(e) {
if (e.target === *element you want*)
// remove other selected classes code here.
document.addClass += " " + ".selected"