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>
Related
N-Body gravity simulation seems to be working fine at first glance, and the same is true for body collisions, but once gravitationally attracted objects start to collide, they start to spiral around each other frantically and the collection of them as a whole have very erratic motion... The code (html-javascript) will be included below, and to reproduce what I'm talking about, you can create a new body by clicking in a random location on the screen.
The math for gravitational attraction is done in the Body.prototype.gravityCalc() method of the Body object type (line 261). The math for the collision resolution is found in the dynamic collision section of the bodyHandle() function (line 337).
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// event handling
document.addEventListener('keydown', keyDown);
document.addEventListener('mousedown', mouseDown)
document.addEventListener('mouseup', mouseUp)
document.addEventListener('mousemove', mouseMove);
document.addEventListener('touchstart', touchStart);
document.addEventListener('touchmove', touchMove);
document.addEventListener('touchend', touchEnd);
window.addEventListener('resize', resize);
window.onload = function() {reset()}
mouseDown = false;
nothingGrabbed = true;
mouseX = 0;
mouseY = 0;
function keyDown(data) {
if(data.key == "r") {
clearInterval(loop);
reset();
}
else if(data.key == 'g') {
gravityOn = !gravityOn;
}
else if(data.key == 'Delete') {
for(i = 0; i < bodies.length ; i++) {
if(((mouseX - bodies[i].x)**2 + (mouseY - bodies[i].y)**2) <= bodies[i].radius**2) {
bodies.splice(i, 1);
}
}
}
else if(data.key == 'c') {
gravity_c *= -1;
}
else if(data.key == 'f') {
falling = !falling;
}
else if(data.key == 'a') {
acceleration *= -1;
}
}
function mouseDown(data) {
mouseDown = true;
nothingGrabbed = true;
mouseX = data.clientX;
mouseY = canvas.height - data.clientY;
}
function mouseUp(data) {
mouseDown = false;
nothingGrabbed = true;
for(i = 0; i < bodies.length; i++) {
bodies[i].grabbed = false
}
}
function mouseMove(data) {
mouseX = data.clientX;
mouseY = canvas.height - data.clientY;
}
function touchStart(data) {
mouseDown = true;
nothingGrabbed = true;
mouseX = data.touches[0].clientX;
mouseY = canvas.height - data.touches[0].clientY;
}
function touchMove(data) {
mouseX = data.touches[0].clientX;
mouseY = canvas.height - data.touches[0].clientY;
}
function touchEnd(data) {
mouseDown = false;
nothingGrabbed = true;
for(i=0;i<bodies.length;i++) {
bodies[i].grabbed = false;
}
}
function resize(data) {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Initialize Variables
function reset() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.color = 'rgb(70, 70, 70)';
scale = Math.min(canvas.width, canvas.height);
fps = 120;
running = true;
loop = setInterval(main, 1000/fps);
gravityOn = true // if true, objects are gravitationally attracted to each other
gravity_c = 334000 // universe's gravitational constant
boundaryCollision = true // if true, objects collide with edges of canvas
wallDampen = 0.7 // number to multiply by when an objects hit a wall
bodyCollision = true // if true, bodies will collide with each other
bodyDampen = 0.4 // number to multiply when two objects collide
falling = false // if true, objects will fall to the bottom of the screen
acceleration = 400
bodies = [] // a list of each Body object
collidingPairs = [] // a list of pairs of colliding bodies
/*
var bounds = 200;
for(i = 0; i<70; i++) { // randomly place bodies
Body.create({
x: Math.floor(Math.random()*canvas.width),
y: Math.floor(Math.random()*canvas.height),
a: Math.random()*Math.PI*2,
xV: Math.floor(Math.random() * (bounds - -bounds)) + -bounds,
yV: Math.floor(Math.random() * (bounds - -bounds)) + -bounds,
mass: Math.ceil(Math.random()*23)
})
} */
/*
Body.create({
x: canvas.width/2 - 50,
xV: 10,
yV: 0,
aV: 3,
y: canvas.height/2 + 0,
mass: 10
});
Body.create({
x: canvas.width/2 + 50,
xV: 0,
aV: 0,
y: canvas.height/2,
mass: 10
});
*/
Body.create({
x: canvas.width/2,
y: canvas.height/2,
mass: 24,
xV: -10.83
});
Body.create({
x: canvas.width/2,
y: canvas.height/2 + 150,
mass: 1,
xV: 260,
color: 'teal'
});
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Body Type Object
function Body(params) {
this.x = params.x || canvas.width/2;
this.y = params.y || canvas.height/2;
this.a = params.a || 0;
this.xV = params.xV || 0;
this.yV = params.yV || 0;
this.aV = params.aV || 0;
this.xA = params.xA || 0;
this.yA = params.yA || 0;
this.aA = params.aA || 0;
this.grabbed = false;
this.edgeBlock = params.edgeBlock || boundaryCollision;
this.gravity = params.gravityOn || gravityOn;
this.mass = params.mass || 6;
this.density = params.density || 0.008;
this.radius = params.radius || (this.mass/(Math.PI*this.density))**0.5;
this.color = params.color || 'crimson';
this.lineWidth = params.lineWidth || 2;
}
Body.create = function(params) {
bodies.push(new Body(params));
}
Body.prototype.move = function() {
this.xV += this.xA/fps;
this.yV += this.yA/fps;
this.aV += this.aA/fps;
this.x += this.xV/fps;
this.y += this.yV/fps;
this.a += this.aV/fps;
if(this.edgeBlock) {
if(this.x + this.radius > canvas.width) {
this.x = canvas.width - this.radius;
this.xV *= -wallDampen
}
else if(this.x - this.radius < 0) {
this.x = this.radius;
this.xV *= -wallDampen;
}
if(this.y + this.radius > canvas.height) {
this.y = canvas.height - this.radius;
this.yV *= -wallDampen;
}
else if(this.y - this.radius < 0) {
this.y = this.radius;
this.yV *= -wallDampen;
}
}
if(this.grabbed) {
this.xA = 0;
this.yA = 0;
this.xV = 0;
this.yV = 0;
this.x = mouseX;
this.y = mouseY;
}
}
Body.prototype.draw = function() {
ctx.beginPath();
ctx.strokeStyle = 'black';
ctx.lineWidth = this.lineWidth;
ctx.fillStyle = this.color;
ctx.arc(this.x, canvas.height - this.y, this.radius, 0, Math.PI*2, true);
ctx.fill();
ctx.stroke();
ctx.closePath()
ctx.beginPath();
ctx.strokeStyle = 'black';
ctx.lineWidth = this.linewidth;
ctx.moveTo(this.x, canvas.height - this.y);
ctx.lineTo(this.x + this.radius*Math.cos(this.a), canvas.height - (this.y + this.radius*Math.sin(this.a)))
ctx.stroke();
ctx.closePath();
}
// calculates gravitational attraction to 'otherObject'
Body.prototype.gravityCalc = function(otherObject) {
var x1 = this.x;
var y1 = this.y;
var x2 = otherObject.x;
var y2 = otherObject.y;
var distSquare = ((x2-x1)**2 + (y2-y1)**2);
var val = (gravity_c*otherObject.mass)/((distSquare)**(3/2));
var xA = val * (x2 - x1);
var yA = val * (y2 - y1);
return [xA, yA]
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Physics Code
function bodyHandle() {
for(i = 0; i < bodies.length; i++) {
if(mouseDown && nothingGrabbed) {
if(Math.abs((mouseX - bodies[i].x)**2 + (mouseY - bodies[i].y)**2) <= bodies[i].radius**2) {
bodies[i].grabbed = true;
nothingGrabbed = false;
}
}
bodies[i].draw()
if(running) {
if(falling) {
bodies[i].yV -= acceleration/fps;
}
bodies[i].move();
}
bodies[i].xA = 0;
bodies[i].yA = 0;
collidingPairs = []
if(gravityOn || bodyCollision) {
for(b = 0; b < bodies.length; b++) {
if(i != b) {
if(bodyCollision) {
var x1 = bodies[i].x;
var y1 = bodies[i].y;
var x2 = bodies[b].x;
var y2 = bodies[b].y;
var rSum = bodies[i].radius + bodies[b].radius;
var dist = { // vector
i: x2 - x1,
j: y2 - y1,
mag: ((x2-x1)**2 + (y2-y1)**2)**0.5,
norm: {
i: (x2-x1)/(((x2-x1)**2 + (y2-y1)**2)**0.5),
j: (y2-y1)/(((x2-x1)**2 + (y2-y1)**2)**0.5)
}
}
if(dist.mag <= rSum) { // static collision
var overlap = rSum - dist.mag;
bodies[i].x -= overlap/2 * dist.norm.i;
bodies[i].y -= overlap/2 * dist.norm.j;
bodies[b].x += overlap/2 * dist.norm.i;
bodies[b].y += overlap/2 * dist.norm.j;
collidingPairs.push([bodies[i], bodies[b]]);
}
}
if(gravityOn) {
if(bodies[i].gravity) {
var accel = bodies[i].gravityCalc(bodies[b]);
bodies[i].xA += accel[0];
bodies[i].yA += accel[1];
}
}
}
}
}
for(c = 0; c < collidingPairs.length; c++) { // dynamic collision
var x1 = collidingPairs[c][0].x;
var y1 = collidingPairs[c][0].y;
var r1 = collidingPairs[c][0].radius;
var x2 = collidingPairs[c][1].x;
var y2 = collidingPairs[c][1].y;
var r2 = collidingPairs[c][1].radius;
var dist = { // vector from b1 to b2
i: x2 - x1,
j: y2 - y1,
mag: ((x2-x1)**2 + (y2-y1)**2)**0.5,
norm: {
i: (x2-x1)/(((x2-x1)**2 + (y2-y1)**2)**0.5),
j: (y2-y1)/(((x2-x1)**2 + (y2-y1)**2)**0.5)
}
}
var m1 = collidingPairs[c][0].mass;
var m2 = collidingPairs[c][1].mass;
var norm = { // vector normal along 'wall' of collision
i: -dist.j/(((dist.i)**2 + (-dist.j)**2)**0.5),
j: dist.i/(((dist.i)**2 + (-dist.j)**2)**0.5)
}
var perp = { // vector normal pointing from b1 to b2
i: dist.norm.i,
j: dist.norm.j
}
var vel1 = { // vector of b1 velocity
i: collidingPairs[c][0].xV,
j: collidingPairs[c][0].yV,
dot: function(vect) {
return collidingPairs[c][0].xV * vect.i + collidingPairs[c][0].yV * vect.j
}
}
var vel2 = { // vector of b2 velocity
i: collidingPairs[c][1].xV,
j: collidingPairs[c][1].yV,
dot: function(vect) {
return collidingPairs[c][1].xV * vect.i + collidingPairs[c][1].yV * vect.j
}
}
// new velocities along perp^ of b1 and b2
var nV1Perp = (vel1.dot(perp))*(m1-m2)/(m1+m2) + (vel2.dot(perp))*(2*m2)/(m1+m2);
var nV2Perp = (vel1.dot(perp))*(2*m1)/(m1+m2) + (vel2.dot(perp))*(m2-m1)/(m1+m2);
/* testing rotation after collision
// velocities of the points of collision on b1 and b2
var pVel1M = vel1.dot(norm) + collidingPairs[c][0].aV*r1;
var pVel2M = vel2.dot(norm) + collidingPairs[c][1].aV*r2;
// moment of inertia for b1 and b2
var I1 = 1/2 * m1 * r1**2;
var I2 = 1/2 * m2 * r2**2;
// new velocities of the points of collisions on b1 and b2
var newpVel1M = ((I1-I2)/(I1+I2))*pVel1M + ((2*I2)/(I1+I2))*pVel2M;
var newpVel2M = ((2*I1)/(I1+I2))*pVel1M + ((I2-I1)/(I1+I2))*pVel2M;
var vectToCol1 = { // vector from x1,y1 to point of collision on b1
i: r1*perp.i,
j: r1*perp.j
};
var vectToCol2 = { // vector from x2,y2 to point of collision on b2
i: r2*-perp.i,
j: r2*-perp.j
};
// sign of cross product of pVelM and vectToCol
var vCrossR1 = (pVel1M*norm.i)*(vectToCol1.j) - (pVel1M*norm.j)*(vectToCol1.i);
vCrossR1 = vCrossR1/Math.abs(vCrossR1);
var vCrossR2 = (pVel2M*norm.i)*(vectToCol2.j) - (pVel2M*norm.j)*(vectToCol2.i);
vCrossR2 = vCrossR2/Math.abs(vCrossR2);
collidingPairs[c][0].aV = vCrossR1 * (newpVel1M)/r1;
collidingPairs[c][1].aV = vCrossR2 * (newpVel2M)/r2;
/* draw collision point velocity vectors [debugging]
ctx.beginPath();
ctx.strokeStyle = 'black';
ctx.moveTo(x1 + vectToCol1.i, canvas.height - (y1 + vectToCol1.j));
ctx.lineTo((x1+vectToCol1.i) + pVel1M*norm.i, (canvas.height- (y1+vectToCol1.j + pVel1M*norm.j)));
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.strokeStyle = 'white';
ctx.moveTo(x2 + vectToCol2.i, canvas.height - (y2 + vectToCol2.j));
ctx.lineTo((x2+vectToCol2.i) + pVel2M*norm.i, (canvas.height- (y2+vectToCol2.j + pVel2M*norm.j)));
ctx.stroke();
ctx.closePath();
console.log(pVel1M, pVel2M);
clearInterval(loop);
*/
collidingPairs[c][0].xV = vel1.dot(norm)*norm.i + nV1Perp*perp.i * bodyDampen;
collidingPairs[c][0].yV = vel1.dot(norm)*norm.j + nV1Perp*perp.j * bodyDampen;
collidingPairs[c][1].xV = vel2.dot(norm)*norm.i + nV2Perp*perp.i * bodyDampen;
collidingPairs[c][1].yV = vel2.dot(norm)*norm.j + nV2Perp*perp.j * bodyDampen;
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Main Loop
function main() {
// blank out canvas
ctx.fillStyle = canvas.color;
ctx.fillRect(0, 0, canvas.width, canvas.height);
bodyHandle();
if(nothingGrabbed && mouseDown) {
bodies.push(new Body({x: mouseX,
y: mouseY,
mass: 90}));
bodies[bodies.length-1].move();
bodies[bodies.length-1].draw();
}
}
<html>
<meta name='viewport' content='width=device-width,height=device-height'>
<body>
<canvas id="canvas" width='300px' height='300px'></canvas>
<style>
body {
padding: 0;
margin: 0;
}
canvas {
padding: 0;
margin: 0;
}
</style>
</html>
I cannot tell you much about the code. Personally it seems to me that the animations could be correct.
If you want to test your code you could try to test if laws of conservation of energy and momentum are respected. You could, for example, sum the momentum of every object (mass times velocity) and see if the number are maintained constant when there are no forces from the outside (collisions with the wall). To do this I would suggest to make the free space available larger. Another quantity is the total energy (kinetic plus potential) which is a bit harder, but still easy to compute (to compute tot. pot. energy you have to sum over all pairs).
I'm currently using a canvas animation as the background of my new portfolio page. It works wonderfully until there's more content than can be displayed on a single page, but once you scroll down you'll find the canvas stops at the dimensions of the initial page display even though it's supposed to be the same size as the body element.
I apologize if this is a question that has been answered but I've been looking for a solution all morning and I'm coming up with nothing. Any help you can give is greatly appreciated.
My deployed page can be found here, and below is the JS.
Javascript:
var canvas,
ctx,
circ,
nodes,
mouse,
SENSITIVITY,
SIBLINGS_LIMIT,
DENSITY,
NODES_QTY,
ANCHOR_LENGTH,
MOUSE_RADIUS;
// how close next node must be to activate connection (in px)
// shorter distance == better connection (line width)
SENSITIVITY = 100;
// note that siblings limit is not 'accurate' as the node can actually have more connections than this value that's because the node accepts sibling nodes with no regard to their current connections this is acceptable because potential fix would not result in significant visual difference
// more siblings == bigger node
SIBLINGS_LIMIT = 10;
// default node margin
DENSITY = 50;
// total number of nodes used (incremented after creation)
NODES_QTY = 0;
// avoid nodes spreading
ANCHOR_LENGTH = 20;
// highlight radius
MOUSE_RADIUS = 200;
circ = 2 * Math.PI;
nodes = [];
canvas = document.querySelector("canvas");
resizeWindow();
mouse = {
x: canvas.width / 2,
y: canvas.height / 2
};
ctx = canvas.getContext("2d");
if (!ctx) {
alert("Ooops! Your browser does not support canvas :'(");
}
function Node(x, y) {
this.anchorX = x;
this.anchorY = y;
this.x = Math.random() * (x - (x - ANCHOR_LENGTH)) + (x - ANCHOR_LENGTH);
this.y = Math.random() * (y - (y - ANCHOR_LENGTH)) + (y - ANCHOR_LENGTH);
this.vx = Math.random() * 2 - 1;
this.vy = Math.random() * 2 - 1;
this.energy = Math.random() * 100;
this.radius = Math.random();
this.siblings = [];
this.brightness = 0;
}
Node.prototype.drawNode = function() {
var color = "rgba(216, 48, 168, " + this.brightness + ")";
ctx.beginPath();
ctx.arc(
this.x,
this.y,
2 * this.radius + (2 * this.siblings.length) / SIBLINGS_LIMIT,
0,
circ
);
ctx.fillStyle = color;
ctx.fill();
};
Node.prototype.drawConnections = function() {
for (var i = 0; i < this.siblings.length; i++) {
var color = "rgba(24, 168, 216, " + this.brightness + ")";
ctx.beginPath();
ctx.moveTo(this.x, this.y);
ctx.lineTo(this.siblings[i].x, this.siblings[i].y);
ctx.lineWidth = 1 - calcDistance(this, this.siblings[i]) / SENSITIVITY;
ctx.strokeStyle = color;
ctx.stroke();
}
};
Node.prototype.moveNode = function() {
this.enbergy -= 2;
if (this.energy < 1) {
this.energy = Math.random() * 100;
if (this.x - this.anchorX < -ANCHOR_LENGTH) {
this.vx = Math.random() * 2;
} else if (this.x - this.anchorX > ANCHOR_LENGTH) {
this.vx = Math.random() * -2;
} else {
this.vx = Math.random() * 4 - 2;
}
if (this.y - this.anchorY < -ANCHOR_LENGTH) {
this.vy = Math.random() * 2;
} else if (this.y - this.anchorY > ANCHOR_LENGTH) {
this.vy = Math.random() * -2;
} else {
this.vy = Math.random() * 4 - 2;
}
}
this.x += (this.vx * this.energy) / 100;
this.y += (this.vy * this.energy) / 100;
};
function initNodes() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
nodes = [];
for (var i = DENSITY; i < canvas.width; i += DENSITY) {
for (var j = DENSITY; j < canvas.height; j += DENSITY) {
nodes.push(new Node(i, j));
NODES_QTY++;
}
}
}
function calcDistance(node1, node2) {
return Math.sqrt(
Math.pow(node1.x - node2.x, 2) + Math.pow(node1.y - node2.y, 2)
);
}
function findSiblings() {
var node1, node2, distance;
for (var i = 0; i < NODES_QTY; i++) {
node1 = nodes[i];
node1.siblings = [];
for (var j = 0; j < NODES_QTY; j++) {
node2 = nodes[j];
if (node1 !== node2) {
distance = calcDistance(node1, node2);
if (distance < SENSITIVITY) {
if (node1.siblings.length < SIBLINGS_LIMIT) {
node1.siblings.push(node2);
} else {
var node_sibling_distance = 0;
var max_distance = 0;
var s;
for (var k = 0; k < SIBLINGS_LIMIT; k++) {
node_sibling_distance = calcDistance(node1, node1.siblings[k]);
if (node_sibling_distance > max_distance) {
max_distance = node_sibling_distance;
s = k;
}
}
if (distance < max_distance) {
node1.siblings.splice(s, 1);
node1.siblings.push(node2);
}
}
}
}
}
}
}
function redrawScene() {
resizeWindow();
ctx.clearRect(0, 0, canvas.width, canvas.height);
findSiblings();
var i, node, distance;
for (i = 0; i < NODES_QTY; i++) {
node = nodes[i];
distance = calcDistance(
{
x: mouse.x,
y: mouse.y
},
node
);
if (distance < MOUSE_RADIUS) {
node.brightness = 1 - distance / MOUSE_RADIUS;
} else {
node.brightness = 0;
}
}
for (i = 0; i < NODES_QTY; i++) {
node = nodes[i];
if (node.brightness) {
node.drawNode();
node.drawConnections();
}
node.moveNode();
}
requestAnimationFrame(redrawScene);
}
function initHandlers() {
document.addEventListener("resize", resizeWindow, false);
canvas.addEventListener("mousemove", mousemoveHandler, false);
}
function resizeWindow() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
function mousemoveHandler(e) {
mouse.x = e.clientX;
mouse.y = e.clientY;
}
initHandlers();
initNodes();
redrawScene();
})();
Set the canvas width property to document.body.scrollHeight, that's the full height of the document
Set the canvas height property to document.body.clientWidth, that's the full width of the document minus the scroll bar.
Change the height style of the canvas to fit-content or remove it. height: 100% will make it as high as the viewport.
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)
-->
i"m working in angular projet and i want to add two javascript file in my project ; so i just include those js file in my assets and call them in my angular cli script part . i can see that those file are called correcty .
but i have this problems :
my html code is :
<div class=" demo-1">
<div class="content">
<div id="large-header" class="large-header">
<canvas id="demo-canvas"></canvas>
<h1 class="main-title">ALTEN <span class="thin">GAV²</span></h1>
</div>
</div>
</div><!-- /container -->
and my js code is :
(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);
}
})();
when i try to log the largeHeader viariable in my js it return null .
this code work correctly . but including it in angular cli make problems .
is that a problem of webpack ?
thank you in advance
It's important to say what build tool you are using. If it's Webpack based (ie. Angular CLI) then you can reference a JavaScript file (or any other type) with one of the following:
import * as test from './test.js';
// or
require('./test.js');
However, your error message indicates that your JavaScript is running, but it's failing on these lines:
largeHeader = document.getElementById('large-header');
largeHeader.style.height = height+'px';
It's not finding an element on your page with ID large-header, so the call to .style fails. I suspect that, because you are importing the file from the top level HTML page, the JavaScript code is running before the template has a chance to render, so the large-header element is not created at that point.
To diagnose further, you could use the Sources tab of the Chrome Dev Tools to set a breakpoint on the line in question, then inspect the Elements tab to see if the expected div is actually present at this point.
I'm not sure exactly what you're trying to achieve here, but throwing in arbitrary bits of JavaScript that are not part of the "Angular world" might not be the best way to approach an Angular app. In the long term, perhaps it would be better to refactor this code into a Component or a Directive.
I'm creating one drawing app, there I have option to zoom in/out of the canvas image which I have drawn using drawImage() method, after zoom the image I am trying to save the image using toDataUrl() method but its showing blank page after assigning width and height of zoomed image to canvas.
Below code is to save the image after zoomed
destinationCanvas.width = 500; // actual size given with integer values
destinationCanvas.height = 500;
destinationCanvas.style.width = '500px'; // show at 50% on screen
destinationCanvas.style.height = '500px';
var destinationCanvasURL = destinationCanvas.toDataURL();
console.log("markerNormalStyleChange() destinationCanvasURL - "+destinationCanvasURL);
function drawImage(_onScreenMarkingImagePath) {
var canvas = document.getElementById('drawOnScreen');
var ctx = canvas.getContext("2d");
var imageObject = new Image();
var div = $('#drawOnScreenContext'),
w = $(window).width() - 1,
h = $(window).height() - 150;
canvas.width = w;
canvas.height = h ;
$(imageObject).load(function () {
ctx.drawImage(imageObject, 0, 0, w,h);
});
}
Below code is for rawing and zooming the image, here after draw on canvas if I try to zoom then drawn contents will removed because its drawing image only, so for zooming I want to zoom drawn contents also
var requestID;
(function() {
var root = this; //global object
var ImgTouchCanvas = function(options) {
if( !options || !options.canvas || !options.path) {
throw 'ImgZoom constructor: missing arguments canvas or path';
}
this.canvas = options.canvas;
this.canvas.width = this.canvas.clientWidth;
this.canvas.height = this.canvas.clientHeight;
this.context = this.canvas.getContext('2d');
console.log("ImgTouchCanvas() initiated this.canvas.width - "+this.canvas.width);
console.log("ImgTouchCanvas() initiated this.canvas.height - "+this.canvas.height);
this.desktop = options.desktop || false; //non touch events
this.position = {
x: 0,
y: 0
};
this.scale = {
x: 0.5,
y: 0.5
};
this.imgTexture = new Image();
this.imgTexture.src = options.path;
this.lastZoomScale = null;
this.lastX = null;
this.lastY = null;
this.init = false;
this.checkRequestAnimationFrame();
requestID = requestAnimationFrame(this.animate.bind(this));
this.setEventListeners();
};
ImgTouchCanvas.prototype = {
animate: function() {
console.log("ImgTouchCanvas requestAnimationFrame()");
//set scale such as image cover all the canvas
if(!this.init) {
if(this.imgTexture.width) {
var scaleRatio = null;
if(this.canvas.clientWidth > this.canvas.clientHeight) {
scaleRatio = this.canvas.clientWidth / this.imgTexture.width;
}
else {
scaleRatio = this.canvas.clientHeight / this.imgTexture.height;
}
this.scale.x = scaleRatio;
this.scale.y = scaleRatio;
this.init = true;
}
}
//this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
//canvas.width = w;
//canvas.height = h ;
/*this.canvas.width = zoomWidth;
this.canvas.height = zoomHeight;*/
this.context.drawImage(
this.imgTexture,
this.position.x, this.position.y,
this.scale.x * this.imgTexture.width,
this.scale.y * this.imgTexture.height);
console.log("this.scale.x * this.imgTexture.width -- "+this.scale.x * this.imgTexture.width);
console.log("this.scale.y * this.imgTexture.height -- "+this.scale.y * this.imgTexture.height);
mWidth = this.scale.x * this.imgTexture.width;
mHeight = this.scale.y * this.imgTexture.height;
console.log("mWidth -- "+mWidth);
console.log("mHeight -- "+mHeight);
//if($('#pinchZoomInZoomOut').find('#pinchZoomInZoomOutBg').hasClass('btnIconHighLight')) {
//requestAnimationFrame(this.animate.bind(this));
//}else{
//cancelAnimationFrame(this.animate.bind(this));
//}
},
gesturePinchZoom: function(event) {
var zoom = false;
if( event.targetTouches.length >= 2 ) {
var p1 = event.targetTouches[0];
var p2 = event.targetTouches[1];
var zoomScale = Math.sqrt(Math.pow(p2.pageX - p1.pageX, 2) + Math.pow(p2.pageY - p1.pageY, 2)); //euclidian distance
if( this.lastZoomScale ) {
zoom = zoomScale - this.lastZoomScale;
}
this.lastZoomScale = zoomScale;
}
return zoom;
},
doZoom: function(zoom) {
if(!zoom) return;
//new scale
var currentScale = this.scale.x;
var newScale = this.scale.x + zoom/100;
//some helpers
var deltaScale = newScale - currentScale;
var currentWidth = (this.imgTexture.width * this.scale.x);
var currentHeight = (this.imgTexture.height * this.scale.y);
var deltaWidth = this.imgTexture.width*deltaScale;
var deltaHeight = this.imgTexture.height*deltaScale;
//by default scale doesnt change position and only add/remove pixel to right and bottom
//so we must move the image to the left to keep the image centered
//ex: coefX and coefY = 0.5 when image is centered <=> move image to the left 0.5x pixels added to the right
var canvasmiddleX = this.canvas.clientWidth / 2;
var canvasmiddleY = this.canvas.clientHeight / 2;
var xonmap = (-this.position.x) + canvasmiddleX;
var yonmap = (-this.position.y) + canvasmiddleY;
var coefX = -xonmap / (currentWidth);
var coefY = -yonmap / (currentHeight);
var newPosX = this.position.x + deltaWidth*coefX;
var newPosY = this.position.y + deltaHeight*coefY;
//edges cases
var newWidth = currentWidth + deltaWidth;
var newHeight = currentHeight + deltaHeight;
zoomWidth = newWidth;
zoomHeight = newHeight;
//console.log("doZoom() newWidth -- "+newWidth);
//console.log("doZoom() newHeight -- "+newHeight);
if( newWidth < this.canvas.clientWidth ) return;
if( newPosX > 0 ) { newPosX = 0; }
if( newPosX + newWidth < this.canvas.clientWidth ) { newPosX = this.canvas.clientWidth - newWidth;}
if( newHeight < this.canvas.clientHeight ) return;
if( newPosY > 0 ) { newPosY = 0; }
if( newPosY + newHeight < this.canvas.clientHeight ) { newPosY = this.canvas.clientHeight - newHeight; }
//finally affectations
this.scale.x = newScale;
this.scale.y = newScale;
this.position.x = newPosX;
this.position.y = newPosY;
},
doMove: function(relativeX, relativeY) {
if(this.lastX && this.lastY) {
var deltaX = relativeX - this.lastX;
var deltaY = relativeY - this.lastY;
var currentWidth = (this.imgTexture.width * this.scale.x);
var currentHeight = (this.imgTexture.height * this.scale.y);
//console.log("doZoom() currentWidth -- "+currentWidth);
//console.log("doZoom() currentHeight -- "+currentHeight);
this.position.x += deltaX;
this.position.y += deltaY;
//edge cases
if( this.position.x > 0 ) {
this.position.x = 0;
}
else if( this.position.x + currentWidth < this.canvas.clientWidth ) {
this.position.x = this.canvas.clientWidth - currentWidth;
}
if( this.position.y > 0 ) {
this.position.y = 0;
}
else if( this.position.y + currentHeight < this.canvas.clientHeight ) {
this.position.y = this.canvas.clientHeight - currentHeight;
}
}
this.lastX = relativeX;
this.lastY = relativeY;
},
Draw222: function(x, y, isDown) {
//console.log("Draw222() -- "+isDown);
if (isDown) {
this.context.beginPath();
this.context.strokeStyle="#FF0000";
this.context.lineWidth = 5;
this.context.lineJoin = "round";
this.context.moveTo(lx, ly);
this.context.lineTo(x, y);
this.context.closePath();
this.context.stroke();
}
lx = x; ly = y;
},
setEventListeners: function() {
// touch
this.canvas.addEventListener('touchstart', function(e) {
this.lastX = null;
this.lastY = null;
this.lastZoomScale = null;
//newCtx = this.canvas.getContext("2d");
var relativeX = e.targetTouches[0].pageX - this.canvas.getBoundingClientRect().left;
var relativeY = e.targetTouches[0].pageY - this.canvas.getBoundingClientRect().top;
if($('#pinchZoomInZoomOut').find('#pinchZoomInZoomOutBg').hasClass('btnIconHighLight')) {
//requestAnimationFrame(this.animate.bind(this));
}else{
$( '#undoIcon' ).css({
opacity: 1,
pointerEvents: 'auto'
});
cancelAnimationFrame(this.animate.bind(this));
canvasPressed = true;
this.Draw222(parseInt(relativeX), parseInt(relativeY), false);
}
}.bind(this));
this.canvas.addEventListener('touchmove', function(e) {
e.preventDefault();
if(e.targetTouches.length == 2 && $('#pinchZoomInZoomOut').find('#pinchZoomInZoomOutBg').hasClass('btnIconHighLight')) { //pinch
console.log("pinch zoom")
requestID = requestAnimationFrame(this.animate.bind(this));
this.doZoom(this.gesturePinchZoom(e));
}
else {
//console.log("touchmove --- 1")
var relativeX = e.targetTouches[0].pageX - this.canvas.getBoundingClientRect().left;
var relativeY = e.targetTouches[0].pageY - this.canvas.getBoundingClientRect().top;
if($('#pinchZoomInZoomOut').find('#pinchZoomInZoomOutBg').hasClass('btnIconHighLight')) {
//console.log("hasClass btnIconHighLight --- ");
requestID = requestAnimationFrame(this.animate.bind(this));
this.doMove(relativeX, relativeY);
}else{
//console.log("touchmove --- canvasPressed -- "+canvasPressed)
if (canvasPressed) {
cancelAnimationFrame(this.animate.bind(this));
this.Draw222(parseInt(relativeX), parseInt(relativeY), true);
}
}
}
}.bind(this));
this.canvas.addEventListener('touchend', function(e) {
e.preventDefault();
//cPush();
canvasPressed = false;
/*var base64String = null;
var canvas = document.getElementById('drawOnScreen');
var context = canvas.getContext('2d');
// save canvas image as data url (png format by default)
var dataURL = canvas.toDataURL();
console.log("dataURL - "+dataURL);*/
//base64ByteString = dataURL;
//dataURL = dataURL.substr(dataURL.lastIndexOf(',') + 1);
}.bind(this));
},
checkRequestAnimationFrame: 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);
};
}
}
};
root.ImgTouchCanvas = ImgTouchCanvas;
}).call(this);
And for pinch zoom in/out the image, I am using this https://github.com/rombdn/img-touch-canvas