Skip to content

Commit

Permalink
Merge pull request #1 from Andrey-1988-dev/feature_1
Browse files Browse the repository at this point in the history
Add destroy method and improve snowflake calculations. Add demo page.
  • Loading branch information
Andrey-1988-dev committed Nov 27, 2023
2 parents 7cd3231 + 96fe0f2 commit 058fdfd
Show file tree
Hide file tree
Showing 2 changed files with 207 additions and 39 deletions.
139 changes: 139 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1" name="viewport">
<title>Snowfall demo</title>
<meta name="description"
content="This page is a demo of Snowfall.js, a JavaScript script that creates a realistic and customizable snowfall effect on your website. You can adjust various parameters of the snowfall, such as the number, size, speed, color and text of the snowflakes. You can also see the source code and documentation of the script on GitHub."/>
<link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" rel="stylesheet">
</head>
<body>
<div class="container mt-3 mb-3">
<div class="row">
<div class="col">
<h1>Snowfall demo</h1>
<p>With this page, you can customize various parameters of the snowfall, such as the number, size, speed,
color and text of the snowflakes. You can enter the desired values in the form below and click the
"Accept" button to apply the changes. You can also click the "Default" button to return to the initial
settings. You will see how your snowfall will be animated on the background of your page. This is a fun
and interesting way to decorate your website.</p>
<p>This script was created using JavaScript and HTML5 canvas. You can find the source code and detailed
documentation at <a href="https://github.com/Andrey-1988-dev/snowfall-js">snowfall-js</a>. You can
freely use, modify and
distribute this script under the GPL-3.0 license. If you liked this script, you can support the author
by leaving a star or a comment on GitHub.</p>
</div>
</div>
<div class="row">
<div class="col">
<form class="row g-3" id="form">
<div class="col-md-6">
<label class="form-label" for="count">Number of snowflakes (count)</label>
<input class="form-control" id="count" name="count" type="number" value="100">
</div>
<div class="col-md-6">
<label class="form-label" for="text">Text for a snowflake (can be any symbol or text) (text)</label>
<input class="form-control" id="text" name="text" type="text" value="">
</div>
<div class="col-md-6">
<label class="form-label" for="color">Color of a snowflake in HEX format (color)</label>
<input class="form-control" id="color" name="color" style="height: 2.5em;" type="color"
value="#99ccff">
</div>
<div class="col-md-6">
<label class="form-label" for="zIndex">Z-index for the snowflakes canvas (zIndex)</label>
<input class="form-control" id="zIndex" name="zIndex" type="number" value="1000">
</div>

<div class="col-md-6">
<label class="form-label" for="minRadius">Minimum radius of a snowflake in pixels
(minRadius)</label>
<input class="form-control" id="minRadius" name="minRadius" type="number" value="10">
</div>
<div class="col-md-6">
<label class="form-label" for="maxRadius">Maximum radius of a snowflake in pixels
(maxRadius)</label>
<input class="form-control" id="maxRadius" name="maxRadius" type="number" value="30">
</div>
<div class="col-md-6">
<label class="form-label" for="minSpeed">Minimum speed of a snowflake in pixels per frame
(minSpeed)</label>
<input class="form-control" id="minSpeed" name="minSpeed" type="number" value="3">
</div>
<div class="col-md-6">
<label class="form-label" for="maxSpeed">Maximum speed of a snowflake in pixels per frame
(maxSpeed)</label>
<input class="form-control" id="maxSpeed" name="maxSpeed" type="number" value="10">
</div>
<div class="col-12">
<button class="btn btn-primary" type="submit">Accept</button>
<button class="btn btn-secondary" id="default" type="button">Default</button>
</div>
</form>
</div>
</div>
</div>
<script crossorigin="anonymous"
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script src="snowfall.js"></script>
<script>
// Создаем объект с параметрами по умолчанию
let defaultParams = {
count: "100", // number of snowflakes
minRadius: "10", // minimum radius of a snowflake in pixels
maxRadius: "30", // maximum radius of a snowflake in pixels
minSpeed: "3", // minimum speed of a snowflake in pixels per frame
maxSpeed: "10", // maximum speed of a snowflake in pixels per frame
text: "❄", // text for a snowflake (can be any symbol or text)
color: "#99ccff", // color of a snowflake in HEX format
zIndex: "1000" // z-index for the snowflakes canvas
};

// Создаем снегопад с параметрами по умолчанию
let snowfall = new Snowfall();

// Находим форму на странице
let form = document.getElementById("form");
// Находим кнопку "Default" на странице
let defaultButton = document.getElementById("default");

// Добавляем обработчик события на форму
form.addEventListener("submit", event => {
// Отменяем действие по умолчанию (отправку формы)
event.preventDefault();
// Создаем пустой объект для новых параметров
let newParams = {};
// Перебираем все элементы input в форме
for (let input of form.elements) {
// Если элемент имеет атрибут name, то добавляем его в объект новых параметров
if (input.name) {
newParams[input.name] = input.value;
}
}

// Удаляем старый снегопад
snowfall.destroy();
// Создаем новый снегопад с новыми параметрами
snowfall = new Snowfall(newParams);
});

// Добавляем обработчик события на кнопку "Default"
defaultButton.addEventListener("click", () => {
// Удаляем старый снегопад
snowfall.destroy();
// Создаем новый снегопад с параметрами по умолчанию
snowfall = new Snowfall();
// Перебираем все элементы input в форме
for (let input of form.elements) {
// Если элемент имеет атрибут name, то устанавливаем его значение равным значению по умолчанию
if (input.name) {
input.value = defaultParams[input.name];
}
}
});
</script>
</body>
</html>
107 changes: 68 additions & 39 deletions snowfall.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Version: 1.0.0
* Date: 2021-11-18T00:00Z
* Version: 1.1.0
* Date: 2021-11-27T00:00Z
*/

'use strict'
Expand All @@ -39,15 +39,15 @@ class Snowflake {
}

// Function to calculate the new position of the snowflake relative to the edge of the canvas
calculateNewPosition(oldPosition, oldCanvasSize, newCanvasSize) {
calculateNewPosition = (oldPosition, oldCanvasSize, newCanvasSize) => {
// Calculate the old position of the snowflake from the edge in percentage
let percentage = oldPosition / (oldCanvasSize / 100);
// Calculate the new position of the snowflake from the edge in pixels
// Return the new position
return newCanvasSize / 100 * percentage;
}

updateAfterCanvasResize(oldCanvasWidth, oldCanvasHeight, newCanvasWidth, newCanvasHeight) {
updateAfterCanvasResize = (oldCanvasWidth, oldCanvasHeight, newCanvasWidth, newCanvasHeight) => {
if (oldCanvasWidth !== newCanvasWidth) {
// Call the function to calculate the new position of the snowflake from the left edge
this.x = this.calculateNewPosition(this.x, oldCanvasWidth, newCanvasWidth);
Expand All @@ -59,61 +59,70 @@ class Snowflake {
}

// Method to draw the snowflake on the canvas
draw(ctx) {
// Get the scroll offset of the window
let scrollX = window.scrollX;
let scrollY = window.scrollY;
// Get the width and height of the window
let windowWidth = window.innerWidth;
let windowHeight = window.innerHeight;
draw = ctx => {
// Check if the snowflake is within the visible area
if (
this.x + this.h >= scrollX && this.x - this.h <= scrollX + windowWidth
&&
this.y + this.h >= scrollY && this.y - this.h <= scrollY + windowHeight
) {
if (this.x + this.h >= window.scrollX && this.x - this.h <= window.scrollX + window.innerWidth && this.y + this.h >= window.scrollY && this.y - this.h <= window.scrollY + window.innerHeight) {
ctx.font = this.h + "px Arial, sans-serif"; // set the font and text size
ctx.fillText(this.t, this.x, this.y); // draw the text with the snowflake symbol
ctx.fillStyle = this.c; // set the color
}
}

// Method to update the position of the snowflake
update(canvas) {
update = canvas => {
this.y += this.s; // increase the y coordinate by the speed
// if the snowflake goes beyond the bottom edge of the canvas, move it to the top
if (this.y > canvas.height) {
this.y = -this.h;
this.x = Math.random() * canvas.width;
if (this.s > 0) {
if (this.y > canvas.height) {
this.y = -this.h;
this.x = Math.random() * canvas.width;
}
} else {
if (this.y < 0) {
this.y = canvas.height + this.h;
this.x = Math.random() * canvas.width;
}
}
}
}

class Snowfall {
requestAnimationFrame;

// Constructor takes parameters for creating snowflakes
constructor(options) {
constructor(options = {}) {
let {
count = 100,
minRadius = 10,
maxRadius = 30,
minRadius = 10,
maxRadius = 30,
minSpeed = 3,
maxSpeed = 10,
text = "\u2744",
color = "#ffffff",
maxSpeed = 10,
text = "❄",
color = "#99ccff",
zIndex = "1000"
} = options;

let snowfieldCanvas = document.createElement("canvas");

count = Number(count);
minRadius = Number(minRadius);
if (minRadius <= 0) {
minRadius = 10
}
maxRadius = Number(maxRadius);
if (maxRadius <= 0) {
maxRadius = 30
}
minSpeed = Number(minSpeed);
maxSpeed = Number(maxSpeed);

const snowfieldCanvas = document.createElement("canvas");
snowfieldCanvas.id = "snowfall";
snowfieldCanvas.style.zIndex = zIndex;
snowfieldCanvas.style.position = "absolute";
snowfieldCanvas.style.top = "0";
snowfieldCanvas.style.left = "0";
snowfieldCanvas.style.pointerEvents = "none";

// Wait for the document to be loaded before appending the canvas
document.addEventListener("DOMContentLoaded", () => {
document.body.append(snowfieldCanvas);
});

document.body.append(snowfieldCanvas);

// Get the canvas element by id
this.canvas = snowfieldCanvas;
Expand Down Expand Up @@ -154,7 +163,8 @@ class Snowfall {
oldCanvasWidth = this.canvas.width
oldCanvasHeight = this.canvas.height
}
this.canvas.style.display = 'none'
this.canvas.style.display = 'none';

// Set the width and height of the canvas equal to the width and height of the browser window
if (window.devicePixelRatio > 1) {
let scrollWidth = document.documentElement.scrollWidth
Expand All @@ -178,22 +188,28 @@ class Snowfall {
snowflake.updateAfterCanvasResize(oldCanvasWidth, oldCanvasHeight, newCanvasWidth, newCanvasHeight);
}
}
};
}

// Function to create snowflakes and add them to the array
createSnowflakes = () => {
// Loop through the number of snowflakes
for (let i = 0; i < this.count; i++) {
// Generate a random radius within the minimum and maximum radius
let r = Math.random() * (this.maxRadius - this.minRadius) + this.minRadius;
let r = this.minRadius + Math.random() * (this.maxRadius - this.minRadius);
// Generate the speed based on the size of the snowflake
let s = (this.maxSpeed - this.minSpeed) / 100 * r;
let rp;
if (this.minRadius !== this.maxRadius) {
rp = (r - this.minRadius) / ((this.maxRadius - this.minRadius) / 100);
} else {
rp = 100;
}
let s = this.minSpeed + ((this.maxSpeed - this.minSpeed) / 100 * rp);
// Create a new snowflake object with the given parameters
let snowflake = new Snowflake(this.canvas, r, s, this.color, this.text);
// Add the snowflake to the array
this.snowflakes.push(snowflake);
}
};
}

// Function to animate the snowflakes
animateSnowflakes = () => {
Expand All @@ -208,6 +224,19 @@ class Snowfall {
snowflake.update(this.canvas);
}
// Request a new animation frame
requestAnimationFrame(this.animateSnowflakes);
this.requestAnimationFrame = requestAnimationFrame(this.animateSnowflakes);
}

// Method to destroy the snowfall and remove the canvas element
destroy = () => {
cancelAnimationFrame(this.requestAnimationFrame);
document.getElementById("snowfall").remove();
for (let name in this) {
delete this[name];
}
// Empty the array of snowflakes
this.snowflakes = [];
// Remove the event listener for resize
window.removeEventListener("resize", this.resizeCanvas);
}
}

0 comments on commit 058fdfd

Please sign in to comment.