Created
August 25, 2017 20:09
-
-
Save smhutch/1f6eb72ed4f1574f7de92f837aa60918 to your computer and use it in GitHub Desktop.
Animated Background Effect
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// React Component to render animated background on https://www.smhutch.co.uk | |
import React from 'react' | |
import Chance from 'chance' | |
export default class extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
showCanvas: true, | |
playAnimation: true | |
} | |
this.createBackgroundPattern = this.createBackgroundPattern.bind(this); | |
this.handleResize = this.handleResize.bind(this); | |
} | |
componentDidMount() { | |
this.createBackgroundPattern(); | |
window.addEventListener('resize', this.handleResize); | |
} | |
componentWillUnmount() { | |
window.removeEventListener('resize', this.handleResize); | |
} | |
handleResize = () => { | |
if (this.state.showCanvas === true) { | |
this.setState({showCanvas:false}); | |
setTimeout(() => { | |
this.setState({showCanvas:true}); | |
this.createBackgroundPattern(); | |
}, 400); | |
} | |
} | |
createBackgroundPattern = () => { | |
// get height of canvas | |
const w = window.innerWidth; | |
const h = window.innerHeight; | |
// get reference to canvas | |
const canvas = this.refs.canvas; | |
// If canvas reference is set | |
if (canvas) { | |
let ctx = canvas.getContext('2d'); | |
// scale up canvas for retina screens | |
ctx.scale(2,2); | |
// canvas varaibles; | |
canvas.width=w; | |
canvas.height=h; | |
canvas.style.width= (w) + "px"; | |
canvas.style.height= (h) + "px"; | |
// colours to be used for elements | |
const colors = [ | |
"#7f9eb2", | |
"#77919d", | |
"#dae9f4", | |
"#274c5e" | |
] | |
// Set initial values for elements randomly | |
let initialElements = []; | |
for(let i = 0; i < w/40; i++) { | |
const size = chance.integer({min:4, max:8}); | |
const x = chance.integer({min:size * 2, max:w}); | |
const y = chance.integer({min:size * 2, max:h}); | |
const shape = { | |
x, | |
y, | |
size, | |
col: colors[chance.integer({ | |
min:0, | |
max:(colors.length-1) | |
})], | |
opacity: chance.floating({min: 0.2, max: 0.6, fixed:2}), | |
rotation: chance.floating({min: 0.1, max:0.9}), | |
moveX: chance.floating({min:-0.5, max:0.5}), | |
moveY: chance.floating({min:-0.5, max:0.5}), | |
} | |
initialElements.push(shape); | |
} | |
let elements = []; | |
let lastAnimationTime = 0; | |
const animate = () => { | |
if (this.state.playAnimation) { | |
ctx.clearRect(0, 0, w, h); | |
let currAnimationTime = new Date(); | |
let delta = 0; | |
if (lastAnimationTime === 0) { | |
elements = initialElements; | |
delta = currAnimationTime - new Date(); | |
} else { | |
delta = currAnimationTime - lastAnimationTime; | |
} | |
lastAnimationTime = currAnimationTime; | |
elements.forEach(e => { | |
let center = e.size/2; | |
e.rotation = e.rotation + (delta * 0.2); | |
e.x += e.moveX; | |
e.y += e.moveY; | |
// If new position overflows container | |
if (e.x <= center) {e.moveX = e.moveX + 0.5;} | |
if (e.y <= center) {e.moveY = e.moveY + 0.5;} | |
if (e.x > w-e.size) {e.moveX = e.moveX - 0.5;} | |
if (e.y >= h-e.size) {e.moveY = e.moveY - 0.5;} | |
let translateX = e.x + center; | |
let translateY = e.y + center; | |
let undoX = 0 - translateX; | |
let undoY = 0 - translateY; | |
let radian = (Math.PI / 180) * e.rotation; | |
let reverseRadian = (Math.PI / 180) * (0 - e.rotation); | |
// set attributes | |
ctx.globalAlpha = e.opacity; | |
ctx.strokeStyle = e.col; | |
// translate to center of rectangle | |
ctx.translate(translateX,translateY); | |
// rotate to correct angle | |
ctx.rotate(radian); | |
// translate back to corner | |
ctx.translate(undoX,undoY); | |
// draw the rectangle | |
ctx.strokeRect(e.x,e.y,e.size,e.size); | |
// Undo angle | |
ctx.translate(translateX,translateY); | |
ctx.rotate(reverseRadian); | |
ctx.translate(undoX,undoY); | |
}) | |
window.requestAnimationFrame(animate); | |
} | |
} | |
animate(this); | |
} | |
} | |
render () { | |
return <div> | |
<canvas | |
ref="canvas" | |
height="100vh" | |
width="100vw" | |
className={this.state.showCanvas ? '' : 'hide'}/> | |
<style jsx>{` | |
canvas { | |
position:absolute; | |
top:0; | |
left:0; | |
opacity:1; | |
z-index:-2; | |
} | |
.hide {opacity:0;} | |
`}</style> | |
</div> | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment