Skip to content

Commit

Permalink
feat: add Rearrangement Algorithm Implementation (#1473)
Browse files Browse the repository at this point in the history
* Rearrangement Algorithm Implementation

* day layout algorithm as strategy pattern

* day layout algorithm css customizable

& move Event class into overlap algorithm

* restore yarn.lock
  • Loading branch information
ckcks12 authored and jquense committed Oct 17, 2019
1 parent 0c9b1f2 commit e622651
Show file tree
Hide file tree
Showing 12 changed files with 483 additions and 190 deletions.
3 changes: 3 additions & 0 deletions examples/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Card from './Card'
import ExampleControlSlot from './ExampleControlSlot'
import Basic from './demos/basic'
import Selectable from './demos/selectable'
import CreateEventWithNoOverlap from './demos/createEventWithNoOverlap'
import Cultures from './demos/cultures'
import Popup from './demos/popup'
import Rendering from './demos/rendering'
Expand All @@ -37,6 +38,7 @@ let demoRoot =
const EXAMPLES = {
basic: 'Basic Calendar',
selectable: 'Create events',
createEventWithNoOverlap: 'Create events with no-overlap algorithm',
cultures: 'Localization',
popup: 'Show more via a popup',
timeslots: 'Custom Time Grids',
Expand Down Expand Up @@ -82,6 +84,7 @@ class Example extends React.Component {
dnd: Dnd,
dndresource: DndResource,
dndOutsideSource: DndOutsideSource,
createEventWithNoOverlap: CreateEventWithNoOverlap,
}[selected]

return (
Expand Down
64 changes: 64 additions & 0 deletions examples/demos/createEventWithNoOverlap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React from 'react'
import { Calendar, Views } from 'react-big-calendar'
import events from '../events'
import ExampleControlSlot from '../ExampleControlSlot'
import _ from 'lodash'

const propTypes = {}

class CreateEventWithNoOverlap extends React.Component {
constructor(...args) {
super(...args)

this.state = {
events: _.cloneDeep(events),
dayLayoutAlgorithm: 'no-overlap',
}
}

handleSelect = ({ start, end }) => {
const title = window.prompt('New Event name')
if (title)
this.setState({
events: [
...this.state.events,
{
start,
end,
title,
},
],
})
}

render() {
const { localizer } = this.props
return (
<>
<ExampleControlSlot.Entry waitForOutlet>
<strong>
Click an event to see more info, or drag the mouse over the calendar
to select a date/time range.
<br />
The events are being arranged by `no-overlap` algorithm.
</strong>
</ExampleControlSlot.Entry>
<Calendar
selectable
localizer={localizer}
events={this.state.events}
defaultView={Views.WEEK}
scrollToTime={new Date(1970, 1, 1, 6)}
defaultDate={new Date(2015, 3, 12)}
onSelectEvent={event => alert(event.title)}
onSelectSlot={this.handleSelect}
dayLayoutAlgorithm={this.state.dayLayoutAlgorithm}
/>
</>
)
}
}

CreateEventWithNoOverlap.propTypes = propTypes

export default CreateEventWithNoOverlap
48 changes: 48 additions & 0 deletions examples/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,52 @@ export default [
start: now,
end: now,
},
{
id: 16,
title: 'Video Record',
start: new Date(2015, 3, 14, 15, 30, 0),
end: new Date(2015, 3, 14, 19, 0, 0),
},
{
id: 17,
title: 'Dutch Song Producing',
start: new Date(2015, 3, 14, 16, 30, 0),
end: new Date(2015, 3, 14, 20, 0, 0),
},
{
id: 18,
title: 'Itaewon Halloween Meeting',
start: new Date(2015, 3, 14, 16, 30, 0),
end: new Date(2015, 3, 14, 17, 30, 0),
},
{
id: 19,
title: 'Online Coding Test',
start: new Date(2015, 3, 14, 17, 30, 0),
end: new Date(2015, 3, 14, 20, 30, 0),
},
{
id: 20,
title: 'An overlapped Event',
start: new Date(2015, 3, 14, 17, 0, 0),
end: new Date(2015, 3, 14, 18, 30, 0),
},
{
id: 21,
title: 'Phone Interview',
start: new Date(2015, 3, 14, 17, 0, 0),
end: new Date(2015, 3, 14, 18, 30, 0),
},
{
id: 22,
title: 'Cooking Class',
start: new Date(2015, 3, 14, 17, 30, 0),
end: new Date(2015, 3, 14, 19, 0, 0),
},
{
id: 23,
title: 'Go to the gym',
start: new Date(2015, 3, 14, 18, 30, 0),
end: new Date(2015, 3, 14, 20, 0, 0),
},
]
10 changes: 10 additions & 0 deletions src/Calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
accessor,
dateFormat,
dateRangeFormat,
DayLayoutAlgorithmPropType,
views as componentViews,
} from './utils/propTypes'
import warning from 'warning'
Expand Down Expand Up @@ -719,6 +720,14 @@ class Calendar extends React.Component {
noEventsInRange: PropTypes.node,
showMore: PropTypes.func,
}),

/**
* A day event layout(arrangement) algorithm.
* `overlap` allows events to be overlapped.
* `no-overlap` resizes events to avoid overlap.
* or custom `Function(events, minimumStartDifference, slotMetrics, accessors)`
*/
dayLayoutAlgorithm: DayLayoutAlgorithmPropType,
}

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

longPressThreshold: 250,
getNow: () => new Date(),
dayLayoutAlgorithm: 'overlap',
}

constructor(...args) {
Expand Down
7 changes: 6 additions & 1 deletion src/DayColumn.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import { notify } from './utils/helpers'
import * as DayEventLayout from './utils/DayEventLayout'
import TimeSlotGroup from './TimeSlotGroup'
import TimeGridEvent from './TimeGridEvent'
import { DayLayoutAlgorithmPropType } from './utils/propTypes'

class DayColumn extends React.Component {
state = { selecting: false, timeIndicatorPosition: null }
intervalTriggered = false

constructor(...args) {
super(...args)
Expand Down Expand Up @@ -70,7 +72,6 @@ class DayColumn extends React.Component {
}
}

intervalTriggered = false
/**
* @param tail {Boolean} - whether `positionTimeIndicator` call should be
* deferred or called upon setting interval (`true` - if deferred);
Expand Down Expand Up @@ -183,6 +184,7 @@ class DayColumn extends React.Component {
components,
step,
timeslots,
dayLayoutAlgorithm,
} = this.props

const { slotMetrics } = this
Expand All @@ -193,6 +195,7 @@ class DayColumn extends React.Component {
accessors,
slotMetrics,
minimumStartDifference: Math.ceil((step * timeslots) / 2),
dayLayoutAlgorithm,
})

return styledEvents.map(({ event, style }, idx) => {
Expand Down Expand Up @@ -402,6 +405,8 @@ DayColumn.propTypes = {
className: PropTypes.string,
dragThroughEvents: PropTypes.bool,
resource: PropTypes.any,

dayLayoutAlgorithm: DayLayoutAlgorithmPropType,
}

DayColumn.defaultProps = {
Expand Down
13 changes: 12 additions & 1 deletion src/TimeGrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import TimeGridHeader from './TimeGridHeader'
import { notify } from './utils/helpers'
import { inRange, sortEvents } from './utils/eventLevels'
import Resources from './utils/Resources'
import { DayLayoutAlgorithmPropType } from './utils/propTypes'

export default class TimeGrid extends Component {
constructor(props) {
Expand Down Expand Up @@ -103,7 +104,14 @@ export default class TimeGrid extends Component {
}

renderEvents(range, events, now) {
let { min, max, components, accessors, localizer } = this.props
let {
min,
max,
components,
accessors,
localizer,
dayLayoutAlgorithm,
} = this.props

const resources = this.memoizedResources(this.props.resources, accessors)
const groupedEvents = resources.groupEvents(events)
Expand Down Expand Up @@ -131,6 +139,7 @@ export default class TimeGrid extends Component {
key={i + '-' + jj}
date={date}
events={daysEvents}
dayLayoutAlgorithm={dayLayoutAlgorithm}
/>
)
})
Expand Down Expand Up @@ -328,6 +337,8 @@ TimeGrid.propTypes = {
onDoubleClickEvent: PropTypes.func,
onDrillDown: PropTypes.func,
getDrilldownView: PropTypes.func.isRequired,

dayLayoutAlgorithm: DayLayoutAlgorithmPropType,
}

TimeGrid.defaultProps = {
Expand Down
12 changes: 8 additions & 4 deletions src/TimeGridEvent.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import clsx from 'clsx'
import React from 'react'

function stringifyPercent(v) {
return typeof v === 'string' ? v : v + '%'
}

/* eslint-disable react/prop-types */
function TimeGridEvent(props) {
const {
Expand Down Expand Up @@ -42,10 +46,10 @@ function TimeGridEvent(props) {
onDoubleClick={onDoubleClick}
style={{
...userProps.style,
top: `${top}%`,
height: `${height}%`,
[rtl ? 'right' : 'left']: `${Math.max(0, xOffset)}%`,
width: `${width}%`,
top: stringifyPercent(top),
[rtl ? 'right' : 'left']: stringifyPercent(xOffset),
width: stringifyPercent(width),
height: stringifyPercent(height),
}}
title={
tooltip
Expand Down
Loading

0 comments on commit e622651

Please sign in to comment.