Fix rotation issues, simplify scrolling code.
This commit is contained in:
parent
7c94fcbb45
commit
10c9cedc8e
@ -115,20 +115,25 @@ const contentHeight = computed(() => {
|
|||||||
|
|
||||||
const visibleWeeks = ref([])
|
const visibleWeeks = ref([])
|
||||||
let lastScrollRange = { startVW: null, endVW: null }
|
let lastScrollRange = { startVW: null, endVW: null }
|
||||||
let pendingRebuild = false
|
|
||||||
|
let rebuildTimer = null
|
||||||
|
let lastReason = null
|
||||||
|
const REBUILD_DEBOUNCE_MS = 40
|
||||||
|
|
||||||
function scheduleRebuild(reason) {
|
function scheduleRebuild(reason) {
|
||||||
if (pendingRebuild) return
|
lastReason = lastReason ? lastReason + ',' + reason : reason
|
||||||
pendingRebuild = true
|
if (rebuildTimer) return
|
||||||
const cb = () => {
|
rebuildTimer = setTimeout(() => {
|
||||||
pendingRebuild = false
|
const r = lastReason
|
||||||
rebuildVisibleWeeks(reason)
|
rebuildTimer = null
|
||||||
}
|
lastReason = null
|
||||||
if ('requestIdleCallback' in window) {
|
const fn = () => rebuildVisibleWeeks(r)
|
||||||
requestIdleCallback(cb, { timeout: 120 })
|
if ('requestIdleCallback' in window) {
|
||||||
} else {
|
requestIdleCallback(fn, { timeout: 120 })
|
||||||
requestAnimationFrame(cb)
|
} else {
|
||||||
}
|
requestAnimationFrame(fn)
|
||||||
|
}
|
||||||
|
}, REBUILD_DEBOUNCE_MS)
|
||||||
}
|
}
|
||||||
|
|
||||||
const scrollManager = createScrollManager({ viewport, scheduleRebuild })
|
const scrollManager = createScrollManager({ viewport, scheduleRebuild })
|
||||||
@ -152,7 +157,7 @@ const monthScrollManager = createMonthScrollManager({
|
|||||||
setScrollTop,
|
setScrollTop,
|
||||||
})
|
})
|
||||||
|
|
||||||
const { handleMonthScrollMouseDown, handleMonthScrollTouchStart, handleMonthScrollWheel } =
|
const { handleMonthScrollPointerDown, handleMonthScrollTouchStart, handleMonthScrollWheel } =
|
||||||
monthScrollManager
|
monthScrollManager
|
||||||
|
|
||||||
const initialScrollTop = computed(() => {
|
const initialScrollTop = computed(() => {
|
||||||
@ -178,7 +183,7 @@ function rebuildVisibleWeeks(reason) {
|
|||||||
)
|
)
|
||||||
const startVW = Math.max(minVirtualWeek.value, startIdx + minVirtualWeek.value)
|
const startVW = Math.max(minVirtualWeek.value, startIdx + minVirtualWeek.value)
|
||||||
const endVW = Math.min(maxVirtualWeek.value, endIdx + minVirtualWeek.value)
|
const endVW = Math.min(maxVirtualWeek.value, endIdx + minVirtualWeek.value)
|
||||||
console.log('[CalendarView] rebuildVisibleWeeks', {
|
console.debug('[CalendarView] rebuildVisibleWeeks', {
|
||||||
reason,
|
reason,
|
||||||
currentScrollTop,
|
currentScrollTop,
|
||||||
startIdx,
|
startIdx,
|
||||||
@ -229,13 +234,6 @@ function measureFromProbe() {
|
|||||||
const topVirtualWeek = Math.floor(scrollTop.value / oldH) + minVirtualWeek.value
|
const topVirtualWeek = Math.floor(scrollTop.value / oldH) + minVirtualWeek.value
|
||||||
rowHeight.value = newH
|
rowHeight.value = newH
|
||||||
const newScrollTop = (topVirtualWeek - minVirtualWeek.value) * newH
|
const newScrollTop = (topVirtualWeek - minVirtualWeek.value) * newH
|
||||||
console.log('[CalendarView] measureFromProbe rowHeight change', {
|
|
||||||
oldH,
|
|
||||||
newH,
|
|
||||||
topVirtualWeek,
|
|
||||||
oldScrollTop: scrollTop.value,
|
|
||||||
newScrollTop,
|
|
||||||
})
|
|
||||||
setScrollTop(newScrollTop, 'row-height-change')
|
setScrollTop(newScrollTop, 'row-height-change')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -712,8 +710,8 @@ window.addEventListener('resize', () => {
|
|||||||
height: `calc(var(--row-h) * ${monthWeek.monthLabel?.weeksSpan || 1})`,
|
height: `calc(var(--row-h) * ${monthWeek.monthLabel?.weeksSpan || 1})`,
|
||||||
top: (monthWeek.top || 0) + 'px',
|
top: (monthWeek.top || 0) + 'px',
|
||||||
}"
|
}"
|
||||||
@mousedown="handleMonthScrollMouseDown"
|
@pointerdown="handleMonthScrollPointerDown"
|
||||||
@touchstart="handleMonthScrollTouchStart"
|
@touchstart.prevent="handleMonthScrollTouchStart"
|
||||||
@wheel="handleMonthScrollWheel"
|
@wheel="handleMonthScrollWheel"
|
||||||
>
|
>
|
||||||
<span :class="{ bottomup: shouldRotateMonth(monthWeek.monthLabel?.text) }">{{
|
<span :class="{ bottomup: shouldRotateMonth(monthWeek.monthLabel?.text) }">{{
|
||||||
@ -805,6 +803,7 @@ header h1 {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
cursor: ns-resize;
|
cursor: ns-resize;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
touch-action: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.month-label > span {
|
.month-label > span {
|
||||||
|
@ -156,79 +156,79 @@ export function createMonthScrollManager({
|
|||||||
contentHeight,
|
contentHeight,
|
||||||
setScrollTop,
|
setScrollTop,
|
||||||
}) {
|
}) {
|
||||||
let isMonthScrolling = false
|
let dragging = false
|
||||||
let monthScrollStartY = 0
|
let startY = 0
|
||||||
let monthScrollStartScroll = 0
|
let startScroll = 0
|
||||||
|
const SPEED = 10
|
||||||
|
|
||||||
const handleMonthScrollMouseDown = (e) => {
|
function applyDrag(clientY, reason) {
|
||||||
if (e.button !== 0) return
|
const deltaY = clientY - startY
|
||||||
isMonthScrolling = true
|
const newScrollTop = startScroll - deltaY * SPEED
|
||||||
monthScrollStartY = e.clientY
|
|
||||||
monthScrollStartScroll = viewport.value?.scrollTop || 0
|
|
||||||
|
|
||||||
const handleMouseMove = (e) => {
|
|
||||||
if (!isMonthScrolling) return
|
|
||||||
const deltaY = e.clientY - monthScrollStartY
|
|
||||||
const newScrollTop = monthScrollStartScroll - deltaY * 10
|
|
||||||
const maxScroll = Math.max(0, contentHeight.value - viewportHeight.value)
|
|
||||||
const clampedScroll = Math.max(0, Math.min(newScrollTop, maxScroll))
|
|
||||||
|
|
||||||
setScrollTop(clampedScroll, 'month-scroll-drag')
|
|
||||||
e.preventDefault()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleMouseUp = () => {
|
|
||||||
isMonthScrolling = false
|
|
||||||
document.removeEventListener('mousemove', handleMouseMove)
|
|
||||||
document.removeEventListener('mouseup', handleMouseUp)
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('mousemove', handleMouseMove)
|
|
||||||
document.addEventListener('mouseup', handleMouseUp)
|
|
||||||
e.preventDefault()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleMonthScrollTouchStart = (e) => {
|
|
||||||
if (e.touches.length !== 1) return
|
|
||||||
isMonthScrolling = true
|
|
||||||
monthScrollStartY = e.touches[0].clientY
|
|
||||||
monthScrollStartScroll = viewport.value?.scrollTop || 0
|
|
||||||
|
|
||||||
const handleTouchMove = (e) => {
|
|
||||||
if (!isMonthScrolling || e.touches.length !== 1) return
|
|
||||||
const deltaY = e.touches[0].clientY - monthScrollStartY
|
|
||||||
const newScrollTop = monthScrollStartScroll - deltaY * 10
|
|
||||||
const maxScroll = Math.max(0, contentHeight.value - viewportHeight.value)
|
|
||||||
const clampedScroll = Math.max(0, Math.min(newScrollTop, maxScroll))
|
|
||||||
|
|
||||||
setScrollTop(clampedScroll, 'month-scroll-touch')
|
|
||||||
e.preventDefault()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleTouchEnd = () => {
|
|
||||||
isMonthScrolling = false
|
|
||||||
document.removeEventListener('touchmove', handleTouchMove)
|
|
||||||
document.removeEventListener('touchend', handleTouchEnd)
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('touchmove', handleTouchMove, { passive: false })
|
|
||||||
document.addEventListener('touchend', handleTouchEnd)
|
|
||||||
e.preventDefault()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleMonthScrollWheel = (e) => {
|
|
||||||
const currentScroll = viewport.value?.scrollTop || 0
|
|
||||||
const newScrollTop = currentScroll + e.deltaY * 10
|
|
||||||
const maxScroll = Math.max(0, contentHeight.value - viewportHeight.value)
|
const maxScroll = Math.max(0, contentHeight.value - viewportHeight.value)
|
||||||
const clampedScroll = Math.max(0, Math.min(newScrollTop, maxScroll))
|
const clamped = Math.max(0, Math.min(newScrollTop, maxScroll))
|
||||||
|
setScrollTop(clamped, reason)
|
||||||
|
}
|
||||||
|
|
||||||
setScrollTop(clampedScroll, 'month-scroll-wheel')
|
function endDrag() {
|
||||||
|
dragging = false
|
||||||
|
window.removeEventListener('pointermove', onPointerMove, true)
|
||||||
|
window.removeEventListener('pointerup', onPointerUp, true)
|
||||||
|
window.removeEventListener('pointercancel', onPointerUp, true)
|
||||||
|
window.removeEventListener('touchmove', onTouchMove)
|
||||||
|
window.removeEventListener('touchend', onTouchEnd)
|
||||||
|
window.removeEventListener('touchcancel', onTouchEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPointerMove(e) {
|
||||||
|
if (!dragging) return
|
||||||
|
applyDrag(e.clientY, 'month-scroll-drag')
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
function onPointerUp() {
|
||||||
|
if (dragging) endDrag()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTouchMove(e) {
|
||||||
|
if (!dragging) return
|
||||||
|
const t = e.touches[0]
|
||||||
|
applyDrag(t.clientY, 'month-scroll-touch')
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
function onTouchEnd() {
|
||||||
|
if (dragging) endDrag()
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMonthScrollPointerDown(e) {
|
||||||
|
if (e.button !== undefined && e.button !== 0) return
|
||||||
|
e.preventDefault()
|
||||||
|
dragging = true
|
||||||
|
startY = e.clientY
|
||||||
|
startScroll = viewport.value?.scrollTop || 0
|
||||||
|
window.addEventListener('pointermove', onPointerMove, true)
|
||||||
|
window.addEventListener('pointerup', onPointerUp, true)
|
||||||
|
window.addEventListener('pointercancel', onPointerUp, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMonthScrollTouchStart(e) {
|
||||||
|
if (e.touches.length !== 1) return
|
||||||
|
dragging = true
|
||||||
|
const t = e.touches[0]
|
||||||
|
startY = t.clientY
|
||||||
|
startScroll = viewport.value?.scrollTop || 0
|
||||||
|
window.addEventListener('touchmove', onTouchMove, { passive: false })
|
||||||
|
window.addEventListener('touchend', onTouchEnd, { passive: false })
|
||||||
|
window.addEventListener('touchcancel', onTouchEnd, { passive: false })
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
function handleMonthScrollWheel(e) {
|
||||||
handleMonthScrollMouseDown,
|
const currentScroll = viewport.value?.scrollTop || 0
|
||||||
handleMonthScrollTouchStart,
|
const newScrollTop = currentScroll + e.deltaY * SPEED
|
||||||
handleMonthScrollWheel,
|
const maxScroll = Math.max(0, contentHeight.value - viewportHeight.value)
|
||||||
|
const clamped = Math.max(0, Math.min(newScrollTop, maxScroll))
|
||||||
|
setScrollTop(clamped, 'month-scroll-wheel')
|
||||||
|
e.preventDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return { handleMonthScrollPointerDown, handleMonthScrollTouchStart, handleMonthScrollWheel }
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user