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

Demo/move resize items moves timeline when item close to left right border #875

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
205 changes: 205 additions & 0 deletions demo/app/demo-scroll-close-to-borders/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
/* eslint-disable no-console */
import React, { Component } from 'react'
import moment from 'moment'

import Timeline, {
TimelineMarkers,
TodayMarker,
} from 'react-calendar-timeline'

import generateFakeData from '../generate-fake-data'

var minTime = moment()
.add(-6, 'months')
.valueOf()
var maxTime = moment()
.add(6, 'months')
.valueOf()

var keys = {
groupIdKey: 'id',
groupTitleKey: 'title',
groupRightTitleKey: 'rightTitle',
itemIdKey: 'id',
itemTitleKey: 'title',
itemDivTitleKey: 'title',
itemGroupKey: 'group',
itemTimeStartKey: 'start',
itemTimeEndKey: 'end'
}

export default class App extends Component {
constructor(props) {
super(props)
this.timelineComponent = React.createRef();

const { groups, items } = generateFakeData()
const defaultTimeStart = moment()
.startOf('day')
.toDate()
const defaultTimeEnd = moment()
.startOf('day')
.add(1, 'day')
.toDate()

this.state = {
groups,
items,
defaultTimeStart,
defaultTimeEnd
}
}

handleItemMove = (itemId, dragTime, newGroupOrder) => {
const { items, groups } = this.state

const group = groups[newGroupOrder]

this.setState({
items: items.map(
item =>
item.id === itemId
? Object.assign({}, item, {
start: dragTime,
end: dragTime + (item.end - item.start),
group: group.id
})
: item
)
})

console.log('Moved', itemId, dragTime, newGroupOrder)
}

handleItemResize = (itemId, time, edge) => {
const { items } = this.state

this.setState({
items: items.map(
item =>
item.id === itemId
? Object.assign({}, item, {
start: edge === 'left' ? time : item.start,
end: edge === 'left' ? item.end : time
})
: item
)
})

console.log('Resized', itemId, time, edge)
}

// this limits the timeline to -6 months ... +6 months
handleTimeChange = (visibleTimeStart, visibleTimeEnd, updateScrollCanvas) => {
if (visibleTimeStart < minTime && visibleTimeEnd > maxTime) {
updateScrollCanvas(minTime, maxTime)
} else if (visibleTimeStart < minTime) {
updateScrollCanvas(minTime, minTime + (visibleTimeEnd - visibleTimeStart))
} else if (visibleTimeEnd > maxTime) {
updateScrollCanvas(maxTime - (visibleTimeEnd - visibleTimeStart), maxTime)
} else {
updateScrollCanvas(visibleTimeStart, visibleTimeEnd)
}
}

handleZoom = (timelineContext, unit) => {
console.log('Zoomed', timelineContext, unit)
}

moveResizeValidator = (action, item, timeDONOTUSE, resizeEdge, e, dragStart) => {
if (action === 'move' && this.timelineComponent && this.timelineComponent.current && this.timelineComponent.current.state) {
const time = this.timelineComponent.current.timeFromItemEvent(e) // time from drag/resize event, DO NOT USE "time" param
const stateFrom = this.timelineComponent.current.state.visibleTimeStart;
const stateTo = this.timelineComponent.current.state.visibleTimeEnd;

const zoomMillis = Math.round((stateTo - stateFrom));
const closeToBorderTolerance = 3; // How close item to border enables the auto-scroll canvas, 2-5 are good values.

// Percent of the window area will be used for activanting the move Time window, will change base on zoom level
const timeBorderArea = Math.round(((zoomMillis * closeToBorderTolerance) / 100));
const duration = item.end - item.start;
const rightBorderTime = time + duration;

// Moves timeline to right, when item close to right border
if (rightBorderTime > stateTo - timeBorderArea) {
const newFrom = stateFrom + (timeBorderArea / closeToBorderTolerance);
const newTo = stateTo + (timeBorderArea / closeToBorderTolerance);

this.timelineComponent.current.updateScrollCanvas(newFrom, newTo);
return time + (dragStart.offset);
}

// Moves canvas to left, when item close to left border
if (time < stateFrom + timeBorderArea) {
const newFrom = stateFrom - (timeBorderArea / closeToBorderTolerance);
const newTo = stateTo - (timeBorderArea / closeToBorderTolerance);

this.timelineComponent.current.updateScrollCanvas(newFrom, newTo);
return time + (dragStart.offset);
}
}


if (action === 'resize' && this.timelineComponent && this.timelineComponent.current && this.timelineComponent.current.state) {
const time = this.timelineComponent.current.timeFromItemEvent(e) // time from drag/resize event, DO NOT USE "time" param
const stateFrom = this.timelineComponent.current.state.visibleTimeStart;
const stateTo = this.timelineComponent.current.state.visibleTimeEnd;

const zoomMillis = Math.round((stateTo - stateFrom));
const closeToBorderTolerance = 2; // How close item to border enables the auto-scroll canvas, 2-5 are good values.

// Percent of the window area will be used for activanting the move Time window, will change base on zoom level
const timeBorderArea = Math.round(((zoomMillis * closeToBorderTolerance) / 100));

// Moves timeline to right, when item close to right border
if (resizeEdge === 'right' && time > stateTo - timeBorderArea) {
const newFrom = stateFrom + (timeBorderArea / closeToBorderTolerance);
const newTo = stateTo + (timeBorderArea / closeToBorderTolerance);

this.timelineComponent.current.updateScrollCanvas(newFrom, newTo);
return time + (timeBorderArea / 2);
} else if (time < stateFrom + timeBorderArea) { // Moves canvas to left, when item close to left border
const newFrom = stateFrom - (timeBorderArea / closeToBorderTolerance);
const newTo = stateTo - (timeBorderArea / closeToBorderTolerance);

this.timelineComponent.current.updateScrollCanvas(newFrom, newTo);
return time - (timeBorderArea / 2);
}
}

return timeDONOTUSE;
}

render() {
const { groups, items, defaultTimeStart, defaultTimeEnd } = this.state

return (
<Timeline
ref={this.timelineComponent}
groups={groups}
items={items}
keys={keys}
sidebarWidth={150}
canMove
canResize="both"
canSelect
itemsSorted
itemTouchSendsClick={false}
stackItems
itemHeightRatio={0.75}
defaultTimeStart={defaultTimeStart}
defaultTimeEnd={defaultTimeEnd}
onItemMove={this.handleItemMove}
onItemResize={this.handleItemResize}
onTimeChange={this.handleTimeChange}
onZoom={this.handleZoom}
moveResizeValidator={this.moveResizeValidator}
buffer={3}
>
<TimelineMarkers>
<TodayMarker />
</TimelineMarkers>
</Timeline>
)
}
}
1 change: 1 addition & 0 deletions demo/app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const demos = {
customInfoLabel: require('./demo-custom-info-label').default,
controledSelect: require('./demo-controlled-select').default,
controlledScrolling: require('./demo-controlled-scrolling').default,
scrollCloseToBorders: require('./demo-scroll-close-to-borders').default,
}

// A simple component that shows the pathname of the current location
Expand Down
6 changes: 6 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,9 @@ Native info label was removed with 0.26.0 and now the responsibility to render t

[Example Codesandbox](https://codesandbox.io/s/timeline-demo-info-label-neec9)

## Move/Resize item close to left/right border, auto scroll timeline

This demo shows how to use the `moveResizeValidator()` function to move/resize an item close to the left/right border of the timeline, and auto scroll the timeline bounds to the direction of the move/resize item. By doing this you can keep moving/resizing the item without to stop, move timeline and move/resize again and item. Below you can check the example "scrollCloseToBorders"

[Example Codesandbox](https://codesandbox.io/p/github/davidbejarcaceres/react-calendar-timeline/demo/MoveResize-items-moves-timeline-when-item-close-to-left-right-border)

25 changes: 19 additions & 6 deletions src/lib/items/Item.js
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,10 @@ export default class Item extends Component {
dragStart: {
x: e.pageX,
y: e.pageY,
offset: this.itemTimeStart - clickTime },
clientX: e.clientX,
offset: this.itemTimeStart - clickTime,
itemTimeStart: this.itemTimeStart
},
preDragPosition: { x: e.target.offsetLeft, y: e.target.offsetTop },
dragTime: this.itemTimeStart,
dragGroupDelta: 0
Expand All @@ -265,7 +268,10 @@ export default class Item extends Component {
dragTime = this.props.moveResizeValidator(
'move',
this.props.item,
dragTime
dragTime,
null,
e,
this.state.dragStart
)
}

Expand All @@ -292,7 +298,10 @@ export default class Item extends Component {
dragTime = this.props.moveResizeValidator(
'move',
this.props.item,
dragTime
dragTime,
null,
e,
this.state.dragStart
)
}

Expand Down Expand Up @@ -339,7 +348,9 @@ export default class Item extends Component {
'resize',
this.props.item,
resizeTime,
resizeEdge
resizeEdge,
e,
this.state.dragStart
)
}

Expand All @@ -362,7 +373,9 @@ export default class Item extends Component {
'resize',
this.props.item,
resizeTime,
resizeEdge
resizeEdge,
e,
this.state.dragStart
)
}

Expand Down Expand Up @@ -425,7 +438,7 @@ export default class Item extends Component {
const willBeAbleToResizeRight =
this.props.selected && this.canResizeRight(this.props)

if(!!this.item){
if(this.item){
if (this.props.selected && !interactMounted) {
this.mountInteract()
interactMounted = true
Expand Down