Skip to content

Commit 8f232d6

Browse files
authored
Merge pull request #11 from gencay/vinsibal/cherrypick-rearrangement-algo
feat: add Rearrangement Algorithm Implementation (jquense#1473)
2 parents 5253568 + 75da33c commit 8f232d6

File tree

12 files changed

+667
-205
lines changed

12 files changed

+667
-205
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',
@@ -81,6 +83,7 @@ class Example extends React.Component {
8183
dnd: Dnd,
8284
dndresource: DndResource,
8385
dndOutsideSource: DndOutsideSource,
86+
createEventWithNoOverlap: CreateEventWithNoOverlap,
8487
}[selected]
8588

8689
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
@@ -7,6 +7,7 @@ import {
77
elementType,
88
dateFormat,
99
dateRangeFormat,
10+
DayLayoutAlgorithmPropType,
1011
views as componentViews,
1112
} from './utils/propTypes'
1213
import warning from 'warning'
@@ -733,6 +734,14 @@ class Calendar extends React.Component {
733734
noEventsInRange: PropTypes.node,
734735
showMore: PropTypes.func,
735736
}),
737+
738+
/**
739+
* A day event layout(arrangement) algorithm.
740+
* `overlap` allows events to be overlapped.
741+
* `no-overlap` resizes events to avoid overlap.
742+
* or custom `Function(events, minimumStartDifference, slotMetrics, accessors)`
743+
*/
744+
dayLayoutAlgorithm: DayLayoutAlgorithmPropType,
736745
}
737746

738747
static defaultProps = {
@@ -759,6 +768,7 @@ class Calendar extends React.Component {
759768

760769
longPressThreshold: 250,
761770
getNow: () => new Date(),
771+
dayLayoutAlgorithm: 'overlap',
762772
}
763773

764774
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)
@@ -69,7 +71,6 @@ class DayColumn extends React.Component {
6971
}
7072
}
7173

72-
intervalTriggered = false
7374
/**
7475
* @param tail {Boolean} - whether `positionTimeIndicator` call should be
7576
* deferred or called upon setting interval (`true` - if deferred);
@@ -186,6 +187,7 @@ class DayColumn extends React.Component {
186187
components,
187188
step,
188189
timeslots,
190+
dayLayoutAlgorithm,
189191
} = this.props
190192

191193
const { slotMetrics } = this
@@ -196,6 +198,7 @@ class DayColumn extends React.Component {
196198
accessors,
197199
slotMetrics,
198200
minimumStartDifference: Math.ceil((step * timeslots) / 2),
201+
dayLayoutAlgorithm,
199202
})
200203

201204
// TODO sort this on getStyledEvents instead
@@ -427,6 +430,8 @@ DayColumn.propTypes = {
427430
className: PropTypes.string,
428431
dragThroughEvents: PropTypes.bool,
429432
resource: PropTypes.any,
433+
434+
dayLayoutAlgorithm: DayLayoutAlgorithmPropType,
430435
}
431436

432437
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
})
@@ -325,6 +334,8 @@ TimeGrid.propTypes = {
325334
onDoubleClickEvent: PropTypes.func,
326335
onDrillDown: PropTypes.func,
327336
getDrilldownView: PropTypes.func.isRequired,
337+
338+
dayLayoutAlgorithm: DayLayoutAlgorithmPropType,
328339
}
329340

330341
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 cn from 'classnames'
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 {
@@ -66,10 +70,10 @@ function TimeGridEvent(props) {
6670
data-event-id={props.event && props.event.id}
6771
style={{
6872
...userProps.style,
69-
top: `${top}%`,
70-
height: `${height}%`,
71-
[isRtl ? 'right' : 'left']: `${Math.max(1, xOffset + 1)}%`,
72-
width: `${width}%`,
73+
top: stringifyPercent(top),
74+
[isRtl ? 'right' : 'left']: stringifyPercent(xOffset),
75+
width: stringifyPercent(width),
76+
height: stringifyPercent(height),
7377
}}
7478
title={
7579
tooltip

0 commit comments

Comments
 (0)