Sa-m commited on
Commit
83e16ac
·
verified ·
1 Parent(s): 8624420

Update assets/js/script.js

Browse files
Files changed (1) hide show
  1. assets/js/script.js +148 -177
assets/js/script.js CHANGED
@@ -74,37 +74,37 @@ const emails = [
74
  },
75
  {
76
  id: 11,
77
- sender: "Travel Agency",
78
- subject: "Your Paris Hotel Confirmation",
79
- snippet: "Your reservation at the Eiffel Tower View Hotel is confirmed for September 10-15.",
80
  timestamp: "Aug 29"
81
  },
82
  {
83
  id: 12,
84
  sender: "University Alumni",
85
- subject: "Alumni Networking Event Next Week",
86
- snippet: "Join us for a special networking event with industry leaders. Register now to secure your spot.",
87
  timestamp: "Aug 28"
88
  },
89
  {
90
  id: 13,
91
- sender: "Gym Membership",
92
- subject: "Your Membership is Expiring Soon",
93
- snippet: "Your gym membership will expire in 5 days. Renew now to continue enjoying our facilities.",
94
  timestamp: "Aug 27"
95
  },
96
  {
97
  id: 14,
98
- sender: "Online Course",
99
- subject: "Your Course Certificate is Ready",
100
- snippet: "Congratulations! You've completed the Data Science Fundamentals course. Download your certificate now.",
101
  timestamp: "Aug 26"
102
  },
103
  {
104
  id: 15,
105
- sender: "Tech Conference",
106
- subject: "Your Conference Ticket is Confirmed",
107
- snippet: "Your ticket for the AI Summit is confirmed. Check your email for event details and schedule.",
108
  timestamp: "Aug 25"
109
  }
110
  ];
@@ -199,14 +199,10 @@ class UIManager {
199
  this.selectionHighlight = document.getElementById('selectionHighlight');
200
  this.handLandmarks = document.getElementById('handLandmarks');
201
  this.gesturePath = document.getElementById('gesturePath');
202
- this.scrollIndicator = document.getElementById('scrollIndicator');
203
 
204
  this.selectedEmail = null;
205
  this.emailElements = [];
206
- this.scrollOffset = 0;
207
- this.maxScroll = 0;
208
- this.scrollSpeed = 0;
209
- this.isScrolling = false;
210
 
211
  this.renderEmails();
212
  this.setupEventListeners();
@@ -214,8 +210,8 @@ class UIManager {
214
  // Create confirmation overlay
215
  this.createConfirmationOverlay();
216
 
217
- // Setup scroll indicator
218
- this.setupScrollIndicator();
219
  }
220
 
221
  createConfirmationOverlay() {
@@ -256,20 +252,6 @@ class UIManager {
256
  });
257
  }
258
 
259
- setupScrollIndicator() {
260
- this.scrollIndicator.style.display = 'none';
261
- }
262
-
263
- showScrollIndicator(direction) {
264
- this.scrollIndicator.style.display = 'block';
265
- this.scrollIndicator.className = `scroll-indicator ${direction}`;
266
-
267
- // Auto-hide after 500ms
268
- setTimeout(() => {
269
- this.scrollIndicator.style.display = 'none';
270
- }, 500);
271
- }
272
-
273
  showConfirmation(message, callback) {
274
  this.confirmationOverlay.querySelector('.confirmation-message').textContent = message;
275
  this.confirmationCallback = callback;
@@ -281,6 +263,23 @@ class UIManager {
281
  this.confirmationCallback = null;
282
  }
283
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
  renderEmails() {
285
  this.emailList.innerHTML = '';
286
  this.emailElements = [];
@@ -309,9 +308,6 @@ class UIManager {
309
 
310
  // Update email positions
311
  this.updateEmailPositions();
312
-
313
- // Calculate max scroll
314
- this.maxScroll = this.emailList.scrollHeight - this.emailList.clientHeight;
315
  }
316
 
317
  updateEmailPositions() {
@@ -355,7 +351,7 @@ class UIManager {
355
  showSelectionHighlight(rect) {
356
  this.selectionHighlight.style.display = 'block';
357
  this.selectionHighlight.style.left = `${rect.left}px`;
358
- this.selectionHighlight.style.top = `${rect.top}px - ${this.scrollOffset}px`;
359
  this.selectionHighlight.style.width = `${rect.width}px`;
360
  this.selectionHighlight.style.height = `${rect.height}px`;
361
 
@@ -409,15 +405,23 @@ class UIManager {
409
  this.showSelectionHighlight(element.rect);
410
  }
411
  }
412
-
413
- // Recalculate max scroll
414
- this.maxScroll = this.emailList.scrollHeight - this.emailList.clientHeight;
415
  });
416
 
417
- // Add scroll event listener
418
  this.emailList.addEventListener('scroll', () => {
419
- this.scrollOffset = this.emailList.scrollTop;
420
- this.updateEmailPositions();
 
 
 
 
 
 
 
 
 
 
 
421
  });
422
  }
423
 
@@ -462,38 +466,11 @@ class UIManager {
462
  }
463
  }
464
 
465
- // Scroll the email list
466
- scrollEmailList(direction, speed) {
467
- const scrollAmount = direction === 'up' ? -speed : speed;
468
- this.emailList.scrollTop += scrollAmount;
469
-
470
- // Update scroll offset
471
- this.scrollOffset = this.emailList.scrollTop;
472
-
473
- // Show scroll indicator
474
- this.showScrollIndicator(direction);
475
-
476
- // Update email positions
477
- this.updateEmailPositions();
478
- }
479
-
480
- // Calculate the position of the hand relative to the email list
481
- getRelativePosition(landmark, videoParams) {
482
- const emailListRect = this.emailList.getBoundingClientRect();
483
- const videoRect = document.getElementById('webcam').getBoundingClientRect();
484
-
485
- // Convert landmark coordinates to screen coordinates
486
- const screenX = landmark.x * videoRect.width;
487
- const screenY = landmark.y * videoRect.height;
488
-
489
- // Calculate relative position within email list
490
- const relativeX = screenX - emailListRect.left;
491
- const relativeY = screenY - emailListRect.top + this.scrollOffset;
492
-
493
- return {
494
- x: relativeX,
495
- y: relativeY
496
- };
497
  }
498
  }
499
 
@@ -507,7 +484,6 @@ class GestureDetector {
507
  this.selectedEmailId = null;
508
  this.gestureBuffer = [];
509
  this.circlePoints = [];
510
- this.scrollBuffer = [];
511
  this.circleThreshold = 12;
512
  this.swipeThreshold = 35;
513
  this.scrollThreshold = 20;
@@ -518,9 +494,8 @@ class GestureDetector {
518
 
519
  this.gestureStartPos = null;
520
  this.holdTimer = null;
521
- this.isPanning = false;
522
- this.lastScrollTime = 0;
523
- this.scrollSpeedFactor = 1.5;
524
 
525
  this.debugManager.updateStatus('Setting up MediaPipe...');
526
  this.setupMediaPipe();
@@ -611,7 +586,6 @@ class GestureDetector {
611
  this.uiManager.clearSelection();
612
  this.gestureBuffer = [];
613
  this.circlePoints = [];
614
- this.scrollBuffer = [];
615
  this.debugManager.updateGestureType('None');
616
  this.debugManager.updateBufferCount(0);
617
  this.debugManager.updateCircleCount(0);
@@ -621,52 +595,6 @@ class GestureDetector {
621
  }
622
  }
623
 
624
- calculateCircleMetrics() {
625
- if (this.circlePoints.length < 3) {
626
- return { center: { x: 0, y: 0 }, radius: 0, circularity: 0 };
627
- }
628
-
629
- // Find centroid
630
- let centerX = 0;
631
- let centerY = 0;
632
- for (const point of this.circlePoints) {
633
- centerX += point.x;
634
- centerY += point.y;
635
- }
636
- centerX /= this.circlePoints.length;
637
- centerY /= this.circlePoints.length;
638
-
639
- // Calculate radius and circularity
640
- let totalRadius = 0;
641
- let radiusVariance = 0;
642
- const radii = [];
643
-
644
- for (const point of this.circlePoints) {
645
- const dx = point.x - centerX;
646
- const dy = point.y - centerY;
647
- const radius = Math.sqrt(dx * dx + dy * dy);
648
- radii.push(radius);
649
- totalRadius += radius;
650
- }
651
-
652
- const avgRadius = totalRadius / this.circlePoints.length;
653
-
654
- // Calculate variance to determine circularity
655
- for (const radius of radii) {
656
- radiusVariance += Math.pow(radius - avgRadius, 2);
657
- }
658
- radiusVariance /= this.circlePoints.length;
659
-
660
- // Calculate circularity (1 = perfect circle, 0 = not circular)
661
- const circularity = radiusVariance < 0.0001 ? 1 : Math.max(0, 1 - radiusVariance / (avgRadius * avgRadius));
662
-
663
- return {
664
- center: { x: centerX, y: centerY },
665
- radius: avgRadius,
666
- circularity: circularity
667
- };
668
- }
669
-
670
  detectGesture(landmarks) {
671
  try {
672
  const indexTip = landmarks[8];
@@ -677,23 +605,18 @@ class GestureDetector {
677
  const screenX = indexTip.x * window.innerWidth;
678
  const screenY = indexTip.y * window.innerHeight;
679
 
680
- // Get video parameters for proper coordinate calculation
681
- const videoParams = this.getVideoParameters();
682
-
683
- // Convert to email list relative coordinates
684
- const relativePos = this.uiManager.getRelativePosition(indexTip, videoParams);
685
 
686
  // Pointing detection (index finger higher than middle)
687
  if (indexTip.y < middleTip.y && wrist.y > indexTip.y) {
688
- this.checkEmailSelection(relativePos.x, relativePos.y);
689
-
690
- // Check for scroll gestures
691
- this.checkScrollGesture(landmarks);
692
  } else {
693
  this.uiManager.clearSelection();
694
  this.gestureBuffer = [];
695
  this.circlePoints = [];
696
- this.scrollBuffer = [];
697
  this.debugManager.updateGestureType('None');
698
  this.debugManager.updateBufferCount(0);
699
  this.debugManager.updateCircleCount(0);
@@ -701,6 +624,7 @@ class GestureDetector {
701
 
702
  // Only process gestures if an email is selected
703
  if (this.selectedEmailId === null) {
 
704
  return;
705
  }
706
 
@@ -774,55 +698,102 @@ class GestureDetector {
774
  }
775
  }
776
 
777
- checkScrollGesture(landmarks) {
778
  const wrist = landmarks[0];
779
  const indexTip = landmarks[8];
780
- const middleTip = landmarks[12];
781
-
782
- // Only check for scrolling if index finger is lower than middle finger (scrolling gesture)
783
- if (indexTip.y > middleTip.y) {
784
- // Add to scroll buffer
785
- this.scrollBuffer.push({
786
- x: indexTip.x,
787
- y: indexTip.y,
788
- timestamp: Date.now()
789
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
790
 
791
- // Process scroll if we have enough points
792
- if (this.scrollBuffer.length > 3) {
793
- const recentPoints = this.scrollBuffer.slice(-3);
794
- const first = recentPoints[0];
795
- const last = recentPoints[recentPoints.length - 1];
796
- const dt = last.timestamp - first.timestamp;
 
 
 
797
 
798
- if (dt > 0) {
799
- // Calculate vertical movement
800
- const dy = (last.y - first.y) * window.innerHeight;
801
- const scrollSpeed = Math.abs(dy) / dt * this.scrollSpeedFactor;
802
-
803
- // Check if movement is significant
804
- if (Math.abs(dy) > this.scrollThreshold && scrollSpeed > 0.5) {
805
- const direction = dy > 0 ? 'down' : 'up';
806
- this.uiManager.scrollEmailList(direction, scrollSpeed * 50);
807
-
808
- // Clear buffer after processing
809
- this.scrollBuffer = [];
810
- this.debugManager.updateGestureType(`Scroll ${direction}`);
811
- }
812
- }
813
  }
814
  }
815
  }
816
 
817
- getVideoParameters() {
818
- const video = document.getElementById('webcam');
819
- const videoRect = video.getBoundingClientRect();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
820
 
821
  return {
822
- videoWidth: video.videoWidth,
823
- videoHeight: video.videoHeight,
824
- rect: videoRect,
825
- aspectRatio: video.videoWidth / video.videoHeight
826
  };
827
  }
828
 
 
74
  },
75
  {
76
  id: 11,
77
+ sender: "Tech News",
78
+ subject: "The Future of AI is Here",
79
+ snippet: "Discover how AI is transforming industries and what it means for your career.",
80
  timestamp: "Aug 29"
81
  },
82
  {
83
  id: 12,
84
  sender: "University Alumni",
85
+ subject: "Alumni Reunion This Weekend",
86
+ snippet: "Join us for our annual alumni reunion and reconnect with old friends.",
87
  timestamp: "Aug 28"
88
  },
89
  {
90
  id: 13,
91
+ sender: "Travel Agency",
92
+ subject: "Exclusive Deal: 50% Off Caribbean Cruise",
93
+ snippet: "Book now and enjoy a luxury cruise with significant savings.",
94
  timestamp: "Aug 27"
95
  },
96
  {
97
  id: 14,
98
+ sender: "Fitness Center",
99
+ subject: "New Workouts Available",
100
+ snippet: "Check out our new workout routines designed by top trainers.",
101
  timestamp: "Aug 26"
102
  },
103
  {
104
  id: 15,
105
+ sender: "Online Course",
106
+ subject: "Your Certificate of Completion",
107
+ snippet: "Congratulations! You've completed the course. Download your certificate now.",
108
  timestamp: "Aug 25"
109
  }
110
  ];
 
199
  this.selectionHighlight = document.getElementById('selectionHighlight');
200
  this.handLandmarks = document.getElementById('handLandmarks');
201
  this.gesturePath = document.getElementById('gesturePath');
202
+ this.emailListRect = null;
203
 
204
  this.selectedEmail = null;
205
  this.emailElements = [];
 
 
 
 
206
 
207
  this.renderEmails();
208
  this.setupEventListeners();
 
210
  // Create confirmation overlay
211
  this.createConfirmationOverlay();
212
 
213
+ // Create scroll indicator
214
+ this.createScrollIndicator();
215
  }
216
 
217
  createConfirmationOverlay() {
 
252
  });
253
  }
254
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
  showConfirmation(message, callback) {
256
  this.confirmationOverlay.querySelector('.confirmation-message').textContent = message;
257
  this.confirmationCallback = callback;
 
263
  this.confirmationCallback = null;
264
  }
265
 
266
+ createScrollIndicator() {
267
+ const indicator = document.createElement('div');
268
+ indicator.className = 'scroll-indicator';
269
+ indicator.innerHTML = '↑';
270
+
271
+ document.body.appendChild(indicator);
272
+ this.scrollIndicator = indicator;
273
+ }
274
+
275
+ showScrollIndicator() {
276
+ this.scrollIndicator.classList.add('show');
277
+ }
278
+
279
+ hideScrollIndicator() {
280
+ this.scrollIndicator.classList.remove('show');
281
+ }
282
+
283
  renderEmails() {
284
  this.emailList.innerHTML = '';
285
  this.emailElements = [];
 
308
 
309
  // Update email positions
310
  this.updateEmailPositions();
 
 
 
311
  }
312
 
313
  updateEmailPositions() {
 
351
  showSelectionHighlight(rect) {
352
  this.selectionHighlight.style.display = 'block';
353
  this.selectionHighlight.style.left = `${rect.left}px`;
354
+ this.selectionHighlight.style.top = `${rect.top}px`;
355
  this.selectionHighlight.style.width = `${rect.width}px`;
356
  this.selectionHighlight.style.height = `${rect.height}px`;
357
 
 
405
  this.showSelectionHighlight(element.rect);
406
  }
407
  }
 
 
 
408
  });
409
 
410
+ // Add scroll event for indicator
411
  this.emailList.addEventListener('scroll', () => {
412
+ if (this.emailList.scrollTop > 0) {
413
+ this.showScrollIndicator();
414
+ } else {
415
+ this.hideScrollIndicator();
416
+ }
417
+ });
418
+
419
+ // Click handler for scroll indicator
420
+ this.scrollIndicator?.addEventListener('click', () => {
421
+ this.emailList.scrollTo({
422
+ top: 0,
423
+ behavior: 'smooth'
424
+ });
425
  });
426
  }
427
 
 
466
  }
467
  }
468
 
469
+ // Audio feedback simulation (if needed)
470
+ provideAudioFeedback() {
471
+ // Could implement audio feedback here
472
+ // const sound = new Audio('click-sound.mp3');
473
+ // sound.play();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
474
  }
475
  }
476
 
 
484
  this.selectedEmailId = null;
485
  this.gestureBuffer = [];
486
  this.circlePoints = [];
 
487
  this.circleThreshold = 12;
488
  this.swipeThreshold = 35;
489
  this.scrollThreshold = 20;
 
494
 
495
  this.gestureStartPos = null;
496
  this.holdTimer = null;
497
+ this.scrollActive = false;
498
+ this.scrollDirection = null;
 
499
 
500
  this.debugManager.updateStatus('Setting up MediaPipe...');
501
  this.setupMediaPipe();
 
586
  this.uiManager.clearSelection();
587
  this.gestureBuffer = [];
588
  this.circlePoints = [];
 
589
  this.debugManager.updateGestureType('None');
590
  this.debugManager.updateBufferCount(0);
591
  this.debugManager.updateCircleCount(0);
 
595
  }
596
  }
597
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
598
  detectGesture(landmarks) {
599
  try {
600
  const indexTip = landmarks[8];
 
605
  const screenX = indexTip.x * window.innerWidth;
606
  const screenY = indexTip.y * window.innerHeight;
607
 
608
+ // Calculate relative position within email list
609
+ const emailListRect = this.uiManager.emailList.getBoundingClientRect();
610
+ const relativeX = screenX - emailListRect.left;
611
+ const relativeY = screenY - emailListRect.top;
 
612
 
613
  // Pointing detection (index finger higher than middle)
614
  if (indexTip.y < middleTip.y && wrist.y > indexTip.y) {
615
+ this.checkEmailSelection(relativeX, relativeY);
 
 
 
616
  } else {
617
  this.uiManager.clearSelection();
618
  this.gestureBuffer = [];
619
  this.circlePoints = [];
 
620
  this.debugManager.updateGestureType('None');
621
  this.debugManager.updateBufferCount(0);
622
  this.debugManager.updateCircleCount(0);
 
624
 
625
  // Only process gestures if an email is selected
626
  if (this.selectedEmailId === null) {
627
+ this.processScrolling(landmarks);
628
  return;
629
  }
630
 
 
698
  }
699
  }
700
 
701
+ processScrolling(landmarks) {
702
  const wrist = landmarks[0];
703
  const indexTip = landmarks[8];
704
+
705
+ // Only process scrolling when no email is selected
706
+ if (this.selectedEmailId !== null) return;
707
+
708
+ // Calculate screen coordinates
709
+ const screenX = indexTip.x * window.innerWidth;
710
+ const screenY = indexTip.y * window.innerHeight;
711
+
712
+ // Calculate relative position within email list
713
+ const emailListRect = this.uiManager.emailList.getBoundingClientRect();
714
+ const relativeX = screenX - emailListRect.left;
715
+ const relativeY = screenY - emailListRect.top;
716
+
717
+ // Only scroll if finger is in the email list area
718
+ if (relativeX < 0 || relativeX > emailListRect.width ||
719
+ relativeY < 0 || relativeY > emailListRect.height) {
720
+ return;
721
+ }
722
+
723
+ // Calculate velocity for scrolling
724
+ if (this.gestureBuffer.length > 1) {
725
+ const lastPoint = this.gestureBuffer[this.gestureBuffer.length - 2];
726
+ const currentPoint = this.gestureBuffer[this.gestureBuffer.length - 1];
727
 
728
+ const dx = (currentPoint.x - lastPoint.x) * window.innerWidth;
729
+ const dy = (currentPoint.y - lastPoint.y) * window.innerHeight;
730
+ const distance = Math.sqrt(dx * dx + dy * dy);
731
+ const speed = distance / (this.lastTimestamp - lastPoint.timestamp);
732
+
733
+ // Only scroll if movement is primarily vertical
734
+ if (Math.abs(dy) > this.scrollThreshold && Math.abs(dy) > Math.abs(dx) * 1.5 && speed > 0.5) {
735
+ this.scrollActive = true;
736
+ this.scrollDirection = dy > 0 ? 'down' : 'up';
737
 
738
+ // Show scroll indicator
739
+ this.uiManager.showScrollIndicator();
740
+
741
+ // Perform scroll
742
+ const scrollAmount = Math.min(150, Math.abs(dy) * 2);
743
+ this.uiManager.emailList.scrollBy({
744
+ top: this.scrollDirection === 'up' ? -scrollAmount : scrollAmount,
745
+ behavior: 'smooth'
746
+ });
747
+
748
+ // Reset buffer to prevent multiple scrolls from same movement
749
+ this.gestureBuffer = [];
 
 
 
750
  }
751
  }
752
  }
753
 
754
+ calculateCircleMetrics() {
755
+ if (this.circlePoints.length < 3) {
756
+ return { center: { x: 0, y: 0 }, radius: 0, circularity: 0 };
757
+ }
758
+
759
+ // Find centroid
760
+ let centerX = 0;
761
+ let centerY = 0;
762
+ for (const point of this.circlePoints) {
763
+ centerX += point.x;
764
+ centerY += point.y;
765
+ }
766
+ centerX /= this.circlePoints.length;
767
+ centerY /= this.circlePoints.length;
768
+
769
+ // Calculate radius and circularity
770
+ let totalRadius = 0;
771
+ let radiusVariance = 0;
772
+ const radii = [];
773
+
774
+ for (const point of this.circlePoints) {
775
+ const dx = point.x - centerX;
776
+ const dy = point.y - centerY;
777
+ const radius = Math.sqrt(dx * dx + dy * dy);
778
+ radii.push(radius);
779
+ totalRadius += radius;
780
+ }
781
+
782
+ const avgRadius = totalRadius / this.circlePoints.length;
783
+
784
+ // Calculate variance to determine circularity
785
+ for (const radius of radii) {
786
+ radiusVariance += Math.pow(radius - avgRadius, 2);
787
+ }
788
+ radiusVariance /= this.circlePoints.length;
789
+
790
+ // Calculate circularity (1 = perfect circle, 0 = not circular)
791
+ const circularity = radiusVariance < 0.0001 ? 1 : Math.max(0, 1 - radiusVariance / (avgRadius * avgRadius));
792
 
793
  return {
794
+ center: { x: centerX, y: centerY },
795
+ radius: avgRadius,
796
+ circularity: circularity
 
797
  };
798
  }
799