Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix overlapping background events, fixes #2452 #2510

Merged
merged 4 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 9 additions & 17 deletions src/TimeGridEvent.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ function TimeGridEvent(props) {

let userProps = getters.eventProp(event, start, end, selected)

let { height, top, width, xOffset } = style
const inner = [
<div key="1" className="rbc-event-label">
{label}
Expand All @@ -41,22 +40,15 @@ function TimeGridEvent(props) {
</div>,
]

const eventStyle = isBackgroundEvent
? {
...userProps.style,
top: stringifyPercent(top),
height: stringifyPercent(height),
// Adding 10px to take events container right margin into account
width: `calc(${width} + 10px)`,
[rtl ? 'right' : 'left']: stringifyPercent(Math.max(0, xOffset)),
}
: {
...userProps.style,
top: stringifyPercent(top),
width: stringifyPercent(width),
height: stringifyPercent(height),
[rtl ? 'right' : 'left']: stringifyPercent(xOffset),
}
const { height, top, width, xOffset } = style

const eventStyle = {
...userProps.style,
top: stringifyPercent(top),
height: stringifyPercent(height),
width: stringifyPercent(width),
[rtl ? 'right' : 'left']: stringifyPercent(xOffset),
}

return (
<EventWrapper type="time" {...props}>
Expand Down
104 changes: 104 additions & 0 deletions stories/Layout.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,107 @@ export const ZeroDurationOverlap = () => {
/>
)
}

export const OverlappingBackgroundEventsOverlap = Template.bind({})
OverlappingBackgroundEventsOverlap.storyName =
"Overlapping Background Events - 'overlap'"
OverlappingBackgroundEventsOverlap.args = {
defaultDate: new Date(2016, 11, 3),
dayLayoutAlgorithm: 'overlap',
defaultView: Views.WEEK,
scrollToTime: new Date(2016, 11, 1, 7, 0),
backgroundEvents: [
{
title: 'First Event',
start: new Date(2016, 10, 28, 10, 30),
end: new Date(2016, 10, 28, 18, 0),
},
{
title: 'Second Event',
start: new Date(2016, 10, 28, 12, 0),
end: new Date(2016, 10, 28, 16, 30),
},
{
title: 'Third Event',
start: new Date(2016, 10, 29, 8, 0),
end: new Date(2016, 10, 29, 21, 0),
},
{
title: 'Fourth Event',
start: new Date(2016, 10, 29, 9, 30),
end: new Date(2016, 10, 29, 19, 30),
},
{
title: 'Fifth Event',
start: new Date(2016, 10, 29, 11, 0),
end: new Date(2016, 10, 29, 18, 0),
},
{
title: 'Sixth Event',
start: new Date(2016, 11, 1, 9, 0),
end: new Date(2016, 11, 1, 14, 0),
},
{
title: 'Seventh Event',
start: new Date(2016, 11, 1, 11, 0),
end: new Date(2016, 11, 1, 16, 0),
},
{
title: 'Eighth Event',
start: new Date(2016, 11, 1, 13, 0),
end: new Date(2016, 11, 1, 18, 0),
},
],
}

export const OverlappingBackgroundEventsNoOverlap = Template.bind({})
OverlappingBackgroundEventsNoOverlap.storyName =
"Overlapping Background Events - 'no-overlap'"
OverlappingBackgroundEventsNoOverlap.args = {
defaultDate: new Date(2016, 11, 3),
dayLayoutAlgorithm: 'no-overlap',
defaultView: Views.WEEK,
scrollToTime: new Date(2016, 11, 1, 7, 0),
backgroundEvents: [
{
title: 'First Event',
start: new Date(2016, 10, 28, 10, 30),
end: new Date(2016, 10, 28, 18, 0),
},
{
title: 'Second Event',
start: new Date(2016, 10, 28, 12, 0),
end: new Date(2016, 10, 28, 16, 30),
},
{
title: 'Third Event',
start: new Date(2016, 10, 29, 8, 0),
end: new Date(2016, 10, 29, 21, 0),
},
{
title: 'Fourth Event',
start: new Date(2016, 10, 29, 9, 30),
end: new Date(2016, 10, 29, 19, 30),
},
{
title: 'Fifth Event',
start: new Date(2016, 10, 29, 11, 0),
end: new Date(2016, 10, 29, 18, 0),
},
{
title: 'Sixth Event',
start: new Date(2016, 11, 1, 9, 0),
end: new Date(2016, 11, 1, 14, 0),
},
{
title: 'Seventh Event',
start: new Date(2016, 11, 1, 11, 0),
end: new Date(2016, 11, 1, 16, 0),
},
{
title: 'Eighth Event',
start: new Date(2016, 11, 1, 13, 0),
end: new Date(2016, 11, 1, 18, 0),
},
],
}
150 changes: 128 additions & 22 deletions test/utils/DayEventLayout.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,9 @@ describe('getStyledEvents', () => {
localizer,
})
const accessors = { start: (e) => e.start, end: (e) => e.end }
const dayLayoutAlgorithm = 'overlap'

describe('matrix', () => {
function compare(title, events, expectedResults) {
it(title, () => {
const styledEvents = getStyledEvents({
events,
accessors,
slotMetrics,
minimumStartDifference: 10,
dayLayoutAlgorithm,
})
const results = styledEvents.map((result) => ({
width: Math.floor(result.style.width),
xOffset: Math.floor(result.style.xOffset),
}))
expect(results).toEqual(expectedResults)
})
}

const toCheck = [
describe('with overlap dayLayoutAlgorithm', () => {
it.each([
[
'single event',
[{ start: d(11), end: d(12) }],
Expand Down Expand Up @@ -123,7 +105,131 @@ describe('getStyledEvents', () => {
{ width: 33, xOffset: 66 },
],
],
]
toCheck.forEach((args) => compare(...args))
])('%s', (_, events, expectedStyles) => {
const dayLayoutAlgorithm = 'overlap'

const styledEvents = getStyledEvents({
events,
accessors,
slotMetrics,
minimumStartDifference: 10,
dayLayoutAlgorithm,
})

const results = styledEvents.map((result) => ({
width: Math.floor(result.style.width),
xOffset: Math.floor(result.style.xOffset),
}))

expect(results).toEqual(expectedStyles)
})
})

describe('with no-overlap dayLayoutAlgorithm', () => {
it.each([
[
'single event',
[{ start: d(11), end: d(12) }],
[{ width: 'calc(100% - 0px)', xOffset: 'calc(0% + 0px)' }],
],
[
'two consecutive events',
[
{ start: d(11), end: d(11, 10) },
{ start: d(11, 10), end: d(11, 20) },
],
[
{ width: 'calc(100% - 0px)', xOffset: 'calc(0% + 0px)' },
{ width: 'calc(100% - 0px)', xOffset: 'calc(0% + 0px)' },
],
],
[
'two consecutive events too close together',
[
{ start: d(11), end: d(11, 5) },
{ start: d(11, 5), end: d(11, 10) },
],
[
{ width: 'calc(100% - 0px)', xOffset: 'calc(0% + 0px)' },
{ width: 'calc(100% - 0px)', xOffset: 'calc(0% + 0px)' },
],
],
[
'two overlapping events',
[
{ start: d(11), end: d(12) },
{ start: d(11), end: d(12) },
],
[
{ width: 'calc(50% - 0px)', xOffset: 'calc(0% + 0px)' },
{ width: 'calc(50% - 3px)', xOffset: 'calc(50% + 3px)' },
],
],
[
'three overlapping events',
[
{ start: d(11), end: d(12) },
{ start: d(11), end: d(12) },
{ start: d(11), end: d(12) },
],
[
{
width: 'calc(33.333333333333336% - 0px)',
xOffset: 'calc(0% + 0px)',
},
{
width: 'calc(33.333333333333336% - 3px)',
xOffset: 'calc(33.333333333333336% + 3px)',
},
{
width: 'calc(33.33333333333333% - 3px)',
xOffset: 'calc(66.66666666666667% + 3px)',
},
],
],
[
'one big event overlapping with two consecutive events',
[
{ start: d(11), end: d(12) },
{ start: d(11), end: d(11, 30) },
{ start: d(11, 30), end: d(12) },
],
[
{ width: 'calc(50% - 0px)', xOffset: 'calc(0% + 0px)' },
{ width: 'calc(50% - 3px)', xOffset: 'calc(50% + 3px)' },
{ width: 'calc(50% - 3px)', xOffset: 'calc(50% + 3px)' },
],
],
[
'one big event overlapping with two consecutive events starting too close together',
[
{ start: d(11), end: d(12) },
{ start: d(11), end: d(11, 5) },
{ start: d(11, 5), end: d(11, 10) },
],
[
{ width: 'calc(50% - 0px)', xOffset: 'calc(0% + 0px)' },
{ width: 'calc(50% - 3px)', xOffset: 'calc(50% + 3px)' },
{ width: 'calc(50% - 3px)', xOffset: 'calc(50% + 3px)' },
],
],
])('%s', (_, events, expectedStyles) => {
const dayLayoutAlgorithm = 'no-overlap'

const styledEvents = getStyledEvents({
events,
accessors,
slotMetrics,
minimumStartDifference: 10,
dayLayoutAlgorithm,
})

const results = styledEvents.map((result) => ({
width: result.style.width,
xOffset: result.style.xOffset,
}))

expect(results).toEqual(expectedStyles)
})
})
})
Loading