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

Rearrangement Algorithm Implementation #1473

Merged
merged 4 commits into from
Oct 17, 2019
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
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),
},
Comment on lines +114 to +161
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are for overlapping situation

]
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 @@ -718,6 +719,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 @@ -743,6 +752,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),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes the algorithm needs calc() so I just made it as 'string' || 'number'. number will be followed by %.

Maybe you think it is no good that I didn't make it all string only. Frankly I tried it but you know that plain css string is quite annoying for testing, right?

image

I also tried to parse() and floor() but... yeah... too much. so this is why.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its fine 👍

}}
title={
tooltip
Expand Down
Loading