calendar/jogwheel.js
2025-08-20 21:38:28 -06:00

80 lines
2.4 KiB
JavaScript

// jogwheel.js — Jogwheel synchronization for calendar scrolling
export class JogwheelManager {
constructor(calendar) {
this.calendar = calendar
this.viewport = null
this.content = null
this.syncLock = null
this.init()
}
init() {
this.viewport = document.getElementById('jogwheel-viewport')
this.content = document.getElementById('jogwheel-content')
if (!this.viewport || !this.content) {
console.warn('Jogwheel elements not found - jogwheel functionality disabled')
return
}
this.setupScrollSync()
}
setupScrollSync() {
// Check if calendar viewport is available
if (!this.calendar.viewport || !this.calendar.content) {
console.warn('Calendar viewport not available - jogwheel sync disabled')
return
}
// Bind sync function to maintain proper context
const sync = this.sync.bind(this)
this.viewport.addEventListener('scroll', () =>
sync(this.viewport, this.calendar.viewport, this.content, this.calendar.content)
)
this.calendar.viewport.addEventListener('scroll', () =>
sync(this.calendar.viewport, this.viewport, this.calendar.content, this.content)
)
}
sync(fromEl, toEl, fromContent, toContent) {
if (this.syncLock === toEl) return
this.syncLock = fromEl
const fromScrollable = Math.max(0, fromContent.scrollHeight - fromEl.clientHeight)
const toScrollable = Math.max(0, toContent.scrollHeight - toEl.clientHeight)
const ratio = fromScrollable > 0 ? fromEl.scrollTop / fromScrollable : 0
toEl.scrollTop = ratio * toScrollable
setTimeout(() => {
if (this.syncLock === fromEl) this.syncLock = null
}, 50)
}
updateHeight(totalVirtualWeeks, rowHeight) {
if (this.content) {
this.content.style.height = `${(totalVirtualWeeks * rowHeight) / 10}px`
}
}
scrollTo(targetScrollTop, mainScrollable, smooth = false) {
if (!this.viewport || !this.content) return
const jogScrollable = Math.max(0, this.content.scrollHeight - this.viewport.clientHeight)
const jogwheelTarget = mainScrollable > 0 ? (targetScrollTop / mainScrollable) * jogScrollable : 0
if (smooth) {
this.viewport.scrollTo({ top: jogwheelTarget, behavior: 'smooth' })
} else {
this.viewport.scrollTop = jogwheelTarget
}
}
isAvailable() {
return !!(this.viewport && this.content)
}
}