JavaScript | 文字が降るアニメーションサンプル

2023-04-21JavaScript アニメーション サンプル集,JavaScript

JavaScript | 文字が降るアニメーションサンプル

指定したHTML要素内に文字が降ってくるJavaScriptアニメーションです。

文字が降るJavaScriptアニメーションの使い方

以下は文字が降るJavaScriptアニメーションの動作サンプルになります。
オプションを指定する事で、文字の種類、色や、落下速度、サイズ、角度、回転、発光の有無などをカスタマイズができるようにしてあります。

See the Pen JavaScript | Falling Letters Animation by yochans (@yochans) on CodePen.

様々な文字が範囲外から降り注ぐアニメーションのJavaScriptコードは「falling_letters_animation.js」として以下の場所に置いてあります。

ダウンロード:falling_letters_animation.js(v.1.0)

ダウンロードしたjsファイルを読み込む、または既存のJavaScriptコードに貼り付けて利用できます。

<script src="falling_letters_animation.js"></script>

動作サンプルでは以下のHTMLを作成しています。
<div>要素の「container」内に文字を落下、降らせています。
画像のありなしや要素のサイズなど、変更しても対応できているはずです。

<div id="container"></div>

CSSは以下の通りです。
「aspect-ratio」でアスペクト比を固定しています。

#container {
	width: 100%;
	aspect-ratio: 3 / 1;
}

fallingLettersAnim()という関数を実行する事で、指定したHTML要素に文字を降らせます。
オプションを指定する事でカスタマイズが可能です。

「target_element」以外のオプションは必須ではありません。
「target_element」が未指定の場合や存在しなかった場合、<body>全体を対象にします。

//////////////////////////// call function

let option = {
	target_element: '#container', // taget HTML element
	where_to_insert: 'img', // Insert after the specified element in target_element. If unspecified, insert at the end of the target_element. ('img' 'p' '#id' etc)
	letters_amount: 5, // Amount of letters (min 1 max 10)
	letters_speed: 5, // Speed of letters (min 1 max 10)
	letters_size: 1.0, // Size of letters (min 0.1)
	letters_color: 'random', // Color of letters (hex, rgba, name, random)
	letters_type: 'Aऄก', // select letter (aA1ऄกあア)
	letters_angle: true, // Random default angle / affect rotation mode
	letters_rotate_mode: 1, //Rotation mode (0=false 1=X 2=Y 3=XY)
	letters_rotate_deg: 180, // (0 = false 720 = 720deg)
	letters_rotate_reverse: true, // reverse rotation
	letters_neon_light: true, // Emission of light from letters.
	letters_neon_color: 'random', // Color of letters (hex, rgba, name, random)
	animation_time: 600 // Animation time (s)
};

fallingLettersAnim(option);

fallingLettersAnim()で利用可能なオプション設定です。
オプションの指定がないものはデフォルト値が割り当てられます。

オプション内容初期値
target_element文字を降らすHTML要素body
where_to_inserttarget_element内の指定した要素の次に挿入
未指定の場合はtarget_element内の最後に挿入
('img’ 'p’ '#id’ など)
未指定
letters_amount文字の量 (min 1 max 10)5
letters_speed文字の速さ (min 1 max 10)5
letters_size文字の多きさ (min 0.1)1
letters_color文字の色
(hex, rgba, name, random)
random
letters_type抽出する文字の種類
※平仮名なら「あ」を含める
(aA1ऄกあア)
Aऄก
letters_angle文字の角度をランダムにするかtrue
letters_rotate_mode文字の回転モード
(0=false 1=X 2=Y 3=XY)
1
letters_rotate_deg文字の回転量、単位はdeg、360以上も可
(0 = false 720 = 720deg)
180
letters_rotate_reverse文字の逆回転true
letters_neon_light文字を発光するかどうかtrue
letters_neon_color文字の発光色
(hex, rgba, name, random)
random
animation_timeアニメーション時間 (s)60
fallingLettersAnim()のオプション
  • 「target_element」以外のオプションは必須ではありません。
  • 「target_element」が未指定の場合や存在しなかった場合、<body>全体を対象にします。
  • 「letters_amount」を未指定の場合、「target_element」の最後に追加されますが、指定するとその要素の次に追加されます。
  • 文字の種類は、例えばアルファベットの大文字と平仮名にする場合は「Aあ」と指定できます。
  • ランダム角度を有効にしてX軸回転、Y軸回転を選択した場合は斜めに回転します。
  • 回転量にて回転速度を調節できます。
  • 文字の発光はネオン文字みたいになります。
  • アニメーション時間経過後、アニメーションは停止します。指定に制限はありません。

文字が降るアニメーションのJavaScriptコード詳細

以下は文字が降るアニメーションの実行部分のJavaScriptコードになります。

  • 対象のHTML要素が見つからない場合は<body>を対象とします。
  • ランダム色はスクリプトで生成しています。
  • 平仮名・片仮名はString.fromCharCode()でユニコードから取得しています。
// drop letters animation function
const fallingLettersAnim = (option) => {
	// default option
	let default_option = {
		target_element: 'body', // taget HTML element
		where_to_insert: 'img', // Insert after the specified element in target_element. If unspecified, insert at the end of the target_element. ('img' 'p' '#id' etc)
		letters_amount: 5, // Amount of letters (min 1 max 10)
		letters_speed: 5, // Speed of letters (min 1 max 10)
		letters_size: 1.0, // Size of letters (min 0.1)
		letters_type: 'Aऄก', // select letter (aA1ऄกあア)
		letters_angle: true, // Random default angle / affect rotation mode
		letters_rotate_mode: 1, //Rotation mode (0=false 1=X 2=Y 3=XY)
		letters_rotate_deg: 180, // (0 = false 360 = 360deg)
		letters_rotate_reverse: true, // reverse rotation
		letters_color: 'random', // Color of letters (hex, rgba, name, random)
		letters_neon_light: true, // Emission of light from letters.
		letters_neon_color: 'random', // Color of letters (hex, rgba, name, random)
		animation_time: 600 // Animation time (s)
	};

	// merge option
	let op = Object.assign(default_option, option);

	// whether the target element exists
	if (!document.querySelector(op.target_element)) {
		console.log('no target element.');
		return;
	}

	// target element
	let target_element = document.querySelector(op.target_element);
	target_element.style.position = 'relative';
	target_element.style.overflow = 'hidden';

	// Insert after the specified element
	let insert_after_element = '';
	if (op.where_to_insert != '') {
		insert_after_element = target_element.querySelector(op.where_to_insert);
	}

	// main container
	let container = document.createElement('div');
	if (!insert_after_element) {
		target_element.appendChild(container);
	} else {
		insert_after_element.after(container);
	}
	container.style.position = 'absolute';
	container.style.top = 0;
	container.style.left = 0;
	container.style.width = '100%';
	container.style.height = '100%';
	container.style.overflow = 'hidden';

	// letters container
	let letters_container = document.createElement('div');
	container.appendChild(letters_container);
	letters_container.style.position = 'absolute';
	letters_container.style.width = '100%';
	letters_container.style.height = '100%';

	// letter clone
	let letter = document.createElement('div');
	letter.style.position = 'absolute';
	letter.style.opacity = 1;
	letter.style.fontFamily = '';

	// letters
	let chars = '';
	if (op.letters_type.includes('a')) {
		chars += 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz';
	}
	if (op.letters_type.includes('A')) {
		chars += 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ';
	}
	if (op.letters_type.includes('1')) {
		chars += '012345678901234567890123456789012345678901234567890123456789';
	}
	if (op.letters_type.includes('ऄ')) {
		chars += 'ऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनऩपफबभमयरऱलळऴवशषसह';
	}
	if (op.letters_type.includes('ก')) {
		chars += 'กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ';
	}
	if (op.letters_type.includes('あ')) {
		for (let i = 12353; i < 12435; i++) {
			chars += String.fromCharCode(i);
		}
	}
	if (op.letters_type.includes('ア')) {
		for (let i = 12439; i < 12538; i++) {
			chars += String.fromCharCode(i);
		}
	}

	let colors = [];
	if (op.letters_color == 'random' || op.letters_neon_color == 'random') {
		for (let i = 0; i < 110; i++) {
			colors.push('#' + Math.floor(Math.random() * 16777215).toString(16));
		}
	}
	;
	let letters = '';
	for (var i = 0; i < 500; i++) {
		letters += chars.charAt(Math.floor(Math.random() * chars.length));
	}

	let no = 0;
	let count = 0;
	op.animation_time *= 60;
	const update = () => {
		let rand1 = Math.floor(Math.random() * 110);
		let rand2 = Math.floor(Math.random() * 100);

		// font color
		let letters_color = op.letters_color;
		if (op.letters_color == 'random') {
			letters_color = colors[rand1];
		}

		// neon color
		let letters_neon_color = op.letters_neon_color;
		if (op.letters_neon_color == 'random') {
			letters_neon_color = colors[rand2];
		}

		// angle
		let angle = 0;
		if (op.letters_angle == true) {
			angle = Math.floor(Math.random() * 360);
		}

		// rotate set reverse
		if (rand2 % 2 == 0 && op.letters_rotate_reverse == true) {
			op.letters_rotate_deg = -(op.letters_rotate_deg);
		}

		// rotate set
		let angle_set = 0;
		let rotate_angle_set = '';
		if (op.letters_rotate_mode == 0) {
			rotate_angle_set = `rotateX(0deg)`;
			rotate_angle_set = `rotateX(0deg)`;
		} else if (op.letters_rotate_mode == 1) {
			angle_set = `rotate(${angle}deg)`;
			rotate_angle_set = `rotateX(${angle + op.letters_rotate_deg}deg)`;
		} else if (op.letters_rotate_mode == 2) {
			angle_set = `rotate(${angle}deg)`;
			rotate_angle_set = `rotateY(${angle + op.letters_rotate_deg}deg)`;
		} else if (op.letters_rotate_mode == 3) {
			angle_set = `rotate(${angle}deg)`;
			rotate_angle_set = `rotate(${angle + op.letters_rotate_deg}deg)`;
		}

		// letter drop
		if (count % (11 - op.letters_amount) == 0) {

			let letter_clone = letter.cloneNode();
			letter_clone.innerText = letters[no];
			letter_clone.style.fontSize = `${0.1 * rand2 * op.letters_size}vw`;
			letter_clone.style.left = `${rand1 - 10}%`;
			letter_clone.style.color = letters_color;
			letter_clone.style.transform = `rotate(${angle}deg)`;
			if (op.letters_neon_light == true) {
				letter_clone.style.textShadow = `
				0 0 1.0em ${letters_neon_color},
				0 0 0.5em ${letters_neon_color},
				0 0 0.1em ${letters_neon_color}
				`;
			}
			letters_container.appendChild(letter_clone);

			let letters_anim = letter_clone.animate(
				[
					{ top: `-20%`, transform: angle_set },
					{ top: `100%`, transform: rotate_angle_set }
				],
				{
					fill: 'forwards',
					duration: 6000 / op.letters_speed
				}
			);

			letters_anim.onfinish = (event) => {
				letter_clone.remove();
			};

			if (no < 499) {
				no++;
			} else {
				no = 1;
			}
		}

		// stop or run animation
		count++;
		if (op.animation_time >= count) {
			requestAnimationFrame(update);
		} else {
			cancelAnimationFrame(update);
		}
	};

	update();
};