Spaces:
Running
Running
try another sync approach
Browse files- index.html +20 -32
index.html
CHANGED
@@ -12,7 +12,7 @@
|
|
12 |
justify-content: center;
|
13 |
align-items: center;
|
14 |
height: 100vh;
|
15 |
-
background-color: black;
|
16 |
}
|
17 |
|
18 |
.video-container {
|
@@ -33,7 +33,6 @@
|
|
33 |
|
34 |
.second-video {
|
35 |
clip-path: inset(0 50% 0 0);
|
36 |
-
/* Initially shows half of the second video */
|
37 |
}
|
38 |
|
39 |
.slider {
|
@@ -84,7 +83,7 @@
|
|
84 |
}
|
85 |
|
86 |
.slider.ready:hover::before,
|
87 |
-
.slider.ready::after {
|
88 |
opacity: 1;
|
89 |
}
|
90 |
|
@@ -92,23 +91,18 @@
|
|
92 |
0% {
|
93 |
left: 100%;
|
94 |
}
|
95 |
-
|
96 |
10% {
|
97 |
left: 80%;
|
98 |
}
|
99 |
-
|
100 |
20% {
|
101 |
left: 85%;
|
102 |
}
|
103 |
-
|
104 |
50% {
|
105 |
left: 20%;
|
106 |
}
|
107 |
-
|
108 |
70% {
|
109 |
left: 60%;
|
110 |
}
|
111 |
-
|
112 |
100% {
|
113 |
left: 30%;
|
114 |
}
|
@@ -129,29 +123,23 @@
|
|
129 |
const video2 = document.getElementById('video2');
|
130 |
|
131 |
let isDragging = false;
|
|
|
132 |
|
133 |
-
//
|
134 |
-
function syncVideos(
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
if (
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
video1.play();
|
143 |
-
video2.play();
|
144 |
}
|
145 |
}
|
146 |
|
147 |
-
//
|
148 |
-
video1.addEventListener('
|
149 |
-
|
150 |
-
video1.addEventListener('seeked', () => syncVideos(video1));
|
151 |
-
|
152 |
-
video2.addEventListener('play', () => syncVideos(video2));
|
153 |
-
video2.addEventListener('pause', () => syncVideos(video2));
|
154 |
-
video2.addEventListener('seeked', () => syncVideos(video2));
|
155 |
|
156 |
// Mouse events for slider
|
157 |
slider.addEventListener('mousedown', () => isDragging = true);
|
@@ -168,7 +156,7 @@
|
|
168 |
|
169 |
window.addEventListener('touchmove', (event) => {
|
170 |
if (!isDragging) return;
|
171 |
-
handleSlide(event.touches[0].clientX);
|
172 |
});
|
173 |
|
174 |
function handleSlide(positionX) {
|
@@ -180,20 +168,20 @@
|
|
180 |
slider.style.left = `${sliderPosition}px`;
|
181 |
|
182 |
// Adjust second video visibility using clip-path
|
183 |
-
|
184 |
}
|
185 |
|
186 |
// Function to update clip-path in real-time
|
187 |
function updateClipPath() {
|
188 |
const rect = container.getBoundingClientRect();
|
189 |
-
const sliderPosition = parseFloat(window.getComputedStyle(slider).left);
|
190 |
video2.style.clipPath = `inset(0 ${rect.width - sliderPosition}px 0 0)`;
|
191 |
-
requestAnimationFrame(updateClipPath);
|
192 |
}
|
193 |
|
194 |
// Enable user control after the animation ends
|
195 |
slider.addEventListener('animationend', () => {
|
196 |
-
slider.classList.add('ready');
|
197 |
slider.style.animation = 'none';
|
198 |
slider.style.cursor = 'ew-resize';
|
199 |
slider.style.pointerEvents = 'auto';
|
|
|
12 |
justify-content: center;
|
13 |
align-items: center;
|
14 |
height: 100vh;
|
15 |
+
background-color: black;
|
16 |
}
|
17 |
|
18 |
.video-container {
|
|
|
33 |
|
34 |
.second-video {
|
35 |
clip-path: inset(0 50% 0 0);
|
|
|
36 |
}
|
37 |
|
38 |
.slider {
|
|
|
83 |
}
|
84 |
|
85 |
.slider.ready:hover::before,
|
86 |
+
.slider.ready:hover::after {
|
87 |
opacity: 1;
|
88 |
}
|
89 |
|
|
|
91 |
0% {
|
92 |
left: 100%;
|
93 |
}
|
|
|
94 |
10% {
|
95 |
left: 80%;
|
96 |
}
|
|
|
97 |
20% {
|
98 |
left: 85%;
|
99 |
}
|
|
|
100 |
50% {
|
101 |
left: 20%;
|
102 |
}
|
|
|
103 |
70% {
|
104 |
left: 60%;
|
105 |
}
|
|
|
106 |
100% {
|
107 |
left: 30%;
|
108 |
}
|
|
|
123 |
const video2 = document.getElementById('video2');
|
124 |
|
125 |
let isDragging = false;
|
126 |
+
const syncTolerance = 0.1; // Tolerance in seconds for syncing
|
127 |
|
128 |
+
// Function to sync the second video to the first video
|
129 |
+
function syncVideos(mainVideo, secondaryVideo) {
|
130 |
+
if (Math.abs(mainVideo.currentTime - secondaryVideo.currentTime) > syncTolerance) {
|
131 |
+
secondaryVideo.currentTime = mainVideo.currentTime;
|
132 |
+
}
|
133 |
+
if (mainVideo.paused && !secondaryVideo.paused) {
|
134 |
+
secondaryVideo.pause();
|
135 |
+
} else if (!mainVideo.paused && secondaryVideo.paused) {
|
136 |
+
secondaryVideo.play();
|
|
|
|
|
137 |
}
|
138 |
}
|
139 |
|
140 |
+
// Set up timeupdate event listeners for smoother sync
|
141 |
+
video1.addEventListener('timeupdate', () => syncVideos(video1, video2));
|
142 |
+
video2.addEventListener('timeupdate', () => syncVideos(video2, video1));
|
|
|
|
|
|
|
|
|
|
|
143 |
|
144 |
// Mouse events for slider
|
145 |
slider.addEventListener('mousedown', () => isDragging = true);
|
|
|
156 |
|
157 |
window.addEventListener('touchmove', (event) => {
|
158 |
if (!isDragging) return;
|
159 |
+
handleSlide(event.touches[0].clientX);
|
160 |
});
|
161 |
|
162 |
function handleSlide(positionX) {
|
|
|
168 |
slider.style.left = `${sliderPosition}px`;
|
169 |
|
170 |
// Adjust second video visibility using clip-path
|
171 |
+
video2.style.clipPath = `inset(0 ${rect.width - sliderPosition}px 0 0)`;
|
172 |
}
|
173 |
|
174 |
// Function to update clip-path in real-time
|
175 |
function updateClipPath() {
|
176 |
const rect = container.getBoundingClientRect();
|
177 |
+
const sliderPosition = parseFloat(window.getComputedStyle(slider).left);
|
178 |
video2.style.clipPath = `inset(0 ${rect.width - sliderPosition}px 0 0)`;
|
179 |
+
requestAnimationFrame(updateClipPath);
|
180 |
}
|
181 |
|
182 |
// Enable user control after the animation ends
|
183 |
slider.addEventListener('animationend', () => {
|
184 |
+
slider.classList.add('ready');
|
185 |
slider.style.animation = 'none';
|
186 |
slider.style.cursor = 'ew-resize';
|
187 |
slider.style.pointerEvents = 'auto';
|