File indexing completed on 2025-01-18 09:16:07
0001 <!DOCTYPE html>
0002 <html>
0003 <head>
0004 <title>Particle Trajectory Animation with Multiple Tracks</title>
0005 <style>
0006 body { margin: 0; }
0007 canvas { display: block; }
0008 #controls { position: absolute; top: 10px; left: 10px; z-index: 100; }
0009 </style>
0010 </head>
0011 <body>
0012 <div id="controls">
0013 <input type="range" id="timeSlider" min="0" max="9000" step="10" value="0" />
0014 </div>
0015 <script type="module">
0016 import * as THREE from 'https://unpkg.com/three@0.141.0/build/three.module.js';
0017 import { TWEEN } from 'https://unpkg.com/@tweenjs/tween.js@18.6.4/dist/tween.esm.js';
0018
0019 // Set up the scene, camera, and renderer
0020 const scene = new THREE.Scene();
0021 const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
0022 const renderer = new THREE.WebGLRenderer();
0023 renderer.setSize(window.innerWidth, window.innerHeight);
0024 document.body.appendChild(renderer.domElement);
0025
0026 // Create spheres to represent the particles
0027 const geometry = new THREE.SphereGeometry(0.1, 32, 32);
0028 const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
0029 const particle1 = new THREE.Mesh(geometry, material);
0030 const particle2 = new THREE.Mesh(geometry, material);
0031 particle1.visible = false; // Initially invisible
0032 particle2.visible = false; // Initially invisible
0033 scene.add(particle1);
0034 scene.add(particle2);
0035
0036 // Position the camera
0037 camera.position.z = 5;
0038
0039 // Define the trajectories with points and timestamps
0040 const trajectories = [
0041 [
0042 { x: 0, y: 0, z: 0, time: 1000 },
0043 { x: 1, y: 1, z: 0, time: 2000 },
0044 { x: 2, y: 0, z: 1, time: 3000 },
0045 { x: 3, y: -1, z: 0, time: 4000 },
0046 { x: 4, y: 0, z: -1, time: 5000 }
0047 ],
0048 [
0049 { x: 4, y: 0, z: -1, time: 5000 },
0050 { x: 5, y: 1, z: -1, time: 6000 },
0051 { x: 6, y: 2, z: 0, time: 7000 },
0052 { x: 7, y: 1, z: 1, time: 8000 },
0053 { x: 8, y: 0, z: 1, time: 9000 }
0054 ],
0055 [
0056 { x: 8, y: 0, z: 1, time: 5000 },
0057 { x: 9, y: -1, z: 1, time: 6000 },
0058 { x: 10, y: -2, z: 0, time: 7000 },
0059 { x: 11, y: -1, z: -1, time: 8000 },
0060 { x: 12, y: 0, z: -1, time: 9000 }
0061 ]
0062 ];
0063
0064 // Create splines for each trajectory
0065 const curves = trajectories.map(points => {
0066 return new THREE.CatmullRomCurve3(points.map(p => new THREE.Vector3(p.x, p.y, p.z)));
0067 });
0068
0069 // Create full line geometries for each trajectory
0070 const lines = curves.map(curve => {
0071 const linePoints = curve.getPoints(100);
0072 const lineGeometry = new THREE.BufferGeometry().setFromPoints(linePoints);
0073 const lineMaterial = new THREE.LineBasicMaterial({ color: 0x0000ff });
0074 const line = new THREE.Line(lineGeometry, lineMaterial);
0075 line.visible = false; // Initially invisible
0076 scene.add(line);
0077 return line;
0078 });
0079
0080 // Get the time slider element
0081 const timeSlider = document.getElementById('timeSlider');
0082
0083 // Function to update the particles' positions and line visibility based on the current time
0084 function updateParticlePosition(currentTime) {
0085 const delay = 1000; // Delay before the particles appear
0086 if (currentTime < delay) {
0087 particle1.visible = false;
0088 particle2.visible = false;
0089 lines.forEach(line => line.visible = false);
0090 return;
0091 }
0092
0093 particle1.visible = true;
0094 particle2.visible = currentTime >= 5000;
0095
0096 let adjustedTime = currentTime - delay;
0097
0098 // Track 1
0099 if (adjustedTime <= 4000) {
0100 lines[0].visible = true;
0101 const t1 = adjustedTime / 4000;
0102 const position1 = curves[0].getPoint(t1);
0103 particle1.position.copy(position1);
0104 const visiblePoints1 = curves[0].getPoints(Math.floor(t1 * 100) + 1);
0105 lines[0].geometry.setFromPoints(visiblePoints1);
0106 }
0107
0108 // Track 2
0109 if (adjustedTime >= 4000 && adjustedTime <= 8000) {
0110 lines[1].visible = true;
0111 const t2 = (adjustedTime - 4000) / 4000;
0112 const position2 = curves[1].getPoint(t2);
0113 particle1.position.copy(position2);
0114 const visiblePoints2 = curves[1].getPoints(Math.floor(t2 * 100) + 1);
0115 lines[1].geometry.setFromPoints(visiblePoints2);
0116 }
0117
0118 // Track 3 (second particle)
0119 if (adjustedTime >= 4000 && adjustedTime <= 8000) {
0120 lines[2].visible = true;
0121 const t3 = (adjustedTime - 4000) / 4000;
0122 const position3 = curves[2].getPoint(t3);
0123 particle2.position.copy(position3);
0124 const visiblePoints3 = curves[2].getPoints(Math.floor(t3 * 100) + 1);
0125 lines[2].geometry.setFromPoints(visiblePoints3);
0126 }
0127 }
0128
0129 // Event listener for the time slider
0130 timeSlider.addEventListener('input', (event) => {
0131 const currentTime = parseInt(event.target.value, 10);
0132 updateParticlePosition(currentTime);
0133 });
0134
0135 // Function to control the tweens and set the state at a specific time t0
0136 function setAnimationTime(t0) {
0137 timeSlider.value = t0;
0138 updateParticlePosition(t0);
0139 }
0140
0141 // Add event listener to the slider for manual control
0142 timeSlider.addEventListener('change', (event) => {
0143 const currentTime = parseInt(event.target.value, 10);
0144 setAnimationTime(currentTime);
0145 });
0146
0147 // Initial update
0148 updateParticlePosition(timeSlider.value);
0149
0150 // Animation loop
0151 function animate() {
0152 requestAnimationFrame(animate);
0153 TWEEN.update();
0154 renderer.render(scene, camera);
0155 }
0156
0157 animate();
0158 </script>
0159 </body>
0160 </html>