Anne-Charlotte commited on
Commit
eba3bab
·
verified ·
1 Parent(s): d10fa74

Update script.js

Browse files
Files changed (1) hide show
  1. script.js +339 -87
script.js CHANGED
@@ -1,8 +1,76 @@
1
- // Assembly Guide JavaScript
2
- let currentStep = 1;
3
- const totalSteps = 51;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
- // Map of available images (only step1 and step2 exist, rest are placeholders)
 
 
6
  const availableImages = {
7
  1: 'assets/step1.jpg',
8
  2: 'assets/step2.jpg',
@@ -55,126 +123,310 @@ const availableImages = {
55
  49: 'assets/step49.jpg',
56
  50: 'assets/step50.jpg',
57
  51: 'assets/step51.jpg',
58
-
59
  };
60
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  // DOM Elements
62
- const stepDisplay = document.getElementById('stepDisplay');
63
- const stepImage = document.getElementById('stepImage');
64
- const placeholderText = document.getElementById('placeholderText');
65
- const placeholderNumber = document.getElementById('placeholderNumber');
66
- const placeholderStep = document.getElementById('placeholderStep');
67
- const prevBtn = document.getElementById('prevBtn');
68
- const nextBtn = document.getElementById('nextBtn');
69
- const progressFill = document.getElementById('progressFill');
70
- const indicatorsContainer = document.getElementById('indicators');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
 
72
- // Initialize
73
- function init() {
74
- createIndicators();
75
- updateDisplay();
 
 
 
76
  }
77
 
78
- // Create step indicators
79
- function createIndicators() {
80
- const indicatorsToShow = Math.min(totalSteps, 10);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
- for (let i = 0; i < indicatorsToShow; i++) {
 
 
 
 
 
83
  const button = document.createElement('button');
84
- button.className = 'indicator';
85
- button.setAttribute('aria-label', `Go to step ${i + 1}`);
86
- button.addEventListener('click', () => {
87
- const targetStep = Math.floor((currentStep - 1) / 10) * 10 + i + 1;
88
- if (targetStep <= totalSteps) {
89
- goToStep(targetStep);
90
- }
91
- });
92
- indicatorsContainer.appendChild(button);
93
  }
94
- }
95
-
96
- // Update indicators
97
- function updateIndicators() {
98
- const indicators = indicatorsContainer.children;
99
- const startStep = Math.floor((currentStep - 1) / 10) * 10 + 1;
100
 
101
- Array.from(indicators).forEach((indicator, i) => {
102
- const step = startStep + i;
103
- if (step > totalSteps) {
104
- indicator.style.display = 'none';
105
- } else {
106
- indicator.style.display = 'block';
107
- indicator.classList.toggle('active', step === currentStep);
108
- }
109
- });
110
  }
111
 
112
- // Update display
113
- function updateDisplay() {
 
 
 
114
  // Update step counter
115
- stepDisplay.textContent = `Step ${currentStep}/${totalSteps}`;
116
-
117
- // Update image or placeholder
118
- if (availableImages[currentStep]) {
119
- stepImage.src = availableImages[currentStep];
120
- stepImage.alt = `Assembly step ${currentStep}`;
121
- stepImage.style.display = 'block';
122
- placeholderText.style.display = 'none';
123
  } else {
124
- stepImage.style.display = 'none';
125
- placeholderText.style.display = 'block';
126
- placeholderNumber.textContent = currentStep;
127
- placeholderStep.textContent = currentStep;
128
  }
129
 
 
 
 
130
  // Update buttons
131
  prevBtn.disabled = currentStep === 1;
132
- nextBtn.disabled = currentStep === totalSteps;
 
 
 
133
 
134
  // Update progress bar
135
- const progress = (currentStep / totalSteps) * 100;
136
- progressFill.style.width = `${progress}%`;
137
 
138
- // Update indicators
139
- updateIndicators();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  }
141
 
142
- // Go to specific step
143
  function goToStep(step) {
144
- if (step >= 1 && step <= totalSteps) {
145
  currentStep = step;
146
- updateDisplay();
147
  }
148
  }
149
 
150
- // Next step
151
- function nextStep() {
152
- if (currentStep < totalSteps) {
153
- currentStep++;
154
- updateDisplay();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  }
156
  }
157
 
158
- // Previous step
159
- function prevStep() {
160
- if (currentStep > 1) {
161
- currentStep--;
162
- updateDisplay();
 
 
163
  }
164
  }
165
 
166
- // Event listeners
167
- nextBtn.addEventListener('click', nextStep);
168
- prevBtn.addEventListener('click', prevStep);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
 
170
  // Keyboard navigation
171
  document.addEventListener('keydown', (e) => {
172
- if (e.key === 'ArrowRight') {
173
- nextStep();
174
- } else if (e.key === 'ArrowLeft') {
175
- prevStep();
 
 
 
 
 
 
176
  }
177
  });
178
 
179
- // Initialize on load
180
- init();
 
1
+ // Assembly Steps Data
2
+ const YOUTUBE_VIDEO_ID = "WeKKdnuXca4";
3
+
4
+ const stepsData = [
5
+ { timestamp: "00:14", title: "Set all parts aside" },
6
+ { timestamp: "00:45", title: "Stick Foot Pads" },
7
+ { timestamp: "01:30", title: "Position the protective sleeve on the USB cable" },
8
+ { timestamp: "02:51", title: "Fix the USB Extension Cable" },
9
+ { timestamp: "03:23", title: "Insert the Power Board" },
10
+ { timestamp: "03:39", title: "Fix the Power Board" },
11
+ { timestamp: "04:30", title: "Connect the Battery" },
12
+ { timestamp: "05:23", title: "Connect the cables to the Power Board" },
13
+ { timestamp: "06:27", title: "Position the Bottom Assembly" },
14
+ { timestamp: "07:34", title: "Fix the Foot Assembly to the Bottom Assembly" },
15
+ { timestamp: "08:31", title: "Connect the Foot Motor" },
16
+ { timestamp: "09:15", title: "Screw the link rods onto the motor arms" },
17
+ { timestamp: "12:57", title: "Connect Motor 1 to 2" },
18
+ { timestamp: "13:23", title: "Connect Motor 2 to 3" },
19
+ { timestamp: "13:45", title: "Connect Motor 4 to 5" },
20
+ { timestamp: "14:05", title: "Connect Motor 5 to 6" },
21
+ { timestamp: "14:31", title: "Insert all motors into the Bottom Assembly" },
22
+ { timestamp: "16:13", title: "Clip the motor cables into the Bottom Assembly" },
23
+ { timestamp: "18:56", title: "Position the Tricap" },
24
+ { timestamp: "19:37", title: "Route the cables" },
25
+ { timestamp: "20:23", title: "Connect Motor 3 to 4" },
26
+ { timestamp: "21:06", title: "Route the cables" },
27
+ { timestamp: "23:28", title: "Check rotation" },
28
+ { timestamp: "23:53", title: "Screw the Tricap" },
29
+ { timestamp: "25:44", title: "Screw the Bottom Head onto the link rods" },
30
+ { timestamp: "28:58", title: "Route the cables through the Bottom Head" },
31
+ { timestamp: "30:07", title: "Route the Wi-Fi Antenna and the fan cable through the Head PCB" },
32
+ { timestamp: "30:14", title: "Connect the flexible camera cable (step for reference only)" },
33
+ { timestamp: "30:47", title: "Route the cables through the Head PCB" },
34
+ { timestamp: "31:48", title: "Screw the Head PCB" },
35
+ { timestamp: "33:00", title: "Position the Top Shell" },
36
+ { timestamp: "34:00", title: "Screw the Top Shell" },
37
+ { timestamp: "35:32", title: "Place the lenses in the Glasses Holder" },
38
+ { timestamp: "35:43", title: "Insert the Fisheye Lenses into the caps" },
39
+ { timestamp: "36:07", title: "Snap the Fisheye Lenses" },
40
+ { timestamp: "36:52", title: "Screw the Glasses Assembly onto the Front Head Shell" },
41
+ { timestamp: "37:53", title: "Attach the cases to Antenna's motors" },
42
+ { timestamp: "38:24", title: "Fix Antenna's Assembly to Back Head Shell" },
43
+ { timestamp: "39:41", title: "Connect the Antenna's motors" },
44
+ { timestamp: "40:22", title: "Slide the Back Head Assembly onto the Reachy Mini body" },
45
+ { timestamp: "40:45", title: "Screw the Back Head" },
46
+ { timestamp: "41:45", title: "Fix the Cable Holder" },
47
+ { timestamp: "42:20", title: "Connect Speaker, fan and Motor Cables" },
48
+ { timestamp: "42:53", title: "Connect Power and USB Extension Cables" },
49
+ { timestamp: "43:28", title: "Stick the Wi-Fi Antenna" },
50
+ { timestamp: "44:08", title: "Slide the Top Head Assembly onto the Back Head" },
51
+ { timestamp: "44:33", title: "Connect the Flexible Printed Cable to the Head PCB" },
52
+ { timestamp: "44:52", title: "Connect the Flexible Camera Cable on the Front Head" },
53
+ { timestamp: "45:16", title: "Fix the Front Head" },
54
+ { timestamp: "46:25", title: "Fix the Antennas" },
55
+ ];
56
+
57
+ // Parse timestamp to seconds (MM:SS format)
58
+ function parseTimestamp(ts) {
59
+ const parts = ts.split(':').map(Number);
60
+ return parts[0] * 60 + parts[1];
61
+ }
62
+
63
+ // Create assembly steps with parsed timestamps
64
+ const assemblySteps = stepsData.map((step, index) => ({
65
+ id: index + 1,
66
+ title: step.title,
67
+ timestamp: step.timestamp,
68
+ timestampSeconds: parseTimestamp(step.timestamp)
69
+ }));
70
 
71
+ const TOTAL_STEPS = assemblySteps.length;
72
+
73
+ // Available step images
74
  const availableImages = {
75
  1: 'assets/step1.jpg',
76
  2: 'assets/step2.jpg',
 
123
  49: 'assets/step49.jpg',
124
  50: 'assets/step50.jpg',
125
  51: 'assets/step51.jpg',
 
126
  };
127
 
128
+ function getStepImage(stepId) {
129
+ return availableImages[stepId] || null;
130
+ }
131
+
132
+ // App State
133
+ let currentStep = 1;
134
+ let isFullscreen = false;
135
+ let scale = 1;
136
+ let position = { x: 0, y: 0 };
137
+ let isDragging = false;
138
+ let dragStart = { x: 0, y: 0 };
139
+
140
  // DOM Elements
141
+ const stepCounterText = document.getElementById('step-counter-text');
142
+ const stepImage = document.getElementById('step-image');
143
+ const placeholder = document.getElementById('placeholder');
144
+ const placeholderNumber = document.getElementById('placeholder-number');
145
+ const imageWrapper = document.getElementById('image-wrapper');
146
+ const youtubeIframeDesktop = document.getElementById('youtube-iframe-desktop');
147
+ const youtubeIframeMobile = document.getElementById('youtube-iframe-mobile');
148
+ const prevBtn = document.getElementById('prev-btn');
149
+ const nextBtn = document.getElementById('next-btn');
150
+ const stepIndicators = document.getElementById('step-indicators');
151
+ const progressBar = document.getElementById('progress-bar');
152
+ const fullscreenBtn = document.getElementById('fullscreen-btn');
153
+ const fullscreenModal = document.getElementById('fullscreen-modal');
154
+ const closeFullscreenBtn = document.getElementById('close-fullscreen-btn');
155
+ const fullscreenStepTitle = document.getElementById('fullscreen-step-title');
156
+ const fullscreenImage = document.getElementById('fullscreen-image');
157
+ const fullscreenPlaceholder = document.getElementById('fullscreen-placeholder');
158
+ const fullscreenPlaceholderNumber = document.getElementById('fullscreen-placeholder-number');
159
+ const fullscreenImageContainer = document.getElementById('fullscreen-image-container');
160
+ const fullscreenYoutubeIframeDesktop = document.getElementById('fullscreen-youtube-iframe-desktop');
161
+ const fullscreenYoutubeIframeMobile = document.getElementById('fullscreen-youtube-iframe-mobile');
162
+ const fullscreenPrevBtn = document.getElementById('fullscreen-prev-btn');
163
+ const fullscreenNextBtn = document.getElementById('fullscreen-next-btn');
164
+ const fullscreenStepIndicators = document.getElementById('fullscreen-step-indicators');
165
+ const fullscreenProgressBar = document.getElementById('fullscreen-progress-bar');
166
+ const zoomInBtn = document.getElementById('zoom-in-btn');
167
+ const zoomOutBtn = document.getElementById('zoom-out-btn');
168
+ const zoomLevel = document.getElementById('zoom-level');
169
 
170
+ // Update YouTube embed
171
+ function updateYouTubeEmbed(timestampSeconds) {
172
+ const embedUrl = `https://www.youtube.com/embed/${YOUTUBE_VIDEO_ID}?start=${timestampSeconds}&rel=0&autoplay=1&mute=1`;
173
+ youtubeIframeDesktop.src = embedUrl;
174
+ youtubeIframeMobile.src = embedUrl;
175
+ fullscreenYoutubeIframeDesktop.src = embedUrl;
176
+ fullscreenYoutubeIframeMobile.src = embedUrl;
177
  }
178
 
179
+ // Render step indicators with pagination
180
+ function renderStepIndicators(containerId, currentStep, onClick) {
181
+ const container = document.getElementById(containerId);
182
+ container.innerHTML = '';
183
+
184
+ const groupStart = Math.floor((currentStep - 1) / 10) * 10 + 1;
185
+ const groupEnd = Math.min(groupStart + 9, TOTAL_STEPS);
186
+ const canGoPrevGroup = groupStart > 1;
187
+ const canGoNextGroup = groupEnd < TOTAL_STEPS;
188
+
189
+ // Previous group button
190
+ if (canGoPrevGroup) {
191
+ const prevGroupBtn = document.createElement('button');
192
+ prevGroupBtn.className = 'step-indicator-nav';
193
+ prevGroupBtn.innerHTML = '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M15 18l-6-6 6-6"/></svg>';
194
+ prevGroupBtn.setAttribute('aria-label', 'Previous group');
195
+ prevGroupBtn.addEventListener('click', () => onClick(groupStart - 1));
196
+ container.appendChild(prevGroupBtn);
197
+ }
198
 
199
+ // Step number buttons
200
+ for (let i = 0; i < 10; i++) {
201
+ const stepNum = groupStart + i;
202
+ if (stepNum > TOTAL_STEPS) break;
203
+
204
+ const isActive = stepNum === currentStep;
205
  const button = document.createElement('button');
206
+ button.className = `step-indicator-num ${isActive ? 'step-indicator-num-active' : ''}`;
207
+ button.textContent = stepNum;
208
+ button.setAttribute('aria-label', `Go to step ${stepNum}`);
209
+ button.addEventListener('click', () => onClick(stepNum));
210
+ container.appendChild(button);
 
 
 
 
211
  }
 
 
 
 
 
 
212
 
213
+ // Next group button
214
+ if (canGoNextGroup) {
215
+ const nextGroupBtn = document.createElement('button');
216
+ nextGroupBtn.className = 'step-indicator-nav';
217
+ nextGroupBtn.innerHTML = '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg>';
218
+ nextGroupBtn.setAttribute('aria-label', 'Next group');
219
+ nextGroupBtn.addEventListener('click', () => onClick(groupEnd + 1));
220
+ container.appendChild(nextGroupBtn);
221
+ }
222
  }
223
 
224
+ // Update UI
225
+ function updateUI() {
226
+ const step = assemblySteps[currentStep - 1];
227
+ const imageSrc = getStepImage(step.id);
228
+
229
  // Update step counter
230
+ stepCounterText.textContent = `Step ${step.id}/${TOTAL_STEPS}`;
231
+
232
+ // Update image
233
+ if (imageSrc) {
234
+ stepImage.src = imageSrc;
235
+ stepImage.alt = `Assembly step ${step.id}`;
236
+ stepImage.classList.remove('hidden');
237
+ placeholder.classList.add('hidden');
238
  } else {
239
+ stepImage.classList.add('hidden');
240
+ placeholder.classList.remove('hidden');
241
+ placeholderNumber.textContent = step.id;
 
242
  }
243
 
244
+ // Update YouTube embed
245
+ updateYouTubeEmbed(step.timestampSeconds);
246
+
247
  // Update buttons
248
  prevBtn.disabled = currentStep === 1;
249
+ nextBtn.disabled = currentStep === TOTAL_STEPS;
250
+
251
+ // Update step indicators
252
+ renderStepIndicators('step-indicators', currentStep, goToStep);
253
 
254
  // Update progress bar
255
+ const progress = (currentStep / TOTAL_STEPS) * 100;
256
+ progressBar.style.width = `${progress}%`;
257
 
258
+ // Update fullscreen UI
259
+ updateFullscreenUI();
260
+ }
261
+
262
+ // Update fullscreen UI
263
+ function updateFullscreenUI() {
264
+ const step = assemblySteps[currentStep - 1];
265
+ const imageSrc = getStepImage(step.id);
266
+
267
+ fullscreenStepTitle.textContent = `Step ${step.id}/${TOTAL_STEPS} - ${step.title}`;
268
+
269
+ if (imageSrc) {
270
+ fullscreenImage.src = imageSrc;
271
+ fullscreenImage.alt = `Step ${step.id}`;
272
+ fullscreenImage.classList.remove('hidden');
273
+ fullscreenPlaceholder.classList.add('hidden');
274
+ } else {
275
+ fullscreenImage.classList.add('hidden');
276
+ fullscreenPlaceholder.classList.remove('hidden');
277
+ fullscreenPlaceholderNumber.textContent = step.id;
278
+ }
279
+
280
+ fullscreenPrevBtn.disabled = currentStep === 1;
281
+ fullscreenNextBtn.disabled = currentStep === TOTAL_STEPS;
282
+
283
+ renderStepIndicators('fullscreen-step-indicators', currentStep, goToStepFullscreen);
284
+
285
+ const progress = (currentStep / TOTAL_STEPS) * 100;
286
+ fullscreenProgressBar.style.width = `${progress}%`;
287
+
288
+ updateZoomDisplay();
289
+ }
290
+
291
+ // Navigation functions
292
+ function goToPrevious() {
293
+ if (currentStep > 1) {
294
+ currentStep--;
295
+ updateUI();
296
+ }
297
+ }
298
+
299
+ function goToNext() {
300
+ if (currentStep < TOTAL_STEPS) {
301
+ currentStep++;
302
+ updateUI();
303
+ }
304
  }
305
 
 
306
  function goToStep(step) {
307
+ if (step >= 1 && step <= TOTAL_STEPS) {
308
  currentStep = step;
309
+ updateUI();
310
  }
311
  }
312
 
313
+ function goToStepFullscreen(step) {
314
+ resetZoom();
315
+ goToStep(step);
316
+ }
317
+
318
+ function goToPreviousFullscreen() {
319
+ resetZoom();
320
+ goToPrevious();
321
+ }
322
+
323
+ function goToNextFullscreen() {
324
+ resetZoom();
325
+ goToNext();
326
+ }
327
+
328
+ // Fullscreen functions
329
+ function openFullscreen() {
330
+ isFullscreen = true;
331
+ fullscreenModal.classList.remove('hidden');
332
+ document.body.style.overflow = 'hidden';
333
+ updateFullscreenUI();
334
+ }
335
+
336
+ function closeFullscreen() {
337
+ isFullscreen = false;
338
+ fullscreenModal.classList.add('hidden');
339
+ document.body.style.overflow = '';
340
+ resetZoom();
341
+ }
342
+
343
+ // Zoom functions
344
+ function zoomIn() {
345
+ scale = Math.min(scale + 0.5, 4);
346
+ updateZoomDisplay();
347
+ }
348
+
349
+ function zoomOut() {
350
+ scale = Math.max(scale - 0.5, 0.5);
351
+ updateZoomDisplay();
352
+ }
353
+
354
+ function resetZoom() {
355
+ scale = 1;
356
+ position = { x: 0, y: 0 };
357
+ updateZoomDisplay();
358
+ }
359
+
360
+ function updateZoomDisplay() {
361
+ zoomLevel.textContent = `${Math.round(scale * 100)}%`;
362
+ fullscreenImage.style.transform = `translate(${position.x}px, ${position.y}px) scale(${scale})`;
363
+ }
364
+
365
+ // Drag functions for fullscreen image
366
+ function handleMouseDown(e) {
367
+ if (scale > 1) {
368
+ isDragging = true;
369
+ dragStart = {
370
+ x: e.clientX - position.x,
371
+ y: e.clientY - position.y
372
+ };
373
+ fullscreenImageContainer.style.cursor = 'grabbing';
374
  }
375
  }
376
 
377
+ function handleMouseMove(e) {
378
+ if (isDragging && scale > 1) {
379
+ position = {
380
+ x: e.clientX - dragStart.x,
381
+ y: e.clientY - dragStart.y
382
+ };
383
+ updateZoomDisplay();
384
  }
385
  }
386
 
387
+ function handleMouseUp() {
388
+ isDragging = false;
389
+ fullscreenImageContainer.style.cursor = 'grab';
390
+ }
391
+
392
+ function handleWheel(e) {
393
+ e.preventDefault();
394
+ const delta = e.deltaY > 0 ? -0.2 : 0.2;
395
+ scale = Math.max(0.5, Math.min(4, scale + delta));
396
+ updateZoomDisplay();
397
+ }
398
+
399
+ // Event Listeners
400
+ prevBtn.addEventListener('click', goToPrevious);
401
+ nextBtn.addEventListener('click', goToNext);
402
+ fullscreenBtn.addEventListener('click', openFullscreen);
403
+ stepImage.addEventListener('click', openFullscreen);
404
+ closeFullscreenBtn.addEventListener('click', closeFullscreen);
405
+ fullscreenPrevBtn.addEventListener('click', goToPreviousFullscreen);
406
+ fullscreenNextBtn.addEventListener('click', goToNextFullscreen);
407
+ zoomInBtn.addEventListener('click', zoomIn);
408
+ zoomOutBtn.addEventListener('click', zoomOut);
409
+
410
+ fullscreenImageContainer.addEventListener('mousedown', handleMouseDown);
411
+ fullscreenImageContainer.addEventListener('mousemove', handleMouseMove);
412
+ fullscreenImageContainer.addEventListener('mouseup', handleMouseUp);
413
+ fullscreenImageContainer.addEventListener('mouseleave', handleMouseUp);
414
+ fullscreenImageContainer.addEventListener('wheel', handleWheel, { passive: false });
415
 
416
  // Keyboard navigation
417
  document.addEventListener('keydown', (e) => {
418
+ if (isFullscreen) {
419
+ if (e.key === 'Escape') closeFullscreen();
420
+ if (e.key === '+' || e.key === '=') zoomIn();
421
+ if (e.key === '-') zoomOut();
422
+ if (e.key === '0') resetZoom();
423
+ if (e.key === 'ArrowLeft' && currentStep > 1) goToPreviousFullscreen();
424
+ if (e.key === 'ArrowRight' && currentStep < TOTAL_STEPS) goToNextFullscreen();
425
+ } else {
426
+ if (e.key === 'ArrowRight') goToNext();
427
+ if (e.key === 'ArrowLeft') goToPrevious();
428
  }
429
  });
430
 
431
+ // Initialize
432
+ updateUI();