diff --git a/src/parallax-css-testpage/particles.js b/src/parallax-css-testpage/particles.js index 7bc7882aeaaddb6914bfacbe26cd73b18b260879..f28b9911a7d68bc25a6ed57f7253f43e9334b8d2 100644 --- a/src/parallax-css-testpage/particles.js +++ b/src/parallax-css-testpage/particles.js @@ -4,8 +4,19 @@ * Particle emitter and renderer. */ -const Debug = false -const Static = true + +// Polyfill: requestAnimationFrame() +// +// window.requestAnimationFrame = function() { +// return window.requestAnimationFrame || +// window.webkitRequestAnimationFrame || +// window.mozRequestAnimationFrame || +// window.msRequestAnimationFrame || +// window.oRequestAnimationFrame || +// function(f) { +// window.setTimeout(f,1e3/60); +// } +// }(); // @@ -50,9 +61,9 @@ function MaxValue(value, max) { } function RandomPoint2D(minMaxX, minMaxY) { - const x = randomValue(minMaxX.min, minMaxX.max) - const y = randomValue(minMaxY.min, minMaxY.max) - return Point2D(x, y) + var x = randomValue(minMaxX.min, minMaxX.max) + var y = randomValue(minMaxY.min, minMaxY.max) + return Point2D( x, y ) } function Particle({ position, direction, size, color }) { @@ -69,87 +80,85 @@ function Update(scene, particle) { // Cache object access var width = scene.width var height = scene.height + var particleSize = particle.size + var particleSizeValue = particleSize.value + var particleSizeBound = particleSize.bound + var particleSizeStep = particleSize.step + var particlePosition = particle.position + var particlePositionX = particlePosition.x + var particlePositionY = particlePosition.y + var particleDirection = particle.direction + var particleDirectionX = particleDirection.x + var particleDirectionY = particleDirection.y // Animate the pulse effect of the particle // - const isMaxSize = particle.size.value >= particle.size.bound.max - const isMinSize = particle.size.value <= particle.size.bound.min - const updateSizeStep = - Object.assign({}, particle, { - size: Object.assign({}, particle.size, { - direction: - (isMaxSize || isMinSize) - ? particle.size.direction * -1 - : particle.size.direction - }) - }) - const updateSize = - Object.assign({}, updateSizeStep, { - size: Object.assign({}, updateSizeStep.size, { - value: - updateSizeStep.size.value + updateSizeStep.size.step * updateSizeStep.size.direction, - // updateSizeStep.size.value - }) - }) + var isMaxSize = particleSizeValue >= particleSizeBound.max + var isMinSize = particleSizeValue <= particleSizeBound.min + var sizeDirection = + (isMaxSize || isMinSize) + ? particleSize.direction * -1 + : particleSize.direction + var sizeValue = + particleSizeValue + particleSizeStep * sizeDirection // Animate the movement of the particle // - const sizeOffset = particle.size.value * 0.5 - const y = particle.position.y - - const top = y + sizeOffset - const bottom = y - sizeOffset - const left = particle.position.x - sizeOffset - const right = particle.position.x + sizeOffset - - const isRightEdge = (right >= width) - const isLeftEdge = (left <= 0) - const isTopEdge = (bottom < 0) - const isBottomEdge = (top > height) - - const updateDirection = - Object.assign({}, updateSize, { - direction: - Point2D( - // Bounce of the right and left edges of the scene - (isRightEdge || isLeftEdge) - ? updateSize.direction.x * -1 - : updateSize.direction.x, - // Bounce from the top and bottom edges of the scene - (isTopEdge || isBottomEdge) - ? particle.direction.y * -1 - : particle.direction.y, - ) - }) - const updatePosition = - Object.assign({}, updateDirection, { - position: - Point2D( - updateDirection.position.x + updateDirection.direction.x, - updateDirection.position.y + updateDirection.direction.y, - // (isTopEdge) - // ? height + sizeOffset - // : (isBottomEdge) - // ? -sizeOffset - // : (updateDirection.position.y + updateDirection.direction.y), - ) - }) - - const updatedParticle = Particle(updatePosition) - return updatedParticle + var sizeOffset = sizeValue * 0.5 + var top = particlePositionY + sizeOffset + var bottom = particlePositionY - sizeOffset + var left = particlePositionX - sizeOffset + var right = particlePositionX + sizeOffset + + var isRightEdge = (left > width) + var isLeftEdge = (right < 0) + var isTopEdge = (bottom < 0) + var isBottomEdge = (top > height) + + var positionX = + (isRightEdge) + ? -sizeOffset + : (isLeftEdge) + ? width + sizeOffset + : particlePositionX + particleDirectionX + + var positionY = + (isBottomEdge) + ? -sizeOffset + : (isTopEdge) + ? height + sizeOffset + : particlePositionY + particleDirectionY + + return Particle({ + position: { + x: positionX, + y: positionY, + }, + direction: { + x: particleDirectionX, + y: particleDirectionY, + }, + size: { + value: sizeValue, + bound: particleSizeBound, + step: particleSizeStep, + direction: sizeDirection + }, + color: particle.color + }) } function Draw(scene, particle) { // Cache object access - const size = particle.size.value - const position = particle.position + var size = particle.size.value + var position = particle.position // Draw calculations - const yOffset = scene.yOffset * scene.depthScale - const drawOffset = size * 0.5 - const y = yOffset + (position.y - drawOffset) - const ctx = scene.ctx - const isVisible = (size > 0) && (y < window.innerHeight) && (y > 0) + var yOffset = scene.yOffset * scene.depthScale + var drawOffset = size * 0.5 + var y = yOffset + (position.y - drawOffset) + var ctx = scene.ctx + var isVisible = (size > 0) && (y < window.innerHeight) && (y > 0) // Draw if (isVisible) { @@ -172,39 +181,43 @@ function Render(scene, particles) { } function Animate(scene, particles) { - var fpsInterval = scene.fpsInterval - var now = Date.now() - var then = scene.then - var elapsed = now - then + var updatedParticles = [], + fpsInterval = scene.fpsInterval, + now = performance.now(), + then = scene.then, + elapsed = now - then, + tolerance = 0.1 // Just render when we're reaching the configured fps - if (elapsed > scene.fpsInterval) { + if (elapsed >= (scene.fpsInterval - tolerance)) { scene.yOffset = getNodeYOffset(scene.anchorNode) scene.then = now - (elapsed % fpsInterval) Render(scene, particles) } // Update particle positions for the next render call - const updatedParticles = particles.map(function doUpdate(p) { + updatedParticles = particles.map(function doUpdate(p) { return Update(scene, p) }) // Function to animate the next frame return function () { - return Animate(scene, updatedParticles) + return Animate( + scene, + updatedParticles + ) } } function CreateScene({ canvasId, contentId, depth, fps }) { - const contentNode = document.getElementById(contentId) - const height = getNodeHeight(contentNode) - - const fpsInterval = 1000 / fps - const width = window.innerWidth - const yOffset = 0 - const canvas = document.getElementById(canvasId) - const ctx = canvas.getContext('2d') - const depthScaledHeight = height * (depth+1) + var contentNode = document.getElementById(contentId), + height = getNodeHeight(contentNode), + width = window.innerWidth, + fpsInterval = 1000 / fps, + yOffset = 0, + canvas = document.getElementById(canvasId), + ctx = canvas.getContext('2d'), + depthScaledHeight = height * (depth+1) ctx.canvas.width = width ctx.canvas.height = window.innerHeight @@ -217,7 +230,7 @@ function CreateScene({ canvasId, contentId, depth, fps }) { ctx, fps, fpsInterval, - then: Date.now(), + then: performance.now(), anchorNode: contentNode } } @@ -268,9 +281,16 @@ function CreateParticles(scene, { function Particles(configs) { + + var particles = [] + var isRunning = false + var throttled = false + var delay = 25 + var rafId = undefined + function animate(rendererList) { if (isRunning) { - requestAnimationFrame(function () { + rafId = requestAnimationFrame(function () { animate( rendererList.map(function doRender(render) { return render() @@ -281,43 +301,38 @@ function Particles(configs) { } function init() { - return configs.map(function (particleConfig) { + particles = configs.map(function (particleConfig) { var scene = CreateScene(particleConfig.scene) var particles = CreateParticles(scene, particleConfig.particles) return Animate(scene, particles) }) + return particles } - var particles = [] - var isRunning = false - var throttled = false - var delay = 250 - - return { - init: function () { + function run() { + if (particles.length === 0) { particles = init() - }, - - run: function () { - if (particles.length === 0) { - particles = init() - } - isRunning = true - animate(particles) - }, + } + isRunning = true + animate(particles) + } - stop: function () { - isRunning = false - }, + function stop() { + isRunning = false + cancelAnimationFrame(rafId) + } + return { + init: init, + run: run, + stop: stop, onScreenSizeChange: function () { - isRunning = false + stop() if (!throttled) { throttled = true setTimeout(function () { particles = init() - isRunning = true - animate(particles) + run() throttled = false }, delay) } diff --git a/src/parallax-css-testpage/template.html b/src/parallax-css-testpage/template.html index 4e26a8770ea90757318849f88c8b065651bc0ffd..fe10fd3894019c37e82ce550e8559959611b7317 100644 --- a/src/parallax-css-testpage/template.html +++ b/src/parallax-css-testpage/template.html @@ -109,7 +109,7 @@ // rendering height and it's the anchor to get the y offset // to simulate scrolling. contentId: 'content', - fps: 14, + fps: 16, depth: 0.08, }, particles: {