Compare commits

...

18 Commits

Author SHA1 Message Date
Asif Bacchus b3038644ad redo parameter handling properly, allow dynamic 2020-04-08 06:06:12 -06:00
Asif Bacchus fb5a4675f8 change speed parameter base to 100 2020-04-08 05:26:04 -06:00
Asif Bacchus fe51090807 create speed parameter 2020-04-08 05:23:28 -06:00
Asif Bacchus 24af3c33ac add particle multiplier parameter 2020-04-08 05:12:44 -06:00
Asif Bacchus 8d08d145c4 hover effect based on parameter (default enabled) 2020-04-08 05:10:24 -06:00
Asif Bacchus bf5321eec5 set mouse avoidance via parameter, default enabled 2020-04-08 05:02:34 -06:00
Asif Bacchus 6b165f24da call particles function onload while testing 2020-04-08 05:00:18 -06:00
Asif Bacchus c0e4424257 make everything one function 2020-04-08 05:00:04 -06:00
Asif Bacchus 89263b1495 set colours via css variables 2020-04-08 04:47:22 -06:00
Asif Bacchus e937b17e17 import palette partial, use for background 2020-04-08 04:35:40 -06:00
Asif Bacchus 63971cb860 'wine' palette for testing 2020-04-08 04:35:21 -06:00
Asif Bacchus 5b0d2d108a initialize mouse position as undefined
This stops the particles from sticking at 0,0 on start.
2020-04-08 04:35:04 -06:00
Asif Bacchus d9b18cdb9e update css with new canvas id 2020-04-08 04:29:13 -06:00
Asif Bacchus 1a519a1d55 change canvas id 2020-04-08 04:27:32 -06:00
Asif Bacchus e52855f954 change stroke colour when mouse nearby 2020-04-08 04:18:55 -06:00
Asif Bacchus 507c5f6e38 basic animation as per tutorial 2020-04-08 04:08:51 -06:00
Asif Bacchus b410e55915 general skeleton and linking 2020-04-08 02:56:45 -06:00
Asif Bacchus bcfe64f427 repo setup 2020-04-08 02:56:29 -06:00
7 changed files with 415 additions and 0 deletions

81
.gitattributes vendored Normal file
View File

@ -0,0 +1,81 @@
# Common settings that generally should always be used with your language specific settings
# Auto detect text files and perform LF normalization
# https://www.davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/
* text=auto
#
# The above will handle all files NOT found below
#
# Documents
*.bibtex text diff=bibtex
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
*.md text
*.tex text diff=tex
*.adoc text
*.textile text
*.mustache text
*.csv text
*.tab text
*.tsv text
*.txt text
*.sql text
# Graphics
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.tif binary
*.tiff binary
*.ico binary
# SVG treated as an asset (binary) by default.
*.svg text
# If you want to treat it as binary,
# use the following line instead.
# *.svg binary
*.eps binary
# Scripts
*.bash text eol=lf
*.fish text eol=lf
*.sh text eol=lf
# These are explicitly windows files and should use crlf
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlf
# Serialisation
*.json text
*.toml text
*.xml text
*.yaml text
*.yml text
# Archives
*.7z binary
*.gz binary
*.tar binary
*.tgz binary
*.zip binary
# Text files where line endings should be preserved
*.patch -text
#
# Exclude files from exporting
#
.gitattributes export-ignore
.gitignore export-ignore
.vscode export-ignore

14
.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/numbered-bookmarks.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# compiled CSS
css-review
css

21
index.html Normal file
View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>animated particles</title>
<link rel="stylesheet"
href="css/index.min.css"
crossorigin="anonymous"/>
</head>
<body onload='particles(avoidMouse=false)'>
<canvas id="particles"></canvas>
<!-- javascript -->
<script
src="js/particles.js"
crossorigin="anonymous"
async>
</script>
<!-- end javascript -->
</body>
</html>

194
js/particles.js Normal file
View File

@ -0,0 +1,194 @@
function particles(){
/* create particles animation
based on the amazing tutorial by 'Franks Labratory'
https://youtu.be/d620nV6bp0A
*/
// handle parameters
particles = (
typeof particles !== 'undefined'
&& Number.isFinite(particles)
) ? particles : 1;
sizeMultiplier = (
typeof sizeMultiplier !== 'undefined'
&& Number.isFinite(sizeMultiplier)
) ? sizeMultiplier : 3;
speed = (
typeof speed !== 'undefined'
&& Number.isFinite(speed)
&& (1 <= speed && speed <= 1000)
) ? (speed / 100) : 0.5;
avoidMouse = (
typeof avoidMouse !== 'undefined'
&& typeof avoidMouse === 'boolean'
) ? avoidMouse : true;
hover = (
typeof hover !== 'undefined'
&& typeof hover === 'boolean'
) ? hover : true;
// read css colour variables from root element
const particleColour = getComputedStyle(document.documentElement).getPropertyValue('--col-particle');
const strokeColour = getComputedStyle(document.documentElement).getPropertyValue('--col-particle-stroke');
const strokeHoverColour = getComputedStyle(document.documentElement).getPropertyValue('--col-particle-stroke-hover');
// get canvas element, set context and size
const canvas = document.getElementById('particles');
const canvasContext = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let particlesArray;
// get mouse position
let mousePosition ={
x: undefined,
y: undefined,
radius: (canvas.height / 80) * (canvas.width / 80)
};
// add mouse position event listener
window.addEventListener('mousemove', function(event){
mousePosition.x = event.x;
mousePosition.y = event.y;
});
// create particle class
class Particle{
constructor(x, y, directionX, directionY, size, colour) {
this.x = x;
this.y = y;
this.directionX = directionX;
this.directionY = directionY;
this.size = size;
this.colour = colour;
}
// method to draw individual particles
draw(){
canvasContext.beginPath();
canvasContext.arc(this.x, this.y, this.size, 0, Math.PI * 2, false);
canvasContext.fillStyle = particleColour;
canvasContext.fill();
}
// check particle position, mouse position, move particle and draw it
update(){
// check if particle is still within canvas
if (this.x > canvas.width || this.x < 0){
this.directionX = -this.directionX;
}
if (this.y > canvas.height || this.y < 0){
this.directionY = -this.directionY;
}
// avoid the mouse if avoidMouse = true (default)
if (avoidMouse){
let dx = mousePosition.x - this.x;
let dy = mousePosition.y - this.y;
let distance = Math.sqrt((dx * dx) + (dy * dy));
if (distance < mousePosition.radius + this.size){
if (mousePosition.x < this.x && this.x < canvas.width - this.size * 10){
this.x += 10;
}
if (mousePosition.x > this.x && this.x > this.size * 10){
this.x -= 10;
}
if (mousePosition.y < this.y && this.y < canvas.height - this.size * 10){
this.y += 10;
}
if (mousePosition.y > this.y && this.y > this.size * 10){
this.y -= 10;
}
}
}
// move particle
this.x += this.directionX * speed;
this.y += this.directionY * speed;
// draw particle
this.draw();
}
}
// create particle array
function init(){
particlesArray = [];
let numberOfParticles = (canvas.height * canvas.width) / 9000;
for (let i = 0; i < numberOfParticles * particles; i++){
let size = (Math.random() * sizeMultiplier) + 1;
let x = (Math.random() * ((innerWidth - size * 2) - (size * 2)) + size * 2);
let y = (Math.random() * ((innerHeight - size * 2) - (size * 2)) + size * 2);
let directionX = (Math.random() * 5) - 2.5;
let directionY = (Math.random() * 5) - 2.5;
let colour = '#8c5523';
particlesArray.push(new Particle(x, y, directionX, directionY, size, colour));
}
}
// check if particles are close enough to connect to eachother
function connect(){
let opacityValue = 1;
for (let a = 0; a < particlesArray.length; a++){
for (let b = a; b < particlesArray.length; b++){
let distance = ((particlesArray[a].x - particlesArray[b].x) * (particlesArray[a].x - particlesArray[b].x)) + ((particlesArray[a].y - particlesArray[b].y) * (particlesArray[a].y - particlesArray[b].y));
if (distance < (canvas.width / 10) * (canvas.height / 10)){
opacityValue = 1 - (distance / 20000);
// change colour on 'hover' if hover = true (default)
if(hover){
let dx = mousePosition.x - particlesArray[a].x;
let dy = mousePosition.y - particlesArray[a].y;
let mouseDistance = Math.sqrt((dx * dx) + (dy * dy));
if (mouseDistance < 200) {
// change colour if mouse is close
canvasContext.globalAlpha = opacityValue;
canvasContext.strokeStyle = strokeHoverColour;
}
else {
// use regular stroke colour
canvasContext.globalAlpha = opacityValue;
canvasContext.strokeStyle = strokeColour;
}
}
else {
canvasContext.globalAlpha = opacityValue;
canvasContext.strokeStyle = strokeColour;
}
canvasContext.lineWidth = 1;
canvasContext.beginPath();
canvasContext.moveTo(particlesArray[a].x, particlesArray[a].y);
canvasContext.lineTo(particlesArray[b].x, particlesArray[b].y);
canvasContext.stroke();
}
}
}
}
// animation loop
function animate(){
requestAnimationFrame(animate);
canvasContext.clearRect(0, 0, innerWidth, innerHeight);
for (let i = 0; i < particlesArray.length; i++){
particlesArray[i].update();
}
connect();
}
// resize event
window.addEventListener('resize', function(){
canvas.width = innerWidth;
canvas.height = innerHeight;
mousePosition.radius = ((canvas.height / 80) * (canvas.width / 80));
init();
});
// mouse-out event (mouse leaving the window)
window.addEventListener('mouseout', function(){
mousePosition.x = undefined;
mousePosition.y = undefined;
});
init();
animate();
}

7
scss/_palette.scss Normal file
View File

@ -0,0 +1,7 @@
// colours used thoughout site
:root {
--col-bg-canvas: #2c2830;
--col-particle: #ebe7c5;
--col-particle-stroke: #692e50;
--col-particle-stroke-hover: #9aa68b;
}

82
scss/_reset.scss Normal file
View File

@ -0,0 +1,82 @@
/* based on Eric Meyer's CSS Reset 2.0 (http://meyerweb/eric/tools/css/reset/)
modified for easier implementation of REM font-sizing with default set to
62.5% or 10px on most browsers by default. Media-queries adjusts this base conversion.
*/
@media only screen and (max-width: 640px) {
:root {
font-size: 42.5%;
}
}
@media only screen and (min-width: 641px) and (max-width: 1024px) {
:root {
font-size: 50%;
}
}
@media only screen and (min-width: 1025px) {
:root {
font-size: 62.5%;
}
}
:root {
height: 100%;
scroll-behavior: smooth;
width: 100%;
body {
font-size: 2.2rem;
height: 100%;
line-height: 2.2rem * 1.25;
width: 100%;
}
}
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
border: 0;
box-sizing: border-box;
font-size: inherit;
font: inherit;
margin: 0;
padding: 0;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}

16
scss/index.scss Normal file
View File

@ -0,0 +1,16 @@
/* styles of index */
/*
import partials
*/
@import 'reset';
@import 'palette';
#particles {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--col-bg-canvas);
}