episode-visualizer / index.html
qhrong's picture
Create index.html
e6a00c1 verified
raw
history blame
7 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Synchronized 3D Motion Capture Visualization with Video</title>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.0/papaparse.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
}
#plotDiv {
width: 100%;
height: 600px;
}
.video-container {
display: flex;
justify-content: space-around;
width: 100%;
margin-bottom: 20px;
}
.video-wrapper {
width: 45%;
}
video {
width: 100%;
height: auto;
}
.controls {
display: flex;
justify-content: center;
margin-top: 10px;
}
button {
margin: 0 5px;
font-size: 20px;
}
</style>
</head>
<body>
<h1>Synchronized 3D Motion Capture Visualization with Video</h1>
<div class="video-container">
<div class="video-wrapper">
<video id="laptopVideo">
<source src="video.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
<!--
<div class="video-wrapper">
<video id="phoneVideo">
<source src="video.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
-->
</div>
<div class="controls">
<button id="playPauseBtn">▶️</button>
<button id="rewindBtn"></button>
<button id="forwardBtn"></button>
<button id="restartBtn">↩️</button>
</div>
<div id="plotDiv"></div>
<script>
const csvFilePath = 'MoCap_mocap.csv';
const body_part_names = [
'Left Shoulder', 'Right Upper Arm', 'Left Lower Leg', 'Spine1', 'Right Upper Leg',
'Spine3', 'Right Lower Arm', 'Left Foot', 'Right Lower Leg', 'Right Shoulder',
'Left Hand', 'Left Upper Leg', 'Right Foot', 'Spine', 'Spine2', 'Left Lower Arm',
'Left Toe', 'Neck', 'Right Hand', 'Right Toe', 'Head', 'Left Upper Arm', 'Hips'
];
const laptopVideo = document.getElementById('laptopVideo');
//const phoneVideo = document.getElementById('phoneVideo');
const playPauseBtn = document.getElementById('playPauseBtn');
const rewindBtn = document.getElementById('rewindBtn');
const forwardBtn = document.getElementById('forwardBtn');
const restartBtn = document.getElementById('restartBtn');
let animationFrameId;
let isPlaying = false;
function togglePlayPause() {
if (!isPlaying) {
laptopVideo.play();
//phoneVideo.play();
playPauseBtn.textContent = '⏸️';
isPlaying = true;
animate3DVisualization();
} else {
laptopVideo.pause();
//phoneVideo.pause();
playPauseBtn.textContent = '▶️';
isPlaying = false;
cancelAnimationFrame(animationFrameId);
}
}
function rewind() {
laptopVideo.currentTime -= 5;
//phoneVideo.currentTime -= 5;
update3DVisualization();
}
function forward() {
laptopVideo.currentTime += 5;
//phoneVideo.currentTime += 5;
update3DVisualization();
}
function restart() {
laptopVideo.currentTime = 0;
//phoneVideo.currentTime = 0;
update3DVisualization();
}
playPauseBtn.addEventListener('click', togglePlayPause);
rewindBtn.addEventListener('click', rewind);
forwardBtn.addEventListener('click', forward);
restartBtn.addEventListener('click', restart);
function getCoordinates(data, coordinate) {
return body_part_names.map(part => parseFloat(data[`${part}_${coordinate}`]));
}
let frames;
function processData(results) {
console.log("Processing data:", results);
const motion_capture_data = results.data.filter((_, index) => index % 3 === 0);
frames = motion_capture_data.map((row, index) => ({
name: index.toString(),
data: [{
x: getCoordinates(row, 'x'),
y: getCoordinates(row, 'y'),
z: getCoordinates(row, 'z'),
mode: 'markers',
type: 'scatter3d',
marker: { size: 5, color: 'blue' }
}]
}));
if (frames.length === 0) {
console.error("No frames were created from the data");
return;
}
const initialFrame = frames[0].data[0];
const layout = {
title: '3D Motion Capture',
scene: {
xaxis: { title: 'X' },
yaxis: { title: 'Y' },
zaxis: { title: 'Z' }
}
};
Plotly.newPlot('plotDiv', [initialFrame], layout);
}
function update3DVisualization() {
if (!frames) return;
const currentTime = laptopVideo.currentTime;
const totalDuration = laptopVideo.duration;
const frameIndex = Math.floor((currentTime / totalDuration) * frames.length);
const frame = frames[Math.min(frameIndex, frames.length - 1)];
Plotly.animate('plotDiv', frame, {
transition: { duration: 0 },
frame: { duration: 0, redraw: true }
});
}
function animate3DVisualization() {
update3DVisualization();
if (isPlaying) {
animationFrameId = requestAnimationFrame(animate3DVisualization);
}
}
fetch(csvFilePath)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.text();
})
.then(csvString => {
console.log("CSV data loaded successfully");
Papa.parse(csvString, {
header: true,
dynamicTyping: true,
complete: processData
});
})
.catch(error => console.error('Error loading the CSV file:', error));
</script>
</body>
</html>