smarter time labels
This commit is contained in:
		
							parent
							
								
									2ef039da12
								
							
						
					
					
						commit
						0da9524f87
					
				
							
								
								
									
										139
									
								
								src/index.html
									
									
									
									
									
								
							
							
						
						
									
										139
									
								
								src/index.html
									
									
									
									
									
								
							| @ -107,7 +107,16 @@ | ||||
|             border-radius: 2px; | ||||
|             transition: width 0.3s ease; | ||||
|             width: 0%; | ||||
|             margin: 0 0 0.5rem; | ||||
|             margin: 0 0 1rem; | ||||
|         } | ||||
| 
 | ||||
|         .timeline-labels { | ||||
|             display: flex; | ||||
|             justify-content: space-between; | ||||
|             font-size: 0.7rem; | ||||
|             color: rgba(255,255,255,0.8); | ||||
|             margin-bottom: 0.5rem; | ||||
|             height: 1.2rem; | ||||
|         } | ||||
| 
 | ||||
|         .control-group { | ||||
| @ -174,6 +183,7 @@ | ||||
| 
 | ||||
|         <article class="controls-card"> | ||||
|             <div class="timeline-progress" id="timelineProgress"></div> | ||||
|             <div class="timeline-labels" id="timelineLabels" style="display: flex; justify-content: space-between; font-size: 0.8rem; color: #fff; margin-bottom: 0.5rem;"></div> | ||||
|             <div class="control-group"> | ||||
|                  | ||||
| 
 | ||||
| @ -291,14 +301,14 @@ | ||||
|                 thumb.classList.toggle('active', index === currentIndex); | ||||
|             }); | ||||
| 
 | ||||
|             // Scroll active thumbnail into view | ||||
|             // if (thumbnails[currentIndex]) { | ||||
|             //     thumbnails[currentIndex].scrollIntoView({ | ||||
|             //         behavior: 'smooth', | ||||
|             //         block: 'nearest', | ||||
|             //         inline: 'center' | ||||
|             //     }); | ||||
|             // } | ||||
|                 // Scroll active thumbnail into view | ||||
|             if (thumbnails[currentIndex]) { | ||||
|                 thumbnails[currentIndex].scrollIntoView({ | ||||
|                     behavior: 'smooth', | ||||
|                     block: 'nearest', | ||||
|                     inline: 'center' | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         function goToFirst() { | ||||
| @ -350,6 +360,117 @@ | ||||
|         function updateTimeline() { | ||||
|             const progress = images.length > 0 ? ((currentIndex + 1) / images.length) * 100 : 0; | ||||
|             document.getElementById('timelineProgress').style.width = progress + '%'; | ||||
|             updateTimelineLabels(); | ||||
|         } | ||||
| 
 | ||||
|         function updateTimelineLabels() { | ||||
|             const labelsContainer = document.getElementById('timelineLabels'); | ||||
|             labelsContainer.innerHTML = ''; | ||||
|             if (images.length === 0) return; | ||||
| 
 | ||||
|             const firstDate = images[0].createdDate; | ||||
|             const lastDate = images[images.length - 1].createdDate; | ||||
|             const totalDuration = lastDate.getTime() - firstDate.getTime(); | ||||
| 
 | ||||
|             // Aim for approximately 6-8 labels depending on the container width | ||||
|             const desiredLabels = Math.min(8, Math.max(6, Math.floor(window.innerWidth / 200))); | ||||
|              | ||||
|             const labels = []; | ||||
|              | ||||
|             // Always add the first timestamp | ||||
|             labels.push({ | ||||
|                 time: firstDate, | ||||
|                 pos: 0 | ||||
|             }); | ||||
| 
 | ||||
|             // Add evenly spaced timestamps | ||||
|             for (let i = 1; i < desiredLabels - 1; i++) { | ||||
|                 const time = new Date(firstDate.getTime() + (totalDuration * i / (desiredLabels - 1))); | ||||
|                  | ||||
|                 // Find closest image to this time | ||||
|                 let closestIdx = 0; | ||||
|                 let minDiff = Math.abs(images[0].createdDate - time); | ||||
|                  | ||||
|                 for (let j = 1; j < images.length; j++) { | ||||
|                     const diff = Math.abs(images[j].createdDate - time); | ||||
|                     if (diff < minDiff) { | ||||
|                         minDiff = diff; | ||||
|                         closestIdx = j; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 const pos = (closestIdx / (images.length - 1)) * 100; | ||||
|                 labels.push({ | ||||
|                     time: images[closestIdx].createdDate, | ||||
|                     pos: pos | ||||
|                 }); | ||||
|             } | ||||
| 
 | ||||
|             // Add the last timestamp | ||||
|             labels.push({ | ||||
|                 time: lastDate, | ||||
|                 pos: 100 | ||||
|             }); | ||||
| 
 | ||||
|             // Remove any labels that are too close to each other | ||||
|             const filteredLabels = labels.filter((label, index) => { | ||||
|                 if (index === 0) return true; | ||||
|                 return Math.abs(label.pos - labels[index - 1].pos) >= 5; | ||||
|             }); | ||||
| 
 | ||||
|             // Calculate if we need to show seconds (if total duration is less than 5 minutes) | ||||
|             const showSeconds = totalDuration < 5 * 60 * 1000; | ||||
|              | ||||
|             // Calculate optimal spacing between labels | ||||
|             const containerWidth = labelsContainer.offsetWidth; | ||||
|             const labelWidth = 70; // Approximate width of a time label | ||||
|             const minSpacing = labelWidth * 1.5; // Minimum space needed between labels | ||||
|             const maxLabels = Math.floor(containerWidth / minSpacing); | ||||
|             const targetLabels = Math.min(filteredLabels.length, maxLabels); | ||||
|              | ||||
|             // Select evenly spaced labels | ||||
|             const finalLabels = []; | ||||
|             if (filteredLabels.length > 0) { | ||||
|                 const step = (filteredLabels.length - 1) / (targetLabels - 1); | ||||
|                 for (let i = 0; i < targetLabels; i++) { | ||||
|                     const index = Math.round(i * step); | ||||
|                     finalLabels.push(filteredLabels[index]); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // Round the timestamps | ||||
|             const roundedLabels = finalLabels.map(label => { | ||||
|                 const newTime = new Date(label.time); | ||||
|                  | ||||
|                 if (showSeconds) { | ||||
|                     // Round seconds to nearest 5 | ||||
|                     const seconds = newTime.getSeconds(); | ||||
|                     const roundedSeconds = Math.round(seconds / 5) * 5; | ||||
|                     newTime.setSeconds(roundedSeconds); | ||||
|                 } else { | ||||
|                     // Round minutes to nearest 5 and set seconds to 0 | ||||
|                     const minutes = newTime.getMinutes(); | ||||
|                     const roundedMinutes = Math.round(minutes / 5) * 5; | ||||
|                     newTime.setMinutes(roundedMinutes); | ||||
|                     newTime.setSeconds(0); | ||||
|                 } | ||||
|                  | ||||
|                 return { | ||||
|                     ...label, | ||||
|                     time: newTime | ||||
|                 }; | ||||
|             }); | ||||
| 
 | ||||
|             // Render labels | ||||
|             labelsContainer.style.position = 'relative'; | ||||
|             labelsContainer.innerHTML = roundedLabels.map(l => { | ||||
|                 const options = showSeconds  | ||||
|                     ? {hour: '2-digit', minute:'2-digit', second:'2-digit'}  | ||||
|                     : {hour: '2-digit', minute:'2-digit'}; | ||||
|                 return `<span style="position: absolute; left: ${l.pos}%; transform: translateX(-50%); white-space: nowrap;"> | ||||
|                     ${l.time.toLocaleTimeString([], options)} | ||||
|                 </span>`; | ||||
|             }).join(''); | ||||
|         } | ||||
| 
 | ||||
|         function togglePlay() { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user