vuetify
Version:
Vue Material Component Framework
141 lines (110 loc) • 4.04 kB
text/typescript
import { CalendarEventParsed, CalendarEventVisual, CalendarTimestamp } from 'vuetify/types'
import { getTimestampIdentifier } from '../util/timestamp'
const MILLIS_IN_DAY = 86400000
export type GetRange = (event: CalendarEventParsed) => [number, number]
export function getVisuals (events: CalendarEventParsed[], minStart = 0): CalendarEventVisual[] {
const visuals = events.map(event => ({
event,
columnCount: 0,
column: 0,
left: 0,
width: 100,
}))
visuals.sort((a, b) => {
return (Math.max(minStart, a.event.startTimestampIdentifier) - Math.max(minStart, b.event.startTimestampIdentifier)) ||
(b.event.endTimestampIdentifier - a.event.endTimestampIdentifier)
})
return visuals
}
export interface ColumnGroup {
start: number
end: number
visuals: CalendarEventVisual[]
}
export function hasOverlap (s0: number, e0: number, s1: number, e1: number, exclude = true): boolean {
return exclude ? !(s0 >= e1 || e0 <= s1) : !(s0 > e1 || e0 < s1)
}
export function setColumnCount (groups: ColumnGroup[]) {
groups.forEach(group => {
group.visuals.forEach(groupVisual => {
groupVisual.columnCount = groups.length
})
})
}
export function getRange (event: CalendarEventParsed): [number, number] {
return [event.startTimestampIdentifier, event.endTimestampIdentifier]
}
export function getDayRange (event: CalendarEventParsed): [number, number] {
return [event.startIdentifier, event.endIdentifier]
}
export function getNormalizedRange (event: CalendarEventParsed, dayStart: number): [number, number] {
return [Math.max(dayStart, event.startTimestampIdentifier), Math.min(dayStart + MILLIS_IN_DAY, event.endTimestampIdentifier)]
}
export function getOpenGroup (groups: ColumnGroup[], start: number, end: number, timed: boolean) {
for (let i = 0; i < groups.length; i++) {
const group = groups[i]
let intersected = false
if (hasOverlap(start, end, group.start, group.end, timed)) {
for (let k = 0; k < group.visuals.length; k++) {
const groupVisual = group.visuals[k]
const [groupStart, groupEnd] = timed ? getRange(groupVisual.event) : getDayRange(groupVisual.event)
if (hasOverlap(start, end, groupStart, groupEnd, timed)) {
intersected = true
break
}
}
}
if (!intersected) {
return i
}
}
return -1
}
export function getOverlapGroupHandler (firstWeekday: number) {
const handler = {
groups: [] as ColumnGroup[],
min: -1,
max: -1,
reset: () => {
handler.groups = []
handler.min = handler.max = -1
},
getVisuals: (day: CalendarTimestamp, dayEvents: CalendarEventParsed[], timed: boolean, reset = false) => {
if (day.weekday === firstWeekday || reset) {
handler.reset()
}
const dayStart = getTimestampIdentifier(day)
const visuals = getVisuals(dayEvents, dayStart)
visuals.forEach(visual => {
const [start, end] = timed ? getRange(visual.event) : getDayRange(visual.event)
if (handler.groups.length > 0 && !hasOverlap(start, end, handler.min, handler.max, timed)) {
setColumnCount(handler.groups)
handler.reset()
}
let targetGroup = getOpenGroup(handler.groups, start, end, timed)
if (targetGroup === -1) {
targetGroup = handler.groups.length
handler.groups.push({ start, end, visuals: [] })
}
const target = handler.groups[targetGroup]
target.visuals.push(visual)
target.start = Math.min(target.start, start)
target.end = Math.max(target.end, end)
visual.column = targetGroup
if (handler.min === -1) {
handler.min = start
handler.max = end
} else {
handler.min = Math.min(handler.min, start)
handler.max = Math.max(handler.max, end)
}
})
setColumnCount(handler.groups)
if (timed) {
handler.reset()
}
return visuals
},
}
return handler
}