80 lines
2.4 KiB
JavaScript
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)
|
|
}
|
|
}
|