I have been using getBoundingClientRect(). At the beginning, I'm getting performance issues due to this. If I remove this method from my code, there is working well. Any alternatives to getBoundingClientRect() in javascript.
In this sample, I have created 2000 elements in button click and changed their positions in another button click. In that, I'm getting performance issues when using getBoundingClientRect().
Anyone help me to resolve this.
document.getElementById("click1").onclick = function() {
for (var i = 0; i < 2000; i++) {
var ele = document.createElement("DIV");
ele.id = i + '';
ele.className = "square";
ele.setAttribute("style", "position: absolute;left: 200px; top: 100px");
document.getElementById("marker").appendChild(ele);
}
};
document.getElementById("click").onclick = function() {
var markerCollection = document.getElementById("marker");
var width = 20,
height = 20;
var radius = width * 2;
var area = 2 * 3.14 * radius;
var totalMarker = 0;
var numberOfMarker = Math.round(area / width);
totalMarker += numberOfMarker;
var percent = Math.round((height / area) * 100);
percent =
markerCollection.children.length - 1 < numberOfMarker ?
100 / markerCollection.children.length - 1 :
percent;
var angle = (percent / 100) * 360;
var centerX = 200,
centerY = 100;
var count = 1;
var newAngle = 0,
first = false;
var dt1 = 0,
dt2 = 0;
dt1 = new Date().getTime();
for (var i = 0; i < markerCollection.children.length; i++) {
if (i != 1 && (i - 1) % totalMarker === 0) {
count++;
radius = (width + 10) * count;
newAngle = 0;
area = 2 * 3.14 * radius;
numberOfMarker = Math.round(area / width);
percent = Math.round((height / area) * 100);
angle = (percent / 100) * 360;
totalMarker += numberOfMarker;
}
var x1 = centerX + radius * Math.sin((Math.PI * 2 * newAngle) / 360);
var y1 = centerY + radius * Math.cos((Math.PI * 2 * newAngle) / 360);
var offset = markerCollection.children[i].getBoundingClientRect();
markerCollection.children[i]["style"].left = (x1 - (offset.width / 2)) + "px";
markerCollection.children[i]["style"].top = (y1 - (offset.height / 2)) + "px";
newAngle += angle;
}
dt2 = new Date().getTime();
alert(dt2 - dt1);
};
<!DOCTYPE html>
<html>
<head>
<style>
.square {
height: 20px;
width: 20px;
background-color: #555;
border: 1px solid red;
}
</style>
</head>
<body>
<button id="click1">Create Element</button>
<button id="click">Click To Change</button>
<div id='marker' style="width: 350px;height: 200px;border: 1px solid red">
</div>
</div>
<script>
</script>
</body>
</html>
If I'm not misreading your code, all you're using getBoundingClientRect() for is to calculate the width and height of an element you already know the width and height of (20x20px).
Just use your width and height variables directly, or possibly avoid having to do the offset calculation entirely, add transform: translate(-50% -50%) to the element's style.
Related
I am trying to do a Fibonacci Sphere with a canvas like the following code, but instead of the same point showing everywhere I want to show different images, possibly svgs like logos and other images. I've done some research in google like visiting codepen and other places but couldn't find anything that worked. I imagine it would be something like the one in this website here. Any idea on how to approach this?
var cant = 100;
var offset = 2 / cant;
var increment = Math.PI * (3 - Math.sqrt(5));
var canvas = document.getElementById("canvas");
var i;
var circle;
//---Build the elements
for(i = 0; i < cant; i++){
circle = document.createElement("div");
circle.className = "point";
circle.setAttribute("data-index", i);
canvas.appendChild(circle);
};
//---Apply transformations to points
function updatePoints(evt){
var x, y, z, r, a, scale, opacity, point, style;
var angle = (evt) ? (-evt.pageX / 4) * Math.PI / 180 : 0;
for(i = 0; i < cant; i++){
y = (i * offset - 1) + (offset / 2);
r = Math.sqrt(1 - Math.pow(y, 2));
a = ((i + 1) % cant) * increment + angle;
x = Math.cos(a) * r;
z = Math.sin(a) * r;
scale = Math.round(z * 20000) / 100;
opacity = (1 + z) / 1.5;
style = "translate3d(" + (125 + x * 100) + "px, " + (125 + y * 100) + "px, " + scale + "px)";
point = canvas.querySelectorAll("[data-index='" + i +"']");
point[0].style.WebkitTransform = style;
point[0].style.msTransform = style;
point[0].style.transform = style;
point[0].style.opacity = opacity;
}
}
//---Update the points at start
updatePoints();
//---Update the points on mouse move
document.addEventListener("mousemove", updatePoints);
body, html{
height: 100%;
position: relative;
}
body{
background-color: #232B2B;
margin: 0;
padding: 0;
}
#canvas{
height: 250vh;
margin: 0 0;
position: relative;
width: 250vh;
}
.point{
background: red;
border-radius: 50%;
height: 4px;
position: absolute;
transform-style: preserve-3d;
width: 4px;
}
<div id="canvas">
</div>
Any help would be most helpful.
You can continue using the createElement method.
I added this, to show a random image (from picsum) for each dot:
// Create a new img element
img = document.createElement('img');
// Add the src to each img element.
//Here using the iterator variable to
//change the id of the photo we are retrieving
img.src = 'https://picsum.photos/id/' + i +'/20/20'
// Append the img to the div
circle.appendChild(img);
And I made the circles a bit larger in the CSS (20px) so you can see it.
If you want specific images, you could create an array inside your JS, or pull from a folder on your server.
var cant = 100;
var offset = 2 / cant;
var increment = Math.PI * (3 - Math.sqrt(5));
var canvas = document.getElementById("canvas");
var i;
var circle;
//---Build the elements
for(i = 0; i < cant; i++){
circle = document.createElement("div");
img = document.createElement('img');
img.src = 'https://picsum.photos/id/' + i +'/20/20'
circle.appendChild(img);
circle.className = "point";
circle.setAttribute("data-index", i);
canvas.appendChild(circle);
};
//---Apply transformations to points
function updatePoints(evt){
var x, y, z, r, a, scale, opacity, point, style;
var angle = (evt) ? (-evt.pageX / 4) * Math.PI / 180 : 0;
for(i = 0; i < cant; i++){
y = (i * offset - 1) + (offset / 2);
r = Math.sqrt(1 - Math.pow(y, 2));
a = ((i + 1) % cant) * increment + angle;
x = Math.cos(a) * r;
z = Math.sin(a) * r;
scale = Math.round(z * 20000) / 100;
opacity = (1 + z) / 1.5;
style = "translate3d(" + (125 + x * 100) + "px, " + (125 + y * 100) + "px, " + scale + "px)";
point = canvas.querySelectorAll("[data-index='" + i +"']");
point[0].style.WebkitTransform = style;
point[0].style.msTransform = style;
point[0].style.transform = style;
point[0].style.opacity = opacity;
}
}
//---Update the points at start
updatePoints();
//---Update the points on mouse move
document.addEventListener("mousemove", updatePoints);
body, html{
height: 100%;
position: relative;
}
body{
background-color: #232B2B;
margin: 0;
padding: 0;
}
#canvas{
height: 250vh;
margin: 0 0;
position: relative;
width: 250vh;
}
.point{
background: red;
border-radius: 50%;
height: 20px;
position: absolute;
transform-style: preserve-3d;
width: 20px;
overflow: hidden;
}
<div id="canvas">
</div>
So I've been reading this post which I found is the closest to what I want. Basically, I want two different text elements (two different words) moving around the page randomly and also bouncing off each other when they come in contact.
I have tried to edit the code so that it's black and have only one text element. However how can I also include a second text element (a different word) moving randomly as well?
Also how can I change it to Roboto Mono font?
// Return random RGB color string:
function randomColor() {
var hex = Math.floor(Math.random() * 0x1000000).toString(16);
return "#" + ("000000" + hex).slice(0);
}
// Poor man's box physics update for time step dt:
function doPhysics(boxes, width, height, dt) {
for (let i = 0; i < boxes.length; i++) {
var box = boxes[i];
// Update positions:
box.x += box.dx * dt;
box.y += box.dy * dt;
// Handle boundary collisions:
if (box.x < 0) {
box.x = 0;
box.dx = -box.dx;
} else if (box.x + box.width > width) {
box.x = width - box.width;
box.dx = -box.dx;
}
if (box.y < 0) {
box.y = 0;
box.dy = -box.dy;
} else if (box.y + box.height > height) {
box.y = height - box.height;
box.dy = -box.dy;
}
}
// Handle box collisions:
for (let i = 0; i < boxes.length; i++) {
for (let j = i + 1; j < boxes.length; j++) {
var box1 = boxes[i];
var box2 = boxes[j];
var dx = Math.abs(box1.x - box2.x);
var dy = Math.abs(box1.y - box2.y);
// Check for overlap:
if (2 * dx < (box1.width + box2.width ) &&
2 * dy < (box1.height + box2.height)) {
// Swap dx if moving towards each other:
if ((box1.x > box2.x) == (box1.dx < box2.dx)) {
var swap = box1.dx;
box1.dx = box2.dx;
box2.dx = swap;
}
// Swap dy if moving towards each other:
if ((box1.y > box2.y) == (box1.dy < box2.dy)) {
var swap = box1.dy;
box1.dy = box2.dy;
box2.dy = swap;
}
}
}
}
}
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
// Initialize random boxes:
var boxes = [];
for (var i = 0; i < 1; i++) {
var box = {
x: Math.floor(Math.random() * canvas.width),
y: Math.floor(Math.random() * canvas.height),
width: 50,
height: 20,
dx: (Math.random() - 0.5) * 0.3,
dy: (Math.random() - 0.5) * 0.3
};
boxes.push(box);
}
// Initialize random color and set up interval:
var color = randomColor();
setInterval(function() {
color = randomColor();
}, 450);
// Update physics at fixed rate:
var last = performance.now();
setInterval(function(time) {
var now = performance.now();
doPhysics(boxes, canvas.width, canvas.height, now - last);
last = now;
}, 50);
// Draw animation frames at optimal frame rate:
function draw(now) {
context.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < boxes.length; i++) {
var box = boxes[i];
// Interpolate position:
var x = box.x + box.dx * (now - last);
var y = box.y + box.dy * (now - last);
context.beginPath();
context.fillStyle = color;
context.font = "40px 'Roboto Mono'";
context.textBaseline = "hanging";
context.fillText("motion", x, y);
context.closePath();
}
requestAnimationFrame(draw);
}
requestAnimationFrame(draw);
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
<!DOCTYPE html>
<html>
<body>
<head>
<link rel="stylesheet" href="test.css">
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
</head>
<canvas id="canvas"></canvas>
<script src="test.js"></script>
</body>
</html>
Multiple text boxes is easy :
Change the initialize boxes part to include more than one.
// Initialize random boxes:
var boxes = [];
var boxCount = 2
for (var i = 0; i < boxCount; i++) {
Second your random color is flawed , try this :
function randomColor() {
var hex = Math.floor(Math.random() * 0x1000000).toString(16);
return "#" + ("000000" + hex).substr(hex.length);
}
I don't think that roboto is available in the canvas element. (I could be wrong)
monospace is available though.
Edit
If you want different words you could use another array for them:
var words = ['motion','designer']
for (var i = 0; i < words.length; i++) {
as you create boxes use the words array.
You can't hard code the size of the box if you want have the words to collide. Height should be at least the font height 40px and if you want to get the width of the text box there is a context helping function :
box.width = context.measureText(words[i]).width;
See the snippet for usage :
// Return random RGB color string:
function randomColor() {
var hex = Math.floor(Math.random() * 0x1000000).toString(16);
return "#" + ("000000" + hex).substr(hex.length);
}
// Poor man's box physics update for time step dt:
function doPhysics(boxes, width, height, dt) {
for (let i = 0; i < boxes.length; i++) {
var box = boxes[i];
// Update positions:
box.x += box.dx * dt;
box.y += box.dy * dt;
// Handle boundary collisions:
if (box.x < 0) {
box.x = 0;
box.dx = -box.dx;
} else if (box.x + box.width > width) {
box.x = width - box.width;
box.dx = -box.dx;
}
if (box.y < 0) {
box.y = 0;
box.dy = -box.dy;
} else if (box.y + box.height > height) {
box.y = height - box.height;
box.dy = -box.dy;
}
}
// Handle box collisions:
for (let i = 0; i < boxes.length; i++) {
for (let j = i + 1; j < boxes.length; j++) {
var box1 = boxes[i];
var box2 = boxes[j];
var dx = Math.abs(box1.x - box2.x);
var dy = Math.abs(box1.y - box2.y);
// Check for overlap:
if (2 * dx < (box1.width + box2.width ) &&
2 * dy < (box1.height + box2.height)) {
// Swap dx if moving towards each other:
if ((box1.x > box2.x) == (box1.dx < box2.dx)) {
var swap = box1.dx;
box1.dx = box2.dx;
box2.dx = swap;
}
// Swap dy if moving towards each other:
if ((box1.y > box2.y) == (box1.dy < box2.dy)) {
var swap = box1.dy;
box1.dy = box2.dy;
box2.dy = swap;
}
}
}
}
}
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
// Initialize random boxes:
var boxes = [];
var words = ["designer","motion","hi"]
for (var i = 0; i < words.length; i++) {
var box = {
x: Math.floor(Math.random() * canvas.width),
y: Math.floor(Math.random() * canvas.height),
width: 50, // Will be dynamic
height: 42,
dx: (Math.random() - 0.5) * 0.3,
dy: (Math.random() - 0.5) * 0.3
};
boxes.push(box);
}
// Initialize random color and set up interval:
var color = randomColor();
setInterval(function() {
color = randomColor();
}, 450);
// Update physics at fixed rate:
var last = performance.now();
setInterval(function(time) {
var now = performance.now();
doPhysics(boxes, canvas.width, canvas.height, now - last);
last = now;
}, 50);
// Draw animation frames at optimal frame rate:
function draw(now) {
context.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < boxes.length; i++) {
var box = boxes[i];
// Interpolate position:
var x = box.x + box.dx * (now - last);
var y = box.y + box.dy * (now - last);
box.width = context.measureText(words[i]).width;
context.beginPath();
context.fillStyle = color;
context.font = "normal 40px monospace";
context.textBaseline = "hanging";
context.fillText(words[i], x, y);
context.closePath();
}
requestAnimationFrame(draw);
}
requestAnimationFrame(draw);
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
<!DOCTYPE html>
<html>
<body>
<head>
<link rel="stylesheet" href="test.css">
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
</head>
<canvas id="canvas"></canvas>
<script src="test.js"></script>
</body>
</html>
This exercise I need a function that moves the div randomly inside of the body when I click with the left button mouse.
I'm having some difficulties to swap this code(jquery) into javascript. How would it be?
var counter = 0;
var div = document.getElementsByClassName('a');
function click() {
if (counter < 1) {
var pos = makeNewPosition();
this.style.left = pos[1] + 'px';
this.style.top = pos[0] + 'px';
}
}
function makeNewPosition() {
// Get viewport dimensions (remove the dimension of the div)
var h = window.innerHeight = -50;
var w = window.innerWidth = -50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh, nw];
}
<div onclick="click()" class="a">Click</div>
This is the jQuery that I wanted to code in javascript.
$(document).ready(function(){
var counter = 0;
$('.a').click( function () {
if (counter < 1 ) {
var pos = makeNewPosition();
this.style.left = pos[1] +'px';
this.style.top = pos[0] +'px';
}
});
});
function makeNewPosition(){
// Get viewport dimensions (remove the dimension of the div)
var h = $(window).height() - 50;
var w = $(window).width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh,nw];
}
JavaScript:
window.addEventListener("load", function() {
var counter = 0,
div = document.querySelector(".a");
div.addEventListener("click", function() {
if (counter < 1) {
var pos = makeNewPosition();
this.style.left = pos[1] + 'px';
this.style.ltop = pos[0] + 'px';
}
counter++;
});
});
function makeNewPosition() {
// Get viewport dimensions (remove the dimension of the div)
var h = window.innerHeight -50;
var w = window.innerWidth -50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh, nw];
}
.a {
position: absolute;
top: 100;
left: 100
}
<div class="a">Click</div>
Based on this jQuery:
$(function() {
var counter = 0;
$('.a').click(function() {
if (counter < 1) {
var pos = makeNewPosition();
$(this).css({
"left": pos[1] + 'px',
"top": pos[0] + 'px'
});
}
counter++;
});
});
function makeNewPosition() {
// Get viewport dimensions (remove the dimension of the div)
var h = $(window).height() - 50;
var w = $(window).width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh, nw];
}
.a {
position: absolute;
top: 100;
left: 100
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="a">Click</div>
The most idiomatic way would be to first get a reference to the element
const div = document.getElementsByClassName('a')[0];
then add an event listener to the element
div.addEventListener('click', click); //Attach your handler function to the event
How can I use Javascript to select multiple elements and move them at the same time? I'm trying to make something like this without using jQuery: https://jenniferdewalt.com/caterpillar.html
// JavaScript source code
var container = document.getElementById("container");
//MAKE NEW DIV
//container.innerHTML = '<div id="circle" class="circle"></div>';
console.log(container.innerHTML);
var mouseX = 0;
var mouseY = 0;
var positionX = 0;
var positionY = 0;
var speed = 50;
var i;
var m = 0;
var newCircle;
//EVENTS / TRIGGERS
window.addEventListener("mousemove", mouseCoords);
setInterval(circlePosition, 30);
//Make Circles
makeCircles(20);
function makeCircles(num) {
for (i = 0; i < num; i++) {
container.innerHTML += '<div id="circle' + i + '" class="circle"></div> ';
//Circle with NEW ID
var newCircle = document.getElementById("circle" + i);
//This Circle Random Color;
var ranColor = genColor();
newCircle.style.backgroundColor = ranColor;
//This Circle Random Size;
var newSize = genSize();
newCircle.style.width = newSize + "px";
newCircle.style.height = newSize + "px";
}
}
console.log(container.innerHTML);
//FUNCTIONS.
//MOUSE COORDS
function mouseCoords(e) {
mouseX = e.clientX;
mouseY = e.clientY;
}
//CIRCLEPOSITION
function circlePosition() {
//Circle go's to Last Mouse position
var circleX = document.getElementById("circle0");
var circleY = document.getElementById("circle0");
positionX += (mouseX - positionX) / speed;
positionY += (mouseY - positionY) / speed;
circleX.style.left = positionX + "px";
circleY.style.top = positionY + "px";
}
// MOST IMPORTANT PART RELATED TO QUESTION
//Random Color
function genColor() {
var RGBarr = [];
for (c = 0; c < 3; c++) {
var newNum = Math.floor(Math.random() * 256);
RGBarr.push(newNum);
}
var newRGB = 'rgb(' + RGBarr[0] + ',' + RGBarr[1] + ',' + RGBarr[2] + ')';
return newRGB;
}
//Random Size
function genSize() {
var ranSize = Math.floor(Math.random() * 100) + 1;
return ranSize;
}
body {
background-color: black;
}
.circle {
position: absolute;
top: 0;
left: 0;
background-color: white;
width: 100px;
height: 100px;
border-radius: 50%;
}
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<link href="./HOWTOMOVEAFUCKINGCIRCLE.css" type="text/css" rel="stylesheet" />
<meta charset="utf-8" />
<title></title>
</head>
<body>
<div id="container"></div>
<!--Javscript-->
<script src="./HOWTOMOVEAFUCKINGCIRCLE.js"></script>
</body>
</html>
I'm Self taught so would really apreciate your help, if u can't be asked to help me with this project, please consider giving me some other example how i can move multiple elements at the same time. Greetings from the Netherlands.
I visited the Stack Exchange Winter Bash website and I love the falling snow! My question is, how can I recreate a similar effect that looks as nice. I attempted to reverse engineer the code to see if I could figure it out but alas no luck there. The JS is over my head. I did a bit of googling and came across some examples but they were not as elegant as the SE site or did not look very good.
Can anyone provide some instructions on how to replicate what the SE Winter Bash site creates or a place where I might learn how to do this?
Edit: I would like to replicate the effect as close as possible, IE: falling snow with snowflakes, and being able to move the mouse and cause the snow to move or swirl with the mouse moments.
Great question, I actually wrote a snow plugin a while ago that I continually update see it in action. Also a link to the pure js source
I noticed you tagged the question html5 and canvas, however you can do it without using either, and just standard elements with images or different background colors.
Here's two really simple ones I put together just now for you to mess with. The key in my opinion is using sin to get the nice wavy effect as the flakes fall. The first one uses the canvas element, the 2nd one uses regular dom elements.
Since I'm absolutely addicted to canvas here's a canvas version that performs quite nicely in my opinion.
Canvas version
Full Screen
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
window.requestAnimationFrame = requestAnimationFrame;
})();
var flakes = [],
canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
flakeCount = 200,
mX = -100,
mY = -100
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
function snow() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < flakeCount; i++) {
var flake = flakes[i],
x = mX,
y = mY,
minDist = 150,
x2 = flake.x,
y2 = flake.y;
var dist = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)),
dx = x2 - x,
dy = y2 - y;
if (dist < minDist) {
var force = minDist / (dist * dist),
xcomp = (x - x2) / dist,
ycomp = (y - y2) / dist,
deltaV = force / 2;
flake.velX -= deltaV * xcomp;
flake.velY -= deltaV * ycomp;
} else {
flake.velX *= .98;
if (flake.velY <= flake.speed) {
flake.velY = flake.speed
}
flake.velX += Math.cos(flake.step += .05) * flake.stepSize;
}
ctx.fillStyle = "rgba(255,255,255," + flake.opacity + ")";
flake.y += flake.velY;
flake.x += flake.velX;
if (flake.y >= canvas.height || flake.y <= 0) {
reset(flake);
}
if (flake.x >= canvas.width || flake.x <= 0) {
reset(flake);
}
ctx.beginPath();
ctx.arc(flake.x, flake.y, flake.size, 0, Math.PI * 2);
ctx.fill();
}
requestAnimationFrame(snow);
};
function reset(flake) {
flake.x = Math.floor(Math.random() * canvas.width);
flake.y = 0;
flake.size = (Math.random() * 3) + 2;
flake.speed = (Math.random() * 1) + 0.5;
flake.velY = flake.speed;
flake.velX = 0;
flake.opacity = (Math.random() * 0.5) + 0.3;
}
function init() {
for (var i = 0; i < flakeCount; i++) {
var x = Math.floor(Math.random() * canvas.width),
y = Math.floor(Math.random() * canvas.height),
size = (Math.random() * 3) + 2,
speed = (Math.random() * 1) + 0.5,
opacity = (Math.random() * 0.5) + 0.3;
flakes.push({
speed: speed,
velY: speed,
velX: 0,
x: x,
y: y,
size: size,
stepSize: (Math.random()) / 30,
step: 0,
angle: 180,
opacity: opacity
});
}
snow();
};
canvas.addEventListener("mousemove", function(e) {
mX = e.clientX,
mY = e.clientY
});
init();
Standard element version
var flakes = [],
bodyHeight = getDocHeight(),
bodyWidth = document.body.offsetWidth;
function snow() {
for (var i = 0; i < 50; i++) {
var flake = flakes[i];
flake.y += flake.velY;
if (flake.y > bodyHeight - (flake.size + 6)) {
flake.y = 0;
}
flake.el.style.top = flake.y + 'px';
flake.el.style.left = ~~flake.x + 'px';
flake.step += flake.stepSize;
flake.velX = Math.cos(flake.step);
flake.x += flake.velX;
if (flake.x > bodyWidth - 40 || flake.x < 30) {
flake.y = 0;
}
}
setTimeout(snow, 10);
};
function init() {
var docFrag = document.createDocumentFragment();
for (var i = 0; i < 50; i++) {
var flake = document.createElement("div"),
x = Math.floor(Math.random() * bodyWidth),
y = Math.floor(Math.random() * bodyHeight),
size = (Math.random() * 5) + 2,
speed = (Math.random() * 1) + 0.5;
flake.style.width = size + 'px';
flake.style.height = size + 'px';
flake.style.background = "#fff";
flake.style.left = x + 'px';
flake.style.top = y;
flake.classList.add("flake");
flakes.push({
el: flake,
speed: speed,
velY: speed,
velX: 0,
x: x,
y: y,
size: 2,
stepSize: (Math.random() * 5) / 100,
step: 0
});
docFrag.appendChild(flake);
}
document.body.appendChild(docFrag);
snow();
};
document.addEventListener("mousemove", function(e) {
var x = e.clientX,
y = e.clientY,
minDist = 150;
for (var i = 0; i < flakes.length; i++) {
var x2 = flakes[i].x,
y2 = flakes[i].y;
var dist = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y));
if (dist < minDist) {
rad = Math.atan2(y2, x2), angle = rad / Math.PI * 180;
flakes[i].velX = (x2 / dist) * 0.2;
flakes[i].velY = (y2 / dist) * 0.2;
flakes[i].x += flakes[i].velX;
flakes[i].y += flakes[i].velY;
} else {
flakes[i].velY *= 0.9;
flakes[i].velX
if (flakes[i].velY <= flakes[i].speed) {
flakes[i].velY = flakes[i].speed;
}
}
}
});
init();
function getDocHeight() {
return Math.max(
Math.max(document.body.scrollHeight, document.documentElement.scrollHeight), Math.max(document.body.offsetHeight, document.documentElement.offsetHeight), Math.max(document.body.clientHeight, document.documentElement.clientHeight));
}
I've created a pure HTML 5 and js snowfall.
Check it out on my code pen here: https://codepen.io/onlintool24/pen/GRMOBVo
// Amount of Snowflakes
var snowMax = 35;
// Snowflake Colours
var snowColor = ["#DDD", "#EEE"];
// Snow Entity
var snowEntity = "•";
// Falling Velocity
var snowSpeed = 0.75;
// Minimum Flake Size
var snowMinSize = 8;
// Maximum Flake Size
var snowMaxSize = 24;
// Refresh Rate (in milliseconds)
var snowRefresh = 50;
// Additional Styles
var snowStyles = "cursor: default; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; -o-user-select: none; user-select: none;";
/*
// End of Configuration
// ----------------------------------------
// Do not modify the code below this line
*/
var snow = [],
pos = [],
coords = [],
lefr = [],
marginBottom,
marginRight;
function randomise(range) {
rand = Math.floor(range * Math.random());
return rand;
}
function initSnow() {
var snowSize = snowMaxSize - snowMinSize;
marginBottom = document.body.scrollHeight - 5;
marginRight = document.body.clientWidth - 15;
for (i = 0; i <= snowMax; i++) {
coords[i] = 0;
lefr[i] = Math.random() * 15;
pos[i] = 0.03 + Math.random() / 10;
snow[i] = document.getElementById("flake" + i);
snow[i].style.fontFamily = "inherit";
snow[i].size = randomise(snowSize) + snowMinSize;
snow[i].style.fontSize = snow[i].size + "px";
snow[i].style.color = snowColor[randomise(snowColor.length)];
snow[i].style.zIndex = 1000;
snow[i].sink = snowSpeed * snow[i].size / 5;
snow[i].posX = randomise(marginRight - snow[i].size);
snow[i].posY = randomise(2 * marginBottom - marginBottom - 2 * snow[i].size);
snow[i].style.left = snow[i].posX + "px";
snow[i].style.top = snow[i].posY + "px";
}
moveSnow();
}
function resize() {
marginBottom = document.body.scrollHeight - 5;
marginRight = document.body.clientWidth - 15;
}
function moveSnow() {
for (i = 0; i <= snowMax; i++) {
coords[i] += pos[i];
snow[i].posY += snow[i].sink;
snow[i].style.left = snow[i].posX + lefr[i] * Math.sin(coords[i]) + "px";
snow[i].style.top = snow[i].posY + "px";
if (snow[i].posY >= marginBottom - 2 * snow[i].size || parseInt(snow[i].style.left) > (marginRight - 3 * lefr[i])) {
snow[i].posX = randomise(marginRight - snow[i].size);
snow[i].posY = 0;
}
}
setTimeout("moveSnow()", snowRefresh);
}
for (i = 0; i <= snowMax; i++) {
document.write("<span id='flake" + i + "' style='" + snowStyles + "position:absolute;top:-" + snowMaxSize + "'>" + snowEntity + "</span>");
}
window.addEventListener('resize', resize);
window.addEventListener('load', initSnow);
body{
background: skyblue;
height:100%;
width:100%;
display:block;
position:relative;
}
<span id="flake0" style="cursor: default; user-select: none; position: absolute; font-family: inherit; font-size: 19px; color: rgb(221, 221, 221); z-index: 1000; left: 226px; top: 561px;">•</span>
The falling snow is simple: Create a canvas, create a bunch of snowflakes, draw them.
You can create a snowflake class like so:
function Snowflake() {
this.x = Math.random()*canvas.width;
this.y = -16;
this.speed = Math.random()*3+1;
this.direction = Math.random()*360;
this.maxSpeed = 4;
}
Or something like that. Then you have a timer that, each step, adjusts each snowflake's direction by a small amount, and then calculates its new X and Y by factoring in the Speed and Direction.
It's hard to explain, but actually quite basic.