Heart Beat Monitor
心電図モニター風の心拍アニメーション。
SVGパスアニメーションとCSSキーフレームで実装したリアルな心拍表現です。
Demo
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Heart Beat Animation</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="heart-monitor">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 150">
<!-- 心電図ライン -->
<path id="ecg-line" d="M0 75 L80 75 L90 75 L95 35 L100 115 L105 75 L115 75 L120 60 L125 75 L200 75 L210 75 L215 35 L220 115 L225 75 L235 75 L240 60 L245 75 L320 75 L330 75 L335 35 L340 115 L345 75 L355 75 L360 60 L365 75 L440 75 L450 75 L455 35 L460 115 L465 75 L475 75 L480 60 L485 75 L600 75" />
<!-- ハート -->
<g id="heart-icon">
<path d="M300 55 C300 45 310 35 320 35 C325 35 328 38 330 42 C332 38 335 35 340 35 C350 35 360 45 360 55 C360 70 330 90 330 90 C330 90 300 70 300 55 Z" />
</g>
</svg>
<div class="bpm-display">
<span class="bpm-value">72</span>
<span class="bpm-label">BPM</span>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
style.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(135deg, #0f2027 0%, #203a43 50%, #2c5364 100%);
font-family: 'Arial', sans-serif;
}
.container {
width: 90%;
max-width: 800px;
}
.heart-monitor {
position: relative;
background: rgba(0, 0, 0, 0.3);
border-radius: 20px;
padding: 40px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5),
inset 0 0 20px rgba(0, 255, 157, 0.1);
border: 2px solid rgba(0, 255, 157, 0.2);
}
svg {
width: 100%;
height: auto;
display: block;
filter: drop-shadow(0 0 8px rgba(0, 255, 157, 0.6));
}
/* 心電図ライン */
#ecg-line {
fill: none;
stroke: #00ff9d;
stroke-width: 3;
stroke-linecap: round;
stroke-linejoin: round;
stroke-dasharray: 600;
stroke-dashoffset: 600;
animation: ecgFlow 3s linear infinite;
}
@keyframes ecgFlow {
0% {
stroke-dashoffset: 600;
}
100% {
stroke-dashoffset: 0;
}
}
/* ハートアイコン */
#heart-icon {
transform-origin: center;
animation: heartbeat 3s ease-in-out infinite;
}
#heart-icon path {
fill: #ff4d6d;
filter: drop-shadow(0 0 10px rgba(255, 77, 109, 0.8));
}
@keyframes heartbeat {
0%, 100% {
transform: scale(1);
opacity: 0.7;
}
10% {
transform: scale(1.3);
opacity: 1;
}
20% {
transform: scale(1);
opacity: 0.8;
}
30% {
transform: scale(1.3);
opacity: 1;
}
40% {
transform: scale(1);
opacity: 0.7;
}
}
/* BPM表示 */
.bpm-display {
position: absolute;
top: 20px;
right: 40px;
text-align: right;
}
.bpm-value {
display: block;
font-size: 3rem;
font-weight: bold;
color: #00ff9d;
text-shadow: 0 0 20px rgba(0, 255, 157, 0.8);
line-height: 1;
animation: bpmPulse 3s ease-in-out infinite;
}
.bpm-label {
display: block;
font-size: 1rem;
color: rgba(0, 255, 157, 0.7);
margin-top: 5px;
letter-spacing: 3px;
}
@keyframes bpmPulse {
0%, 100% {
opacity: 0.7;
}
10%, 30% {
opacity: 1;
transform: scale(1.1);
}
20%, 40% {
opacity: 0.8;
transform: scale(1);
}
}
/* グリッド背景(オプション) */
.heart-monitor::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image:
linear-gradient(rgba(0, 255, 157, 0.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 255, 157, 0.05) 1px, transparent 1px);
background-size: 20px 20px;
border-radius: 20px;
pointer-events: none;
}
/* レスポンシブ */
@media (max-width: 768px) {
.heart-monitor {
padding: 30px 20px;
}
.bpm-display {
right: 20px;
top: 15px;
}
.bpm-value {
font-size: 2rem;
}
.bpm-label {
font-size: 0.8rem;
}
#ecg-line {
stroke-width: 2;
}
}
script.js
// BPM値のランダム変動エフェクト
const bpmValue = document.querySelector('.bpm-value');
let baseBPM = 72;
function updateBPM() {
// 心拍のタイミングで少し値を変動させる
const variation = Math.floor(Math.random() * 5) - 2; // -2 ~ +2
const currentBPM = baseBPM + variation;
bpmValue.textContent = currentBPM;
}
// 3秒ごとに更新(アニメーションサイクルと同期)
setInterval(updateBPM, 3000);
// ハートアイコンをクリックでBPM増加
const heartIcon = document.getElementById('heart-icon');
heartIcon.style.cursor = 'pointer';
heartIcon.addEventListener('click', () => {
// BPMを一時的に上げる
baseBPM = Math.min(baseBPM + 10, 120);
bpmValue.textContent = baseBPM;
// 5秒後に元に戻す
setTimeout(() => {
baseBPM = Math.max(baseBPM - 10, 60);
}, 5000);
// クリックエフェクト
heartIcon.style.animation = 'none';
setTimeout(() => {
heartIcon.style.animation = 'heartbeat 3s ease-in-out infinite';
}, 10);
});
// モニター画面のスキャンラインエフェクト(オプション)
const monitor = document.querySelector('.heart-monitor');
const scanLine = document.createElement('div');
scanLine.style.cssText = `
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 2px;
background: linear-gradient(to bottom, transparent, rgba(0, 255, 157, 0.3), transparent);
animation: scan 4s linear infinite;
pointer-events: none;
z-index: 10;
`;
// スキャンラインアニメーションを追加
const style = document.createElement('style');
style.textContent = `
@keyframes scan {
0% {
top: 0;
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
top: 100%;
opacity: 0;
}
}
`;
document.head.appendChild(style);
monitor.appendChild(scanLine);
Download
すべてのファイルをZIP形式でダウンロードできます。