ブラウザ上で一定時間操作がなかったら〇〇〇するJavaScript

Webシステムの構築をしている中で、特定の権限をもった人間だけが閲覧できる画面を作ることもあります。
閲覧者がその画面を開いたまま離籍をしてしまう際、環境によっては権限のない人間がその画面をのぞき見できる状況が生まれます。
環境整備や従業員教育の話は勝手にやってもらうとして、
エンジニアとしてお手軽に対策できるスクリプトを考えてみました。

## HTML

JavaScriptファイルを呼び出すだけです。

```html:sample.thml
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>sample</title>
<script src="sample.js"></script>
</head>
<body>
これは機密文章です
</body>
</html>
```

## ブラウザ上で一定時間操作がなかったら強制ログアウトするJavaScript

60秒間操作がなかったらログアウト処理が実行されるURLに飛ばすスクリプトです。
onkeydown、onmousemove、onclickのイベント発火でログアウトまでの待機時間をリセットしています。

```javascript:sample.js
(function(){
	const sec = 60;
	const events = ['keydown', 'mousemove', 'click'];
	let timeoutId;

	// タイマー設定
	function setTimer() {
		timeoutId = setTimeout(logout, sec * 1000);
	}
	function resetTimer() {
		clearTimeout(timeoutId);
		setTimer();
	}

	// イベント設定
	function setEvents(func) {
		let len = events.length;
		while (len--) {
			addEventListener(events[len], func, false);
		}
	}

	// ログアウト
	function logout() {
		location.href = 'https://example.com/logout'; // ログアウト処理用URLに飛ばす
	}

	setTimer();
	setEvents(resetTimer);
})();
```

## ブラウザ上で一定時間操作がなかったらスクリーンセイバーを表示するJavaScript

強制ログアウトするスクリプトに手を加えて、スクリーンセイバーを表示するスクリプトにしました。
スクリーンセイバーの内容はお好みで。

requestFullScreenで全画面表示のスクリーンセイバーにしたかったのですが、
ユーザー操作（ボタン押下とか）以外ではrequestFullScreenが拒否られてしまい断念しました。

以下スクリプトでは[JavaScriptで線がなめらかに動くスクリーンセーバー](https://hajimete-program.com/blog/2017/04/02/javascript%E3%81%A7%E7%B7%9A%E3%81%8C%E3%81%AA%E3%82%81%E3%82%89%E3%81%8B%E3%81%AB%E5%8B%95%E3%81%8F%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%BB%E3%83%BC%E3%83%90%E3%83%BC/)を参考にさせていただきました。

```javascript:sample.js
(function(){
	const sec = 60;
	const events = ['keydown', 'mousemove', 'click'];
	let timeoutId;

	// タイマー設定
	function setTimer() {
		timeoutId = setTimeout(switchScreen, sec * 1000);
	}
	function resetTimer() {
		clearTimeout(timeoutId);
		setTimer();
	}

	// イベントの設定と解除
	function setEvents(func) {
		let len = events.length;
		while (len--) {
			addEventListener(events[len], func, false);
		}
	}
	function unsetEvents(func) {
		let len = events.length;
		while (len--) {
			removeEventListener(events[len], func, false);
		}
	}

	// 画面の切替
	function switchScreen() {
		let elm = document.getElementById('sample');
		if (elm) {
			unsetEvents(switchScreen);
			elm.remove();
			resetTimer();
			setEvents(resetTimer);
		} else {
			unsetEvents(resetTimer);
			screensaver();
			setEvents(switchScreen);
		}
	}

	// スクリーンセイバーの描画
	function screensaver() {
		let canvas = document.createElement('canvas');
		canvas.id = 'sample';
		canvas.style.display = 'block';
		canvas.style.position = 'absolute';
		canvas.style.top = 0;
		canvas.style.left = 0;
		canvas.style.width = '100%';
		canvas.style.height = '100%';
		canvas.style.overflow = 'hidden';
		document.body.appendChild(canvas);

		let ctx = canvas.getContext('2d');
		let width = window.innerWidth;
		let height = window.innerHeight;
		canvas.width = width;
		canvas.height = height;

		let t = 0;
		const x11 = (t) => Math.sin(t / 10) * 200 + Math.sin(t / 5) * 20;
		const y11 = (t) => Math.cos(-t / 10) * 200 + Math.sin(t / 5) * 50;
		const x21 = (t) => Math.sin(t / 10) * 400 + Math.sin(t) * 2;
		const y21 = (t) => -Math.cos(t / 20) * 400 + Math.cos(t / 12) * 20;
		const NUM_LINES = 50;
		
		function setup() {
			ctx.shadowBlur = 15;
			ctx.shadowColor = '#fff';
			ctx.strokeStyle = '#fff';
			ctx.lineWidth = 2;
		}
		function line(x1, y1, x2, y2, ctx) {
			ctx.beginPath();
			ctx.moveTo(x1, y1);
			ctx.lineTo(x2, y2);
			ctx.closePath();
			ctx.stroke();
		}
		function loop() {
			window.requestAnimationFrame(loop);
			ctx.fillStyle = 'rgba(0, 0, 0, 0.8)';
			ctx.fillRect(0, 0, width, height);
			ctx.translate(width / 2, height / 2);
			for (let i = 0; i < NUM_LINES; i++) {
				line(x11(t + i), y11(t + i), x21(t + i), y21(t + i), ctx);
			}
			ctx.translate(-width / 2, -height / 2);
			t += 0.2;
		}
		setup();
		loop();
	}

	setTimer();
	setEvents(resetTimer);
})();
```

## さいごに

正直なところ、一定時間操作がなかったら〇〇〇するJavaScriptにあまり需要を感じないですが・・・何かの参考になれば幸いです。