Anne-Charlotte commited on
Commit
d78a473
·
verified ·
1 Parent(s): 0cb0251

Create script.js

Browse files
Files changed (1) hide show
  1. script.js +359 -0
script.js ADDED
@@ -0,0 +1,359 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Assembly Steps Data
2
+ const YOUTUBE_VIDEO_ID = "_r0cHySFbeY";
3
+
4
+ const stepsData = [
5
+ { timestamp: "00:00:00", title: "Apply the foot pads." },
6
+ { timestamp: "00:01:14", title: "Install the USB extension cable." },
7
+ { timestamp: "00:02:55", title: "Mount the body PCB." },
8
+ { timestamp: "00:04:30", title: "Connect the cables to the body PCB." },
9
+ { timestamp: "00:05:05", title: "Insert the ball bearing." },
10
+ { timestamp: "00:05:44", title: "Fit the body down assembly to the foot assembly." },
11
+ { timestamp: "00:06:14", title: "Mount the base foot motor to the body turning unit." },
12
+ { timestamp: "00:07:14", title: "Position the body turning assembly on the body down assembly." },
13
+ { timestamp: "00:08:25", title: "Secure the body turning assembly to the body down assembly." },
14
+ { timestamp: "00:10:15", title: "Screw the Stewart main plate in place." },
15
+ { timestamp: "00:13:10", title: "Connect the base foot motor." },
16
+ { timestamp: "00:14:13", title: "Screw the link rods onto the motor arms." },
17
+ { timestamp: "00:18:05", title: "Connect Motors 1 and 2." },
18
+ { timestamp: "00:18:44", title: "Connect Motors 2 and 3." },
19
+ { timestamp: "00:19:31", title: "Connect Motors 4 and 5." },
20
+ { timestamp: "00:20:19", title: "Connect Motors 5 and 6." },
21
+ { timestamp: "00:20:53", title: "Insert all motors into the Stewart main plate." },
22
+ { timestamp: "00:22:55", title: "Clip the motor cables into the body down assembly." },
23
+ { timestamp: "00:24:46", title: "Screw the speaker into the tricap." },
24
+ { timestamp: "00:25:39", title: "Position the tricap." },
25
+ { timestamp: "00:27:01", title: "Connect Motors 3 and 4." },
26
+ { timestamp: "00:27:44", title: "Route the cables." },
27
+ { timestamp: "00:28:04", title: "Secure the tricap with screws." },
28
+ { timestamp: "00:30:47", title: "Screw the bottom head onto the link rods." },
29
+ { timestamp: "00:35:17", title: "Route the cables through the bottom head." },
30
+ { timestamp: "00:35:49", title: "Route the cables through the head PCB." },
31
+ { timestamp: "00:36:10", title: "Screw the head PCB in place." },
32
+ { timestamp: "00:37:38", title: "Position the top shell." },
33
+ { timestamp: "00:38:42", title: "Screw the top shell in place." },
34
+ { timestamp: "00:41:08", title: "Place the lenses in the glasses holder." },
35
+ { timestamp: "00:41:38", title: "Insert the fisheye lenses into the caps." },
36
+ { timestamp: "00:42:14", title: "Snap the fisheye lenses into the glasses holder." },
37
+ { timestamp: "00:43:07", title: "Position the Arducam camera." },
38
+ { timestamp: "00:43:35", title: "Screw the Arducam camera in place." },
39
+ { timestamp: "00:44:08", title: "Screw the glasses assembly onto the front head shell." },
40
+ { timestamp: "00:45:51", title: "Plug in USB-C." },
41
+ { timestamp: "00:46:06", title: "Attach the cases to the antenna motors." },
42
+ { timestamp: "00:46:46", title: "Mount the motor assembly to the back head shell." },
43
+ { timestamp: "00:50:11", title: "Connect the antenna motors." },
44
+ { timestamp: "00:51:13", title: "Slide the back-head assembly onto the Reachy Mini body." },
45
+ { timestamp: "00:51:45", title: "Screw the back head in place." },
46
+ { timestamp: "00:53:35", title: "Attach the cable holder." },
47
+ { timestamp: "00:54:29", title: "Connect the speaker and motor cables." },
48
+ { timestamp: "00:55:22", title: "Connect the power and USB extension cables." },
49
+ { timestamp: "00:55:48", title: "Connect the flexible printed cable to the top head PCB." },
50
+ { timestamp: "00:56:23", title: "Slide the top-head assembly onto the back head." },
51
+ { timestamp: "00:56:31", title: "Connect the flexible printed cable to the head PCB." },
52
+ { timestamp: "00:57:18", title: "Plug the USB-C cable into the head PCB." },
53
+ { timestamp: "00:58:09", title: "Attach the front head." },
54
+ { timestamp: "00:59:20", title: "Assemble the antennas." },
55
+ { timestamp: "01:00:00", title: "Attach the antennas to the head." }
56
+ ];
57
+
58
+ // Parse timestamp to seconds
59
+ function parseTimestamp(ts) {
60
+ const parts = ts.split(':').map(Number);
61
+ return parts[0] * 3600 + parts[1] * 60 + parts[2];
62
+ }
63
+
64
+ // Create assembly steps with parsed timestamps
65
+ const assemblySteps = stepsData.map((step, index) => ({
66
+ id: index + 1,
67
+ title: step.title,
68
+ timestamp: step.timestamp,
69
+ timestampSeconds: parseTimestamp(step.timestamp)
70
+ }));
71
+
72
+ const TOTAL_STEPS = assemblySteps.length;
73
+
74
+ // Available step images
75
+ const availableImages = {
76
+ 1: "assets/step1.jpg",
77
+ 2: "assets/step2.jpg"
78
+ };
79
+
80
+ function getStepImage(stepId) {
81
+ return availableImages[stepId] || null;
82
+ }
83
+
84
+ // App State
85
+ let currentStep = 1;
86
+ let isFullscreen = false;
87
+ let scale = 1;
88
+ let position = { x: 0, y: 0 };
89
+ let isDragging = false;
90
+ let dragStart = { x: 0, y: 0 };
91
+
92
+ // DOM Elements
93
+ const stepCounterText = document.getElementById('step-counter-text');
94
+ const stepImage = document.getElementById('step-image');
95
+ const placeholder = document.getElementById('placeholder');
96
+ const placeholderNumber = document.getElementById('placeholder-number');
97
+ const imageWrapper = document.getElementById('image-wrapper');
98
+ const youtubeIframeDesktop = document.getElementById('youtube-iframe-desktop');
99
+ const youtubeIframeMobile = document.getElementById('youtube-iframe-mobile');
100
+ const prevBtn = document.getElementById('prev-btn');
101
+ const nextBtn = document.getElementById('next-btn');
102
+ const stepIndicators = document.getElementById('step-indicators');
103
+ const progressBar = document.getElementById('progress-bar');
104
+ const fullscreenBtn = document.getElementById('fullscreen-btn');
105
+ const fullscreenModal = document.getElementById('fullscreen-modal');
106
+ const closeFullscreenBtn = document.getElementById('close-fullscreen-btn');
107
+ const fullscreenStepTitle = document.getElementById('fullscreen-step-title');
108
+ const fullscreenImage = document.getElementById('fullscreen-image');
109
+ const fullscreenPlaceholder = document.getElementById('fullscreen-placeholder');
110
+ const fullscreenPlaceholderNumber = document.getElementById('fullscreen-placeholder-number');
111
+ const fullscreenImageContainer = document.getElementById('fullscreen-image-container');
112
+ const fullscreenYoutubeIframeDesktop = document.getElementById('fullscreen-youtube-iframe-desktop');
113
+ const fullscreenYoutubeIframeMobile = document.getElementById('fullscreen-youtube-iframe-mobile');
114
+ const fullscreenPrevBtn = document.getElementById('fullscreen-prev-btn');
115
+ const fullscreenNextBtn = document.getElementById('fullscreen-next-btn');
116
+ const fullscreenStepIndicators = document.getElementById('fullscreen-step-indicators');
117
+ const fullscreenProgressBar = document.getElementById('fullscreen-progress-bar');
118
+ const zoomInBtn = document.getElementById('zoom-in-btn');
119
+ const zoomOutBtn = document.getElementById('zoom-out-btn');
120
+ const zoomLevel = document.getElementById('zoom-level');
121
+
122
+ // Update YouTube embed
123
+ function updateYouTubeEmbed(timestampSeconds) {
124
+ const embedUrl = `https://www.youtube.com/embed/${YOUTUBE_VIDEO_ID}?start=${timestampSeconds}&rel=0&autoplay=1&mute=1`;
125
+ youtubeIframeDesktop.src = embedUrl;
126
+ youtubeIframeMobile.src = embedUrl;
127
+ fullscreenYoutubeIframeDesktop.src = embedUrl;
128
+ fullscreenYoutubeIframeMobile.src = embedUrl;
129
+ }
130
+
131
+ // Render step indicators
132
+ function renderStepIndicators(containerId, currentStep, onClick) {
133
+ const container = document.getElementById(containerId);
134
+ container.innerHTML = '';
135
+
136
+ const groupStart = Math.floor((currentStep - 1) / 10) * 10 + 1;
137
+
138
+ for (let i = 0; i < 10; i++) {
139
+ const stepNum = groupStart + i;
140
+ if (stepNum > TOTAL_STEPS) break;
141
+
142
+ const isActive = stepNum === currentStep;
143
+ const button = document.createElement('button');
144
+ button.className = `step-indicator ${isActive ? 'step-indicator-active' : 'step-indicator-inactive'}`;
145
+ button.setAttribute('aria-label', `Go to step ${stepNum}`);
146
+ button.addEventListener('click', () => onClick(stepNum));
147
+ container.appendChild(button);
148
+ }
149
+ }
150
+
151
+ // Update UI
152
+ function updateUI() {
153
+ const step = assemblySteps[currentStep - 1];
154
+ const imageSrc = getStepImage(step.id);
155
+
156
+ // Update step counter
157
+ stepCounterText.textContent = `Step ${step.id}/${TOTAL_STEPS}`;
158
+
159
+ // Update image
160
+ if (imageSrc) {
161
+ stepImage.src = imageSrc;
162
+ stepImage.alt = `Assembly step ${step.id}`;
163
+ stepImage.classList.remove('hidden');
164
+ placeholder.classList.add('hidden');
165
+ } else {
166
+ stepImage.classList.add('hidden');
167
+ placeholder.classList.remove('hidden');
168
+ placeholderNumber.textContent = step.id;
169
+ }
170
+
171
+ // Update YouTube embed
172
+ updateYouTubeEmbed(step.timestampSeconds);
173
+
174
+ // Update buttons
175
+ prevBtn.disabled = currentStep === 1;
176
+ nextBtn.disabled = currentStep === TOTAL_STEPS;
177
+
178
+ // Update step indicators
179
+ renderStepIndicators('step-indicators', currentStep, goToStep);
180
+
181
+ // Update progress bar
182
+ const progress = (currentStep / TOTAL_STEPS) * 100;
183
+ progressBar.style.width = `${progress}%`;
184
+
185
+ // Update fullscreen UI
186
+ updateFullscreenUI();
187
+ }
188
+
189
+ // Update fullscreen UI
190
+ function updateFullscreenUI() {
191
+ const step = assemblySteps[currentStep - 1];
192
+ const imageSrc = getStepImage(step.id);
193
+
194
+ fullscreenStepTitle.textContent = `Step ${step.id}/${TOTAL_STEPS} - ${step.title}`;
195
+
196
+ if (imageSrc) {
197
+ fullscreenImage.src = imageSrc;
198
+ fullscreenImage.alt = `Step ${step.id}`;
199
+ fullscreenImage.classList.remove('hidden');
200
+ fullscreenPlaceholder.classList.add('hidden');
201
+ } else {
202
+ fullscreenImage.classList.add('hidden');
203
+ fullscreenPlaceholder.classList.remove('hidden');
204
+ fullscreenPlaceholderNumber.textContent = step.id;
205
+ }
206
+
207
+ fullscreenPrevBtn.disabled = currentStep === 1;
208
+ fullscreenNextBtn.disabled = currentStep === TOTAL_STEPS;
209
+
210
+ renderStepIndicators('fullscreen-step-indicators', currentStep, goToStepFullscreen);
211
+
212
+ const progress = (currentStep / TOTAL_STEPS) * 100;
213
+ fullscreenProgressBar.style.width = `${progress}%`;
214
+
215
+ updateZoomDisplay();
216
+ }
217
+
218
+ // Navigation functions
219
+ function goToPrevious() {
220
+ if (currentStep > 1) {
221
+ currentStep--;
222
+ updateUI();
223
+ }
224
+ }
225
+
226
+ function goToNext() {
227
+ if (currentStep < TOTAL_STEPS) {
228
+ currentStep++;
229
+ updateUI();
230
+ }
231
+ }
232
+
233
+ function goToStep(step) {
234
+ if (step >= 1 && step <= TOTAL_STEPS) {
235
+ currentStep = step;
236
+ updateUI();
237
+ }
238
+ }
239
+
240
+ function goToStepFullscreen(step) {
241
+ resetZoom();
242
+ goToStep(step);
243
+ }
244
+
245
+ function goToPreviousFullscreen() {
246
+ resetZoom();
247
+ goToPrevious();
248
+ }
249
+
250
+ function goToNextFullscreen() {
251
+ resetZoom();
252
+ goToNext();
253
+ }
254
+
255
+ // Fullscreen functions
256
+ function openFullscreen() {
257
+ isFullscreen = true;
258
+ fullscreenModal.classList.remove('hidden');
259
+ document.body.style.overflow = 'hidden';
260
+ updateFullscreenUI();
261
+ }
262
+
263
+ function closeFullscreen() {
264
+ isFullscreen = false;
265
+ fullscreenModal.classList.add('hidden');
266
+ document.body.style.overflow = '';
267
+ resetZoom();
268
+ }
269
+
270
+ // Zoom functions
271
+ function zoomIn() {
272
+ scale = Math.min(scale + 0.5, 4);
273
+ updateZoomDisplay();
274
+ }
275
+
276
+ function zoomOut() {
277
+ scale = Math.max(scale - 0.5, 0.5);
278
+ updateZoomDisplay();
279
+ }
280
+
281
+ function resetZoom() {
282
+ scale = 1;
283
+ position = { x: 0, y: 0 };
284
+ updateZoomDisplay();
285
+ }
286
+
287
+ function updateZoomDisplay() {
288
+ zoomLevel.textContent = `${Math.round(scale * 100)}%`;
289
+ fullscreenImage.style.transform = `translate(${position.x}px, ${position.y}px) scale(${scale})`;
290
+ }
291
+
292
+ // Drag functions for fullscreen image
293
+ function handleMouseDown(e) {
294
+ if (scale > 1) {
295
+ isDragging = true;
296
+ dragStart = {
297
+ x: e.clientX - position.x,
298
+ y: e.clientY - position.y
299
+ };
300
+ fullscreenImageContainer.style.cursor = 'grabbing';
301
+ }
302
+ }
303
+
304
+ function handleMouseMove(e) {
305
+ if (isDragging && scale > 1) {
306
+ position = {
307
+ x: e.clientX - dragStart.x,
308
+ y: e.clientY - dragStart.y
309
+ };
310
+ updateZoomDisplay();
311
+ }
312
+ }
313
+
314
+ function handleMouseUp() {
315
+ isDragging = false;
316
+ fullscreenImageContainer.style.cursor = 'grab';
317
+ }
318
+
319
+ function handleWheel(e) {
320
+ e.preventDefault();
321
+ const delta = e.deltaY > 0 ? -0.2 : 0.2;
322
+ scale = Math.max(0.5, Math.min(4, scale + delta));
323
+ updateZoomDisplay();
324
+ }
325
+
326
+ // Event Listeners
327
+ prevBtn.addEventListener('click', goToPrevious);
328
+ nextBtn.addEventListener('click', goToNext);
329
+ fullscreenBtn.addEventListener('click', openFullscreen);
330
+ stepImage.addEventListener('click', openFullscreen);
331
+ closeFullscreenBtn.addEventListener('click', closeFullscreen);
332
+ fullscreenPrevBtn.addEventListener('click', goToPreviousFullscreen);
333
+ fullscreenNextBtn.addEventListener('click', goToNextFullscreen);
334
+ zoomInBtn.addEventListener('click', zoomIn);
335
+ zoomOutBtn.addEventListener('click', zoomOut);
336
+
337
+ fullscreenImageContainer.addEventListener('mousedown', handleMouseDown);
338
+ fullscreenImageContainer.addEventListener('mousemove', handleMouseMove);
339
+ fullscreenImageContainer.addEventListener('mouseup', handleMouseUp);
340
+ fullscreenImageContainer.addEventListener('mouseleave', handleMouseUp);
341
+ fullscreenImageContainer.addEventListener('wheel', handleWheel, { passive: false });
342
+
343
+ // Keyboard navigation
344
+ document.addEventListener('keydown', (e) => {
345
+ if (isFullscreen) {
346
+ if (e.key === 'Escape') closeFullscreen();
347
+ if (e.key === '+' || e.key === '=') zoomIn();
348
+ if (e.key === '-') zoomOut();
349
+ if (e.key === '0') resetZoom();
350
+ if (e.key === 'ArrowLeft' && currentStep > 1) goToPreviousFullscreen();
351
+ if (e.key === 'ArrowRight' && currentStep < TOTAL_STEPS) goToNextFullscreen();
352
+ } else {
353
+ if (e.key === 'ArrowRight') goToNext();
354
+ if (e.key === 'ArrowLeft') goToPrevious();
355
+ }
356
+ });
357
+
358
+ // Initialize
359
+ updateUI();