From 76cf0ca228140f9a5f81aa3f48cd229df8634d13 Mon Sep 17 00:00:00 2001 From: unstack-underflow Date: Mon, 6 Nov 2023 09:39:53 -0500 Subject: [PATCH] add particles class --- index.html | 36 +++----------- js/main.js | 30 +++++++---- js/particles.js | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ js/utils.js | 3 ++ styles.css | 15 +++--- 5 files changed, 165 insertions(+), 49 deletions(-) create mode 100644 js/particles.js diff --git a/index.html b/index.html index dd307e7..f054a67 100644 --- a/index.html +++ b/index.html @@ -10,6 +10,10 @@ href="https://fonts.googleapis.com/css2?family=Orbitron&display=swap" rel="stylesheet" /> + Aron Lomner @@ -23,36 +27,7 @@
Resume
-
-
- _       __     __                        
-| |     / /__  / /________  ____ ___  ___ 
-| | /| / / _ \/ / ___/ __ \/ __ `__ \/ _ \
-| |/ |/ /  __/ / /__/ /_/ / / / / / /  __/
-|__/|__/\___/_/\___/\____/_/ /_/ /_/\___/ 
-      
-
-   __      
-  / /_____ 
- / __/ __ \
-/ /_/ /_/ /
-\__/\____/ 
-      
-
-    ___                    _      
-   /   |  _________  ____ ( )_____
-  / /| | / ___/ __ \/ __ \|// ___/
- / ___ |/ /  / /_/ / / / / (__  ) 
-/_/  |_/_/   \____/_/ /_/ /____/  
-      
-
- _       __     __         _ __       ______
-| |     / /__  / /_  _____(_) /____  / / / /
-| | /| / / _ \/ __ \/ ___/ / __/ _ \/ / / / 
-| |/ |/ /  __/ /_/ (__  ) / /_/  __/_/_/_/  
-|__/|__/\___/_.___/____/_/\__/\___(_|_|_)
-      
-
+
@@ -62,5 +37,6 @@
+ diff --git a/js/main.js b/js/main.js index 10cccbf..f36b8de 100644 --- a/js/main.js +++ b/js/main.js @@ -1,18 +1,28 @@ -import { typeWrighter } from "./utils.js"; +import { typeWrighter, sleep } from './utils.js'; +import {Particles} from './particles.js'; async function initialize(){ - let greeting = document.getElementById("greeting") - let pause = typeWrighter(greeting, "Hello, I'm") + let greeting = document.getElementById('greeting') + let pause = typeWrighter(greeting, 'Hello, I\'m') await sleep(pause); - let name = document.getElementById("name"); - pause = typeWrighter(name, "Aron Lomner"); + let name = document.getElementById('name'); + pause = typeWrighter(name, 'Aron Lomner'); await sleep(pause); - let occupation = document.getElementById("occupation") - typeWrighter(occupation, "Fullstack developer"); + let occupation = document.getElementById('occupation') + typeWrighter(occupation, 'Fullstack developer'); } initialize(); -async function sleep(time) { - return new Promise((resolve) => setTimeout(resolve, time)); -} \ No newline at end of file +let container = document.getElementById('welcome'); +let data = { + isText: true, + color: '#39FF14', + font: '18px Verdana', + text: 'Welcome!' +}; + +document.fonts.ready.then(() => { + console.log('eady') + new Particles(container, data, 5, 30); +}) \ No newline at end of file diff --git a/js/particles.js b/js/particles.js new file mode 100644 index 0000000..0360e5e --- /dev/null +++ b/js/particles.js @@ -0,0 +1,130 @@ +class Particle { + constructor(x, y, color){ + this.posX = x, + this.posY = y; + this.orginalX = x; + this.orginalY = y; + this.color = color; + this.size = 1; + this.weight = 15; + } + + draw(ctx) { + ctx.fillStyle = this.color; + ctx.beginPath(); + ctx.arc(this.posX, this.posY, this.size, 0, Math.PI * 2); + ctx.closePath(); + ctx.fill(); + } + + update(mouse) { + let dX = mouse.x - this.posX; + let dY = mouse.y - this.posY; + let distance = Math.sqrt(dX*dX + dY * dY); + let velocityX = dX / distance; + let velocityY = dY / distance; + let maxDistance = mouse.radius; + let velocity = (maxDistance - distance) / maxDistance; + if (distance < mouse.radius) { + this.posX -= velocityX * velocity * this.weight; + this.posY -= velocityY * velocity * this.weight; + } else { + if (this.posX!=this.orginalX) { + this.posX -= (this.posX - this.orginalX) / 10; + } + if (this.posY!=this.orginalY){ + this.posY -= (this.posY - this.orginalY) /10; + } + } + } +} + +export class Particles { + constructor(container, data, scale, mouseRadius) { + this.data = data; + this.particles = []; + this.canvas = document.createElement('canvas'); + let canvasSize; + if (data.isText) { + canvasSize = this.getTextSize(data.text, data.font); + } + this.canvas.width = canvasSize.width * scale; + this.canvas.height = canvasSize.height * scale; + container.appendChild(this.canvas); + this.ctx = this.canvas.getContext('2d'); + + this.mouse = { + x: null, + y: null, + radius: mouseRadius + } + window.addEventListener('mousemove',(event) => { + const rect = this.canvas.getBoundingClientRect(); + this.mouse.x = event.x - rect.left; + this.mouse.y = event.y - rect.top; + }); + + + this.particles = this.imageDataToParticles(this.getImageData(), scale); + + + this.animate = () => { + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + for (let i=0; i < this.particles.length; i++) { + this.particles[i].draw(this.ctx); + this.particles[i].update(this.mouse); + } + requestAnimationFrame(this.animate); + } + this.animate(); + } + + getTextSize(text, font) { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + ctx.font = font; + const textMetrics = ctx.measureText(text); + + const width = textMetrics.width; + const height = textMetrics.fontBoundingBoxAscent + textMetrics.fontBoundingBoxDescent; + return {width, height}; + } + getImageData() { + if (this.data.isText) { + const offScreenCanvas = document.createElement('canvas'); + let canvasSize = this.getTextSize(this.data.text, this.data.font); + offScreenCanvas.width = canvasSize.width; // Width of your text canvas + offScreenCanvas.height = canvasSize.height; // Height of your text canvas + const offScreenCtx = offScreenCanvas.getContext('2d'); + + offScreenCtx.fillStyle = 'white'; + offScreenCtx.font = this.data.font; + offScreenCtx.textAlign = 'left'; + offScreenCtx.textBaseline = 'top'; + offScreenCtx.fillText(this.data.text, 0, 0); + + return offScreenCtx.getImageData(0, 0, offScreenCanvas.width, offScreenCanvas.height); + } + } + /** + * Converts an image data object into an array of particles. + * @param {ImageData} imageData - The image data object containing pixel information. + * @param {number} percentage between 50 & 100, the percentage of pixels to keep. 100 -> all pixels; 50 -> half of pixels; + * @param {Boolean} random if true each pixel has the chance of being kept based on the percentage you passed, otherwise it is: the first percentage out of 100 is kept then the rest ignored, percentage kept rest ignored... + */ + imageDataToParticles(imageData, scale) { + let arr = []; + //for every row of pixels + for (let row = 0; row < imageData.height; row++) { + //for every pixel in row + for (let pixel = 0; pixel < imageData.width; pixel++) { + const alpha = imageData.data[(row * imageData.width * 4) + (pixel * 4) + 3]; + if(alpha > 0) { + arr.push(new Particle(pixel * scale, row * scale, this.data.color)); + } + } + }console.log(arr); + return arr; + } +} + diff --git a/js/utils.js b/js/utils.js index 8afea6c..117222d 100644 --- a/js/utils.js +++ b/js/utils.js @@ -22,4 +22,7 @@ export function typeWrighter(element, message) { } loop(0); return message.length * 100; +} +export async function sleep(time) { + return new Promise((resolve) => setTimeout(resolve, time)); } \ No newline at end of file diff --git a/styles.css b/styles.css index e3010de..ec5903e 100644 --- a/styles.css +++ b/styles.css @@ -5,9 +5,9 @@ body { background-color: black; color: #39FF14; + font-family: "Roboto Mono"; } #navbar{ - font-family: "Orbitron"; display: flex; justify-content: space-between; align-items: center; @@ -41,15 +41,12 @@ body { color: inherit; text-decoration: none; } -#asci-art { +/* Welcome */ +#welcome { display: flex; - flex-wrap: wrap; - margin-left: auto; - margin-right: auto; -} -pre { - display: inline-block; - margin: 5px; + justify-content: center; + align-items: center; + margin-top: 25px; } /* Cover */ #cover {