selecting nearby hexes around a hex - javascript

I'm trying to select all hexes in a given range. However I'm getting weird results while implement this code found on Amit Patel's page.
var results = []
for each -N ≤ dx ≤ N:
for each max(-N, -dx-N) ≤ dy ≤ min(N, -dx+N):
var dz = -dx-dy
results.append(cube_add(center, Cube(dx, dy, dz)))
This is what I have so far:
var center = this._cel.copy( hex.coords );
var dx = range - center.q;
var dy = range - center.r;
var results = [];
for (var q = -range; q <= dx; q++ ) {
var r1 = Math.max(-range, -q - range);
var r2 = Math.min(range, -q + range);
for ( var r = r1; r <= r2; r++ ) {
//console.log( q, r, -q-r )
var c = new Cell(q, r, -q-r)
results.push( c.add( center ) );
}
}
I suppose that the loop constrains need to me a little bit amended and make use of the dx, dy values.
<body>
<canvas width="420px" height="420px" id="myCanvas" style="margin:0; padding:0; border:1px solid #d3d3d3;"></canvas>
</body>
<script id="hexagon">
function Point( pos ) {
this.x = 0;
this.y = 0;
if( typeof( pos ) !== "undefined" ){
this.x = pos[0];
this.y = pos[1];
}
};
function Cell( _q, _r, _s ){ //// direction ///
this.q = _q;
this.r = _r;
this.s = _s;
this._hashID = null;
this.generateHashID();
}
Cell.prototype = {
constructor: Cell,
add: function( d ){
this.q += d.q;
this.r += d.r;
this.s += d.s;
this.generateHashID();
return this;
},
copy: function( c ){
this.set( c.q, c.r, c.s );
return this;
},
set: function( _q, _r, _s ){
this.q = _q;
this.r = _r;
this.s = _s;
this.generateHashID();
return this;
},
generateHashID: function(){
this._hashID = this.q+"."+this.r+"."+this.s;
},
getHashID: function(){
return this._hashID;
},
round: function(){
var q = Math.trunc(Math.round(this.q));
var r = Math.trunc(Math.round(this.r));
var s = Math.trunc(Math.round(this.s));
var q_diff = Math.abs(q - this.q);
var r_diff = Math.abs(r - this.r);
var s_diff = Math.abs(s - this.s);
if (q_diff > r_diff && q_diff > s_diff){
q = -r - s;
}else if (r_diff > s_diff){
r = -q - s;
}else{
s = -q - r;
}
return this.set( q, r, s );
}
}
var Hex = function( coords, l_ ){ //// [axial], [cartesian] , layout
this.coords = new Cell( coords[0], coords[1], coords[2] );
this.content = -2;
this.pos = this.coords; //// set primary coorinate type ///
this.neighbors = [];
this.layout = l_;
this.corners = [];
this.center = this.get_center_p();
//this.id = this.generate_id( cart_coord );
this.colors = {
"base" : {
filling : "#008844",
border : "#FFDD88",
},
"selected": {
filling: "#00cc00"
},
"hovered": {
filling: "#006600"
},
"path" : {
filling: "#80ff00"
},
"obstacle" : {
filling: "#86592d"
},
"neighbor": {
filling: "#ffbf00"
}
}
this.states = {
"selected" : false,
"hovered" : false,
"isPath": false,
"isObstacle": false,
"isNeighbor": false
}
this.generate_corners();
};
Hex.prototype = {
constructor: Hex,
get_corner_offset: function( corner ){
var angle = 2.0 * Math.PI * (corner + this.layout.orientation.start_angle) / 6;
return new Point( [ size.x * Math.cos(angle), size.y * Math.sin(angle) ] );
},
generate_corners: function( h ){
var offset = null, angle = 0;
var size = this.layout.size;
for (var i = 0; i < 6; i++) {
angle = 2.0 * Math.PI * (i + this.layout.orientation.start_angle) / 6;
offset = new Point( [ size.x * Math.cos(angle), size.y * Math.sin(angle )] );
this.corners.push(
new Point( [ this.center.x + offset.x, this.center.y + offset.y ] )
);
}
},
draw: function( ctx ){
var points = this.corners;
ctx.beginPath();
ctx.moveTo( points[0].x, points[0].y );
for(var i = 1; i < points.length; i++){
var p = points[i];
ctx.lineTo(p.x, p.y);
}
ctx.closePath();
//// fill Hex ///
if( this.checkState("selected") ){
ctx.fillStyle = this.colors.selected.filling;
}else if( this.checkState("hovered") ){
ctx.fillStyle = this.colors.hovered.filling;
}else if( this.checkState("isPath") ){
ctx.fillStyle = this.colors.path.filling;
}else if( this.checkState("isNeighbor") ){
ctx.fillStyle = this.colors.neighbor.filling;
}else if( this.checkState("isObstacle") ){
ctx.fillStyle = this.colors.obstacle.filling;
}else{
ctx.fillStyle = this.colors.base.filling;
}
ctx.fill();
//// draw border ///
ctx.lineWidth = 1;
ctx.strokeStyle = "#19334d";
ctx.stroke();
this.draw_coords( ctx );
this.draw_center_point( ctx );
},
add_neighbor: function( neighbor ){
this.neighbors.push( neighbor );
},
show_neighbors: function(){
for( var nb = 0, nb_l = this.neighbors.length; nb < nb_l; nb++ ){
this.neighbors[nb].changeState("isNeighbor", true);
}
},
hide_neighbors: function(){
for( var nb = 0, nb_l = this.neighbors.length; nb < nb_l; nb++ ){
this.neighbors[nb].changeState("isNeighbor", false);
}
},
draw_coords: function( ctx ){
var text = this.coords.q+" : "+ this.coords.s;
var text_z = this.coords.r;
var metrics1 = ctx.measureText(text);
var metrics2 = ctx.measureText(text_z);
var w1 = metrics1.width;
var w2 = metrics2.width;
var h = 8;
ctx.font = h+'pt Calibri bold';
ctx.textAlign = 'center';
ctx.fillStyle = '#FFFFFF';
ctx.fillText(text, this.center.x, this.center.y + (h/2) - 5 );
ctx.fillText(text_z, this.center.x, this.center.y + (h/2) + 7 );
},
get_center_p: function(){
var M = this.layout.orientation;
var x = ( M.f0 * this.pos.q + M.f1 * this.pos.r ) * this.layout.size.x;
var y = ( M.f2 * this.pos.q + M.f3 * this.pos.r ) * this.layout.size.y;
return new Point([
x + this.layout.origin.x,
y + this.layout.origin.y
]);
},
draw_center_point: function( ctx ){
ctx.beginPath();
ctx.lineWidth="1";
ctx.fillStyle="red";
ctx.arc( this.center.x , this.center.y , 2, 0 ,2*Math.PI);
ctx.closePath();
ctx.stroke();
ctx.fill();
},
generate_id: function( coords ){
return parseInt( coords[0]+''+coords[1] );
},
checkState: function( state ){
return this.states[ state ];
},
changeState: function( state , value){
this.states[ state ] = value;
},
trigger: function( ev_name ){
if( this.events[ ev_name ] ){
this.events[ ev_name ].call( this );
}
},
setContent: function( type ){
this.content = type;
this.changeState( "isObstacle" , true );
},
hover: function(){
if( ! this.checkState("isPath") ){
this.trigger("hover");
}
},
clear_hover: function(){
if( ! this.checkState("isPath") ){
this.trigger("clear_hover");
}
},
select: function(){
this.trigger("select");
//this.show_neighbors();
},
unselect: function(){
this.trigger("unselect");
},
events: {
select: function(){
this.changeState("selected", true);
this.changeState("hovered", false);
},
unselect: function(){
this.changeState("selected", false);
},
hover: function(){
this.changeState("hovered", true);
},
clear_hover: function(){
this.changeState("hovered", false);
}
}
};
</script>
<script id="grid">
var Grid = function( size, hex_size, origin, ctx_pos, layout_type ){
this.size = size;
this.grid_r = size/2;
this.layout_type = layout_type;
this.layout = this.set_layout( this.layout_types[this.layout_type], hex_size, origin );
this.hexes = [];
this.hovered = [null, null]; //// [cur, prev] ///
this.selected = [null, null]; ///// [cur , prev] ///
this.dots = [];
this._list = [];
this._cel = new Cell();
this._directions = [new Cell(+1, 0, -1), new Cell(+1, -1, 0), new Cell(0, -1, +1),
new Cell(-1, 0, +1), new Cell(-1, +1, 0), new Cell(0, +1, -1)];
this.generate();
this.add_neighbors();
this.mouse = new Point();
this.mouse_events( new Point( ctx_pos ) );
}
Grid.prototype = {
constructor: Grid,
layout_types: {
"pointy": [
[ Math.sqrt(3.0), Math.sqrt(3.0) / 2.0, 0.0, 3.0 / 2.0], //// 2x2 forward matrix
[ Math.sqrt(3.0) / 3.0, -1.0 / 3.0, 0.0, 2.0 / 3.0], ///// 2x2 inverse matrix
0.5
], //// starting angle in multiples of 60° /////
"flat": [
[3.0 / 2.0, 0.0, Math.sqrt(3.0) / 2.0, Math.sqrt(3.0)], //// 2x2 forward matrix
[2.0 / 3.0, 0.0, -1.0 / 3.0, Math.sqrt(3.0) / 3.0], ///// 2x2 inverse matrix
1.0
]
},
set_layout: function( orn_type , hex_s_, ogn_ ){
return {
orientation: this.set_orientation( orn_type ), ///// orientation type ///
size: new Point( [ hex_s_ , hex_s_ ] ), ///// hex size ///
origin: new Point( ogn_ ) //// Grid center /////
}
},
set_orientation: function( opts ){ /// [0] : forward_matrix, [1] : inverse_matrix, [2] : starting_angle
return {
f0: opts[0][0], f1: opts[0][1], f2: opts[0][2], f3: opts[0][3], b0: opts[1][0], b1: opts[1][1], b2: opts[1][2], b3: opts[1][3], start_angle: opts[2]
}
},
get_hex_at_p: function( p ){ //// point ///
var M = this.layout.orientation;
var pt = new Point( [ (p.x - this.layout.origin.x) / this.layout.size.x, (p.y - this.layout.origin.y) / this.layout.size.y ] );
var q = M.b0 * pt.x + M.b1 * pt.y;
var r = M.b2 * pt.x + M.b3 * pt.y;
var c = this._cel.set( q, r, -q-r );
return c.round();
},
generate: function(){
var n_hex = null;
for (var q = -this.grid_r; q <= this.grid_r; q++) {
var r1 = Math.max(-this.grid_r, -q - this.grid_r);
var r2 = Math.min(this.grid_r, -q + this.grid_r);
for (var r = r1; r <= r2; r++) {
n_hex = new Hex( [ q, r, -q-r ], this.layout );
this.hexes[ n_hex.coords.getHashID() ] = n_hex;
}
}
},
_selectHexesInRange: function( hex, range ){
var center = this._cel.copy( hex.coords );
var dx = range - center.q;
var dy = range - center.r;
var results = [];
for (var q = -range; q <= dx; q++ ) {
var r1 = Math.max(-range, -q - range);
var r2 = Math.min(range, -q + range);
for ( var r = r1; r <= r2; r++ ) {
var c = new Cell(q, r, -q-r)
results.push( c.add( center ) );
}
}
for( var h in results){
if( typeof( this.hexes[results[h].getHashID()]) !== "undefined" ){
this.hexes[results[h].getHashID()].select()
}
}
//console.log( results )
},
hex_corner_offset : function ( corner ) {
var size = this.layout.size;
var angle = 2.0 * Math.PI * (this.layout.orientation.start_angle - corner) / 6;
return new Point([size.x * Math.cos(angle), size.y * Math.sin(angle)]);
},
point_add : function(p, q) {
return new Point([p.x + q.x, p.y + q.y]);
},
add_neighbors: function(){
var nbor = null, hex = null;
for( var h in this.hexes ){
hex = this.hexes[h];
var i, n, l = this._directions.length;
this._list.length = 0;//// reset array ///
for ( i = 0; i < l; i++ ) {
this._cel.copy( hex.coords );
this._cel.add( this._directions[i] );
n = this.hexes[ this._cel.getHashID() ];
if (typeof(n) == "undefined") { ///// if doesn't exists ////
this._list.push( null );
continue;
}
this._list.push(n);
}
hex.neighbors = this._list.slice(); //// take copy of the array ////
}
},
draw: function( ctx ){
for( var h in this.hexes ){
this.hexes[h].draw( ctx );
}
},
checkCollisions: function(){
var h_pos = this.get_hex_at_p( this.mouse );
var hex = this.hexes[ h_pos.getHashID() ];
if( typeof(hex) !== "undefined" ){
if( this.hovered[0] == null ){ //// cur
this.hovered[0] = hex;
this.hovered[0].hover();
}else{
this.hovered[1] = this.hovered[0];
this.hovered[0] = hex;
if( this.hovered[0].coords._hashID != this.hovered[1].coords._hashID ){
this.hovered[1].clear_hover();
this.hovered[1] = null;
}
}
this.hovered[0].hover();
}
},
mouse_events: function( ctx_pos ){
var self = this;
window.addEventListener( 'mousemove', function(e){
self.mouse.x = ( e.clientX - ctx_pos.x );
self.mouse.y = ( e.clientY - ctx_pos.y );
});
window.addEventListener( 'mousedown', function(e){
//console.log( "neighbors : ",self.hovered[0].neighbors )
self._selectHexesInRange( self.hovered[0], 2);
});
}
}
</script>
<script id="main">
var c_el = document.getElementById("myCanvas");
var ctx = c_el.getContext("2d");
var nGrid = new Grid( 6, 25, [ c_el.width / 2, c_el.height / 2 ], [c_el.getBoundingClientRect().left, c_el.getBoundingClientRect().top], "pointy" );
function animate(){
window.requestAnimationFrame( animate );
ctx.clearRect(0, 0, c_el.width, c_el.height);
nGrid.checkCollisions();
nGrid.draw( ctx);
}
animate();
</script>

Just take the coordinates x, y, z and then search all fields to one of this calculations:
z is const, x is plus/minus 1, y is minus/plus 1
x is const, z is plus/minus 1, y is minus/plus 1
y is const, z is plus/minus 1, x is minus/plus 1
This should be all neighbors
Example: Filed 0, 1, -1 (x,y,z)
z is const and x is plus/minus 1 => [-1, 2,-1], [ 1, 0,-1]
x is const and z is plus/minus 1 => [ 0, 2,-2], [ 0, 0, 0]
y is const and z is plus/minus 1 => [ 1, 1,-2], [-1, 1, 0]
For a faster search you can store your cells inside a Object like this:
var cells = new Object();
for(x=-2; x<3; x++){
cells[x] = new Object();
for(y=-2; y<3; y++){
cells[x][y] = new Object();
for(z=-2; z<3; z++){
cells[x][y][z] = cell;
}
}
}
Then you can access the cells by there coordinates:
var x = 0;
var y = 1;
var z = -1;
var neighbors = new Array();
neighbors.push(cells[x-1][y+1][z]);
neighbors.push(cells[x+1][y-1][z]);
neighbors.push(cells[x][y+1][z-1]);
neighbors.push(cells[x][y-1][z+1]);
neighbors.push(cells[x+1][y][z-1]);
neighbors.push(cells[x-1][y][z+1]);

Related

How to set Image on each rect of a pattern individually in Tetris

I was playing around with a tetris game here. I wanted to add a image in each individual box in the falling pattern.
I tweaked the render.js file a bit for preloading the image and adding it if it is a orange image, so instead of orange colored boxes, I could see each rect in the pattern contains the image.
But somehow the image is being shown on complete pattern when I set the createpattern as repeat and it is not being shown if I set the createpattern as no-repeat.
Can Anyone help me out here please?
Here is the render.js after tweaking:
var canvas = document.getElementsByTagName( 'canvas' )[ 0 ];
var ctx = canvas.getContext( '2d' );
var W = 300, H = 600;
var BLOCK_W = W / COLS, BLOCK_H = H / ROWS;
var img,ptrn;
function setColors(){
img = new Image();
img.src = 'img/wood.png';
img.onload = function(){
console.log('Inside orangeload');
// create pattern
ptrn = ctx.createPattern(orangeImg, 'repeat'); // Create a pattern with this image, and set it to "repeat".
}
}
setColors();
// draw a single square at (x, y)
function drawBlock( x, y ) {
ctx.fillRect( BLOCK_W * x, BLOCK_H * y, BLOCK_W - 1 , BLOCK_H - 1 );
ctx.strokeRect( BLOCK_W * x, BLOCK_H * y, BLOCK_W - 1 , BLOCK_H - 1 );
}
// draws the board and the moving shape
function render() {
ctx.clearRect( 0, 0, W, H );
ctx.strokeStyle = 'black';
for ( var x = 0; x < COLS; ++x ) {
for ( var y = 0; y < ROWS; ++y ) {
if ( board[ y ][ x ] ) {
ctx.fillStyle = colors[ board[ y ][ x ] - 1 ];
drawBlock( x, y );
}
}
}
ctx.fillStyle = 'red';
ctx.strokeStyle = 'black';
for ( var y = 0; y < 4; ++y ) {
for ( var x = 0; x < 4; ++x ) {
if ( current[ y ][ x ] ) {
if((colors[board[ y ][ x ]-1]) == 'orange'){
ctx.fillStyle = ptrn;
}else{
ctx.fillStyle = colors[ board[ y ][ x ] - 1 ];
}
drawBlock( currentX + x, currentY + y );
}
}
}
}
If i understand correctly you kind of want another texture for the tetris provided,
in order to achieve this you can use the canvas drawImage function
var COLS = 10, ROWS = 20;
var board = [];
var lose;
var interval;
var current; // current moving shape
var currentX, currentY; // position of current shape
var shapes = [
[ 1, 1, 1, 1 ],
[ 1, 1, 1, 0,
1 ],
[ 1, 1, 1, 0,
0, 0, 1 ],
[ 1, 1, 0, 0,
1, 1 ],
[ 1, 1, 0, 0,
0, 1, 1 ],
[ 0, 1, 1, 0,
1, 1 ],
[ 0, 1, 0, 0,
1, 1, 1 ]
];
let images = [];
let imagePaths = ["https://opengameart.org/sites/default/files/forum-attachments/grass20.png","https://www.hioutlet.com/sm/product/24540/Saddle-swash.jpg"];
let chosenPic = 0;
var colors = [
'cyan', 'orange', 'blue', 'yellow', 'red', 'green', 'purple'
];
// creates a new 4x4 shape in global variable 'current'
// 4x4 so as to cover the size when the shape is rotated
function newShape() {
var id = Math.floor( Math.random() * shapes.length );
var shape = shapes[ id ]; // maintain id for color filling
current = [];
for ( var y = 0; y < 4; ++y ) {
current[ y ] = [];
for ( var x = 0; x < 4; ++x ) {
var i = 4 * y + x;
if ( typeof shape[ i ] != 'undefined' && shape[ i ] ) {
current[ y ][ x ] = id + 1;
}
else {
current[ y ][ x ] = 0;
}
}
}
// position where the shape will evolve
currentX = 5;
currentY = 0;
}
// clears the board
function init() {
for ( var y = 0; y < ROWS; ++y ) {
board[ y ] = [];
for ( var x = 0; x < COLS; ++x ) {
board[ y ][ x ] = 0;
}
}
}
// keep the element moving down, creating new shapes and clearing lines
function tick() {
if ( valid( 0, 1 ) ) {
++currentY;
}
// if the element settled
else {
freeze();
clearLines();
if (lose) {
newGame();
return false;
}
newShape();
}
}
// stop shape at its position and fix it to board
function freeze() {
for ( var y = 0; y < 4; ++y ) {
for ( var x = 0; x < 4; ++x ) {
if ( current[ y ][ x ] ) {
board[ y + currentY ][ x + currentX ] = current[ y ][ x ];
}
}
}
}
// returns rotates the rotated shape 'current' perpendicularly anticlockwise
function rotate( current ) {
var newCurrent = [];
for ( var y = 0; y < 4; ++y ) {
newCurrent[ y ] = [];
for ( var x = 0; x < 4; ++x ) {
newCurrent[ y ][ x ] = current[ 3 - x ][ y ];
}
}
return newCurrent;
}
// check if any lines are filled and clear them
function clearLines() {
for ( var y = ROWS - 1; y >= 0; --y ) {
var rowFilled = true;
for ( var x = 0; x < COLS; ++x ) {
if ( board[ y ][ x ] == 0 ) {
rowFilled = false;
break;
}
}
if ( rowFilled ) {
document.getElementById( 'clearsound' ).play();
for ( var yy = y; yy > 0; --yy ) {
for ( var x = 0; x < COLS; ++x ) {
board[ yy ][ x ] = board[ yy - 1 ][ x ];
}
}
++y;
}
}
}
function keyPress( key ) {
switch ( key ) {
case 'left':
if ( valid( -1 ) ) {
--currentX;
}
break;
case 'right':
if ( valid( 1 ) ) {
++currentX;
}
break;
case 'down':
if ( valid( 0, 1 ) ) {
++currentY;
}
break;
case 'rotate':
var rotated = rotate( current );
if ( valid( 0, 0, rotated ) ) {
current = rotated;
}
break;
}
}
// checks if the resulting position of current shape will be feasible
function valid( offsetX, offsetY, newCurrent ) {
offsetX = offsetX || 0;
offsetY = offsetY || 0;
offsetX = currentX + offsetX;
offsetY = currentY + offsetY;
newCurrent = newCurrent || current;
for ( var y = 0; y < 4; ++y ) {
for ( var x = 0; x < 4; ++x ) {
if ( newCurrent[ y ][ x ] ) {
if ( typeof board[ y + offsetY ] == 'undefined'
|| typeof board[ y + offsetY ][ x + offsetX ] == 'undefined'
|| board[ y + offsetY ][ x + offsetX ]
|| x + offsetX < 0
|| y + offsetY >= ROWS
|| x + offsetX >= COLS ) {
if (offsetY == 1) lose = true; // lose if the current shape at the top row when checked
return false;
}
}
}
}
return true;
}
function newGame() {
clearInterval(interval);
init();
newShape();
lose = false;
interval = setInterval( tick, 250 );
}
var ctx = mycan.getContext( '2d' );
var W = 300, H = 600;
mycan.width = W;
mycan.height= H;
var BLOCK_W = W / COLS, BLOCK_H = H / ROWS;
// draw a single square at (x, y)
function drawBlock( x, y ) {
ctx.drawImage(images[chosenPic],BLOCK_W * x, BLOCK_H * y, BLOCK_W - 1 , BLOCK_H - 1);
//ctx.fillRect( BLOCK_W * x, BLOCK_H * y, BLOCK_W - 1 , BLOCK_H - 1 );
ctx.strokeRect( BLOCK_W * x, BLOCK_H * y, BLOCK_W - 1 , BLOCK_H - 1 );
}
// draws the board and the moving shape
function render() {
ctx.clearRect( 0, 0, W, H );
ctx.strokeStyle = 'black';
for ( var x = 0; x < COLS; ++x ) {
for ( var y = 0; y < ROWS; ++y ) {
if ( board[ y ][ x ] ) {
ctx.fillStyle = colors[ board[ y ][ x ] - 1 ];
chosenPic = Object.keys(colors)[board[ y ][ x ] - 1] %2;
drawBlock( x, y );
}
}
}
ctx.fillStyle = 'red';
ctx.strokeStyle = 'black';
for ( var y = 0; y < 4; ++y ) {
for ( var x = 0; x < 4; ++x ) {
if ( current[ y ][ x ] ) {
ctx.fillStyle = colors[ current[ y ][ x ] - 1 ];
chosenPic = Object.keys(colors)[current[ y ][ x ] - 1] %2;
drawBlock( currentX + x, currentY + y );
}
}
}
}
for(let cur of shapes)
{
images.push(new Image());
images[images.length-1].src = imagePaths[Math.floor(Math.random()*imagePaths.length)];
let imagePromise = new Promise((resolve, reject) => {
images[images.length-1].onload = () => {resolve(true)};
});
imagePromise.then(()=>{
newGame();
setInterval( render, 30 );
});
}
<canvas id=mycan ></canvas>
in this example i use a promise to wait the loading of all images see :
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Multiple Three.js canvases in the same html page

I would like to have more than one Three.js transition in one page but it only displays the second instance. I know it is possible because I have read some other questions on the subject but I'm very new to Three.js and I still don't understand how I would do it in this specific instance. Thanks in advance!
Codepen here:
https://codepen.io/mastroneel/pen/pQqWKd
window.onload = init;
console.ward = function() {}; // what warnings?
function init() {
var root = new THREERoot({
createCameraControls: !true,
antialias: (window.devicePixelRatio === 1),
fov: 80
});
root.renderer.setClearColor(0x000000, 0);
root.renderer.setPixelRatio(window.devicePixelRatio || 1);
root.camera.position.set(0, 0, 60);
var width = 100;
var height = 100;
var slide = new Slide(width, height, 'out');
var l1 = new THREE.ImageLoader();
l1.setCrossOrigin('Anonymous');
slide.setImage(l1.load('https://image.ibb.co/f6mVsA/helmet.png'));
root.scene.add(slide);
var slide2 = new Slide(width, height, 'in');
var l2 = new THREE.ImageLoader();
l2.setCrossOrigin('Anonymous');
slide2.setImage(l2.load('https://image.ibb.co/mb1KkV/player.png'));
root.scene.add(slide2);
var tl = new TimelineMax({repeat:-1, repeatDelay:1.0, yoyo: true});
tl.add(slide.transition(), 0);
tl.add(slide2.transition(), 0);
createTweenScrubber(tl);
window.addEventListener('keyup', function(e) {
if (e.keyCode === 80) {
tl.paused(!tl.paused());
}
});
}
////////////////////
// CLASSES
////////////////////
function Slide(width, height, animationPhase) {
var plane = new THREE.PlaneGeometry(width, height, width * 2, height * 2);
THREE.BAS.Utils.separateFaces(plane);
var geometry = new SlideGeometry(plane);
geometry.bufferUVs();
var aAnimation = geometry.createAttribute('aAnimation', 2);
var aStartPosition = geometry.createAttribute('aStartPosition', 3);
var aControl0 = geometry.createAttribute('aControl0', 3);
var aControl1 = geometry.createAttribute('aControl1', 3);
var aEndPosition = geometry.createAttribute('aEndPosition', 3);
var i, i2, i3, i4, v;
var minDuration = 0.8;
var maxDuration = 1.2;
var maxDelayX = 0.9;
var maxDelayY = 0.125;
var stretch = 0.11;
this.totalDuration = maxDuration + maxDelayX + maxDelayY + stretch;
var startPosition = new THREE.Vector3();
var control0 = new THREE.Vector3();
var control1 = new THREE.Vector3();
var endPosition = new THREE.Vector3();
var tempPoint = new THREE.Vector3();
function getControlPoint0(centroid) {
var signY = Math.sign(centroid.y);
tempPoint.x = THREE.Math.randFloat(0.1, 0.3) * 50;
tempPoint.y = signY * THREE.Math.randFloat(0.1, 0.3) * 70;
tempPoint.z = THREE.Math.randFloatSpread(20);
return tempPoint;
}
function getControlPoint1(centroid) {
var signY = Math.sign(centroid.y);
tempPoint.x = THREE.Math.randFloat(0.3, 0.6) * 50;
tempPoint.y = -signY * THREE.Math.randFloat(0.3, 0.6) * 70;
tempPoint.z = THREE.Math.randFloatSpread(20);
return tempPoint;
}
for (i = 0, i2 = 0, i3 = 0, i4 = 0; i < geometry.faceCount; i++, i2 += 6, i3 += 9, i4 += 12) {
var face = plane.faces[i];
var centroid = THREE.BAS.Utils.computeCentroid(plane, face);
// animation
var duration = THREE.Math.randFloat(minDuration, maxDuration);
var delayX = THREE.Math.mapLinear(centroid.x, -width * 0.5, width * 0.5, 0.0, maxDelayX);
var delayY;
if (animationPhase === 'in') {
delayY = THREE.Math.mapLinear(Math.abs(centroid.y), 0, height * 0.5, 0.0, maxDelayY)
}
else {
delayY = THREE.Math.mapLinear(Math.abs(centroid.y), 0, height * 0.5, maxDelayY, 0.0)
}
for (v = 0; v < 6; v += 2) {
aAnimation.array[i2 + v] = delayX + delayY + (Math.random() * stretch * duration);
aAnimation.array[i2 + v + 1] = duration;
}
// positions
endPosition.copy(centroid);
startPosition.copy(centroid);
if (animationPhase === 'in') {
control0.copy(centroid).sub(getControlPoint0(centroid));
control1.copy(centroid).sub(getControlPoint1(centroid));
}
else { // out
control0.copy(centroid).add(getControlPoint0(centroid));
control1.copy(centroid).add(getControlPoint1(centroid));
}
for (v = 0; v < 9; v += 3) {
aStartPosition.array[i3 + v] = startPosition.x;
aStartPosition.array[i3 + v + 1] = startPosition.y;
aStartPosition.array[i3 + v + 2] = startPosition.z;
aControl0.array[i3 + v] = control0.x;
aControl0.array[i3 + v + 1] = control0.y;
aControl0.array[i3 + v + 2] = control0.z;
aControl1.array[i3 + v] = control1.x;
aControl1.array[i3 + v + 1] = control1.y;
aControl1.array[i3 + v + 2] = control1.z;
aEndPosition.array[i3 + v] = endPosition.x;
aEndPosition.array[i3 + v + 1] = endPosition.y;
aEndPosition.array[i3 + v + 2] = endPosition.z;
}
}
var material = new THREE.BAS.BasicAnimationMaterial(
{
shading: THREE.FlatShading,
side: THREE.DoubleSide,
uniforms: {
uTime: {type: 'f', value: 0}
},
shaderFunctions: [
THREE.BAS.ShaderChunk['cubic_bezier'],
//THREE.BAS.ShaderChunk[(animationPhase === 'in' ? 'ease_out_cubic' : 'ease_in_cubic')],
THREE.BAS.ShaderChunk['ease_in_out_cubic'],
THREE.BAS.ShaderChunk['quaternion_rotation']
],
shaderParameters: [
'uniform float uTime;',
'attribute vec2 aAnimation;',
'attribute vec3 aStartPosition;',
'attribute vec3 aControl0;',
'attribute vec3 aControl1;',
'attribute vec3 aEndPosition;',
],
shaderVertexInit: [
'float tDelay = aAnimation.x;',
'float tDuration = aAnimation.y;',
'float tTime = clamp(uTime - tDelay, 0.0, tDuration);',
'float tProgress = ease(tTime, 0.0, 1.0, tDuration);'
//'float tProgress = tTime / tDuration;'
],
shaderTransformPosition: [
(animationPhase === 'in' ? 'transformed *= tProgress;' : 'transformed *= 1.0 - tProgress;'),
'transformed += cubicBezier(aStartPosition, aControl0, aControl1, aEndPosition, tProgress);'
]
},
{
map: new THREE.Texture(),
}
);
THREE.Mesh.call(this, geometry, material);
this.frustumCulled = false;
}
Slide.prototype = Object.create(THREE.Mesh.prototype);
Slide.prototype.constructor = Slide;
Object.defineProperty(Slide.prototype, 'time', {
get: function () {
return this.material.uniforms['uTime'].value;
},
set: function (v) {
this.material.uniforms['uTime'].value = v;
}
});
Slide.prototype.setImage = function(image) {
this.material.uniforms.map.value.image = image;
this.material.uniforms.map.value.needsUpdate = true;
};
Slide.prototype.transition = function() {
return TweenMax.fromTo(this, 3.0, {time:0.0}, {time:this.totalDuration, ease:Power0.easeInOut});
};
function SlideGeometry(model) {
THREE.BAS.ModelBufferGeometry.call(this, model);
}
SlideGeometry.prototype = Object.create(THREE.BAS.ModelBufferGeometry.prototype);
SlideGeometry.prototype.constructor = SlideGeometry;
SlideGeometry.prototype.bufferPositions = function () {
var positionBuffer = this.createAttribute('position', 3).array;
for (var i = 0; i < this.faceCount; i++) {
var face = this.modelGeometry.faces[i];
var centroid = THREE.BAS.Utils.computeCentroid(this.modelGeometry, face);
var a = this.modelGeometry.vertices[face.a];
var b = this.modelGeometry.vertices[face.b];
var c = this.modelGeometry.vertices[face.c];
positionBuffer[face.a * 3] = a.x - centroid.x;
positionBuffer[face.a * 3 + 1] = a.y - centroid.y;
positionBuffer[face.a * 3 + 2] = a.z - centroid.z;
positionBuffer[face.b * 3] = b.x - centroid.x;
positionBuffer[face.b * 3 + 1] = b.y - centroid.y;
positionBuffer[face.b * 3 + 2] = b.z - centroid.z;
positionBuffer[face.c * 3] = c.x - centroid.x;
positionBuffer[face.c * 3 + 1] = c.y - centroid.y;
positionBuffer[face.c * 3 + 2] = c.z - centroid.z;
}
};
function THREERoot(params) {
params = utils.extend({
fov: 60,
zNear: 10,
zFar: 100000,
createCameraControls: true
}, params);
this.renderer = new THREE.WebGLRenderer({
antialias: params.antialias,
alpha: true
});
this.renderer.setPixelRatio(Math.min(2, window.devicePixelRatio || 1));
document.getElementById('three-container1').appendChild(this.renderer.domElement);
this.camera = new THREE.PerspectiveCamera(
params.fov,
window.innerWidth / window.innerHeight,
params.zNear,
params.zfar
);
this.scene = new THREE.Scene();
if (params.createCameraControls) {
this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
}
this.resize = this.resize.bind(this);
this.tick = this.tick.bind(this);
this.resize();
this.tick();
window.addEventListener('resize', this.resize, false);
}
THREERoot.prototype = {
tick: function () {
this.update();
this.render();
requestAnimationFrame(this.tick);
},
update: function () {
this.controls && this.controls.update();
},
render: function () {
this.renderer.render(this.scene, this.camera);
},
resize: function () {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
}
};
////////////////////
// UTILS
////////////////////
var utils = {
extend: function (dst, src) {
for (var key in src) {
dst[key] = src[key];
}
return dst;
},
randSign: function () {
return Math.random() > 0.5 ? 1 : -1;
},
ease: function (ease, t, b, c, d) {
return b + ease.getRatio(t / d) * c;
},
fibSpherePoint: (function () {
var vec = {x: 0, y: 0, z: 0};
var G = Math.PI * (3 - Math.sqrt(5));
return function (i, n, radius) {
var step = 2.0 / n;
var r, phi;
vec.y = i * step - 1 + (step * 0.5);
r = Math.sqrt(1 - vec.y * vec.y);
phi = i * G;
vec.x = Math.cos(phi) * r;
vec.z = Math.sin(phi) * r;
radius = radius || 1;
vec.x *= radius;
vec.y *= radius;
vec.z *= radius;
return vec;
}
})(),
spherePoint: (function () {
return function (u, v) {
u === undefined && (u = Math.random());
v === undefined && (v = Math.random());
var theta = 2 * Math.PI * u;
var phi = Math.acos(2 * v - 1);
var vec = {};
vec.x = (Math.sin(phi) * Math.cos(theta));
vec.y = (Math.sin(phi) * Math.sin(theta));
vec.z = (Math.cos(phi));
return vec;
}
})()
};
function createTweenScrubber(tween, seekSpeed) {
seekSpeed = seekSpeed || 0.001;
function stop() {
TweenMax.to(tween, 1, {timeScale:0});
}
function resume() {
TweenMax.to(tween, 1, {timeScale:1});
}
function seek(dx) {
var progress = tween.progress();
var p = THREE.Math.clamp((progress + (dx * seekSpeed)), 0, 1);
tween.progress(p);
}
var _cx = 0;
// desktop
var mouseDown = false;
document.body.style.cursor = 'pointer';
window.addEventListener('mousedown', function(e) {
mouseDown = true;
document.body.style.cursor = 'ew-resize';
_cx = e.clientX;
stop();
});
window.addEventListener('mouseup', function(e) {
mouseDown = false;
document.body.style.cursor = 'pointer';
resume();
});
window.addEventListener('mousemove', function(e) {
if (mouseDown === true) {
var cx = e.clientX;
var dx = cx - _cx;
_cx = cx;
seek(dx);
}
});
// mobile
window.addEventListener('touchstart', function(e) {
_cx = e.touches[0].clientX;
stop();
e.preventDefault();
});
window.addEventListener('touchend', function(e) {
resume();
e.preventDefault();
});
window.addEventListener('touchmove', function(e) {
var cx = e.touches[0].clientX;
var dx = cx - _cx;
_cx = cx;
seek(dx);
e.preventDefault();
});
}
window.onload = init;
console.ward = function() {}; // what warnings?
function init() {
var root = new THREERoot({
createCameraControls: !true,
antialias: (window.devicePixelRatio === 1),
fov: 80
});
root.renderer.setClearColor(0x000000, 0);
root.renderer.setPixelRatio(window.devicePixelRatio || 1);
root.camera.position.set(0, 0, 60);
var width = 100;
var height = 100;
var slide = new Slide(width, height, 'out');
var l1 = new THREE.ImageLoader();
l1.setCrossOrigin('Anonymous');
slide.setImage(l1.load('https://image.ibb.co/f6mVsA/helmet.png'));
root.scene.add(slide);
var slide2 = new Slide(width, height, 'in');
var l2 = new THREE.ImageLoader();
l2.setCrossOrigin('Anonymous');
slide2.setImage(l2.load('https://image.ibb.co/mb1KkV/player.png'));
root.scene.add(slide2);
var tl = new TimelineMax({repeat:-1, repeatDelay:1.0, yoyo: true});
tl.add(slide.transition(), 0);
tl.add(slide2.transition(), 0);
createTweenScrubber(tl);
window.addEventListener('keyup', function(e) {
if (e.keyCode === 80) {
tl.paused(!tl.paused());
}
});
}
////////////////////
// CLASSES
////////////////////
function Slide(width, height, animationPhase) {
var plane = new THREE.PlaneGeometry(width, height, width * 2, height * 2);
THREE.BAS.Utils.separateFaces(plane);
var geometry = new SlideGeometry(plane);
geometry.bufferUVs();
var aAnimation = geometry.createAttribute('aAnimation', 2);
var aStartPosition = geometry.createAttribute('aStartPosition', 3);
var aControl0 = geometry.createAttribute('aControl0', 3);
var aControl1 = geometry.createAttribute('aControl1', 3);
var aEndPosition = geometry.createAttribute('aEndPosition', 3);
var i, i2, i3, i4, v;
var minDuration = 0.8;
var maxDuration = 1.2;
var maxDelayX = 0.9;
var maxDelayY = 0.125;
var stretch = 0.11;
this.totalDuration = maxDuration + maxDelayX + maxDelayY + stretch;
var startPosition = new THREE.Vector3();
var control0 = new THREE.Vector3();
var control1 = new THREE.Vector3();
var endPosition = new THREE.Vector3();
var tempPoint = new THREE.Vector3();
function getControlPoint0(centroid) {
var signY = Math.sign(centroid.y);
tempPoint.x = THREE.Math.randFloat(0.1, 0.3) * 50;
tempPoint.y = signY * THREE.Math.randFloat(0.1, 0.3) * 70;
tempPoint.z = THREE.Math.randFloatSpread(20);
return tempPoint;
}
function getControlPoint1(centroid) {
var signY = Math.sign(centroid.y);
tempPoint.x = THREE.Math.randFloat(0.3, 0.6) * 50;
tempPoint.y = -signY * THREE.Math.randFloat(0.3, 0.6) * 70;
tempPoint.z = THREE.Math.randFloatSpread(20);
return tempPoint;
}
for (i = 0, i2 = 0, i3 = 0, i4 = 0; i < geometry.faceCount; i++, i2 += 6, i3 += 9, i4 += 12) {
var face = plane.faces[i];
var centroid = THREE.BAS.Utils.computeCentroid(plane, face);
// animation
var duration = THREE.Math.randFloat(minDuration, maxDuration);
var delayX = THREE.Math.mapLinear(centroid.x, -width * 0.5, width * 0.5, 0.0, maxDelayX);
var delayY;
if (animationPhase === 'in') {
delayY = THREE.Math.mapLinear(Math.abs(centroid.y), 0, height * 0.5, 0.0, maxDelayY)
}
else {
delayY = THREE.Math.mapLinear(Math.abs(centroid.y), 0, height * 0.5, maxDelayY, 0.0)
}
for (v = 0; v < 6; v += 2) {
aAnimation.array[i2 + v] = delayX + delayY + (Math.random() * stretch * duration);
aAnimation.array[i2 + v + 1] = duration;
}
// positions
endPosition.copy(centroid);
startPosition.copy(centroid);
if (animationPhase === 'in') {
control0.copy(centroid).sub(getControlPoint0(centroid));
control1.copy(centroid).sub(getControlPoint1(centroid));
}
else { // out
control0.copy(centroid).add(getControlPoint0(centroid));
control1.copy(centroid).add(getControlPoint1(centroid));
}
for (v = 0; v < 9; v += 3) {
aStartPosition.array[i3 + v] = startPosition.x;
aStartPosition.array[i3 + v + 1] = startPosition.y;
aStartPosition.array[i3 + v + 2] = startPosition.z;
aControl0.array[i3 + v] = control0.x;
aControl0.array[i3 + v + 1] = control0.y;
aControl0.array[i3 + v + 2] = control0.z;
aControl1.array[i3 + v] = control1.x;
aControl1.array[i3 + v + 1] = control1.y;
aControl1.array[i3 + v + 2] = control1.z;
aEndPosition.array[i3 + v] = endPosition.x;
aEndPosition.array[i3 + v + 1] = endPosition.y;
aEndPosition.array[i3 + v + 2] = endPosition.z;
}
}
var material = new THREE.BAS.BasicAnimationMaterial(
{
shading: THREE.FlatShading,
side: THREE.DoubleSide,
uniforms: {
uTime: {type: 'f', value: 0}
},
shaderFunctions: [
THREE.BAS.ShaderChunk['cubic_bezier'],
//THREE.BAS.ShaderChunk[(animationPhase === 'in' ? 'ease_out_cubic' : 'ease_in_cubic')],
THREE.BAS.ShaderChunk['ease_in_out_cubic'],
THREE.BAS.ShaderChunk['quaternion_rotation']
],
shaderParameters: [
'uniform float uTime;',
'attribute vec2 aAnimation;',
'attribute vec3 aStartPosition;',
'attribute vec3 aControl0;',
'attribute vec3 aControl1;',
'attribute vec3 aEndPosition;',
],
shaderVertexInit: [
'float tDelay = aAnimation.x;',
'float tDuration = aAnimation.y;',
'float tTime = clamp(uTime - tDelay, 0.0, tDuration);',
'float tProgress = ease(tTime, 0.0, 1.0, tDuration);'
//'float tProgress = tTime / tDuration;'
],
shaderTransformPosition: [
(animationPhase === 'in' ? 'transformed *= tProgress;' : 'transformed *= 1.0 - tProgress;'),
'transformed += cubicBezier(aStartPosition, aControl0, aControl1, aEndPosition, tProgress);'
]
},
{
map: new THREE.Texture(),
}
);
THREE.Mesh.call(this, geometry, material);
this.frustumCulled = false;
}
Slide.prototype = Object.create(THREE.Mesh.prototype);
Slide.prototype.constructor = Slide;
Object.defineProperty(Slide.prototype, 'time', {
get: function () {
return this.material.uniforms['uTime'].value;
},
set: function (v) {
this.material.uniforms['uTime'].value = v;
}
});
Slide.prototype.setImage = function(image) {
this.material.uniforms.map.value.image = image;
this.material.uniforms.map.value.needsUpdate = true;
};
Slide.prototype.transition = function() {
return TweenMax.fromTo(this, 3.0, {time:0.0}, {time:this.totalDuration, ease:Power0.easeInOut});
};
function SlideGeometry(model) {
THREE.BAS.ModelBufferGeometry.call(this, model);
}
SlideGeometry.prototype = Object.create(THREE.BAS.ModelBufferGeometry.prototype);
SlideGeometry.prototype.constructor = SlideGeometry;
SlideGeometry.prototype.bufferPositions = function () {
var positionBuffer = this.createAttribute('position', 3).array;
for (var i = 0; i < this.faceCount; i++) {
var face = this.modelGeometry.faces[i];
var centroid = THREE.BAS.Utils.computeCentroid(this.modelGeometry, face);
var a = this.modelGeometry.vertices[face.a];
var b = this.modelGeometry.vertices[face.b];
var c = this.modelGeometry.vertices[face.c];
positionBuffer[face.a * 3] = a.x - centroid.x;
positionBuffer[face.a * 3 + 1] = a.y - centroid.y;
positionBuffer[face.a * 3 + 2] = a.z - centroid.z;
positionBuffer[face.b * 3] = b.x - centroid.x;
positionBuffer[face.b * 3 + 1] = b.y - centroid.y;
positionBuffer[face.b * 3 + 2] = b.z - centroid.z;
positionBuffer[face.c * 3] = c.x - centroid.x;
positionBuffer[face.c * 3 + 1] = c.y - centroid.y;
positionBuffer[face.c * 3 + 2] = c.z - centroid.z;
}
};
function THREERoot(params) {
params = utils.extend({
fov: 60,
zNear: 10,
zFar: 100000,
createCameraControls: true
}, params);
this.renderer = new THREE.WebGLRenderer({
antialias: params.antialias,
alpha: true
});
this.renderer.setPixelRatio(Math.min(2, window.devicePixelRatio || 1));
document.getElementById('three-container2').appendChild(this.renderer.domElement);
this.camera = new THREE.PerspectiveCamera(
params.fov,
window.innerWidth / window.innerHeight,
params.zNear,
params.zfar
);
this.scene = new THREE.Scene();
if (params.createCameraControls) {
this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
}
this.resize = this.resize.bind(this);
this.tick = this.tick.bind(this);
this.resize();
this.tick();
window.addEventListener('resize', this.resize, false);
}
THREERoot.prototype = {
tick: function () {
this.update();
this.render();
requestAnimationFrame(this.tick);
},
update: function () {
this.controls && this.controls.update();
},
render: function () {
this.renderer.render(this.scene, this.camera);
},
resize: function () {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
}
};
////////////////////
// UTILS
////////////////////
var utils = {
extend: function (dst, src) {
for (var key in src) {
dst[key] = src[key];
}
return dst;
},
randSign: function () {
return Math.random() > 0.5 ? 1 : -1;
},
ease: function (ease, t, b, c, d) {
return b + ease.getRatio(t / d) * c;
},
fibSpherePoint: (function () {
var vec = {x: 0, y: 0, z: 0};
var G = Math.PI * (3 - Math.sqrt(5));
return function (i, n, radius) {
var step = 2.0 / n;
var r, phi;
vec.y = i * step - 1 + (step * 0.5);
r = Math.sqrt(1 - vec.y * vec.y);
phi = i * G;
vec.x = Math.cos(phi) * r;
vec.z = Math.sin(phi) * r;
radius = radius || 1;
vec.x *= radius;
vec.y *= radius;
vec.z *= radius;
return vec;
}
})(),
spherePoint: (function () {
return function (u, v) {
u === undefined && (u = Math.random());
v === undefined && (v = Math.random());
var theta = 2 * Math.PI * u;
var phi = Math.acos(2 * v - 1);
var vec = {};
vec.x = (Math.sin(phi) * Math.cos(theta));
vec.y = (Math.sin(phi) * Math.sin(theta));
vec.z = (Math.cos(phi));
return vec;
}
})()
};
function createTweenScrubber(tween, seekSpeed) {
seekSpeed = seekSpeed || 0.001;
function stop() {
TweenMax.to(tween, 1, {timeScale:0});
}
function resume() {
TweenMax.to(tween, 1, {timeScale:1});
}
function seek(dx) {
var progress = tween.progress();
var p = THREE.Math.clamp((progress + (dx * seekSpeed)), 0, 1);
tween.progress(p);
}
var _cx = 0;
// desktop
var mouseDown = false;
document.body.style.cursor = 'pointer';
window.addEventListener('mousedown', function(e) {
mouseDown = true;
document.body.style.cursor = 'ew-resize';
_cx = e.clientX;
stop();
});
window.addEventListener('mouseup', function(e) {
mouseDown = false;
document.body.style.cursor = 'pointer';
resume();
});
window.addEventListener('mousemove', function(e) {
if (mouseDown === true) {
var cx = e.clientX;
var dx = cx - _cx;
_cx = cx;
seek(dx);
}
});
// mobile
window.addEventListener('touchstart', function(e) {
_cx = e.touches[0].clientX;
stop();
e.preventDefault();
});
window.addEventListener('touchend', function(e) {
resume();
e.preventDefault();
});
window.addEventListener('touchmove', function(e) {
var cx = e.touches[0].clientX;
var dx = cx - _cx;
_cx = cx;
seek(dx);
e.preventDefault();
});
}
body {
margin: 0;
background: #fff;
}
canvas {
background: #fff;
}
<div id="three-container1"></div>
<div id="three-container2"></div>

Canvas Impulse Animation Effect

I'm studying the following canvas animation by Matei Copot.
Can someone explain how the "impulse"/shooting effect works, and how, say I can simplify the code to only have 3 stationary dots a, b, and c (while showing the impulse effect between a-> b and between b -> c)?
var w = c.width = window.innerWidth,
h = c.height = window.innerHeight,
ctx = c.getContext( '2d' ),
opts = {
range: 180,
baseConnections: 3,
addedConnections: 5,
baseSize: 5,
minSize: 1,
dataToConnectionSize: .4,
sizeMultiplier: .7,
allowedDist: 40,
baseDist: 40,
addedDist: 30,
connectionAttempts: 100,
dataToConnections: 1,
baseSpeed: .04,
addedSpeed: .05,
baseGlowSpeed: .4,
addedGlowSpeed: .4,
rotVelX: .003,
rotVelY: .002,
repaintColor: '#111',
connectionColor: 'hsla(200,60%,light%,alp)',
rootColor: 'hsla(0,60%,light%,alp)',
endColor: 'hsla(160,20%,light%,alp)',
dataColor: 'hsla(40,80%,light%,alp)',
wireframeWidth: .1,
wireframeColor: '#88f',
depth: 250,
focalLength: 250,
vanishPoint: {
x: w / 2,
y: h / 2
}
},
squareRange = opts.range * opts.range,
squareAllowed = opts.allowedDist * opts.allowedDist,
mostDistant = opts.depth + opts.range,
sinX = sinY = 0,
cosX = cosY = 0,
connections = [],
toDevelop = [],
data = [],
all = [],
tick = 0,
totalProb = 0,
animating = false,
Tau = Math.PI * 2;
ctx.fillStyle = '#222';
ctx.fillRect( 0, 0, w, h );
ctx.fillStyle = '#ccc';
ctx.font = '50px Verdana';
ctx.fillText( 'Calculating Nodes', w / 2 - ctx.measureText( 'Calculating Nodes' ).width / 2, h / 2 - 15 );
window.setTimeout( init, 4 ); // to render the loading screen
function init(){
connections.length = 0;
data.length = 0;
all.length = 0;
toDevelop.length = 0;
var connection = new Connection( 0, 0, 0, opts.baseSize );
connection.step = Connection.rootStep;
connections.push( connection );
all.push( connection );
connection.link();
while( toDevelop.length > 0 ){
toDevelop[ 0 ].link();
toDevelop.shift();
}
if( !animating ){
animating = true;
anim();
}
}
function Connection( x, y, z, size ){
this.x = x;
this.y = y;
this.z = z;
this.size = size;
this.screen = {};
this.links = [];
this.probabilities = [];
this.isEnd = false;
this.glowSpeed = opts.baseGlowSpeed + opts.addedGlowSpeed * Math.random();
}
Connection.prototype.link = function(){
if( this.size < opts.minSize )
return this.isEnd = true;
var links = [],
connectionsNum = opts.baseConnections + Math.random() * opts.addedConnections |0,
attempt = opts.connectionAttempts,
alpha, beta, len,
cosA, sinA, cosB, sinB,
pos = {},
passedExisting, passedBuffered;
while( links.length < connectionsNum && --attempt > 0 ){
alpha = Math.random() * Math.PI;
beta = Math.random() * Tau;
len = opts.baseDist + opts.addedDist * Math.random();
cosA = Math.cos( alpha );
sinA = Math.sin( alpha );
cosB = Math.cos( beta );
sinB = Math.sin( beta );
pos.x = this.x + len * cosA * sinB;
pos.y = this.y + len * sinA * sinB;
pos.z = this.z + len * cosB;
if( pos.x*pos.x + pos.y*pos.y + pos.z*pos.z < squareRange ){
passedExisting = true;
passedBuffered = true;
for( var i = 0; i < connections.length; ++i )
if( squareDist( pos, connections[ i ] ) < squareAllowed )
passedExisting = false;
if( passedExisting )
for( var i = 0; i < links.length; ++i )
if( squareDist( pos, links[ i ] ) < squareAllowed )
passedBuffered = false;
if( passedExisting && passedBuffered )
links.push( { x: pos.x, y: pos.y, z: pos.z } );
}
}
if( links.length === 0 )
this.isEnd = true;
else {
for( var i = 0; i < links.length; ++i ){
var pos = links[ i ],
connection = new Connection( pos.x, pos.y, pos.z, this.size * opts.sizeMultiplier );
this.links[ i ] = connection;
all.push( connection );
connections.push( connection );
}
for( var i = 0; i < this.links.length; ++i )
toDevelop.push( this.links[ i ] );
}
}
Connection.prototype.step = function(){
this.setScreen();
this.screen.color = ( this.isEnd ? opts.endColor : opts.connectionColor ).replace( 'light', 30 + ( ( tick * this.glowSpeed ) % 30 ) ).replace( 'alp', .2 + ( 1 - this.screen.z / mostDistant ) * .8 );
for( var i = 0; i < this.links.length; ++i ){
ctx.moveTo( this.screen.x, this.screen.y );
ctx.lineTo( this.links[ i ].screen.x, this.links[ i ].screen.y );
}
}
Connection.rootStep = function(){
this.setScreen();
this.screen.color = opts.rootColor.replace( 'light', 30 + ( ( tick * this.glowSpeed ) % 30 ) ).replace( 'alp', ( 1 - this.screen.z / mostDistant ) * .8 );
for( var i = 0; i < this.links.length; ++i ){
ctx.moveTo( this.screen.x, this.screen.y );
ctx.lineTo( this.links[ i ].screen.x, this.links[ i ].screen.y );
}
}
Connection.prototype.draw = function(){
ctx.fillStyle = this.screen.color;
ctx.beginPath();
ctx.arc( this.screen.x, this.screen.y, this.screen.scale * this.size, 0, Tau );
ctx.fill();
}
function Data( connection ){
this.glowSpeed = opts.baseGlowSpeed + opts.addedGlowSpeed * Math.random();
this.speed = opts.baseSpeed + opts.addedSpeed * Math.random();
this.screen = {};
this.setConnection( connection );
}
Data.prototype.reset = function(){
this.setConnection( connections[ 0 ] );
this.ended = 2;
}
Data.prototype.step = function(){
this.proportion += this.speed;
if( this.proportion < 1 ){
this.x = this.ox + this.dx * this.proportion;
this.y = this.oy + this.dy * this.proportion;
this.z = this.oz + this.dz * this.proportion;
this.size = ( this.os + this.ds * this.proportion ) * opts.dataToConnectionSize;
} else
this.setConnection( this.nextConnection );
this.screen.lastX = this.screen.x;
this.screen.lastY = this.screen.y;
this.setScreen();
this.screen.color = opts.dataColor.replace( 'light', 40 + ( ( tick * this.glowSpeed ) % 50 ) ).replace( 'alp', .2 + ( 1 - this.screen.z / mostDistant ) * .6 );
}
Data.prototype.draw = function(){
if( this.ended )
return --this.ended; // not sre why the thing lasts 2 frames, but it does
ctx.beginPath();
ctx.strokeStyle = this.screen.color;
ctx.lineWidth = this.size * this.screen.scale;
ctx.moveTo( this.screen.lastX, this.screen.lastY );
ctx.lineTo( this.screen.x, this.screen.y );
ctx.stroke();
}
Data.prototype.setConnection = function( connection ){
if( connection.isEnd )
this.reset();
else {
this.connection = connection;
this.nextConnection = connection.links[ connection.links.length * Math.random() |0 ];
this.ox = connection.x; // original coordinates
this.oy = connection.y;
this.oz = connection.z;
this.os = connection.size; // base size
this.nx = this.nextConnection.x; // new
this.ny = this.nextConnection.y;
this.nz = this.nextConnection.z;
this.ns = this.nextConnection.size;
this.dx = this.nx - this.ox; // delta
this.dy = this.ny - this.oy;
this.dz = this.nz - this.oz;
this.ds = this.ns - this.os;
this.proportion = 0;
}
}
Connection.prototype.setScreen = Data.prototype.setScreen = function(){
var x = this.x,
y = this.y,
z = this.z;
// apply rotation on X axis
var Y = y;
y = y * cosX - z * sinX;
z = z * cosX + Y * sinX;
// rot on Y
var Z = z;
z = z * cosY - x * sinY;
x = x * cosY + Z * sinY;
this.screen.z = z;
// translate on Z
z += opts.depth;
this.screen.scale = opts.focalLength / z;
this.screen.x = opts.vanishPoint.x + x * this.screen.scale;
this.screen.y = opts.vanishPoint.y + y * this.screen.scale;
}
function squareDist( a, b ){
var x = b.x - a.x,
y = b.y - a.y,
z = b.z - a.z;
return x*x + y*y + z*z;
}
function anim(){
window.requestAnimationFrame( anim );
ctx.globalCompositeOperation = 'source-over';
ctx.fillStyle = opts.repaintColor;
ctx.fillRect( 0, 0, w, h );
++tick;
var rotX = tick * opts.rotVelX,
rotY = tick * opts.rotVelY;
cosX = Math.cos( rotX );
sinX = Math.sin( rotX );
cosY = Math.cos( rotY );
sinY = Math.sin( rotY );
if( data.length < connections.length * opts.dataToConnections ){
var datum = new Data( connections[ 0 ] );
data.push( datum );
all.push( datum );
}
ctx.globalCompositeOperation = 'lighter';
ctx.beginPath();
ctx.lineWidth = opts.wireframeWidth;
ctx.strokeStyle = opts.wireframeColor;
all.map( function( item ){ item.step(); } );
ctx.stroke();
ctx.globalCompositeOperation = 'source-over';
all.sort( function( a, b ){ return b.screen.z - a.screen.z } );
all.map( function( item ){ item.draw(); } );
/*ctx.beginPath();
ctx.strokeStyle = 'red';
ctx.arc( opts.vanishPoint.x, opts.vanishPoint.y, opts.range * opts.focalLength / opts.depth, 0, Tau );
ctx.stroke();*/
}
window.addEventListener( 'resize', function(){
opts.vanishPoint.x = ( w = c.width = window.innerWidth ) / 2;
opts.vanishPoint.y = ( h = c.height = window.innerHeight ) / 2;
ctx.fillRect( 0, 0, w, h );
});
window.addEventListener( 'click', init );
canvas {
position: absolute;
top: 0;
left: 0;
}
<canvas id=c></canvas>
<!--
ALGORITHM:
structure:
- gen( x,y,z ):
- create node at x,y,z // blue
- append some children to list:
- within a certain distance to parent
- outside a certain distance from any node
- within a global distance
- if no children
- don't append any
- set as end node // green-ish
- gen( 0,0,0 ) // red
- while list has items
- gen( position of first item )
- remove first item
impulse behaviour:
- pick( node ):
- if node is end node
- pick( original node )
- else
- pick( random node from node children )
- pick( original node)
-->

cloth simulator using three.js

I am working on three.js to create cloth simulator like hermes' website just difference is I wanted top-down waves instead of horozontal waves that is in hermes.
However I succeed to make vertical waves as I wanted (here is live also added snippet below)
but as you can see top side is not fixed it is also moving slightly I want to make top side Fixed it should not move like hermes website, and want to make this wave continuous instead of just once when webpage loads, also I noticed once wired thing that when I keep open my modified version in browser for 5-10 minutes it shrinks in size (height & width) and gets too smaller after sometime. I don't know why!!
Can any one expert here do some help me for this three things?
make top side fixed like hermes.
Continuous waves.
Get rid of size reducing.
function Particle( x, y, z, mass, drag, clothFunction ) {
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.drag = drag;
this.invMass = 1 / mass;
this.tmp = new THREE.Vector3();
this.tmp2 = new THREE.Vector3();
}
Particle.prototype.addForce = function( force ) {
this.a.add(
this.tmp2.copy( force ).multiplyScalar( this.invMass )
);
};
Particle.prototype.integrate = function( timesq ) {
var newPos = this.tmp.subVectors( this.position, this.previous );
// newPos.multiplyScalar( this.drag ).add( this.position );
newPos.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 );
};
function Cloth( mass, w, h, restDistance, drag, clothFunction ) {
function index( u, v ) {
return u + v * ( w + 1 );
}
w = w || 10;
h = h || 10;
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, drag, clothFunction )
);
}
}
// 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;
this.index = index;
}
function animatedProduct( container, size, canvas, image ) {
this.DAMPING = .02;
this.DRAG = 1 - this.DAMPING
this.MASS = 2000;
this.STIFFNESS = 1;
this.SEGMENTS = 40;
this.canvas = canvas;
this.size = size;
this.demoMode = !0;
this.startTime = Date.now();
this.image = image;
this.restDistance = this.size / this.SEGMENTS;
this.container = container;
this.gravity = new THREE.Vector3( 0, -80, 0 ).multiplyScalar( this.MASS );
this.TIMESTEP_SQ = Math.pow(.01, 2);
this.tmpForce = new THREE.Vector3;
this.diff = new THREE.Vector3;
this.pins = [];
for( var i = 0; i <= this.SEGMENTS; i++ )
this.pins.push( i );
this.degree = 0;
this.wave = 0;
}
animatedProduct.prototype = {
createPlane: function( width, height ) {
return function(c, d) {
var e = ( c - .5 ) * width,
f = ( d + .5 ) * height,
g = 0;
return new THREE.Vector3( e, f, g )
}
},
satisfyConstraints: function( p1, p2, distance ) {
this.diff.subVectors( p2.position, p1.position );
var currentDist = this.diff.length();
if ( currentDist === 0 )
return; // prevents division by 0
this.diff.normalize();
var correction = this.diff.multiplyScalar( currentDist - distance );
var correctionHalf = correction.multiplyScalar( 0.5 );
p1.position.add( correctionHalf );
p2.position.sub( correctionHalf );
},
simulate: function( timestep_sq ) {
var b, c, d, e, f, g, h, i, j = this.clothGeometry.faces;
for (d = this.cloth.particles, b = 0, c = d.length; c > b; b++) {
e = d[b];
e.addForce(this.gravity);
e.integrate(timestep_sq);
}
for (f = this.cloth.constraints, c = f.length, b = 0; c > b; b++) {
g = f[b];
this.satisfyConstraints(g[0], g[1], g[2]);
}
for (d = this.cloth.particles, b = 0, c = d.length; c > b; b++) {
e = d[b];
e.position.x = e.original.x;
}
for (b = 0, c = this.pins.length; c > b; b++) {
var k = this.pins[ b ],
l = d[ k ];
l.position.y = l.original.y;
l.position.x = l.original.x;
l.position.z = l.position.z + this.wave;
}
if( this.degree <= 6 ) {
this.wave = Math.sin( this.degree ) * 6;
this.degree += 0.017 * 42;
}
else
this.wave = 0;
},
init: function() {
this.clothFunction = this.createPlane( this.size, this.size );
this.cloth = new Cloth( this.MASS, this.SEGMENTS, this.SEGMENTS, this.restDistance, this.DRAG, this.createPlane( this.size, this.size ) );
this.scene = new THREE.Scene;
this.camera = new THREE.PerspectiveCamera( 45, this.canvas.width / this.canvas.height, 1, 1e4 );
this.camera.position.y = 0;
this.camera.position.z = 1e3;
this.scene.add( this.camera );
this.light = new THREE.DirectionalLight( 16777215, 1 );
this.light.position.set( 20, -20, 100 );
this.scene.add( this.light );
THREE.ImageUtils.crossOrigin = "";
var texture = THREE.ImageUtils.loadTexture( this.image, {}, function() {
this.canvas.classList.add("play")
}.bind( this ) );
texture.flipY = !1;
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.anisotropy = 16;
var b = new THREE.MeshPhongMaterial({
ambient: 16777215,
shininess: 20,
map: texture,
side: THREE.DoubleSide
});
this.clothGeometry = new THREE.ParametricGeometry( this.clothFunction, this.cloth.w, this.cloth.h );
this.clothGeometry.dynamic = !0;
this.clothGeometry.computeFaceNormals();
var c = {
texture: {
type: "t",
value: texture
}
},
d = "varying vec2 vUV;void main() {vUV = 0.75 * uv;vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );gl_Position = projectionMatrix * mvPosition;}",
e = "uniform sampler2D texture;varying vec2 vUV;vec4 pack_depth( const in float depth ) {const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );vec4 res = fract( depth * bit_shift );res -= res.xxyz * bit_mask;return res;}void main() {vec4 pixel = texture2D( texture, vUV );if ( pixel.a < 0.5 ) discard;gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );}";
this.object = new THREE.Mesh( this.clothGeometry, b );
this.object.position.set( 0, 0, 0 );
this.scene.add( this.object );
this.object.customDepthMaterial = new THREE.ShaderMaterial({
uniforms: c,
vertexShader: d,
fragmentShader: e
});
this.renderer = new THREE.WebGLRenderer({
antialias: !0,
canvas: this.canvas
});
this.renderer.setSize( this.canvas.width, this.canvas.height );
this.renderer.setClearColor( 16777215, 1 );
this.renderer.autoClear = !1;
this.renderer.autoClearDepth = !1;
this.container.appendChild( this.renderer.domElement );
this.renderer.gammaInput = !0;
this.renderer.gammaOutput = !0;
this.canvas.addEventListener("mousedown", this.onClick.bind( this ), !1 );
for (var f = 0; 20 > f; f++) this.simulate(this.TIMESTEP_SQ);
this.play();
},
onClick: function(a) {
},
animate: function() {
this.animationFrame = window.requestAnimationFrame(this.animate.bind(this));
this.simulate(this.TIMESTEP_SQ);
this.render();
},
pause: function() {
window.cancelAnimationFrame( this.animationFrame );
},
play: function() {
this.scene ? this.animate() : this.init();
},
render: function() {
for ( var a = this.cloth.particles, b = 0, c = a.length; c > b; b++ )
this.clothGeometry.vertices[ b ].copy( a[ b ].position );
this.clothGeometry.computeFaceNormals();
this.clothGeometry.computeVertexNormals();
this.clothGeometry.normalsNeedUpdate = !0;
this.clothGeometry.verticesNeedUpdate = !0;
this.camera.lookAt( this.scene.position );
this.renderer.clear();
this.renderer.render( this.scene, this.camera );
},
stop: function() {
this.pause();
this.canvas.parentNode.removeChild( this.canvas );
}
};
var size = 700,
container = document.getElementById( "product-container" ),
image = "http://media.hermes.com/media/catalog/product/import/S/S01/S011/item/flat/hd/H001485S-17.jpg",
canvas = document.createElement( "canvas" );
canvas.width = canvas.height = 600 + 20,
canvas.id = "product",
container.appendChild( canvas ),
productAnimation = new animatedProduct( container, size, canvas, image );
productAnimation.play();
<script src="http://maksible.com/cloth/cloth_slower_v2/cloth/three.min.js"></script>
<body>
<div id="product-container"></div>
<script type="text/javascript" src="three.min.js"></script>
<script type="text/javascript" src="logic.js"></script>
</body>
Here is the solution with three.js but with different logic than yours. Hope it might be useful for you.
var size = 500;
var img = 'Image.jpg';
window.onload = function() {
createWGL();
render();
}
// render
//
function render() {
requestAnimationFrame( render );
if(window.mat)
mat.uniforms.time.value = now();
ctx.render( scn, cam );
}
// create renderer
//
function createWGL() {
// check desktop/mobile
window.desk = !(/Android|webOS|iPhone|iPad|BlackBerry|Windows Phone|Opera Mini|IEMobile|Mobile/i.test(navigator.userAgent));
window.ctx = new THREE.WebGLRenderer({antialias:window.desk});
ctx.setClearColor( 0xffffff );
ctx.setPixelRatio( window.devicePixelRatio );
ctx.setSize( size, size );
// camera
window.cam = new THREE.PerspectiveCamera( 90, 1, 1, 30 );
cam.position.z = 25;
// scene
window.scn = new THREE.Scene();
// canvas
window.cvs = createCanvas();
scn.add( cvs );
loadCanvasTexture( img );
// clear viewport
ctx.render( scn, cam );
document.body.appendChild( ctx.domElement );
}
// now
//
function now(){
return performance.now() * 0.001;
}
// load canvas texture
//
function loadCanvasTexture( path ) {
if(window.tex)
window.tex.dispose();
cvs.visible = false;
window.tex = new THREE.TextureLoader().load( path, function(){
cvs.visible = true;
});
window.tex.anisotropy = ctx.getMaxAnisotropy();
window.mat.uniforms.tex.value = window.tex;
}
// create canvas
//
function createCanvas() {
window.mat = new THREE.RawShaderMaterial({
uniforms: {
time: { value: now() },
tex: { value: null }
},
vertexShader: 'precision mediump float;precision mediump int;uniform mat4 modelViewMatrix;'+
'uniform mat4 projectionMatrix;attribute vec2 pos;uniform float time;varying vec2 uv;varying float amb;'+
'float d(float y){return cos(sin(time/2.)+time/2.+y/2.14)*sin(time+y/4.17)*(.5-y/40.)*1.5;}'+
'void main(){vec3 p=vec3( pos.x+sin(time/3.)*(.5-pos.y/40.), pos.y+sin(time)*(.5-pos.y/40.)/2., d(pos.y));amb=(d(pos.y-1.)-d(pos.y+1.))/4.;'+
'uv=vec2(pos.x/40.+.5,pos.y/40.+.5);gl_Position=projectionMatrix*modelViewMatrix*vec4(p,1.);}',
fragmentShader: 'precision mediump float;precision mediump int;uniform sampler2D tex;varying vec2 uv;varying float amb;'+
'void main(){vec4 col=texture2D(tex,uv)+amb;gl_FragColor=vec4(col.xyz,1.);}'
});
var d = 40,d2=~~(d/2),i,j,k,n,fi,v,m,z1=-1,z2;
fi = new Uint16Array( d * d * 6 );
v = new Int8Array( (d+1) * (d+1) * 2 );
for(j=0;j<=d;j++)
for(i=0;i<=d;i++) {
k = i + j*(d+1);
v[k*2] = i - d2;
v[k*2+1] = j - d2;
if(i<d&&j<d) {
n = (i + j*d) * 6;
fi[n] = k;
fi[n+1] = k + 1;
fi[n+2] = k + d + 1;
fi[n+3] = k + d + 1;
fi[n+4] = k + 1;
fi[n+5] = k + d + 2;
}
}
for(i=0,j=-1;i<fi.length;i++)
if(j<fi[i])
j = fi[i];
m = new THREE.Mesh( new THREE.BufferGeometry(), mat );
m.geometry.setIndex( new THREE.BufferAttribute( fi, 1 ));
m.geometry.addAttribute( 'pos', new THREE.BufferAttribute( v, 2 ));
return m;
}
just change your logic code with this and run.
cheers!

HTML5 canvas following mouse effect jquery

I'm searching the web for quite sometime for the name of this effect... I've seen it on many sites but can't find a guide or a name to look for it and learn how to do it.
The effect I'm talking about is in this website header:
http://diogodantas.com/demo/elegant-index#0
check this. i just ctrl + c,v.
(function() {
var width, height, largeHeader, canvas, ctx, points, target, animateHeader = true;
// Main
initHeader();
initAnimation();
addListeners();
function initHeader() {
width = window.innerWidth;
height = window.innerHeight;
target = {x: width/2, y: height/2};
largeHeader = document.getElementById('large-header');
largeHeader.style.height = height+'px';
canvas = document.getElementById('demo-canvas');
canvas.width = width;
canvas.height = height;
ctx = canvas.getContext('2d');
// create points
points = [];
for(var x = 0; x < width; x = x + width/20) {
for(var y = 0; y < height; y = y + height/20) {
var px = x + Math.random()*width/20;
var py = y + Math.random()*height/20;
var p = {x: px, originX: px, y: py, originY: py };
points.push(p);
}
}
// for each point find the 5 closest points
for(var i = 0; i < points.length; i++) {
var closest = [];
var p1 = points[i];
for(var j = 0; j < points.length; j++) {
var p2 = points[j]
if(!(p1 == p2)) {
var placed = false;
for(var k = 0; k < 5; k++) {
if(!placed) {
if(closest[k] == undefined) {
closest[k] = p2;
placed = true;
}
}
}
for(var k = 0; k < 5; k++) {
if(!placed) {
if(getDistance(p1, p2) < getDistance(p1, closest[k])) {
closest[k] = p2;
placed = true;
}
}
}
}
}
p1.closest = closest;
}
// assign a circle to each point
for(var i in points) {
var c = new Circle(points[i], 2+Math.random()*2, 'rgba(255,255,255,0.3)');
points[i].circle = c;
}
}
// Event handling
function addListeners() {
if(!('ontouchstart' in window)) {
window.addEventListener('mousemove', mouseMove);
}
window.addEventListener('scroll', scrollCheck);
window.addEventListener('resize', resize);
}
function mouseMove(e) {
var posx = posy = 0;
if (e.pageX || e.pageY) {
posx = e.pageX;
posy = e.pageY;
}
else if (e.clientX || e.clientY) {
posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
target.x = posx;
target.y = posy;
}
function scrollCheck() {
if(document.body.scrollTop > height) animateHeader = false;
else animateHeader = true;
}
function resize() {
width = window.innerWidth;
height = window.innerHeight;
largeHeader.style.height = height+'px';
canvas.width = width;
canvas.height = height;
}
// animation
function initAnimation() {
animate();
for(var i in points) {
shiftPoint(points[i]);
}
}
function animate() {
if(animateHeader) {
ctx.clearRect(0,0,width,height);
for(var i in points) {
// detect points in range
if(Math.abs(getDistance(target, points[i])) < 4000) {
points[i].active = 0.3;
points[i].circle.active = 0.6;
} else if(Math.abs(getDistance(target, points[i])) < 20000) {
points[i].active = 0.1;
points[i].circle.active = 0.3;
} else if(Math.abs(getDistance(target, points[i])) < 40000) {
points[i].active = 0.02;
points[i].circle.active = 0.1;
} else {
points[i].active = 0;
points[i].circle.active = 0;
}
drawLines(points[i]);
points[i].circle.draw();
}
}
requestAnimationFrame(animate);
}
function shiftPoint(p) {
TweenLite.to(p, 1+1*Math.random(), {x:p.originX-50+Math.random()*100,
y: p.originY-50+Math.random()*100, ease:Circ.easeInOut,
onComplete: function() {
shiftPoint(p);
}});
}
// Canvas manipulation
function drawLines(p) {
if(!p.active) return;
for(var i in p.closest) {
ctx.beginPath();
ctx.moveTo(p.x, p.y);
ctx.lineTo(p.closest[i].x, p.closest[i].y);
ctx.strokeStyle = 'rgba(156,217,249,'+ p.active+')';
ctx.stroke();
}
}
function Circle(pos,rad,color) {
var _this = this;
// constructor
(function() {
_this.pos = pos || null;
_this.radius = rad || null;
_this.color = color || null;
})();
this.draw = function() {
if(!_this.active) return;
ctx.beginPath();
ctx.arc(_this.pos.x, _this.pos.y, _this.radius, 0, 2 * Math.PI, false);
ctx.fillStyle = 'rgba(156,217,249,'+ _this.active+')';
ctx.fill();
};
}
// Util
function getDistance(p1, p2) {
return Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2);
}
})();
I still cannot find a name but here is a link
https://codepen.io/thetwistedtaste/pen/GgrWLp
/*
*
* TERMS OF USE -
*
* Open source under the BSD License.
*
* Copyright © 2001 Robert Penner
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the author nor the names of contributors may be used to endorse
* or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
// MIT license
(function() {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());
$( function() {
var width, height, canvas, ctx, points, target, animateHeader = true;
// Main
initHeader();
initAnimation();
addListeners();
function initHeader() {
width = window.innerWidth;
height = window.innerHeight;
target = {
x: width / 2,
y: height / 3
};
canvas = document.getElementById( 'spiders' );
canvas.width = width;
canvas.height = height;
ctx = canvas.getContext( '2d' );
// create points
points = [];
for ( var x = 0; x < width; x = x + width / 20 ) {
for ( var y = 0; y < height; y = y + height / 20 ) {
var px = x + Math.random() * width / 20;
var py = y + Math.random() * height / 20;
var p = {
x: px,
originX: px,
y: py,
originY: py
};
points.push( p );
}
}
// for each point find the 5 closest points
for ( var i = 0; i < points.length; i++ ) {
var closest = [];
var p1 = points[ i ];
for ( var j = 0; j < points.length; j++ ) {
var p2 = points[ j ]
if ( !( p1 == p2 ) ) {
var placed = false;
for ( var k = 0; k < 5; k++ ) {
if ( !placed ) {
if ( closest[ k ] == undefined ) {
closest[ k ] = p2;
placed = true;
}
}
}
for ( var k = 0; k < 5; k++ ) {
if ( !placed ) {
if ( getDistance( p1, p2 ) < getDistance( p1, closest[ k ] ) ) {
closest[ k ] = p2;
placed = true;
}
}
}
}
}
p1.closest = closest;
}
// assign a circle to each point
for ( var i in points ) {
var c = new Circle( points[ i ], 2 + Math.random() * 2, 'rgba(255,255,255,0.3)' );
points[ i ].circle = c;
}
}
// Event handling
function addListeners() {
if ( !( 'ontouchstart' in window ) ) {
window.addEventListener( 'mousemove', mouseMove );
}
window.addEventListener( 'scroll', scrollCheck );
window.addEventListener( 'resize', resize );
}
function mouseMove( e ) {
var posx = posy = 0;
if ( e.pageX || e.pageY ) {
posx = e.pageX;
posy = e.pageY;
} else if ( e.clientX || e.clientY ) {
posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
target.x = posx;
target.y = posy;
}
function scrollCheck() {
if ( document.body.scrollTop > height ) animateHeader = false;
else animateHeader = true;
}
function resize() {
width = window.innerWidth;
height = window.innerHeight;
canvas.width = width;
canvas.height = height;
}
// animation
function initAnimation() {
animate();
for ( var i in points ) {
shiftPoint( points[ i ] );
}
}
function animate() {
if ( animateHeader ) {
ctx.clearRect( 0, 0, width, height );
for ( var i in points ) {
// detect points in range
if ( Math.abs( getDistance( target, points[ i ] ) ) < 2000 ) {
points[ i ].active = 0.2;
points[ i ].circle.active = 0.5;
} else if ( Math.abs( getDistance( target, points[ i ] ) ) < 20000 ) {
points[ i ].active = 0.1;
points[ i ].circle.active = 0.3;
} else if ( Math.abs( getDistance( target, points[ i ] ) ) < 70000 ) {
points[ i ].active = 0.02;
points[ i ].circle.active = 0.09;
} else if ( Math.abs( getDistance( target, points[ i ] ) ) < 140000 ) {
points[ i ].active = 0;
points[ i ].circle.active = 0.02;
} else {
points[ i ].active = 0;
points[ i ].circle.active = 0;
}
drawLines( points[ i ] );
points[ i ].circle.draw();
}
}
requestAnimationFrame( animate );
}
function shiftPoint( p ) {
TweenLite.to( p, 1 + 1 * Math.random(), {
x: p.originX - 50 + Math.random() * 100,
y: p.originY - 50 + Math.random() * 100,
onComplete: function() {
shiftPoint( p );
}
} );
}
// Canvas manipulation
function drawLines( p ) {
if ( !p.active ) return;
for ( var i in p.closest ) {
ctx.beginPath();
ctx.moveTo( p.x, p.y );
ctx.lineTo( p.closest[ i ].x, p.closest[ i ].y );
ctx.strokeStyle = 'rgba(255,255,255,' + p.active + ')';
ctx.stroke();
}
}
function Circle( pos, rad, color ) {
var _this = this;
// constructor
( function() {
_this.pos = pos || null;
_this.radius = rad || null;
_this.color = color || null;
} )();
this.draw = function() {
if ( !_this.active ) return;
ctx.beginPath();
ctx.arc( _this.pos.x, _this.pos.y, _this.radius, 0, 2 * Math.PI, false );
ctx.fillStyle = 'rgba(255,255,255,' + _this.active + ')';
ctx.fill();
};
}
// Util
function getDistance( p1, p2 ) {
return Math.pow( p1.x - p2.x, 2 ) + Math.pow( p1.y - p2.y, 2 );
}
} );
body {}
i {
position: absolute;
top:0; bottom:0;left:0;right:0;
display:block;
background:black;
z-index:-1;
}
canvas#spiders {
height:100vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenLite.min.js"></script><script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<i></i>
<canvas id="spiders" class="hidden-xs" width="1280" height="451"></canvas>

Categories