Skip to content

Commit e622651

Browse files
ckcks12jquense
authored andcommitted
feat: add Rearrangement Algorithm Implementation (#1473)
* Rearrangement Algorithm Implementation * day layout algorithm as strategy pattern * day layout algorithm css customizable & move Event class into overlap algorithm * restore yarn.lock
1 parent 0c9b1f2 commit e622651

File tree

12 files changed

+483
-190
lines changed

12 files changed

+483
-190
lines changed

examples/App.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import Card from './Card'
1717
import ExampleControlSlot from './ExampleControlSlot'
1818
import Basic from './demos/basic'
1919
import Selectable from './demos/selectable'
20+
import CreateEventWithNoOverlap from './demos/createEventWithNoOverlap'
2021
import Cultures from './demos/cultures'
2122
import Popup from './demos/popup'
2223
import Rendering from './demos/rendering'
@@ -37,6 +38,7 @@ let demoRoot =
3738
const EXAMPLES = {
3839
basic: 'Basic Calendar',
3940
selectable: 'Create events',
41+
createEventWithNoOverlap: 'Create events with no-overlap algorithm',
4042
cultures: 'Localization',
4143
popup: 'Show more via a popup',
4244
timeslots: 'Custom Time Grids',
@@ -82,6 +84,7 @@ class Example extends React.Component {
8284
dnd: Dnd,
8385
dndresource: DndResource,
8486
dndOutsideSource: DndOutsideSource,
87+
createEventWithNoOverlap: CreateEventWithNoOverlap,
8588
}[selected]
8689

8790
return (
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import React from 'react'
2+
import { Calendar, Views } from 'react-big-calendar'
3+
import events from '../events'
4+
import ExampleControlSlot from '../ExampleControlSlot'
5+
import _ from 'lodash'
6+
7+
const propTypes = {}
8+
9+
class CreateEventWithNoOverlap extends React.Component {
10+
constructor(...args) {
11+
super(...args)
12+
13+
this.state = {
14+
events: _.cloneDeep(events),
15+
dayLayoutAlgorithm: 'no-overlap',
16+
}
17+
}
18+
19+
handleSelect = ({ start, end }) => {
20+
const title = window.prompt('New Event name')
21+
if (title)
22+
this.setState({
23+
events: [
24+
...this.state.events,
25+
{
26+
start,
27+
end,
28+
title,
29+
},
30+
],
31+
})
32+
}
33+
34+
render() {
35+
const { localizer } = this.props
36+
return (
37+
<>
38+
<ExampleControlSlot.Entry waitForOutlet>
39+
<strong>
40+
Click an event to see more info, or drag the mouse over the calendar
41+
to select a date/time range.
42+
<br />
43+
The events are being arranged by `no-overlap` algorithm.
44+
</strong>
45+
</ExampleControlSlot.Entry>
46+
<Calendar
47+
selectable
48+
localizer={localizer}
49+
events={this.state.events}
50+
defaultView={Views.WEEK}
51+
scrollToTime={new Date(1970, 1, 1, 6)}
52+
defaultDate={new Date(2015, 3, 12)}
53+
onSelectEvent={event => alert(event.title)}
54+
onSelectSlot={this.handleSelect}
55+
dayLayoutAlgorithm={this.state.dayLayoutAlgorithm}
56+
/>
57+
</>
58+
)
59+
}
60+
}
61+
62+
CreateEventWithNoOverlap.propTypes = propTypes
63+
64+
export default CreateEventWithNoOverlap

examples/events.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,52 @@ export default [
111111
start: now,
112112
end: now,
113113
},
114+
{
115+
id: 16,
116+
title: 'Video Record',
117+
start: new Date(2015, 3, 14, 15, 30, 0),
118+
end: new Date(2015, 3, 14, 19, 0, 0),
119+
},
120+
{
121+
id: 17,
122+
title: 'Dutch Song Producing',
123+
start: new Date(2015, 3, 14, 16, 30, 0),
124+
end: new Date(2015, 3, 14, 20, 0, 0),
125+
},
126+
{
127+
id: 18,
128+
title: 'Itaewon Halloween Meeting',
129+
start: new Date(2015, 3, 14, 16, 30, 0),
130+
end: new Date(2015, 3, 14, 17, 30, 0),
131+
},
132+
{
133+
id: 19,
134+
title: 'Online Coding Test',
135+
start: new Date(2015, 3, 14, 17, 30, 0),
136+
end: new Date(2015, 3, 14, 20, 30, 0),
137+
},
138+
{
139+
id: 20,
140+
title: 'An overlapped Event',
141+
start: new Date(2015, 3, 14, 17, 0, 0),
142+
end: new Date(2015, 3, 14, 18, 30, 0),
143+
},
144+
{
145+
id: 21,
146+
title: 'Phone Interview',
147+
start: new Date(2015, 3, 14, 17, 0, 0),
148+
end: new Date(2015, 3, 14, 18, 30, 0),
149+
},
150+
{
151+
id: 22,
152+
title: 'Cooking Class',
153+
start: new Date(2015, 3, 14, 17, 30, 0),
154+
end: new Date(2015, 3, 14, 19, 0, 0),
155+
},
156+
{
157+
id: 23,
158+
title: 'Go to the gym',
159+
start: new Date(2015, 3, 14, 18, 30, 0),
160+
end: new Date(2015, 3, 14, 20, 0, 0),
161+
},
114162
]

src/Calendar.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
accessor,
77
dateFormat,
88
dateRangeFormat,
9+
DayLayoutAlgorithmPropType,
910
views as componentViews,
1011
} from './utils/propTypes'
1112
import warning from 'warning'
@@ -719,6 +720,14 @@ class Calendar extends React.Component {
719720
noEventsInRange: PropTypes.node,
720721
showMore: PropTypes.func,
721722
}),
723+
724+
/**
725+
* A day event layout(arrangement) algorithm.
726+
* `overlap` allows events to be overlapped.
727+
* `no-overlap` resizes events to avoid overlap.
728+
* or custom `Function(events, minimumStartDifference, slotMetrics, accessors)`
729+
*/
730+
dayLayoutAlgorithm: DayLayoutAlgorithmPropType,
722731
}
723732

724733
static defaultProps = {
@@ -744,6 +753,7 @@ class Calendar extends React.Component {
744753

745754
longPressThreshold: 250,
746755
getNow: () => new Date(),
756+
dayLayoutAlgorithm: 'overlap',
747757
}
748758

749759
constructor(...args) {

src/DayColumn.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ import { notify } from './utils/helpers'
1212
import * as DayEventLayout from './utils/DayEventLayout'
1313
import TimeSlotGroup from './TimeSlotGroup'
1414
import TimeGridEvent from './TimeGridEvent'
15+
import { DayLayoutAlgorithmPropType } from './utils/propTypes'
1516

1617
class DayColumn extends React.Component {
1718
state = { selecting: false, timeIndicatorPosition: null }
19+
intervalTriggered = false
1820

1921
constructor(...args) {
2022
super(...args)
@@ -70,7 +72,6 @@ class DayColumn extends React.Component {
7072
}
7173
}
7274

73-
intervalTriggered = false
7475
/**
7576
* @param tail {Boolean} - whether `positionTimeIndicator` call should be
7677
* deferred or called upon setting interval (`true` - if deferred);
@@ -183,6 +184,7 @@ class DayColumn extends React.Component {
183184
components,
184185
step,
185186
timeslots,
187+
dayLayoutAlgorithm,
186188
} = this.props
187189

188190
const { slotMetrics } = this
@@ -193,6 +195,7 @@ class DayColumn extends React.Component {
193195
accessors,
194196
slotMetrics,
195197
minimumStartDifference: Math.ceil((step * timeslots) / 2),
198+
dayLayoutAlgorithm,
196199
})
197200

198201
return styledEvents.map(({ event, style }, idx) => {
@@ -402,6 +405,8 @@ DayColumn.propTypes = {
402405
className: PropTypes.string,
403406
dragThroughEvents: PropTypes.bool,
404407
resource: PropTypes.any,
408+
409+
dayLayoutAlgorithm: DayLayoutAlgorithmPropType,
405410
}
406411

407412
DayColumn.defaultProps = {

src/TimeGrid.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import TimeGridHeader from './TimeGridHeader'
1414
import { notify } from './utils/helpers'
1515
import { inRange, sortEvents } from './utils/eventLevels'
1616
import Resources from './utils/Resources'
17+
import { DayLayoutAlgorithmPropType } from './utils/propTypes'
1718

1819
export default class TimeGrid extends Component {
1920
constructor(props) {
@@ -103,7 +104,14 @@ export default class TimeGrid extends Component {
103104
}
104105

105106
renderEvents(range, events, now) {
106-
let { min, max, components, accessors, localizer } = this.props
107+
let {
108+
min,
109+
max,
110+
components,
111+
accessors,
112+
localizer,
113+
dayLayoutAlgorithm,
114+
} = this.props
107115

108116
const resources = this.memoizedResources(this.props.resources, accessors)
109117
const groupedEvents = resources.groupEvents(events)
@@ -131,6 +139,7 @@ export default class TimeGrid extends Component {
131139
key={i + '-' + jj}
132140
date={date}
133141
events={daysEvents}
142+
dayLayoutAlgorithm={dayLayoutAlgorithm}
134143
/>
135144
)
136145
})
@@ -328,6 +337,8 @@ TimeGrid.propTypes = {
328337
onDoubleClickEvent: PropTypes.func,
329338
onDrillDown: PropTypes.func,
330339
getDrilldownView: PropTypes.func.isRequired,
340+
341+
dayLayoutAlgorithm: DayLayoutAlgorithmPropType,
331342
}
332343

333344
TimeGrid.defaultProps = {

src/TimeGridEvent.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import clsx from 'clsx'
22
import React from 'react'
33

4+
function stringifyPercent(v) {
5+
return typeof v === 'string' ? v : v + '%'
6+
}
7+
48
/* eslint-disable react/prop-types */
59
function TimeGridEvent(props) {
610
const {
@@ -42,10 +46,10 @@ function TimeGridEvent(props) {
4246
onDoubleClick={onDoubleClick}
4347
style={{
4448
...userProps.style,
45-
top: `${top}%`,
46-
height: `${height}%`,
47-
[rtl ? 'right' : 'left']: `${Math.max(0, xOffset)}%`,
48-
width: `${width}%`,
49+
top: stringifyPercent(top),
50+
[rtl ? 'right' : 'left']: stringifyPercent(xOffset),
51+
width: stringifyPercent(width),
52+
height: stringifyPercent(height),
4953
}}
5054
title={
5155
tooltip

0 commit comments

Comments
 (0)