summaryrefslogtreecommitdiff
path: root/tools/timeline_editor/timeline-viewport.js
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-15 14:54:32 +0100
committerskal <pascal.massimino@gmail.com>2026-02-15 14:54:32 +0100
commit2031e24c976d1a11eb48badb97e824b1db07741a (patch)
tree479120fe608bc5645e73c25e50e07937c986c343 /tools/timeline_editor/timeline-viewport.js
parenta7bd63b1fc2b573141677da2d613c2a84455260e (diff)
feat(timeline-editor): add timing tooltip and cursor in waveform view
Shows precise time (seconds) and beat position under mouse cursor with a vertical guide line for accurate sample timing measurements. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'tools/timeline_editor/timeline-viewport.js')
-rw-r--r--tools/timeline_editor/timeline-viewport.js36
1 files changed, 36 insertions, 0 deletions
diff --git a/tools/timeline_editor/timeline-viewport.js b/tools/timeline_editor/timeline-viewport.js
index becf8e9..396b648 100644
--- a/tools/timeline_editor/timeline-viewport.js
+++ b/tools/timeline_editor/timeline-viewport.js
@@ -32,6 +32,11 @@ export class ViewportController {
this.dom.propertiesPanel.addEventListener('wheel', e => e.stopPropagation());
document.querySelector('.zoom-controls').addEventListener('wheel', e => e.stopPropagation());
document.querySelector('.stats').addEventListener('wheel', e => e.stopPropagation());
+
+ // Waveform hover tracking
+ this.dom.waveformContainer.addEventListener('mouseenter', () => this.showWaveformCursor());
+ this.dom.waveformContainer.addEventListener('mouseleave', () => this.hideWaveformCursor());
+ this.dom.waveformContainer.addEventListener('mousemove', e => this.updateWaveformCursor(e));
}
handleZoomSlider(e) {
@@ -126,6 +131,37 @@ export class ViewportController {
}
}
+ showWaveformCursor() {
+ this.dom.waveformCursor.style.display = 'block';
+ this.dom.waveformTooltip.style.display = 'block';
+ }
+
+ hideWaveformCursor() {
+ this.dom.waveformCursor.style.display = 'none';
+ this.dom.waveformTooltip.style.display = 'none';
+ }
+
+ updateWaveformCursor(e) {
+ const rect = this.dom.waveformContainer.getBoundingClientRect();
+ const mouseX = e.clientX - rect.left;
+ const scrollLeft = this.dom.timelineContent.scrollLeft;
+ const timeBeats = (scrollLeft + mouseX - this.TIMELINE_LEFT_PADDING) / this.state.pixelsPerSecond;
+ const timeSeconds = timeBeats * 60.0 / this.state.bpm;
+
+ // Position cursor
+ this.dom.waveformCursor.style.left = `${mouseX}px`;
+
+ // Position and update tooltip
+ const tooltipText = `${timeSeconds.toFixed(3)}s (${timeBeats.toFixed(2)}b)`;
+ this.dom.waveformTooltip.textContent = tooltipText;
+
+ // Position tooltip above cursor, offset to the right
+ const tooltipX = mouseX + 10;
+ const tooltipY = 5;
+ this.dom.waveformTooltip.style.left = `${tooltipX}px`;
+ this.dom.waveformTooltip.style.top = `${tooltipY}px`;
+ }
+
// Helper
timeToBeats(seconds) {
return seconds * this.state.bpm / 60.0;