Full-page background made with JavaScript and Canvas: the animation follows movement on non-touch devices
Forked from Marco Guglielmelli's Pen Animated Background.
Full-page background made with JavaScript and Canvas: the animation follows movement on non-touch devices
Forked from Marco Guglielmelli's Pen Animated Background.
| <div id="large-header" class="large-header"> | |
| <canvas id="demo-canvas"></canvas> | |
| <h1 class="main-title">Connect <span class="thin">Three</span></h1> | |
| </div> |
| (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); | |
| } | |
| })(); |
| /* Header */ | |
| .large-header { | |
| position: relative; | |
| width: 100%; | |
| background: #333; | |
| overflow: hidden; | |
| background-size: cover; | |
| background-position: center center; | |
| z-index: 1; | |
| } | |
| #large-header { | |
| background-image: url('http://www.marcoguglielmelli.it/AnimatedHeaderBg/demo-1/img/demo-1-bg.jpg'); | |
| } | |
| .main-title { | |
| position: absolute; | |
| margin: 0; | |
| padding: 0; | |
| color: #f9f1e9; | |
| text-align: center; | |
| top: 50%; | |
| left: 50%; | |
| -webkit-transform: translate3d(-50%,-50%,0); | |
| transform: translate3d(-50%,-50%,0); | |
| } | |
| .demo-1 .main-title { | |
| text-transform: uppercase; | |
| font-size: 4.2em; | |
| letter-spacing: 0.1em; | |
| } | |
| .main-title .thin { | |
| font-weight: 200; | |
| } | |
| @media only screen and (max-width : 768px) { | |
| .demo-1 .main-title { | |
| font-size: 3em; | |
| } | |
| } |