TIP게시판

제목 javascript - snow fall
글쓴이 darkninja 작성시각 2025/06/09 23:06:26
댓글 : 0 추천 : 0 스크랩 : 0 조회수 : 62   RSS

눈내리는 소스는

canvas 에 직접 그리는 것과 css animation 을 사용하는 것이 있는데

홈페이지 위에 덧 그리는 것은 css animation 을 사용하기 때문에

각각의 눈송이가 랜덤하게 움직이는데 한계가 있습니다.

눈송이를 개별적으로 특성을 주어 움직이게 하려면

눈송이 하나하나 마다 정보를 저장해야 하는데...

 

cpu 시간을 약간 사용합니다.

눈송이 50개나 100개나 별 차이가 없고..

이해가 되지 않는 부분은 chatGPT 에게 코드를 전부 제공하고 알고 싶은 부분을 질문하면 됩니다.

 

background image 에 a태그가 추가 되어  있으면 제거해야 이미지가 보입니다.

?

 

Wham! - Last Christmas (Official Video)

https://www.youtube.com/watch?v=E8gmARGvPlI

 

 

	
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>눈 내리는 애니메이션</title>
    <style>
        body {
			background-image: url(https://images.unsplash.com/photo-1491002052546-bf38f186af56?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2200&q=80);
            background-size: cover;
        }
    </style>
</head>
 
<body>
    <script>
 
		//https://codepen.io/tmrDevelops/pen/PPgjwz
		//https://stickode.tistory.com/413
		//https://forum.squarespace.com/topic/174119-falling-snowflakes-on-webpage#comment-416466_wrap
		//https://chatgpt.com/

		// Flag to reset the position of the snowflakes
		var resetPosition = false;

		var reduceMotionQuery = matchMedia("(prefers-reduced-motion)");

		// Handle accessibility
		var enableAnimations = false;

		// Handle animation accessibility preferences 
		function setAccessibilityState() {
			if (reduceMotionQuery.matches) {
				enableAnimations = false;
			} else { 
				enableAnimations = true;
			}
		}
		setAccessibilityState();

		reduceMotionQuery.addListener(setAccessibilityState);

		//
		// Trigger a reset of all the snowflakes' positions
		//
		function sf_setResetFlag(e) {
			resetPosition = true;
		}

		//
		// It all starts here...
		//
		function snowflake_setup() {
			if (enableAnimations) {
				window.addEventListener("DOMContentLoaded", generateSnowflakes, false);
				window.addEventListener("resize", sf_setResetFlag, false);
			}
		}
		snowflake_setup();

		//
		// The function responsible for creating the snowflake
		//
		function generateSnowflakes() {
			// create our snowflake element's parent container
			var snowflakeDIV = document.getElementById("snowflakeDIV_id");
			if (!snowflakeDIV) {
				snowflakeDIV = document.createElement("div");
				snowflakeDIV.id = "snowflakeDIV_id";
				snowflakeDIV.style.position = "fixed";
				snowflakeDIV.style.left = "0px";
				snowflakeDIV.style.top = "0px";
				snowflakeDIV.style.bottom = "0px";
				snowflakeDIV.style.width = "100vw";
				snowflakeDIV.style.height = "100vh";
				snowflakeDIV.style.overflow = "hidden";
				snowflakeDIV.style.zindex = "9999999";
				snowflakeDIV.style.pointerEvents = "none";

				document.body.appendChild(snowflakeDIV);

				makeSnowflakes(snowflakeDIV);
			}	
		}	

		//
		// The function responsible for creating the snowflake
		//
		function makeSnowflakes(snowflakeDIV) {
			// Global variables to store our browser's window size
			var snowflake_cw = document.documentElement.clientWidth;
			var snowflake_ch = document.documentElement.clientHeight;

			var	randMinMax = function(min,max) {
				return min + Math.floor(Math.random() * ((max - min) + 1));
			};
			var	snowflakeColor = function() { 
				var items = ["#dcf2fd", "#60b4f2", "#dbf2fd", "#d8f8ff", "#b8ddfa"];
				var item = items[Math.floor(Math.random()*items.length)];
				return item;
			};
			var	snowflakeColorRand = function() { 
				var letters = '0123456789ABCDEF';
				var color = '#';
				for (var i = 0; i < 6; i++) {
					color += letters[Math.floor(Math.random() * 16)];
				}
				return color;
			};

			// Array to store our Snowflake objects
			var snowflakes = [];

			// Specify the number of snowflakes you want visible
			var snowflakes_num = 50;

			var fmid = 100;
			var fend = 200;
			var spow = 1; 
			var spn = 100; 
			var spd = 25; // 눈송이 떨어지는 속도 최소, 최대
			var spv = 70; 
			var szn = 100; 
			var szd = 30;  // 눈송이 크기 최소, 최대
			var szv = 52; 
			var sc = 1; 
			var sz = 1; 
			var sp = 1; 
			var spmin = 1;

			var spz;
			var xp;
			var xpv = 0.17; // 눈송이 좌우이동 값 조절

            var viewfpscount = false;
			var viewconsolelog = false;
			var viewcount = 0;
			var viewmax = 0;

			//
			// Constructor for our Snowflake object
			//
			function Snowflake() {
			}

			Snowflake.prototype.animate = function (fpsCount) {
				var snow = this;
			
				xp = Math.random() * snow.sz * xpv; // 눈송이가 좌우로 이동하는 값
				if (snow.sp > 3) {
					xp = xp * randMinMax(3, 5); // 눈송이가 떨어지는 속도가 빠르면 랜덤하게 좌우 이동값을 크게한다
				}	
				else if (snow.sp > 2) {
					xp = xp * randMinMax(1, 3);
				}	
				if (snow.sp > 2.5) { // 속도가 빠르면 규칙적인 이동에 변화를 준다
					if (Math.random() > snow.direction) {
						xp = xp * -1;
					}	
				}	

				snow.frame += 1; 
				xp = snow.frame > snow.fmid ? xp * -1 : xp; // 특정 프레임마다 눈송이가 좌우로 이동하는 방향을 바꿈
				snow.x += xp;
				snow.y += snow.sp; 
				snow.frame = snow.frame >= snow.fend ? snow.frame = 0 : snow.frame; 

				if (snow.y > snowflake_ch) { // 눈송이가 화면 하단을 벗어나면

					if (viewconsolelog) {
						if (viewmax == 0 || (viewmax > 0 && viewcount < viewmax))  {
							viewcount++;
							console.log();	
						}	
					}

					snow.y = 0; 
					snow.x = Math.random() * snowflake_cw; 
					snow.frame = randMinMax(1, fend);
					snow.fmid = randMinMax(1, fmid);
					snow.fend = randMinMax(snow.fmid, fend);

					snow.direction = Math.random();
					
   					snow.sz = szn / (szd + (szv * Math.random())) * sz;
					snow.scale = snow.sz / (szn / (szd + szv)) * sc; // 눈송이 크기
					spz = spn / (spd + (spv * Math.random())) * sp; 
					snow.sp = Math.max(spmin, (Math.pow(spz * spow, 2) * 0.25) * sp); // 눈송이 떨어지는 속도 (눈송이 크기와 비례하지 않음)

					if (snow.sp > 3) { // 눈송이가 떨어지는 속도가 빠르면 좌우 이동값을 느리게 바꾼다 
						snow.fmid = snow.fmid * 2;
						snow.fend = snow.fend * 2;
					}	
					else if (snow.sp > 2) {
						snow.fmid = snow.fmid * 1.5;
						snow.fend = snow.fend * 1.5;
					}	

					snow.flake.style.backgroundColor = snowflakeColorRand();
					snow.flake.style.opacity = (0.65 + Math.random()) / 3; //0.22 ~ 0.55
				}	

				// 실제 눈송이 위치 이동
				snow.flake.style.transform = "translate(" + snow.x + "px, " + snow.y + "px) scale(" + snow.scale + ")";
			}	

			// create snowflake and add it to snowflakeContainer
			var sf = document.createElement('div');
			sf.className = "snowflake";
			sf.style.position = "absolute";
			sf.style.width = "7px";
			sf.style.height = "7px";
			sf.style.borderRadius = "50%";

			var spz;
			// create each individual snowflake
			for (var i = 0; i < snowflakes_num; i++) {

				// create our Snowflake object
				var snow = new Snowflake();

				// set initial snowflake properties
				snow.y = Math.random() * snowflake_ch; 
				snow.x = Math.random() * snowflake_cw; 
				snow.frame = randMinMax(1, fend);
				snow.fmid = randMinMax(1, fmid);
				snow.fend = randMinMax(snow.fmid, fend);

				snow.direction = Math.random();

  				snow.sz = szn / (szd + (szv * Math.random())) * sz;
				snow.scale = snow.sz / (szn / (szd + szv)) * sc;
				spz = spn / (spd + (spv * Math.random())) * sp;
				snow.sp = Math.max(spmin, (Math.pow(spz * spow, 2) * 0.25) * sp);

				if (snow.sp > 3) { // 눈송이가 떨어지는 속도가 빠르면 좌우 이동값을 느리게 바꾼다 
					snow.fmid = snow.fmid * 2;
					snow.fend = snow.fend * 2;
				}	
				else if (snow.sp > 2) {
					snow.fmid = snow.fmid * 1.5;
					snow.fend = snow.fend * 1.5;
				}	

				// clone our original snowflake and add it to snowflakeContainer
				snow.flake = sf.cloneNode(true);

				snow.flake.id = "snowflake"+i;
				snow.flake.style.backgroundColor = snowflakeColorRand();
				snow.flake.style.opacity = (0.65 + Math.random()) / 3; //0.22 ~ 0.55

				if ((i % 3) == 0) {
					snow.flake.style.filter = "drop-shadow(0 0 "+snow.scale+"px blue)";
				}	

				snowflakes.push(snow);

				snowflakeDIV.appendChild(snow.flake);
			}
			sf.remove();

			// 초기화
			var fpsCount = 0;
			var lastCheck = performance.now();

			var lowfpsCount = 0;
			var decsnowflake = false;
			//
			// Responsible for moving each snowflake by calling its update function
			//
			function snowflakes_frame_animate() {
				const now = performance.now();

				fpsCount++;
				if (now - lastCheck >= 1000) {
					if (fpsCount < 60) {
						lowfpsCount++;
						if (lowfpsCount >= 3) {
							lowfpsCount = 0;
							decsnowflake = true;
						}	
					}	
					else {
						lowfpsCount = 0;
					}	

					if (viewfpscount) console.log("fpsCount: " + fpsCount);

					fpsCount = 0;
					lastCheck = now;
				}

				for (let i = 0; i < snowflakes.length; i++) {
					const snow = snowflakes[i];
					if (snow) snow.animate(fpsCount); // 눈송이를 움직인다

						if (decsnowflake && snow.y == 0) { // 눈송이가 화면 하단을 벗어난 거
							snowflakes.splice(i, 1); // 배열 삭제
							snow.flake.remove(); // 눈송이 제거
				
							decsnowflake = false;

							if (viewconsolelog) console.log(snow.flake.id+" 삭제 남은 갯수 : " + snowflakes.length);
						}
				}

				// Reset the position of all the snowflakes to a new value
				if (resetPosition) {
					resetPosition = false;

					snowflake_cw = document.documentElement.clientWidth;
					snowflake_ch = document.documentElement.clientHeight;

					var spz;
					for (let i = 0; i < snowflakes.length; i++) {
						let snow = snowflakes[i];

						// set initial snowflake properties
						snow.y = Math.random() * snowflake_ch; 
						snow.x = Math.random() * snowflake_cw; 
						snow.frame = randMinMax(1, fend);
						snow.fmid = randMinMax(1, fmid);
						snow.fend = randMinMax(snow.fmid, fend);

						snow.direction = Math.random();

						snow.sz = szn / (szd + (szv * Math.random())) * sz;
						snow.scale = snow.sz / (szn / (szd + szv)) * sc;
						spz = spn / (spd + (spv * Math.random())) * sp;
						snow.sp = Math.max(spmin, (Math.pow(spz * spow, 2) * 0.25) * sp);

						if (snow.sp > 3) { // 눈송이가 떨어지는 속도가 빠르면 좌우 이동값을 느리게 바꾼다 
							snow.fmid = snow.fmid * 2;
							snow.fend = snow.fend * 2;
						}	
						else if (snow.sp > 2) {
							snow.fmid = snow.fmid * 1.5;
							snow.fend = snow.fend * 1.5;
						}	

						snow.flake.style.backgroundColor = snowflakeColorRand();
						snow.flake.style.opacity = (0.65 + Math.random()) / 3; //0.22 ~ 0.55
					}
				}

				requestAnimationFrame(snowflakes_frame_animate);
			}
			snowflakes_frame_animate();
		}
 
    </script>
</body>
 
</html>

 

첨부파일 snowfall.zip (3.6 KB)
 이전글 ajaxcall function (beforeSend)...

댓글

없음