Skip to content
Snippets Groups Projects
Commit d63762cb authored by Dj's avatar Dj
Browse files

Add: Perspective

parent 9424f0cc
No related branches found
No related tags found
No related merge requests found
...@@ -2,25 +2,64 @@ ...@@ -2,25 +2,64 @@
* Particles.js * Particles.js
*/ */
const Debug = false
const Static = true
// Needed for fps calculation.
let Then = Date.now() // Argh.. Global, mutable, variable..!
// //
// Helper // Helper
// //
// Variables needed for fps calculation. // Random Value without zero
let Then = Date.now() // Argh.. Global, mutable, variable..!
function randomValue(min, max) { function randomValue(min, max) {
return (Math.random() * (+max - +min) + +min) const value = (Math.random() * (+max - +min) + +min)
return (value === 0) ? randomValue(min, max) : value
}
function getNodeYOffset(node) {
const dimensions = node.getBoundingClientRect()
return (dimensions) ? dimensions.y : 0
}
function getNodeHeight(node) {
const dimensions = node.getBoundingClientRect()
return (dimensions) ? dimensions.height : window.innerHeight
} }
function initCanvas(id) { function getScene(canvasId, height) {
const canvas = document.getElementById(id) const width = window.innerWidth
const fov = 0.8
const perspective = width * fov
const yOffset = 0
const canvas = document.getElementById(canvasId)
const ctx = canvas.getContext('2d') const ctx = canvas.getContext('2d')
ctx.canvas.width = window.innerWidth
ctx.canvas.width = width
ctx.canvas.height = window.innerHeight ctx.canvas.height = window.innerHeight
return ctx
return { width, height, yOffset, perspective, ctx }
}
// function to2dParticle(scene, particle) {
// const perspective = scene.perspective
// const scale = perspective / (perspective + particle.position.z)
// const yOffset = scene.yOffset * scale
// const offset = particle.size.value * 0.5
// const x = particle.position.x - offset
// const y = (yOffset + (particle.position.y - offset))
// const size = particle.size.value
// // const y = (yOffset + (particle.position.y - offset)) * scale
// // const size = particle.size.value * scale
// return { x, y, size }
// }
function calcScrolledYPos(ctx, yPos, yOffset) {
const y = (yPos + yOffset)
return (y <= 0) ? ctx.canvas.height - y : y
} }
...@@ -33,6 +72,10 @@ function Point2D(x, y) { ...@@ -33,6 +72,10 @@ function Point2D(x, y) {
return { x, y } return { x, y }
} }
function Point3D(x, y, z) {
return { x, y, z }
}
function MinMax(min, max) { function MinMax(min, max) {
return { min, max } return { min, max }
} }
...@@ -47,6 +90,16 @@ function RandomPoint2D(minMaxX, minMaxY) { ...@@ -47,6 +90,16 @@ function RandomPoint2D(minMaxX, minMaxY) {
return Point2D(x, y) return Point2D(x, y)
} }
function RandomPoint3D(minMaxX, minMaxY, minMaxZ) {
const x = randomValue(minMaxX.min, minMaxX.max)
const y = randomValue(minMaxY.min, minMaxY.max)
const z =
(typeof minMaxZ === 'number')
? minMaxZ
: randomValue(minMaxZ.min, minMaxZ.max)
return Point3D(x, y, z)
}
function Particle({ position, direction, size, color }) { function Particle({ position, direction, size, color }) {
return { position, direction, size, color } return { position, direction, size, color }
} }
...@@ -57,7 +110,11 @@ function Particle({ position, direction, size, color }) { ...@@ -57,7 +110,11 @@ function Particle({ position, direction, size, color }) {
// //
function Update(canvas, particle) { function Update(scene, particle) {
// Cache object access
const width = scene.width
const height = scene.height
// Animate the pulse effect of the particle // Animate the pulse effect of the particle
// //
const isMaxSize = particle.size.value >= particle.size.bound.max const isMaxSize = particle.size.value >= particle.size.bound.max
...@@ -83,85 +140,100 @@ function Update(canvas, particle) { ...@@ -83,85 +140,100 @@ function Update(canvas, particle) {
// Animate the movement of the particle // Animate the movement of the particle
// //
const sizeOffset = particle.size.value * 0.5 const sizeOffset = particle.size.value * 0.5
const xCenter = particle.position.x - sizeOffset const y = particle.position.y
const yCenter = particle.position.y - sizeOffset
const isRightEdge = const top = y - sizeOffset
(particle.position.x + particle.size.value >= canvas.width) const bottom = y + sizeOffset
const isLeftEdge = (particle.position.x <= 0) const left = particle.position.x - sizeOffset
const isTopEdge = (yCenter <= 0) const right = particle.position.x + sizeOffset
const isBottomEdge = (yCenter >= canvas.height)
const scrollOffset = window.pageYOffset const isRightEdge = (right >= width)
const isLeftEdge = (left <= 0)
const isTopEdge = (bottom < 0)
const isBottomEdge = (top > height)
const updateDirection = const updateDirection =
Object.assign({}, updateSize, { Object.assign({}, updateSize, {
direction: direction:
Point2D( Point2D(
// Bounce of the right and left edges of the screen.
(isRightEdge || isLeftEdge) (isRightEdge || isLeftEdge)
? updateSize.direction.x * -1 ? updateSize.direction.x * -1
: updateSize.direction.x, : updateSize.direction.x,
// (isTopEdge || isBottomEdge) (isTopEdge || isBottomEdge)
// ? particle.direction.y * -1 ? particle.direction.y * -1
// : particle.direction.y : particle.direction.y,
updateSize.direction.y
) )
}) })
const updatePosition = const updatePosition =
Object.assign({}, updateDirection, { Object.assign({}, updateDirection, {
position: position:
Point2D( Point3D(
updateDirection.position.x + updateDirection.direction.x, updateDirection.position.x + updateDirection.direction.x,
(isTopEdge) updateDirection.position.y + updateDirection.direction.y,
? (canvas.height - 1) + updateDirection.direction.y // (isTopEdge)
: (isBottomEdge) // ? height + sizeOffset
? sizeOffset + 1 // : (isBottomEdge)
: updateDirection.position.y + updateDirection.direction.y, // ? -sizeOffset
// : (updateDirection.position.y + updateDirection.direction.y),
updateDirection.position.z
) )
}) })
const updatedParticle = Particle(updatePosition) const updatedParticle = Particle(updatePosition)
return updatedParticle return updatedParticle
} }
function Clear(ctx) { function Draw(scene, particle) {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height) // Cache object access
const size = particle.size.value
const perspective = scene.perspective
const scale = perspective / (perspective + particle.position.z)
const yOffset = scene.yOffset * scale
const drawOffset = size * 0.5
const y = yOffset + (particle.position.y - drawOffset)
const ctx = scene.ctx
const isVisible = (size > 0) && (y < window.innerHeight) && (y > 0)
if (isVisible) {
ctx.fillStyle = particle.color
ctx.fillRect(particle.position.x - drawOffset, y, size, size)
}
} }
function Render(ctx, particles) { function Clear(scene) {
scene.ctx.clearRect(0, 0, scene.width, scene.height)
}
function Render(scene, particles) {
Clear(scene)
particles.forEach( particles.forEach(
function (particle) { function (particle) {
if (particle.size.value > 0) { Draw(scene, particle)
const offset = (particle.size.value*0.5)
ctx.fillStyle = particle.color
ctx.fillRect(
particle.position.x - offset,
particle.position.y - offset,
particle.size.value,
particle.size.value
)
}
} }
) )
} }
function Animate(ctx, fpsInterval, particles) { function Animate({ scene, fpsInterval, particles, anchorNode }) {
scene.yOffset = getNodeYOffset(anchorNode)
// Update particle positions and register for the next frame // Update particle positions and register for the next frame
// to render. // to render.
requestAnimationFrame(() => { requestAnimationFrame(() => {
const updatedParticles = const updatedParticles =
particles.map(function (p) { particles.map(function (p) {
return Update(ctx.canvas, p) return Update(scene, p)
}) })
Animate(ctx, fpsInterval, updatedParticles) Animate({ scene, fpsInterval, particles: updatedParticles, anchorNode })
}) })
// Render particles to canvas // Render particles to canvas and do some fps calculations
const now = Date.now() const now = Date.now()
const elapsed = now - Then const elapsed = now - Then
if (elapsed > fpsInterval) { if (elapsed > fpsInterval) {
Then = now - (elapsed % fpsInterval) Then = now - (elapsed % fpsInterval)
Clear(ctx) Render(scene, particles)
Render(ctx, particles)
} }
} }
...@@ -171,25 +243,66 @@ function Animate(ctx, fpsInterval, particles) { ...@@ -171,25 +243,66 @@ function Animate(ctx, fpsInterval, particles) {
// //
function Particles({ canvasId, fps, amount, color, size, lifespan, speed }) { function Particles({
canvasId,
contentId,
fps,
amount,
color,
size,
speed,
depth,
lifespan,
}) {
const contentNode = document.getElementById(contentId)
const height = getNodeHeight(contentNode)
// Init the canvas for rendering. // Init the canvas for rendering.
// //
const ctx = initCanvas(canvasId) const scene = getScene(canvasId, height)
if (!ctx) { if (!scene.ctx) {
console.error("Particles: Can't find Canvas ", canvasId) console.error("Particles: Can't find Canvas ", canvasId)
return return
} }
// Generate some particles // Generate some particles
// //
const z = depth * -1000
const particles = const particles =
Array.from( (Debug)
? (Static)
? [ Particle({
position: Point3D(100, 500, z),
direction: Point2D(0, 0),
size: {
value: 15,
bound: MinMax(100, 100),
step: 0,
direction: 1
},
color: 'white'
}) ]
: [ Particle({
position: Point3D(100, 100, z),
direction: Point2D(0, +1),
size: {
value: 100,
bound: MinMax(100, 100),
step: 0,
direction: 1
},
color: 'white'
}) ]
: Array.from(
{ length: amount }, { length: amount },
() => Particle({ () => Particle({
position: position:
RandomPoint2D( RandomPoint3D(
MinMax(0, (ctx.canvas.width - (size*2))), MinMax(0, (scene.width - (size*2))),
MinMax(0, (ctx.canvas.height - (size*2))) MinMax(0, (scene.height - (size*2))),
z
), ),
direction: direction:
RandomPoint2D( RandomPoint2D(
...@@ -212,9 +325,6 @@ function Particles({ canvasId, fps, amount, color, size, lifespan, speed }) { ...@@ -212,9 +325,6 @@ function Particles({ canvasId, fps, amount, color, size, lifespan, speed }) {
// Prepare Animation and animate // Prepare Animation and animate
const fpsInterval = 1000 / fps const fpsInterval = 1000 / fps
Then = Date.now() Then = Date.now()
Animate(ctx, fpsInterval, particles) Animate({ scene, fpsInterval, particles, anchorNode: contentNode })
return return
} }
...@@ -83,11 +83,17 @@ ...@@ -83,11 +83,17 @@
<script> <script>
var bgParticles = { var bgParticles = {
// Id of the canvas to render to
canvasId: 'bg-particles', canvasId: 'bg-particles',
fps: 14,
amount: 100, // Id of the content container, we're using it to get the
// rendering height and it's the anchor to get the y offset
// to simulate scrolling.
contentId: 'content',
fps: 16,
amount: 120,
color: 'white', color: 'white',
size: 5, size: 10,
speed: 0.2, speed: 0.2,
depth: -8, depth: -8,
lifespan: 4000 // in milliseconds lifespan: 4000 // in milliseconds
...@@ -96,7 +102,8 @@ ...@@ -96,7 +102,8 @@
var fgParticles = { var fgParticles = {
canvasId: 'fg-particles', canvasId: 'fg-particles',
fps: 20, contentId: 'content',
fps: 24,
amount: 20, amount: 20,
color: 'white', color: 'white',
size: 30, size: 30,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment