1
|
|
import { CalendarEventParsed, CalendarEventVisual, CalendarTimestamp } from 'vuetify/types'
|
2
|
1
|
import { getTimestampIdentifier } from '../util/timestamp'
|
3
|
|
|
4
|
1
|
const MILLIS_IN_DAY = 86400000
|
5
|
|
|
6
|
|
export type GetRange = (event: CalendarEventParsed) => [number, number]
|
7
|
|
|
8
|
1
|
export function getVisuals (events: CalendarEventParsed[], minStart = 0): CalendarEventVisual[] {
|
9
|
1
|
const visuals = events.map(event => ({
|
10
|
|
event,
|
11
|
|
columnCount: 0,
|
12
|
|
column: 0,
|
13
|
|
left: 0,
|
14
|
|
width: 100,
|
15
|
|
}))
|
16
|
|
|
17
|
1
|
visuals.sort((a, b) => {
|
18
|
1
|
return (Math.max(minStart, a.event.startTimestampIdentifier) - Math.max(minStart, b.event.startTimestampIdentifier)) ||
|
19
|
1
|
(b.event.endTimestampIdentifier - a.event.endTimestampIdentifier)
|
20
|
|
})
|
21
|
|
|
22
|
1
|
return visuals
|
23
|
|
}
|
24
|
|
|
25
|
|
export interface ColumnGroup {
|
26
|
|
start: number
|
27
|
|
end: number
|
28
|
|
visuals: CalendarEventVisual[]
|
29
|
|
}
|
30
|
|
|
31
|
1
|
export function hasOverlap (s0: number, e0: number, s1: number, e1: number, exclude = true): boolean {
|
32
|
1
|
return exclude ? !(s0 >= e1 || e0 <= s1) : !(s0 > e1 || e0 < s1)
|
33
|
|
}
|
34
|
|
|
35
|
1
|
export function setColumnCount (groups: ColumnGroup[]) {
|
36
|
0
|
groups.forEach(group => {
|
37
|
0
|
group.visuals.forEach(groupVisual => {
|
38
|
0
|
groupVisual.columnCount = groups.length
|
39
|
|
})
|
40
|
|
})
|
41
|
|
}
|
42
|
|
|
43
|
1
|
export function getRange (event: CalendarEventParsed): [number, number] {
|
44
|
0
|
return [event.startTimestampIdentifier, event.endTimestampIdentifier]
|
45
|
|
}
|
46
|
|
|
47
|
1
|
export function getDayRange (event: CalendarEventParsed): [number, number] {
|
48
|
0
|
return [event.startIdentifier, event.endIdentifier]
|
49
|
|
}
|
50
|
|
|
51
|
1
|
export function getNormalizedRange (event: CalendarEventParsed, dayStart: number): [number, number] {
|
52
|
0
|
return [Math.max(dayStart, event.startTimestampIdentifier), Math.min(dayStart + MILLIS_IN_DAY, event.endTimestampIdentifier)]
|
53
|
|
}
|
54
|
|
|
55
|
1
|
export function getOpenGroup (groups: ColumnGroup[], start: number, end: number, timed: boolean) {
|
56
|
0
|
for (let i = 0; i < groups.length; i++) {
|
57
|
0
|
const group = groups[i]
|
58
|
0
|
let intersected = false
|
59
|
|
|
60
|
1
|
if (hasOverlap(start, end, group.start, group.end, timed)) {
|
61
|
0
|
for (let k = 0; k < group.visuals.length; k++) {
|
62
|
0
|
const groupVisual = group.visuals[k]
|
63
|
1
|
const [groupStart, groupEnd] = timed ? getRange(groupVisual.event) : getDayRange(groupVisual.event)
|
64
|
|
|
65
|
1
|
if (hasOverlap(start, end, groupStart, groupEnd, timed)) {
|
66
|
0
|
intersected = true
|
67
|
0
|
break
|
68
|
|
}
|
69
|
|
}
|
70
|
|
}
|
71
|
|
|
72
|
1
|
if (!intersected) {
|
73
|
0
|
return i
|
74
|
|
}
|
75
|
|
}
|
76
|
|
|
77
|
0
|
return -1
|
78
|
|
}
|
79
|
|
|
80
|
1
|
export function getOverlapGroupHandler (firstWeekday: number) {
|
81
|
0
|
const handler = {
|
82
|
|
groups: [] as ColumnGroup[],
|
83
|
|
min: -1,
|
84
|
|
max: -1,
|
85
|
0
|
reset: () => {
|
86
|
0
|
handler.groups = []
|
87
|
0
|
handler.min = handler.max = -1
|
88
|
|
},
|
89
|
1
|
getVisuals: (day: CalendarTimestamp, dayEvents: CalendarEventParsed[], timed: boolean, reset = false) => {
|
90
|
1
|
if (day.weekday === firstWeekday || reset) {
|
91
|
0
|
handler.reset()
|
92
|
|
}
|
93
|
|
|
94
|
0
|
const dayStart = getTimestampIdentifier(day)
|
95
|
0
|
const visuals = getVisuals(dayEvents, dayStart)
|
96
|
|
|
97
|
0
|
visuals.forEach(visual => {
|
98
|
1
|
const [start, end] = timed ? getRange(visual.event) : getDayRange(visual.event)
|
99
|
|
|
100
|
1
|
if (handler.groups.length > 0 && !hasOverlap(start, end, handler.min, handler.max, timed)) {
|
101
|
0
|
setColumnCount(handler.groups)
|
102
|
0
|
handler.reset()
|
103
|
|
}
|
104
|
|
|
105
|
0
|
let targetGroup = getOpenGroup(handler.groups, start, end, timed)
|
106
|
|
|
107
|
1
|
if (targetGroup === -1) {
|
108
|
0
|
targetGroup = handler.groups.length
|
109
|
|
|
110
|
0
|
handler.groups.push({ start, end, visuals: [] })
|
111
|
|
}
|
112
|
|
|
113
|
0
|
const target = handler.groups[targetGroup]
|
114
|
0
|
target.visuals.push(visual)
|
115
|
0
|
target.start = Math.min(target.start, start)
|
116
|
0
|
target.end = Math.max(target.end, end)
|
117
|
|
|
118
|
0
|
visual.column = targetGroup
|
119
|
|
|
120
|
1
|
if (handler.min === -1) {
|
121
|
0
|
handler.min = start
|
122
|
0
|
handler.max = end
|
123
|
|
} else {
|
124
|
0
|
handler.min = Math.min(handler.min, start)
|
125
|
0
|
handler.max = Math.max(handler.max, end)
|
126
|
|
}
|
127
|
|
})
|
128
|
|
|
129
|
0
|
setColumnCount(handler.groups)
|
130
|
|
|
131
|
1
|
if (timed) {
|
132
|
0
|
handler.reset()
|
133
|
|
}
|
134
|
|
|
135
|
0
|
return visuals
|
136
|
|
},
|
137
|
|
}
|
138
|
|
|
139
|
0
|
return handler
|
140
|
|
}
|