From d85ad6721f963dbfac97c4d546846f00719a678f Mon Sep 17 00:00:00 2001 From: Alex Maclean Date: Fri, 3 Aug 2018 08:28:12 +1000 Subject: [PATCH 01/34] Can stack items by group --- README.md | 5 +- src/lib/Timeline.js | 12 ++- src/lib/items/Item.js | 14 ++-- src/lib/items/Items.js | 12 +-- src/lib/utility/calendar.js | 150 +++++++++++++++++------------------- 5 files changed, 91 insertions(+), 102 deletions(-) diff --git a/README.md b/README.md index 8693e67ae..c6ee2eaed 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,8 @@ Expects either a vanilla JS array or an immutableJS array, consisting of objects { id: 1, title: 'group 1', - rightTitle: 'title in the right sidebar' + rightTitle: 'title in the right sidebar', + stackItems?: true } ``` @@ -232,7 +233,7 @@ Append a special `.rct-drag-right` handle to the elements and only resize if dra ### stackItems -Stack items under each other, so there is no visual overlap when times collide. Defaults to `false`. +Stack items under each other, so there is no visual overlap when times collide. Can be overridden in the `groups` array. Defaults to `false`. ## traditionalZoom diff --git a/src/lib/Timeline.js b/src/lib/Timeline.js index 90754af05..9803f3c02 100644 --- a/src/lib/Timeline.js +++ b/src/lib/Timeline.js @@ -16,8 +16,7 @@ import windowResizeDetector from '../resize-detector/window' import { getMinUnit, getNextUnit, - stack, - nostack, + stackAll, calculateDimensions, getGroupOrders, getVisibleItems, @@ -1000,7 +999,7 @@ export default class ReactCalendarTimeline extends Component { dimension.top = null dimension.order = isDragging ? newGroupOrder - : groupOrders[_get(item, keys.itemGroupKey)] + : groupOrders[_get(item, keys.itemGroupKey)].index dimension.stack = !item.isOverlay dimension.height = lineHeight * itemHeightRatio dimension.isDragging = isDragging @@ -1014,12 +1013,11 @@ export default class ReactCalendarTimeline extends Component { return memo }, []) - const stackingMethod = stackItems ? stack : nostack - - const { height, groupHeights, groupTops } = stackingMethod( + const { height, groupHeights, groupTops } = stackAll( dimensionItems, groupOrders, - lineHeight + lineHeight, + stackItems ) return { dimensionItems, height, groupHeights, groupTops } diff --git a/src/lib/items/Item.js b/src/lib/items/Item.js index 5a7cded4e..672561289 100644 --- a/src/lib/items/Item.js +++ b/src/lib/items/Item.js @@ -26,7 +26,7 @@ export default class Item extends Component { canvasTimeStart: PropTypes.number.isRequired, canvasTimeEnd: PropTypes.number.isRequired, canvasWidth: PropTypes.number.isRequired, - order: PropTypes.number, + order: PropTypes.object, dragSnap: PropTypes.number, minResizeWidth: PropTypes.number, @@ -102,7 +102,7 @@ export default class Item extends Component { nextProps.canvasTimeStart !== this.props.canvasTimeStart || nextProps.canvasTimeEnd !== this.props.canvasTimeEnd || nextProps.canvasWidth !== this.props.canvasWidth || - nextProps.order !== this.props.order || + nextProps.order.index !== this.props.order.index || nextProps.dragSnap !== this.props.dragSnap || nextProps.minResizeWidth !== this.props.minResizeWidth || nextProps.canChangeGroup !== this.props.canChangeGroup || @@ -174,14 +174,14 @@ export default class Item extends Component { for (var key of Object.keys(groupTops)) { var item = groupTops[key] if (e.pageY - topOffset > item) { - groupDelta = parseInt(key, 10) - order + groupDelta = parseInt(key, 10) - order.index } else { break } } - if (this.props.order + groupDelta < 0) { - return 0 - this.props.order + if (this.props.order.index + groupDelta < 0) { + return 0 - this.props.order.index } else { return groupDelta } @@ -259,7 +259,7 @@ export default class Item extends Component { this.props.onDrag( this.itemId, dragTime, - this.props.order + dragGroupDelta + this.props.order.index + dragGroupDelta ) } @@ -285,7 +285,7 @@ export default class Item extends Component { this.props.onDrop( this.itemId, dragTime, - this.props.order + this.dragGroupDelta(e) + this.props.order.index + this.dragGroupDelta(e) ) } diff --git a/src/lib/items/Items.js b/src/lib/items/Items.js index b34d18d94..d68034414 100644 --- a/src/lib/items/Items.js +++ b/src/lib/items/Items.js @@ -82,12 +82,6 @@ export default class Items extends Component { ) } - getGroupOrders() { - const { keys, groups } = this.props - - return getGroupOrders(groups, keys) - } - isSelected(item, itemIdKey) { if (!this.props.selected) { return this.props.selectedItem === _get(item, itemIdKey) @@ -108,10 +102,12 @@ export default class Items extends Component { canvasTimeStart, canvasTimeEnd, dimensionItems, + keys, + groups } = this.props - const { itemIdKey, itemGroupKey } = this.props.keys + const { itemIdKey, itemGroupKey } = keys - const groupOrders = this.getGroupOrders() + const groupOrders = getGroupOrders(groups, keys) const visibleItems = this.getVisibleItems( canvasTimeStart, canvasTimeEnd, diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 4add2d39b..3a8a13a3f 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -193,33 +193,39 @@ export function calculateDimensions({ return dimensions } +// Get the order of groups based on their keys export function getGroupOrders(groups, keys) { const { groupIdKey } = keys let groupOrders = {} for (let i = 0; i < groups.length; i++) { - groupOrders[_get(groups[i], groupIdKey)] = i + groupOrders[_get(groups[i], groupIdKey)] = {index: i, group: groups[i]} } return groupOrders } -export function getGroupedItems(items, groupOrders) { - var arr = [] - - // Initialize with empty arrays for each group +function getGroupedItems(items, groupOrders) { + var groupedItems = {} + // Initialize with result object for each group for (let i = 0; i < Object.keys(groupOrders).length; i++) { - arr[i] = [] + const groupOrder = groupOrders[Object.keys(groupOrders)[i]] + groupedItems[i] = { + index: groupOrder.index, + group: groupOrder.group, + items: [] + } } + // Populate groups for (let i = 0; i < items.length; i++) { if (items[i].dimensions.order !== undefined) { - arr[items[i].dimensions.order].push(items[i]) + groupedItems[items[i].dimensions.order].items.push(items[i]) } } - return arr + return groupedItems } export function getVisibleItems(items, canvasTimeStart, canvasTimeEnd, keys) { @@ -247,70 +253,53 @@ export function collision(a, b, lineHeight, collisionPadding = EPSILON) { ) } -export function stack(items, groupOrders, lineHeight) { - var i, iMax - var totalHeight = 0 - - var groupHeights = [] - var groupTops = [] - - var groupedItems = getGroupedItems(items, groupOrders) - - groupedItems.forEach(function(group) { - // calculate new, non-overlapping positions - groupTops.push(totalHeight) +function groupStack(lineHeight, item, group, groupHeight, totalHeight, i) { + // calculate non-overlapping positions + let x = groupHeight + let verticalMargin = lineHeight - item.dimensions.height + if (item.dimensions.stack && item.dimensions.top === null) { + item.dimensions.top = totalHeight + verticalMargin + x = Math.max(x, lineHeight) + do { + var collidingItem = null + for (var j = i-1, jj = 0; j >= jj; j--) { + var other = group[j] + if ( + other.dimensions.top !== null && + other.dimensions.stack && + collision(item.dimensions, other.dimensions, lineHeight) + ) { + collidingItem = other + break + } else { + // console.log('dont test', other.top !== null, other !== item, other.stack); + } + } - var groupHeight = 0 - var verticalMargin = 0 - for (i = 0, iMax = group.length; i < iMax; i++) { - var item = group[i] - verticalMargin = lineHeight - item.dimensions.height - - if (item.dimensions.stack && item.dimensions.top === null) { - item.dimensions.top = totalHeight + verticalMargin - groupHeight = Math.max(groupHeight, lineHeight) - do { - var collidingItem = null - for (var j = 0, jj = group.length; j < jj; j++) { - var other = group[j] - if ( - other.dimensions.top !== null && - other !== item && - other.dimensions.stack && - collision(item.dimensions, other.dimensions, lineHeight) - ) { - collidingItem = other - break - } else { - // console.log('dont test', other.top !== null, other !== item, other.stack); - } - } - - if (collidingItem != null) { - // There is a collision. Reposition the items above the colliding element - item.dimensions.top = collidingItem.dimensions.top + lineHeight - groupHeight = Math.max( - groupHeight, - item.dimensions.top + item.dimensions.height - totalHeight - ) - } - } while (collidingItem) + if (collidingItem != null) { + // There is a collision. Reposition the items above the colliding element + item.dimensions.top = collidingItem.dimensions.top + lineHeight + x = Math.max( + x, + item.dimensions.top + item.dimensions.height - totalHeight + ) } - } + } while (collidingItem) + } + return {groupHeight: x, verticalMargin} +} - groupHeights.push(Math.max(groupHeight + verticalMargin, lineHeight)) - totalHeight += Math.max(groupHeight + verticalMargin, lineHeight) - }) - return { - height: totalHeight, - groupHeights, - groupTops +function groupNoStack(lineHeight, item, groupHeight, totalHeight) { + let verticalMargin = (lineHeight - item.dimensions.height) / 2 + if (item.dimensions.top === null) { + item.dimensions.top = totalHeight + verticalMargin + groupHeight = Math.max(groupHeight, lineHeight) } + return {groupHeight, verticalMargin: 0} } -export function nostack(items, groupOrders, lineHeight) { +export function stackAll(items, groupOrders, lineHeight, stackItems) { var i, iMax - var totalHeight = 0 var groupHeights = [] @@ -318,24 +307,29 @@ export function nostack(items, groupOrders, lineHeight) { var groupedItems = getGroupedItems(items, groupOrders) - groupedItems.forEach(function(group) { - // calculate new, non-overlapping positions + for (var index in groupedItems) { + const groupItems = groupedItems[index] + const {items, group} = groupItems groupTops.push(totalHeight) - + const isGroupStacked = group.stackItems !== undefined ? group.stackItems : stackItems var groupHeight = 0 - for (i = 0, iMax = group.length; i < iMax; i++) { - var item = group[i] - var verticalMargin = (lineHeight - item.dimensions.height) / 2 - - if (item.dimensions.top === null) { - item.dimensions.top = totalHeight + verticalMargin - groupHeight = Math.max(groupHeight, lineHeight) + var verticalMargin = 0 + for (i = 0, iMax = items.length; i < iMax; i++) { + let r = {} + if (isGroupStacked) { + r = groupStack(lineHeight, items[i], items, groupHeight, totalHeight, i) + } else { + r = groupNoStack(lineHeight, items[i], groupHeight, totalHeight) } + groupHeight = r.groupHeight + verticalMargin = r.verticalMargin + } - groupHeights.push(Math.max(groupHeight, lineHeight)) - totalHeight += Math.max(groupHeight, lineHeight) - }) + + groupHeights.push(Math.max(groupHeight + verticalMargin, lineHeight)) + totalHeight += Math.max(groupHeight + verticalMargin, lineHeight) + } return { height: totalHeight, groupHeights, From 5cd2a488140349b8a6efcf6b3ddddce599ef2739 Mon Sep 17 00:00:00 2001 From: Alex Maclean Date: Mon, 20 Aug 2018 10:52:14 +1000 Subject: [PATCH 02/34] comments --- demo/app/demo-performance/index.js | 2 + src/lib/Timeline.js.orig | 1224 ++++++++++++++++++++++++++++ src/lib/utility/calendar.js | 25 +- 3 files changed, 1241 insertions(+), 10 deletions(-) create mode 100644 src/lib/Timeline.js.orig diff --git a/demo/app/demo-performance/index.js b/demo/app/demo-performance/index.js index a1c4922ed..97c940d00 100644 --- a/demo/app/demo-performance/index.js +++ b/demo/app/demo-performance/index.js @@ -37,6 +37,8 @@ export default class App extends Component { .endOf('month') .toDate() + groups[0].stackItems = false; + groups[0].height = 300; this.state = { groups, items, diff --git a/src/lib/Timeline.js.orig b/src/lib/Timeline.js.orig new file mode 100644 index 000000000..be8cfb6bf --- /dev/null +++ b/src/lib/Timeline.js.orig @@ -0,0 +1,1224 @@ +import PropTypes from 'prop-types' +import React, { Component } from 'react' +import moment from 'moment' + +import Items from './items/Items' +import InfoLabel from './layout/InfoLabel' +import Sidebar from './layout/Sidebar' +import Header from './layout/Header' +import Columns from './columns/Columns' +import GroupRows from './row/GroupRows' +import ScrollElement from './scroll/ScrollElement' +import MarkerCanvas from './markers/MarkerCanvas' + +import windowResizeDetector from '../resize-detector/window' + +import { + getMinUnit, + getNextUnit, + stackAll, + calculateDimensions, + getGroupOrders, + getVisibleItems, + calculateTimeForXPosition +} from './utility/calendar' +import { _get, _length } from './utility/generic' +import { + defaultKeys, + defaultTimeSteps, + defaultHeaderLabelFormats, + defaultSubHeaderLabelFormats +} from './default-config' +import { TimelineStateProvider } from './timeline/TimelineStateContext' +import { TimelineMarkersProvider } from './markers/TimelineMarkersContext' + +export default class ReactCalendarTimeline extends Component { + static propTypes = { + groups: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired, + items: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired, + sidebarWidth: PropTypes.number, + sidebarContent: PropTypes.node, + rightSidebarWidth: PropTypes.number, + rightSidebarContent: PropTypes.node, + dragSnap: PropTypes.number, + minResizeWidth: PropTypes.number, + stickyOffset: PropTypes.number, + stickyHeader: PropTypes.bool, + lineHeight: PropTypes.number, + headerLabelGroupHeight: PropTypes.number, + headerLabelHeight: PropTypes.number, + itemHeightRatio: PropTypes.number, + + minZoom: PropTypes.number, + maxZoom: PropTypes.number, + + clickTolerance: PropTypes.number, + + canChangeGroup: PropTypes.bool, + canMove: PropTypes.bool, + canResize: PropTypes.oneOf([true, false, 'left', 'right', 'both']), + useResizeHandle: PropTypes.bool, + canSelect: PropTypes.bool, + + stackItems: PropTypes.bool, + + traditionalZoom: PropTypes.bool, + + itemTouchSendsClick: PropTypes.bool, + + horizontalLineClassNamesForGroup: PropTypes.func, + + onItemMove: PropTypes.func, + onItemResize: PropTypes.func, + onItemClick: PropTypes.func, + onItemSelect: PropTypes.func, + onItemDeselect: PropTypes.func, + onCanvasClick: PropTypes.func, + onItemDoubleClick: PropTypes.func, + onItemContextMenu: PropTypes.func, + onCanvasDoubleClick: PropTypes.func, + onCanvasContextMenu: PropTypes.func, + onZoom: PropTypes.func, + + moveResizeValidator: PropTypes.func, + + itemRenderer: PropTypes.func, + groupRenderer: PropTypes.func, + + style: PropTypes.object, + + keys: PropTypes.shape({ + groupIdKey: PropTypes.string, + groupTitleKey: PropTypes.string, + groupRightTitleKey: PropTypes.string, + itemIdKey: PropTypes.string, + itemTitleKey: PropTypes.string, + itemDivTitleKey: PropTypes.string, + itemGroupKey: PropTypes.string, + itemTimeStartKey: PropTypes.string, + itemTimeEndKey: PropTypes.string + }), + headerRef: PropTypes.func, + scrollRef: PropTypes.func, + + timeSteps: PropTypes.shape({ + second: PropTypes.number, + minute: PropTypes.number, + hour: PropTypes.number, + day: PropTypes.number, + month: PropTypes.number, + year: PropTypes.number + }), + + defaultTimeStart: PropTypes.object, + defaultTimeEnd: PropTypes.object, + + visibleTimeStart: PropTypes.number, + visibleTimeEnd: PropTypes.number, + onTimeChange: PropTypes.func, + onBoundsChange: PropTypes.func, + + selected: PropTypes.array, + + headerLabelFormats: PropTypes.shape({ + yearShort: PropTypes.string, + yearLong: PropTypes.string, + monthShort: PropTypes.string, + monthMedium: PropTypes.string, + monthMediumLong: PropTypes.string, + monthLong: PropTypes.string, + dayShort: PropTypes.string, + dayLong: PropTypes.string, + hourShort: PropTypes.string, + hourMedium: PropTypes.string, + hourMediumLong: PropTypes.string, + hourLong: PropTypes.string + }), + + subHeaderLabelFormats: PropTypes.shape({ + yearShort: PropTypes.string, + yearLong: PropTypes.string, + monthShort: PropTypes.string, + monthMedium: PropTypes.string, + monthLong: PropTypes.string, + dayShort: PropTypes.string, + dayMedium: PropTypes.string, + dayMediumLong: PropTypes.string, + dayLong: PropTypes.string, + hourShort: PropTypes.string, + hourLong: PropTypes.string, + minuteShort: PropTypes.string, + minuteLong: PropTypes.string + }), + + resizeDetector: PropTypes.shape({ + addListener: PropTypes.func, + removeListener: PropTypes.func + }), + + verticalLineClassNamesForTime: PropTypes.func, + + children: PropTypes.node + } + + static defaultProps = { + sidebarWidth: 150, + rightSidebarWidth: 0, + dragSnap: 1000 * 60 * 15, // 15min + minResizeWidth: 20, + stickyOffset: 0, + stickyHeader: true, + lineHeight: 30, + headerLabelGroupHeight: 30, + headerLabelHeight: 30, + itemHeightRatio: 0.65, + + minZoom: 60 * 60 * 1000, // 1 hour + maxZoom: 5 * 365.24 * 86400 * 1000, // 5 years + + clickTolerance: 3, // how many pixels can we drag for it to be still considered a click? + + canChangeGroup: true, + canMove: true, + canResize: 'right', + useResizeHandle: false, + canSelect: true, + + stackItems: false, + + traditionalZoom: false, + + horizontalLineClassNamesForGroup: null, + + onItemMove: null, + onItemResize: null, + onItemClick: null, + onItemSelect: null, + onItemDeselect: null, + onCanvasClick: null, + onItemDoubleClick: null, + onItemContextMenu: null, + onZoom: null, + + verticalLineClassNamesForTime: null, + + moveResizeValidator: null, + + dayBackground: null, + + defaultTimeStart: null, + defaultTimeEnd: null, + + itemTouchSendsClick: false, + + style: {}, + keys: defaultKeys, + timeSteps: defaultTimeSteps, + headerRef: () => {}, + scrollRef: () => {}, + + // if you pass in visibleTimeStart and visibleTimeEnd, you must also pass onTimeChange(visibleTimeStart, visibleTimeEnd), + // which needs to update the props visibleTimeStart and visibleTimeEnd to the ones passed + visibleTimeStart: null, + visibleTimeEnd: null, + onTimeChange: function( + visibleTimeStart, + visibleTimeEnd, + updateScrollCanvas + ) { + updateScrollCanvas(visibleTimeStart, visibleTimeEnd) + }, + // called when the canvas area of the calendar changes + onBoundsChange: null, + children: null, + + headerLabelFormats: defaultHeaderLabelFormats, + subHeaderLabelFormats: defaultSubHeaderLabelFormats, + + selected: null + } + + static childContextTypes = { + getTimelineContext: PropTypes.func + } + + getChildContext() { + return { + getTimelineContext: () => { + return this.getTimelineContext() + } + } + } + + getTimelineContext = () => { + const { + width, + visibleTimeStart, + visibleTimeEnd, + canvasTimeStart + } = this.state + const zoom = visibleTimeEnd - visibleTimeStart + const canvasTimeEnd = canvasTimeStart + zoom * 3 + + return { + timelineWidth: width, + visibleTimeStart, + visibleTimeEnd, + canvasTimeStart, + canvasTimeEnd + } + } + + constructor(props) { + super(props) + + let visibleTimeStart = null + let visibleTimeEnd = null + + if (this.props.defaultTimeStart && this.props.defaultTimeEnd) { + visibleTimeStart = this.props.defaultTimeStart.valueOf() + visibleTimeEnd = this.props.defaultTimeEnd.valueOf() + } else if (this.props.visibleTimeStart && this.props.visibleTimeEnd) { + visibleTimeStart = this.props.visibleTimeStart + visibleTimeEnd = this.props.visibleTimeEnd + } else { + //throwing an error because neither default or visible time props provided + throw new Error( + 'You must provide either "defaultTimeStart" and "defaultTimeEnd" or "visibleTimeStart" and "visibleTimeEnd" to initialize the Timeline' + ) + } + + this.state = { + width: 1000, + + visibleTimeStart: visibleTimeStart, + visibleTimeEnd: visibleTimeEnd, + canvasTimeStart: visibleTimeStart - (visibleTimeEnd - visibleTimeStart), + + selectedItem: null, + dragTime: null, + dragGroupTitle: null, + resizeTime: null, + topOffset: 0, + resizingItem: null, + resizingEdge: null + } + + const { dimensionItems, height, groupHeights, groupTops } = this.stackItems( + props.items, + props.groups, + this.state.canvasTimeStart, + this.state.visibleTimeStart, + this.state.visibleTimeEnd, + this.state.width + ) + + /* eslint-disable react/no-direct-mutation-state */ + this.state.dimensionItems = dimensionItems + this.state.height = height + this.state.groupHeights = groupHeights + this.state.groupTops = groupTops + + /* eslint-enable */ + } + + componentDidMount() { + this.resize(this.props) + + if (this.props.resizeDetector && this.props.resizeDetector.addListener) { + this.props.resizeDetector.addListener(this) + } + + windowResizeDetector.addListener(this) + + this.lastTouchDistance = null + } + + componentWillUnmount() { + if (this.props.resizeDetector && this.props.resizeDetector.addListener) { + this.props.resizeDetector.removeListener(this) + } + + windowResizeDetector.removeListener(this) + } + + resize = (props = this.props) => { + const { + width: containerWidth, + top: containerTop + } = this.container.getBoundingClientRect() + + let width = containerWidth - props.sidebarWidth - props.rightSidebarWidth + const { headerLabelGroupHeight, headerLabelHeight } = props + const headerHeight = headerLabelGroupHeight + headerLabelHeight + + const { dimensionItems, height, groupHeights, groupTops } = this.stackItems( + props.items, + props.groups, + this.state.canvasTimeStart, + this.state.visibleTimeStart, + this.state.visibleTimeEnd, + width + ) + + // this is needed by dragItem since it uses pageY from the drag events + // if this was in the context of the scrollElement, this would not be necessary + const topOffset = containerTop + window.pageYOffset + headerHeight + + this.setState({ + width, + topOffset, + dimensionItems, + height, + groupHeights, + groupTops + }) + this.scrollComponent.scrollLeft = width + } + + // FIXME: this function calls set state EVERY TIME YOU SCROLL + onScroll = scrollX => { + const canvasTimeStart = this.state.canvasTimeStart + + const zoom = this.state.visibleTimeEnd - this.state.visibleTimeStart + const width = this.state.width + const visibleTimeStart = canvasTimeStart + zoom * scrollX / width + + if (scrollX < this.state.width * 0.5) { + this.setState({ + canvasTimeStart: this.state.canvasTimeStart - zoom + }) + } + if (scrollX > this.state.width * 1.5) { + this.setState({ + canvasTimeStart: this.state.canvasTimeStart + zoom + }) + } + + if ( + this.state.visibleTimeStart !== visibleTimeStart || + this.state.visibleTimeEnd !== visibleTimeStart + zoom + ) { + this.props.onTimeChange( + visibleTimeStart, + visibleTimeStart + zoom, + this.updateScrollCanvas + ) + } + + this.setState({ + currentScrollLeft: scrollX + }) + } + + componentWillReceiveProps(nextProps) { + const { + visibleTimeStart, + visibleTimeEnd, + items, + groups, + sidebarWidth + } = nextProps + + if (visibleTimeStart && visibleTimeEnd) { + this.updateScrollCanvas( + visibleTimeStart, + visibleTimeEnd, + items !== this.props.items || groups !== this.props.groups, + items, + groups + ) + } else if (items !== this.props.items || groups !== this.props.groups) { + this.updateDimensions(items, groups) + } + + // resize if the sidebar width changed + if (sidebarWidth !== this.props.sidebarWidth && items && groups) { + this.resize(nextProps) + } + } + + updateDimensions(items, groups) { + const { + canvasTimeStart, + visibleTimeStart, + visibleTimeEnd, + width + } = this.state + const { dimensionItems, height, groupHeights, groupTops } = this.stackItems( + items, + groups, + canvasTimeStart, + visibleTimeStart, + visibleTimeEnd, + width + ) + + this.setState({ dimensionItems, height, groupHeights, groupTops }) + } + + // called when the visible time changes + updateScrollCanvas = ( + visibleTimeStart, + visibleTimeEnd, + forceUpdateDimensions, + updatedItems, + updatedGroups + ) => { + const oldCanvasTimeStart = this.state.canvasTimeStart + const oldZoom = this.state.visibleTimeEnd - this.state.visibleTimeStart + const newZoom = visibleTimeEnd - visibleTimeStart + const items = updatedItems || this.props.items + const groups = updatedGroups || this.props.groups + + let newState = { + visibleTimeStart: visibleTimeStart, + visibleTimeEnd: visibleTimeEnd + } + + let resetCanvas = false + + const canKeepCanvas = + visibleTimeStart >= oldCanvasTimeStart + oldZoom * 0.5 && + visibleTimeStart <= oldCanvasTimeStart + oldZoom * 1.5 && + visibleTimeEnd >= oldCanvasTimeStart + oldZoom * 1.5 && + visibleTimeEnd <= oldCanvasTimeStart + oldZoom * 2.5 + + // if new visible time is in the right canvas area + if (canKeepCanvas) { + // but we need to update the scroll + const newScrollLeft = Math.round( + this.state.width * (visibleTimeStart - oldCanvasTimeStart) / newZoom + ) + if (this.scrollComponent.scrollLeft !== newScrollLeft) { + resetCanvas = true + } + } else { + resetCanvas = true + } + + if (resetCanvas) { + newState.canvasTimeStart = visibleTimeStart - newZoom + this.scrollComponent.scrollLeft = this.state.width + + if (this.props.onBoundsChange) { + this.props.onBoundsChange( + newState.canvasTimeStart, + newState.canvasTimeStart + newZoom * 3 + ) + } + } + + if (resetCanvas || forceUpdateDimensions) { + const canvasTimeStart = newState.canvasTimeStart + ? newState.canvasTimeStart + : oldCanvasTimeStart + const { + dimensionItems, + height, + groupHeights, + groupTops + } = this.stackItems( + items, + groups, + canvasTimeStart, + visibleTimeStart, + visibleTimeEnd, + this.state.width + ) + newState.dimensionItems = dimensionItems + newState.height = height + newState.groupHeights = groupHeights + newState.groupTops = groupTops + } + + this.setState(newState, () => { + // are we changing zoom? Well then let's report it + // need to wait until state is set so that we get current + // timeline context + if (this.props.onZoom && oldZoom !== newZoom) { + this.props.onZoom(this.getTimelineContext()) + } + }) + } + + handleWheelZoom = (speed, xPosition, deltaY) => { + this.changeZoom(1.0 + speed * deltaY / 500, xPosition / this.state.width) + } + + changeZoom = (scale, offset = 0.5) => { + const { minZoom, maxZoom } = this.props + const oldZoom = this.state.visibleTimeEnd - this.state.visibleTimeStart + const newZoom = Math.min( + Math.max(Math.round(oldZoom * scale), minZoom), + maxZoom + ) // min 1 min, max 20 years + const newVisibleTimeStart = Math.round( + this.state.visibleTimeStart + (oldZoom - newZoom) * offset + ) + + this.props.onTimeChange( + newVisibleTimeStart, + newVisibleTimeStart + newZoom, + this.updateScrollCanvas + ) + } + + showPeriod = (from, unit) => { + let visibleTimeStart = from.valueOf() + let visibleTimeEnd = moment(from) + .add(1, unit) + .valueOf() + let zoom = visibleTimeEnd - visibleTimeStart + + // can't zoom in more than to show one hour + if (zoom < 360000) { + return + } + + // clicked on the big header and already focused here, zoom out + if ( + unit !== 'year' && + this.state.visibleTimeStart === visibleTimeStart && + this.state.visibleTimeEnd === visibleTimeEnd + ) { + let nextUnit = getNextUnit(unit) + + visibleTimeStart = from.startOf(nextUnit).valueOf() + visibleTimeEnd = moment(visibleTimeStart).add(1, nextUnit) + zoom = visibleTimeEnd - visibleTimeStart + } + + this.props.onTimeChange( + visibleTimeStart, + visibleTimeStart + zoom, + this.updateScrollCanvas + ) + } + + selectItem = (item, clickType, e) => { + if ( + this.state.selectedItem === item || + (this.props.itemTouchSendsClick && clickType === 'touch') + ) { + if (item && this.props.onItemClick) { + const time = this.timeFromItemEvent(e) + this.props.onItemClick(item, e, time) + } + } else { + this.setState({ selectedItem: item }) + if (item && this.props.onItemSelect) { + const time = this.timeFromItemEvent(e) + this.props.onItemSelect(item, e, time) + } else if (item === null && this.props.onItemDeselect) { + this.props.onItemDeselect(e) // this isnt in the docs. Is this function even used? + } + } + } + + doubleClickItem = (item, e) => { + if (this.props.onItemDoubleClick) { + const time = this.timeFromItemEvent(e) + this.props.onItemDoubleClick(item, e, time) + } + } + + contextMenuClickItem = (item, e) => { + if (this.props.onItemContextMenu) { + const time = this.timeFromItemEvent(e) + this.props.onItemContextMenu(item, e, time) + } + } + + // TODO: this is very similar to timeFromItemEvent, aside from which element to get offsets + // from. Look to consolidate the logic for determining coordinate to time + // as well as generalizing how we get time from click on the canvas + getTimeFromRowClickEvent = e => { + const { dragSnap } = this.props + const { + width, + canvasTimeStart, + visibleTimeStart, + visibleTimeEnd + } = this.state + // this gives us distance from left of row element, so event is in + // context of the row element, not client or page + const { offsetX } = e.nativeEvent + + // FIXME: DRY up way to calculate canvasTimeEnd + const zoom = visibleTimeEnd - visibleTimeStart + const canvasTimeEnd = zoom * 3 + canvasTimeStart + + let time = calculateTimeForXPosition( + canvasTimeStart, + canvasTimeEnd, + width * 3, + offsetX + ) + time = Math.floor(time / dragSnap) * dragSnap + + return time + } + + timeFromItemEvent = e => { + const { width, visibleTimeStart, visibleTimeEnd } = this.state + const { dragSnap } = this.props + + const scrollComponent = this.scrollComponent + const { left: scrollX } = scrollComponent.getBoundingClientRect() + + const xRelativeToTimeline = e.clientX - scrollX + + const relativeItemPosition = xRelativeToTimeline / width + const zoom = visibleTimeEnd - visibleTimeStart + const timeOffset = relativeItemPosition * zoom + + let time = Math.round(visibleTimeStart + timeOffset) + time = Math.floor(time / dragSnap) * dragSnap + + return time + } + + dragItem = (item, dragTime, newGroupOrder) => { + let newGroup = this.props.groups[newGroupOrder] + const keys = this.props.keys + + this.setState({ + draggingItem: item, + dragTime: dragTime, + newGroupOrder: newGroupOrder, + dragGroupTitle: newGroup ? _get(newGroup, keys.groupTitleKey) : '' + }) + } + + dropItem = (item, dragTime, newGroupOrder) => { + this.setState({ draggingItem: null, dragTime: null, dragGroupTitle: null }) + if (this.props.onItemMove) { + this.props.onItemMove(item, dragTime, newGroupOrder) + } + } + + resizingItem = (item, resizeTime, edge) => { + this.setState({ + resizingItem: item, + resizingEdge: edge, + resizeTime: resizeTime + }) + } + + resizedItem = (item, resizeTime, edge, timeDelta) => { + this.setState({ resizingItem: null, resizingEdge: null, resizeTime: null }) + if (this.props.onItemResize && timeDelta !== 0) { + this.props.onItemResize(item, resizeTime, edge) + } + } + + columns( + canvasTimeStart, + canvasTimeEnd, + canvasWidth, + minUnit, + timeSteps, + height + ) { + return ( + + ) + } + + handleRowClick = (e, rowIndex) => { + // shouldnt this be handled by the user, as far as when to deselect an item? + if (this.state.selectedItem) { + this.selectItem(null) + } + + if (this.props.onCanvasClick == null) return + + const time = this.getTimeFromRowClickEvent(e) + const groupId = _get( + this.props.groups[rowIndex], + this.props.keys.groupIdKey + ) + this.props.onCanvasClick(groupId, time, e) + } + + handleRowDoubleClick = (e, rowIndex) => { + if (this.props.onCanvasDoubleClick == null) return + + const time = this.getTimeFromRowClickEvent(e) + const groupId = _get( + this.props.groups[rowIndex], + this.props.keys.groupIdKey + ) + this.props.onCanvasDoubleClick(groupId, time, e) + } + + handleScrollContextMenu = (e, rowIndex) => { + if (this.props.onCanvasContextMenu == null) return + + const timePosition = this.getTimeFromRowClickEvent(e) + + const groupId = _get( + this.props.groups[rowIndex], + this.props.keys.groupIdKey + ) + + if (this.props.onCanvasContextMenu) { + e.preventDefault() + this.props.onCanvasContextMenu(groupId, timePosition, e) + } + } + + rows(canvasWidth, groupHeights, groups) { + return ( + + ) + } + + items( + canvasTimeStart, + zoom, + canvasTimeEnd, + canvasWidth, + minUnit, + dimensionItems, + groupHeights, + groupTops + ) { + return ( + + ) + } + + infoLabel() { + let label = null + + if (this.state.dragTime) { + label = `${moment(this.state.dragTime).format('LLL')}, ${ + this.state.dragGroupTitle + }` + } else if (this.state.resizeTime) { + label = moment(this.state.resizeTime).format('LLL') + } + + return label ? : '' + } + + header( + canvasTimeStart, + canvasTimeEnd, + canvasWidth, + minUnit, + timeSteps, + headerLabelGroupHeight, + headerLabelHeight + ) { + const { sidebarWidth, rightSidebarWidth } = this.props + const leftSidebar = sidebarWidth != null && + sidebarWidth > 0 && ( +
+ {this.props.sidebarContent} +
+ ) + + const rightSidebar = rightSidebarWidth != null && + rightSidebarWidth > 0 && ( +
+ {this.props.rightSidebarContent} +
+ ) + + return ( +
0} + canvasTimeEnd={canvasTimeEnd} + canvasWidth={canvasWidth} + minUnit={minUnit} + timeSteps={timeSteps} + headerLabelGroupHeight={headerLabelGroupHeight} + headerLabelHeight={headerLabelHeight} + width={this.state.width} + stickyOffset={this.props.stickyOffset} + stickyHeader={this.props.stickyHeader} + showPeriod={this.showPeriod} + headerLabelFormats={this.props.headerLabelFormats} + subHeaderLabelFormats={this.props.subHeaderLabelFormats} + registerScroll={this.registerScrollListener} + leftSidebarHeader={leftSidebar} + rightSidebarHeader={rightSidebar} + headerRef={this.props.headerRef} + /> + ) + } + + componentDidUpdate() { + this.headerScrollListener(this.state.currentScrollLeft) + } + + registerScrollListener = listener => { + this.headerScrollListener = listener + } + + sidebar(height, groupHeights) { + const { sidebarWidth } = this.props + return ( + sidebarWidth != null && + sidebarWidth > 0 && ( + + ) + ) + } + + rightSidebar(height, groupHeights) { + const { rightSidebarWidth } = this.props + + return ( + rightSidebarWidth != null && + rightSidebarWidth > 0 && ( + + ) + ) + } + + stackItems( + items, + groups, + canvasTimeStart, + visibleTimeStart, + visibleTimeEnd, + width + ) { + // if there are no groups return an empty array of dimensions + if (groups.length === 0) { + return { + dimensionItems: [], + height: 0, + groupHeights: [], + groupTops: [] + } + } + + const { keys, lineHeight, stackItems, itemHeightRatio } = this.props + const { + draggingItem, + dragTime, + resizingItem, + resizingEdge, + resizeTime, + newGroupOrder + } = this.state + const zoom = visibleTimeEnd - visibleTimeStart + const canvasTimeEnd = canvasTimeStart + zoom * 3 + const canvasWidth = width * 3 + + const visibleItems = getVisibleItems( + items, + canvasTimeStart, + canvasTimeEnd, + keys + ) + const groupOrders = getGroupOrders(groups, keys) + + let dimensionItems = visibleItems.reduce((memo, item) => { + const itemId = _get(item, keys.itemIdKey) + const isDragging = itemId === draggingItem + const isResizing = itemId === resizingItem + + let dimension = calculateDimensions({ + itemTimeStart: _get(item, keys.itemTimeStartKey), + itemTimeEnd: _get(item, keys.itemTimeEndKey), + isDragging, + isResizing, + canvasTimeStart, + canvasTimeEnd, + canvasWidth, + dragTime, + resizingEdge, + resizeTime + }) + + if (dimension) { + dimension.top = null + dimension.order = isDragging + ? newGroupOrder + : groupOrders[_get(item, keys.itemGroupKey)].index + dimension.stack = !item.isOverlay + dimension.height = lineHeight * itemHeightRatio + dimension.isDragging = isDragging + + memo.push({ + id: itemId, + dimensions: dimension + }) + } + + return memo + }, []) + + const { height, groupHeights, groupTops } = stackAll( + dimensionItems, + groupOrders, + lineHeight, +<<<<<<< HEAD + stackItems +======= + groups +>>>>>>> forked/develop + ) + + return { dimensionItems, height, groupHeights, groupTops } + } + + childrenWithProps( + canvasTimeStart, + canvasTimeEnd, + canvasWidth, + dimensionItems, + groupHeights, + groupTops, + height, + headerHeight, + visibleTimeStart, + visibleTimeEnd, + minUnit, + timeSteps + ) { + if (!this.props.children) { + return null + } + + // convert to an array and remove the nulls + const childArray = Array.isArray(this.props.children) + ? this.props.children.filter(c => c) + : [this.props.children] + + const childProps = { + canvasTimeStart, + canvasTimeEnd, + canvasWidth, + visibleTimeStart: visibleTimeStart, + visibleTimeEnd: visibleTimeEnd, + dimensionItems, + items: this.props.items, + groups: this.props.groups, + keys: this.props.keys, + groupHeights: groupHeights, + groupTops: groupTops, + selected: + this.state.selectedItem && !this.props.selected + ? [this.state.selectedItem] + : this.props.selected || [], + height: height, + headerHeight: headerHeight, + minUnit: minUnit, + timeSteps: timeSteps + } + + return React.Children.map(childArray, child => + React.cloneElement(child, childProps) + ) + } + + render() { + const { + items, + groups, + headerLabelGroupHeight, + headerLabelHeight, + sidebarWidth, + rightSidebarWidth, + timeSteps, + traditionalZoom + } = this.props + const { + draggingItem, + resizingItem, + width, + visibleTimeStart, + visibleTimeEnd, + canvasTimeStart + } = this.state + let { dimensionItems, height, groupHeights, groupTops } = this.state + + const zoom = visibleTimeEnd - visibleTimeStart + const canvasTimeEnd = canvasTimeStart + zoom * 3 + const canvasWidth = width * 3 + const minUnit = getMinUnit(zoom, width, timeSteps) + const headerHeight = headerLabelGroupHeight + headerLabelHeight + + const isInteractingWithItem = !!draggingItem || !!resizingItem + + if (isInteractingWithItem) { + const stackResults = this.stackItems( + items, + groups, + canvasTimeStart, + visibleTimeStart, + visibleTimeEnd, + width + ) + dimensionItems = stackResults.dimensionItems + height = stackResults.height + groupHeights = stackResults.groupHeights + groupTops = stackResults.groupTops + } + + const outerComponentStyle = { + height: `${height}px` + } + + return ( + + +
(this.container = el)} + className="react-calendar-timeline" + > + {this.header( + canvasTimeStart, + canvasTimeEnd, + canvasWidth, + minUnit, + timeSteps, + headerLabelGroupHeight, + headerLabelHeight + )} +
+ {sidebarWidth > 0 ? this.sidebar(height, groupHeights) : null} + { + this.props.scrollRef(el); + this.scrollComponent = el + }} + width={width} + height={height} + onZoom={this.changeZoom} + onWheelZoom={this.handleWheelZoom} + traditionalZoom={traditionalZoom} + onScroll={this.onScroll} + isInteractingWithItem={isInteractingWithItem} + > + + {this.items( + canvasTimeStart, + zoom, + canvasTimeEnd, + canvasWidth, + minUnit, + dimensionItems, + groupHeights, + groupTops + )} + {this.columns( + canvasTimeStart, + canvasTimeEnd, + canvasWidth, + minUnit, + timeSteps, + height, + headerHeight + )} + {this.rows(canvasWidth, groupHeights, groups)} + {this.infoLabel()} + {this.childrenWithProps( + canvasTimeStart, + canvasTimeEnd, + canvasWidth, + dimensionItems, + groupHeights, + groupTops, + height, + headerHeight, + visibleTimeStart, + visibleTimeEnd, + minUnit, + timeSteps + )} + + + {rightSidebarWidth > 0 + ? this.rightSidebar(height, groupHeights) + : null} +
+
+
+
+ ) + } +} diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index ef4271739..a335e231d 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -264,13 +264,8 @@ export function collision(a, b, lineHeight, collisionPadding = EPSILON) { } /** - * Stack a group of items - * @param {*} lineHeight - * @param {*} item - * @param {*} group - * @param {*} groupHeight - * @param {*} totalHeight - * @param {*} i + * Calculate the position of a given item for a group that + * is being stacked */ function groupStack(lineHeight, item, group, groupHeight, totalHeight, i) { // calculate non-overlapping positions @@ -309,6 +304,7 @@ function groupStack(lineHeight, item, group, groupHeight, totalHeight, i) { return {groupHeight: curHeight, verticalMargin} } +// Calculate the position of this item for a group that is not being stacked function groupNoStack(lineHeight, item, groupHeight, totalHeight) { let verticalMargin = (lineHeight - item.dimensions.height) / 2 if (item.dimensions.top === null) { @@ -319,7 +315,11 @@ function groupNoStack(lineHeight, item, groupHeight, totalHeight) { } /** - * Stacks all groups + * Stack all groups + * @param {*} items items to be stacked + * @param {*} groupOrders the groupOrders object + * @param {*} lineHeight + * @param {*} stackItems should items be stacked? */ export function stackAll(items, groupOrders, lineHeight, stackItems) { var i, iMax @@ -334,9 +334,12 @@ export function stackAll(items, groupOrders, lineHeight, stackItems) { const groupItems = groupedItems[index] const {items, group} = groupItems groupTops.push(totalHeight) + + // Is group being stacked? const isGroupStacked = group.stackItems !== undefined ? group.stackItems : stackItems var groupHeight = 0 var verticalMargin = 0 + // Find positions for each item in group for (i = 0, iMax = items.length; i < iMax; i++) { let r = {} if (isGroupStacked) { @@ -349,9 +352,11 @@ export function stackAll(items, groupOrders, lineHeight, stackItems) { } + // If group height is overridden, push new height + // Do this late as item position still needs to be calculated if (group.height) { - groupHeights.push(groupItems.group.height) - totalHeight += groupItems.group.height + groupHeights.push(group.height) + totalHeight += group.height } else { groupHeights.push(Math.max(groupHeight + verticalMargin, lineHeight)) totalHeight += Math.max(groupHeight + verticalMargin, lineHeight) From 1e934a8c453a3b182cb79470e461a122f9cf1716 Mon Sep 17 00:00:00 2001 From: Alex Maclean Date: Tue, 21 Aug 2018 12:41:38 +1000 Subject: [PATCH 03/34] Bug fix to stop including items that cannot render on timeline --- src/lib/Timeline.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Timeline.js b/src/lib/Timeline.js index b260dd7f9..60f57ac71 100644 --- a/src/lib/Timeline.js +++ b/src/lib/Timeline.js @@ -1006,7 +1006,7 @@ export default class ReactCalendarTimeline extends Component { resizeTime }) - if (dimension) { + if (dimension && groupOrders[_get(item, keys.itemGroupKey)]) { dimension.top = null dimension.order = isDragging ? newGroupOrder From 2ab0bf8ece5175f607183c3be095230a4fbbca6e Mon Sep 17 00:00:00 2001 From: Alex Maclean Date: Wed, 19 Sep 2018 20:02:31 +1000 Subject: [PATCH 04/34] Changes from stack branch --- src/lib/Timeline.js | 3 ++- src/lib/utility/calendar.js | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/lib/Timeline.js b/src/lib/Timeline.js index 0906c31b6..6fcd7cc6e 100644 --- a/src/lib/Timeline.js +++ b/src/lib/Timeline.js @@ -17,7 +17,8 @@ import { getMinUnit, getNextUnit, stackItems, - calculateTimeForXPosition + calculateTimeForXPosition, + calculateScrollCanvas } from './utility/calendar' import { _get, _length } from './utility/generic' import { diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 96ca4876a..14ef32f93 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -230,8 +230,9 @@ function getGroupedItems(items, groupOrders) { // Populate groups for (let i = 0; i < items.length; i++) { - if (items[i].dimensions.order !== undefined) { - groupedItems[items[i].dimensions.order].items.push(items[i]) + const groupItem = groupedItems[items[i].dimensions.order.index] + if (groupItem) { + groupItem.items.push(items[i]) } } @@ -449,9 +450,9 @@ state if (dimension) { dimension.top = null - dimension.order = isDragging - ? newGroupOrder - : groupOrders[_get(item, keys.itemGroupKey)] + dimension.order = isDragging ? + { index: newGroupOrder, group: groups[newGroupOrder] } : + groupOrders[_get(item, keys.itemGroupKey)] dimension.stack = !item.isOverlay dimension.height = lineHeight * itemHeightRatio dimension.isDragging = isDragging From c8561491d36f0bc9dc51e7c4197e64ada4a80648 Mon Sep 17 00:00:00 2001 From: Alex Maclean Date: Wed, 19 Sep 2018 20:18:16 +1000 Subject: [PATCH 05/34] safety check --- src/lib/utility/calendar.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 14ef32f93..84894d2aa 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -230,6 +230,9 @@ function getGroupedItems(items, groupOrders) { // Populate groups for (let i = 0; i < items.length; i++) { + if (!items[i].dimensions.order) { + continue + } const groupItem = groupedItems[items[i].dimensions.order.index] if (groupItem) { groupItem.items.push(items[i]) From 875588da9c2b3504618647899e09e07652809710 Mon Sep 17 00:00:00 2001 From: Alex Maclean Date: Wed, 19 Sep 2018 20:19:40 +1000 Subject: [PATCH 06/34] ye olde safety check --- src/lib/utility/calendar.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 84894d2aa..a7d1159bd 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -230,12 +230,11 @@ function getGroupedItems(items, groupOrders) { // Populate groups for (let i = 0; i < items.length; i++) { - if (!items[i].dimensions.order) { - continue - } - const groupItem = groupedItems[items[i].dimensions.order.index] - if (groupItem) { - groupItem.items.push(items[i]) + if (items[i].dimensions.order !== undefined) { + const groupItem = groupedItems[items[i].dimensions.order.index] + if (groupItem) { + groupItem.items.push(items[i]) + } } } From fbcd75183ca2ba2ffaef0ffe7263cce8b3b23a8f Mon Sep 17 00:00:00 2001 From: Alex Maclean Date: Wed, 19 Sep 2018 20:22:22 +1000 Subject: [PATCH 07/34] manually adding stuff from stack branch --- src/lib/items/Item.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/items/Item.js b/src/lib/items/Item.js index 848882b74..a6ccd7d09 100644 --- a/src/lib/items/Item.js +++ b/src/lib/items/Item.js @@ -102,7 +102,8 @@ export default class Item extends Component { nextProps.canvasTimeStart !== this.props.canvasTimeStart || nextProps.canvasTimeEnd !== this.props.canvasTimeEnd || nextProps.canvasWidth !== this.props.canvasWidth || - nextProps.order.index !== this.props.order.index || + (nextProps.order ? nextProps.order.idnex : undefined) !== + (this.props.order ? this.props.order.index : undefined) || nextProps.dragSnap !== this.props.dragSnap || nextProps.minResizeWidth !== this.props.minResizeWidth || nextProps.canChangeGroup !== this.props.canChangeGroup || From b97f17b7f233cd2f2a6c0e8eb64c6a2d6163995e Mon Sep 17 00:00:00 2001 From: Alex Maclean Date: Sun, 23 Sep 2018 07:31:11 +1000 Subject: [PATCH 08/34] Fixes based off requested changes --- .gitignore | 3 + src/lib/Timeline.js.orig | 1224 ----------------------------------- src/lib/items/Item.js | 2 +- src/lib/utility/calendar.js | 5 +- 4 files changed, 7 insertions(+), 1227 deletions(-) delete mode 100644 src/lib/Timeline.js.orig diff --git a/.gitignore b/.gitignore index df4cb0a88..098fa7edc 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ gh-pages # code coverage coverage +#merge stuff +.orig + diff --git a/src/lib/Timeline.js.orig b/src/lib/Timeline.js.orig deleted file mode 100644 index be8cfb6bf..000000000 --- a/src/lib/Timeline.js.orig +++ /dev/null @@ -1,1224 +0,0 @@ -import PropTypes from 'prop-types' -import React, { Component } from 'react' -import moment from 'moment' - -import Items from './items/Items' -import InfoLabel from './layout/InfoLabel' -import Sidebar from './layout/Sidebar' -import Header from './layout/Header' -import Columns from './columns/Columns' -import GroupRows from './row/GroupRows' -import ScrollElement from './scroll/ScrollElement' -import MarkerCanvas from './markers/MarkerCanvas' - -import windowResizeDetector from '../resize-detector/window' - -import { - getMinUnit, - getNextUnit, - stackAll, - calculateDimensions, - getGroupOrders, - getVisibleItems, - calculateTimeForXPosition -} from './utility/calendar' -import { _get, _length } from './utility/generic' -import { - defaultKeys, - defaultTimeSteps, - defaultHeaderLabelFormats, - defaultSubHeaderLabelFormats -} from './default-config' -import { TimelineStateProvider } from './timeline/TimelineStateContext' -import { TimelineMarkersProvider } from './markers/TimelineMarkersContext' - -export default class ReactCalendarTimeline extends Component { - static propTypes = { - groups: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired, - items: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired, - sidebarWidth: PropTypes.number, - sidebarContent: PropTypes.node, - rightSidebarWidth: PropTypes.number, - rightSidebarContent: PropTypes.node, - dragSnap: PropTypes.number, - minResizeWidth: PropTypes.number, - stickyOffset: PropTypes.number, - stickyHeader: PropTypes.bool, - lineHeight: PropTypes.number, - headerLabelGroupHeight: PropTypes.number, - headerLabelHeight: PropTypes.number, - itemHeightRatio: PropTypes.number, - - minZoom: PropTypes.number, - maxZoom: PropTypes.number, - - clickTolerance: PropTypes.number, - - canChangeGroup: PropTypes.bool, - canMove: PropTypes.bool, - canResize: PropTypes.oneOf([true, false, 'left', 'right', 'both']), - useResizeHandle: PropTypes.bool, - canSelect: PropTypes.bool, - - stackItems: PropTypes.bool, - - traditionalZoom: PropTypes.bool, - - itemTouchSendsClick: PropTypes.bool, - - horizontalLineClassNamesForGroup: PropTypes.func, - - onItemMove: PropTypes.func, - onItemResize: PropTypes.func, - onItemClick: PropTypes.func, - onItemSelect: PropTypes.func, - onItemDeselect: PropTypes.func, - onCanvasClick: PropTypes.func, - onItemDoubleClick: PropTypes.func, - onItemContextMenu: PropTypes.func, - onCanvasDoubleClick: PropTypes.func, - onCanvasContextMenu: PropTypes.func, - onZoom: PropTypes.func, - - moveResizeValidator: PropTypes.func, - - itemRenderer: PropTypes.func, - groupRenderer: PropTypes.func, - - style: PropTypes.object, - - keys: PropTypes.shape({ - groupIdKey: PropTypes.string, - groupTitleKey: PropTypes.string, - groupRightTitleKey: PropTypes.string, - itemIdKey: PropTypes.string, - itemTitleKey: PropTypes.string, - itemDivTitleKey: PropTypes.string, - itemGroupKey: PropTypes.string, - itemTimeStartKey: PropTypes.string, - itemTimeEndKey: PropTypes.string - }), - headerRef: PropTypes.func, - scrollRef: PropTypes.func, - - timeSteps: PropTypes.shape({ - second: PropTypes.number, - minute: PropTypes.number, - hour: PropTypes.number, - day: PropTypes.number, - month: PropTypes.number, - year: PropTypes.number - }), - - defaultTimeStart: PropTypes.object, - defaultTimeEnd: PropTypes.object, - - visibleTimeStart: PropTypes.number, - visibleTimeEnd: PropTypes.number, - onTimeChange: PropTypes.func, - onBoundsChange: PropTypes.func, - - selected: PropTypes.array, - - headerLabelFormats: PropTypes.shape({ - yearShort: PropTypes.string, - yearLong: PropTypes.string, - monthShort: PropTypes.string, - monthMedium: PropTypes.string, - monthMediumLong: PropTypes.string, - monthLong: PropTypes.string, - dayShort: PropTypes.string, - dayLong: PropTypes.string, - hourShort: PropTypes.string, - hourMedium: PropTypes.string, - hourMediumLong: PropTypes.string, - hourLong: PropTypes.string - }), - - subHeaderLabelFormats: PropTypes.shape({ - yearShort: PropTypes.string, - yearLong: PropTypes.string, - monthShort: PropTypes.string, - monthMedium: PropTypes.string, - monthLong: PropTypes.string, - dayShort: PropTypes.string, - dayMedium: PropTypes.string, - dayMediumLong: PropTypes.string, - dayLong: PropTypes.string, - hourShort: PropTypes.string, - hourLong: PropTypes.string, - minuteShort: PropTypes.string, - minuteLong: PropTypes.string - }), - - resizeDetector: PropTypes.shape({ - addListener: PropTypes.func, - removeListener: PropTypes.func - }), - - verticalLineClassNamesForTime: PropTypes.func, - - children: PropTypes.node - } - - static defaultProps = { - sidebarWidth: 150, - rightSidebarWidth: 0, - dragSnap: 1000 * 60 * 15, // 15min - minResizeWidth: 20, - stickyOffset: 0, - stickyHeader: true, - lineHeight: 30, - headerLabelGroupHeight: 30, - headerLabelHeight: 30, - itemHeightRatio: 0.65, - - minZoom: 60 * 60 * 1000, // 1 hour - maxZoom: 5 * 365.24 * 86400 * 1000, // 5 years - - clickTolerance: 3, // how many pixels can we drag for it to be still considered a click? - - canChangeGroup: true, - canMove: true, - canResize: 'right', - useResizeHandle: false, - canSelect: true, - - stackItems: false, - - traditionalZoom: false, - - horizontalLineClassNamesForGroup: null, - - onItemMove: null, - onItemResize: null, - onItemClick: null, - onItemSelect: null, - onItemDeselect: null, - onCanvasClick: null, - onItemDoubleClick: null, - onItemContextMenu: null, - onZoom: null, - - verticalLineClassNamesForTime: null, - - moveResizeValidator: null, - - dayBackground: null, - - defaultTimeStart: null, - defaultTimeEnd: null, - - itemTouchSendsClick: false, - - style: {}, - keys: defaultKeys, - timeSteps: defaultTimeSteps, - headerRef: () => {}, - scrollRef: () => {}, - - // if you pass in visibleTimeStart and visibleTimeEnd, you must also pass onTimeChange(visibleTimeStart, visibleTimeEnd), - // which needs to update the props visibleTimeStart and visibleTimeEnd to the ones passed - visibleTimeStart: null, - visibleTimeEnd: null, - onTimeChange: function( - visibleTimeStart, - visibleTimeEnd, - updateScrollCanvas - ) { - updateScrollCanvas(visibleTimeStart, visibleTimeEnd) - }, - // called when the canvas area of the calendar changes - onBoundsChange: null, - children: null, - - headerLabelFormats: defaultHeaderLabelFormats, - subHeaderLabelFormats: defaultSubHeaderLabelFormats, - - selected: null - } - - static childContextTypes = { - getTimelineContext: PropTypes.func - } - - getChildContext() { - return { - getTimelineContext: () => { - return this.getTimelineContext() - } - } - } - - getTimelineContext = () => { - const { - width, - visibleTimeStart, - visibleTimeEnd, - canvasTimeStart - } = this.state - const zoom = visibleTimeEnd - visibleTimeStart - const canvasTimeEnd = canvasTimeStart + zoom * 3 - - return { - timelineWidth: width, - visibleTimeStart, - visibleTimeEnd, - canvasTimeStart, - canvasTimeEnd - } - } - - constructor(props) { - super(props) - - let visibleTimeStart = null - let visibleTimeEnd = null - - if (this.props.defaultTimeStart && this.props.defaultTimeEnd) { - visibleTimeStart = this.props.defaultTimeStart.valueOf() - visibleTimeEnd = this.props.defaultTimeEnd.valueOf() - } else if (this.props.visibleTimeStart && this.props.visibleTimeEnd) { - visibleTimeStart = this.props.visibleTimeStart - visibleTimeEnd = this.props.visibleTimeEnd - } else { - //throwing an error because neither default or visible time props provided - throw new Error( - 'You must provide either "defaultTimeStart" and "defaultTimeEnd" or "visibleTimeStart" and "visibleTimeEnd" to initialize the Timeline' - ) - } - - this.state = { - width: 1000, - - visibleTimeStart: visibleTimeStart, - visibleTimeEnd: visibleTimeEnd, - canvasTimeStart: visibleTimeStart - (visibleTimeEnd - visibleTimeStart), - - selectedItem: null, - dragTime: null, - dragGroupTitle: null, - resizeTime: null, - topOffset: 0, - resizingItem: null, - resizingEdge: null - } - - const { dimensionItems, height, groupHeights, groupTops } = this.stackItems( - props.items, - props.groups, - this.state.canvasTimeStart, - this.state.visibleTimeStart, - this.state.visibleTimeEnd, - this.state.width - ) - - /* eslint-disable react/no-direct-mutation-state */ - this.state.dimensionItems = dimensionItems - this.state.height = height - this.state.groupHeights = groupHeights - this.state.groupTops = groupTops - - /* eslint-enable */ - } - - componentDidMount() { - this.resize(this.props) - - if (this.props.resizeDetector && this.props.resizeDetector.addListener) { - this.props.resizeDetector.addListener(this) - } - - windowResizeDetector.addListener(this) - - this.lastTouchDistance = null - } - - componentWillUnmount() { - if (this.props.resizeDetector && this.props.resizeDetector.addListener) { - this.props.resizeDetector.removeListener(this) - } - - windowResizeDetector.removeListener(this) - } - - resize = (props = this.props) => { - const { - width: containerWidth, - top: containerTop - } = this.container.getBoundingClientRect() - - let width = containerWidth - props.sidebarWidth - props.rightSidebarWidth - const { headerLabelGroupHeight, headerLabelHeight } = props - const headerHeight = headerLabelGroupHeight + headerLabelHeight - - const { dimensionItems, height, groupHeights, groupTops } = this.stackItems( - props.items, - props.groups, - this.state.canvasTimeStart, - this.state.visibleTimeStart, - this.state.visibleTimeEnd, - width - ) - - // this is needed by dragItem since it uses pageY from the drag events - // if this was in the context of the scrollElement, this would not be necessary - const topOffset = containerTop + window.pageYOffset + headerHeight - - this.setState({ - width, - topOffset, - dimensionItems, - height, - groupHeights, - groupTops - }) - this.scrollComponent.scrollLeft = width - } - - // FIXME: this function calls set state EVERY TIME YOU SCROLL - onScroll = scrollX => { - const canvasTimeStart = this.state.canvasTimeStart - - const zoom = this.state.visibleTimeEnd - this.state.visibleTimeStart - const width = this.state.width - const visibleTimeStart = canvasTimeStart + zoom * scrollX / width - - if (scrollX < this.state.width * 0.5) { - this.setState({ - canvasTimeStart: this.state.canvasTimeStart - zoom - }) - } - if (scrollX > this.state.width * 1.5) { - this.setState({ - canvasTimeStart: this.state.canvasTimeStart + zoom - }) - } - - if ( - this.state.visibleTimeStart !== visibleTimeStart || - this.state.visibleTimeEnd !== visibleTimeStart + zoom - ) { - this.props.onTimeChange( - visibleTimeStart, - visibleTimeStart + zoom, - this.updateScrollCanvas - ) - } - - this.setState({ - currentScrollLeft: scrollX - }) - } - - componentWillReceiveProps(nextProps) { - const { - visibleTimeStart, - visibleTimeEnd, - items, - groups, - sidebarWidth - } = nextProps - - if (visibleTimeStart && visibleTimeEnd) { - this.updateScrollCanvas( - visibleTimeStart, - visibleTimeEnd, - items !== this.props.items || groups !== this.props.groups, - items, - groups - ) - } else if (items !== this.props.items || groups !== this.props.groups) { - this.updateDimensions(items, groups) - } - - // resize if the sidebar width changed - if (sidebarWidth !== this.props.sidebarWidth && items && groups) { - this.resize(nextProps) - } - } - - updateDimensions(items, groups) { - const { - canvasTimeStart, - visibleTimeStart, - visibleTimeEnd, - width - } = this.state - const { dimensionItems, height, groupHeights, groupTops } = this.stackItems( - items, - groups, - canvasTimeStart, - visibleTimeStart, - visibleTimeEnd, - width - ) - - this.setState({ dimensionItems, height, groupHeights, groupTops }) - } - - // called when the visible time changes - updateScrollCanvas = ( - visibleTimeStart, - visibleTimeEnd, - forceUpdateDimensions, - updatedItems, - updatedGroups - ) => { - const oldCanvasTimeStart = this.state.canvasTimeStart - const oldZoom = this.state.visibleTimeEnd - this.state.visibleTimeStart - const newZoom = visibleTimeEnd - visibleTimeStart - const items = updatedItems || this.props.items - const groups = updatedGroups || this.props.groups - - let newState = { - visibleTimeStart: visibleTimeStart, - visibleTimeEnd: visibleTimeEnd - } - - let resetCanvas = false - - const canKeepCanvas = - visibleTimeStart >= oldCanvasTimeStart + oldZoom * 0.5 && - visibleTimeStart <= oldCanvasTimeStart + oldZoom * 1.5 && - visibleTimeEnd >= oldCanvasTimeStart + oldZoom * 1.5 && - visibleTimeEnd <= oldCanvasTimeStart + oldZoom * 2.5 - - // if new visible time is in the right canvas area - if (canKeepCanvas) { - // but we need to update the scroll - const newScrollLeft = Math.round( - this.state.width * (visibleTimeStart - oldCanvasTimeStart) / newZoom - ) - if (this.scrollComponent.scrollLeft !== newScrollLeft) { - resetCanvas = true - } - } else { - resetCanvas = true - } - - if (resetCanvas) { - newState.canvasTimeStart = visibleTimeStart - newZoom - this.scrollComponent.scrollLeft = this.state.width - - if (this.props.onBoundsChange) { - this.props.onBoundsChange( - newState.canvasTimeStart, - newState.canvasTimeStart + newZoom * 3 - ) - } - } - - if (resetCanvas || forceUpdateDimensions) { - const canvasTimeStart = newState.canvasTimeStart - ? newState.canvasTimeStart - : oldCanvasTimeStart - const { - dimensionItems, - height, - groupHeights, - groupTops - } = this.stackItems( - items, - groups, - canvasTimeStart, - visibleTimeStart, - visibleTimeEnd, - this.state.width - ) - newState.dimensionItems = dimensionItems - newState.height = height - newState.groupHeights = groupHeights - newState.groupTops = groupTops - } - - this.setState(newState, () => { - // are we changing zoom? Well then let's report it - // need to wait until state is set so that we get current - // timeline context - if (this.props.onZoom && oldZoom !== newZoom) { - this.props.onZoom(this.getTimelineContext()) - } - }) - } - - handleWheelZoom = (speed, xPosition, deltaY) => { - this.changeZoom(1.0 + speed * deltaY / 500, xPosition / this.state.width) - } - - changeZoom = (scale, offset = 0.5) => { - const { minZoom, maxZoom } = this.props - const oldZoom = this.state.visibleTimeEnd - this.state.visibleTimeStart - const newZoom = Math.min( - Math.max(Math.round(oldZoom * scale), minZoom), - maxZoom - ) // min 1 min, max 20 years - const newVisibleTimeStart = Math.round( - this.state.visibleTimeStart + (oldZoom - newZoom) * offset - ) - - this.props.onTimeChange( - newVisibleTimeStart, - newVisibleTimeStart + newZoom, - this.updateScrollCanvas - ) - } - - showPeriod = (from, unit) => { - let visibleTimeStart = from.valueOf() - let visibleTimeEnd = moment(from) - .add(1, unit) - .valueOf() - let zoom = visibleTimeEnd - visibleTimeStart - - // can't zoom in more than to show one hour - if (zoom < 360000) { - return - } - - // clicked on the big header and already focused here, zoom out - if ( - unit !== 'year' && - this.state.visibleTimeStart === visibleTimeStart && - this.state.visibleTimeEnd === visibleTimeEnd - ) { - let nextUnit = getNextUnit(unit) - - visibleTimeStart = from.startOf(nextUnit).valueOf() - visibleTimeEnd = moment(visibleTimeStart).add(1, nextUnit) - zoom = visibleTimeEnd - visibleTimeStart - } - - this.props.onTimeChange( - visibleTimeStart, - visibleTimeStart + zoom, - this.updateScrollCanvas - ) - } - - selectItem = (item, clickType, e) => { - if ( - this.state.selectedItem === item || - (this.props.itemTouchSendsClick && clickType === 'touch') - ) { - if (item && this.props.onItemClick) { - const time = this.timeFromItemEvent(e) - this.props.onItemClick(item, e, time) - } - } else { - this.setState({ selectedItem: item }) - if (item && this.props.onItemSelect) { - const time = this.timeFromItemEvent(e) - this.props.onItemSelect(item, e, time) - } else if (item === null && this.props.onItemDeselect) { - this.props.onItemDeselect(e) // this isnt in the docs. Is this function even used? - } - } - } - - doubleClickItem = (item, e) => { - if (this.props.onItemDoubleClick) { - const time = this.timeFromItemEvent(e) - this.props.onItemDoubleClick(item, e, time) - } - } - - contextMenuClickItem = (item, e) => { - if (this.props.onItemContextMenu) { - const time = this.timeFromItemEvent(e) - this.props.onItemContextMenu(item, e, time) - } - } - - // TODO: this is very similar to timeFromItemEvent, aside from which element to get offsets - // from. Look to consolidate the logic for determining coordinate to time - // as well as generalizing how we get time from click on the canvas - getTimeFromRowClickEvent = e => { - const { dragSnap } = this.props - const { - width, - canvasTimeStart, - visibleTimeStart, - visibleTimeEnd - } = this.state - // this gives us distance from left of row element, so event is in - // context of the row element, not client or page - const { offsetX } = e.nativeEvent - - // FIXME: DRY up way to calculate canvasTimeEnd - const zoom = visibleTimeEnd - visibleTimeStart - const canvasTimeEnd = zoom * 3 + canvasTimeStart - - let time = calculateTimeForXPosition( - canvasTimeStart, - canvasTimeEnd, - width * 3, - offsetX - ) - time = Math.floor(time / dragSnap) * dragSnap - - return time - } - - timeFromItemEvent = e => { - const { width, visibleTimeStart, visibleTimeEnd } = this.state - const { dragSnap } = this.props - - const scrollComponent = this.scrollComponent - const { left: scrollX } = scrollComponent.getBoundingClientRect() - - const xRelativeToTimeline = e.clientX - scrollX - - const relativeItemPosition = xRelativeToTimeline / width - const zoom = visibleTimeEnd - visibleTimeStart - const timeOffset = relativeItemPosition * zoom - - let time = Math.round(visibleTimeStart + timeOffset) - time = Math.floor(time / dragSnap) * dragSnap - - return time - } - - dragItem = (item, dragTime, newGroupOrder) => { - let newGroup = this.props.groups[newGroupOrder] - const keys = this.props.keys - - this.setState({ - draggingItem: item, - dragTime: dragTime, - newGroupOrder: newGroupOrder, - dragGroupTitle: newGroup ? _get(newGroup, keys.groupTitleKey) : '' - }) - } - - dropItem = (item, dragTime, newGroupOrder) => { - this.setState({ draggingItem: null, dragTime: null, dragGroupTitle: null }) - if (this.props.onItemMove) { - this.props.onItemMove(item, dragTime, newGroupOrder) - } - } - - resizingItem = (item, resizeTime, edge) => { - this.setState({ - resizingItem: item, - resizingEdge: edge, - resizeTime: resizeTime - }) - } - - resizedItem = (item, resizeTime, edge, timeDelta) => { - this.setState({ resizingItem: null, resizingEdge: null, resizeTime: null }) - if (this.props.onItemResize && timeDelta !== 0) { - this.props.onItemResize(item, resizeTime, edge) - } - } - - columns( - canvasTimeStart, - canvasTimeEnd, - canvasWidth, - minUnit, - timeSteps, - height - ) { - return ( - - ) - } - - handleRowClick = (e, rowIndex) => { - // shouldnt this be handled by the user, as far as when to deselect an item? - if (this.state.selectedItem) { - this.selectItem(null) - } - - if (this.props.onCanvasClick == null) return - - const time = this.getTimeFromRowClickEvent(e) - const groupId = _get( - this.props.groups[rowIndex], - this.props.keys.groupIdKey - ) - this.props.onCanvasClick(groupId, time, e) - } - - handleRowDoubleClick = (e, rowIndex) => { - if (this.props.onCanvasDoubleClick == null) return - - const time = this.getTimeFromRowClickEvent(e) - const groupId = _get( - this.props.groups[rowIndex], - this.props.keys.groupIdKey - ) - this.props.onCanvasDoubleClick(groupId, time, e) - } - - handleScrollContextMenu = (e, rowIndex) => { - if (this.props.onCanvasContextMenu == null) return - - const timePosition = this.getTimeFromRowClickEvent(e) - - const groupId = _get( - this.props.groups[rowIndex], - this.props.keys.groupIdKey - ) - - if (this.props.onCanvasContextMenu) { - e.preventDefault() - this.props.onCanvasContextMenu(groupId, timePosition, e) - } - } - - rows(canvasWidth, groupHeights, groups) { - return ( - - ) - } - - items( - canvasTimeStart, - zoom, - canvasTimeEnd, - canvasWidth, - minUnit, - dimensionItems, - groupHeights, - groupTops - ) { - return ( - - ) - } - - infoLabel() { - let label = null - - if (this.state.dragTime) { - label = `${moment(this.state.dragTime).format('LLL')}, ${ - this.state.dragGroupTitle - }` - } else if (this.state.resizeTime) { - label = moment(this.state.resizeTime).format('LLL') - } - - return label ? : '' - } - - header( - canvasTimeStart, - canvasTimeEnd, - canvasWidth, - minUnit, - timeSteps, - headerLabelGroupHeight, - headerLabelHeight - ) { - const { sidebarWidth, rightSidebarWidth } = this.props - const leftSidebar = sidebarWidth != null && - sidebarWidth > 0 && ( -
- {this.props.sidebarContent} -
- ) - - const rightSidebar = rightSidebarWidth != null && - rightSidebarWidth > 0 && ( -
- {this.props.rightSidebarContent} -
- ) - - return ( -
0} - canvasTimeEnd={canvasTimeEnd} - canvasWidth={canvasWidth} - minUnit={minUnit} - timeSteps={timeSteps} - headerLabelGroupHeight={headerLabelGroupHeight} - headerLabelHeight={headerLabelHeight} - width={this.state.width} - stickyOffset={this.props.stickyOffset} - stickyHeader={this.props.stickyHeader} - showPeriod={this.showPeriod} - headerLabelFormats={this.props.headerLabelFormats} - subHeaderLabelFormats={this.props.subHeaderLabelFormats} - registerScroll={this.registerScrollListener} - leftSidebarHeader={leftSidebar} - rightSidebarHeader={rightSidebar} - headerRef={this.props.headerRef} - /> - ) - } - - componentDidUpdate() { - this.headerScrollListener(this.state.currentScrollLeft) - } - - registerScrollListener = listener => { - this.headerScrollListener = listener - } - - sidebar(height, groupHeights) { - const { sidebarWidth } = this.props - return ( - sidebarWidth != null && - sidebarWidth > 0 && ( - - ) - ) - } - - rightSidebar(height, groupHeights) { - const { rightSidebarWidth } = this.props - - return ( - rightSidebarWidth != null && - rightSidebarWidth > 0 && ( - - ) - ) - } - - stackItems( - items, - groups, - canvasTimeStart, - visibleTimeStart, - visibleTimeEnd, - width - ) { - // if there are no groups return an empty array of dimensions - if (groups.length === 0) { - return { - dimensionItems: [], - height: 0, - groupHeights: [], - groupTops: [] - } - } - - const { keys, lineHeight, stackItems, itemHeightRatio } = this.props - const { - draggingItem, - dragTime, - resizingItem, - resizingEdge, - resizeTime, - newGroupOrder - } = this.state - const zoom = visibleTimeEnd - visibleTimeStart - const canvasTimeEnd = canvasTimeStart + zoom * 3 - const canvasWidth = width * 3 - - const visibleItems = getVisibleItems( - items, - canvasTimeStart, - canvasTimeEnd, - keys - ) - const groupOrders = getGroupOrders(groups, keys) - - let dimensionItems = visibleItems.reduce((memo, item) => { - const itemId = _get(item, keys.itemIdKey) - const isDragging = itemId === draggingItem - const isResizing = itemId === resizingItem - - let dimension = calculateDimensions({ - itemTimeStart: _get(item, keys.itemTimeStartKey), - itemTimeEnd: _get(item, keys.itemTimeEndKey), - isDragging, - isResizing, - canvasTimeStart, - canvasTimeEnd, - canvasWidth, - dragTime, - resizingEdge, - resizeTime - }) - - if (dimension) { - dimension.top = null - dimension.order = isDragging - ? newGroupOrder - : groupOrders[_get(item, keys.itemGroupKey)].index - dimension.stack = !item.isOverlay - dimension.height = lineHeight * itemHeightRatio - dimension.isDragging = isDragging - - memo.push({ - id: itemId, - dimensions: dimension - }) - } - - return memo - }, []) - - const { height, groupHeights, groupTops } = stackAll( - dimensionItems, - groupOrders, - lineHeight, -<<<<<<< HEAD - stackItems -======= - groups ->>>>>>> forked/develop - ) - - return { dimensionItems, height, groupHeights, groupTops } - } - - childrenWithProps( - canvasTimeStart, - canvasTimeEnd, - canvasWidth, - dimensionItems, - groupHeights, - groupTops, - height, - headerHeight, - visibleTimeStart, - visibleTimeEnd, - minUnit, - timeSteps - ) { - if (!this.props.children) { - return null - } - - // convert to an array and remove the nulls - const childArray = Array.isArray(this.props.children) - ? this.props.children.filter(c => c) - : [this.props.children] - - const childProps = { - canvasTimeStart, - canvasTimeEnd, - canvasWidth, - visibleTimeStart: visibleTimeStart, - visibleTimeEnd: visibleTimeEnd, - dimensionItems, - items: this.props.items, - groups: this.props.groups, - keys: this.props.keys, - groupHeights: groupHeights, - groupTops: groupTops, - selected: - this.state.selectedItem && !this.props.selected - ? [this.state.selectedItem] - : this.props.selected || [], - height: height, - headerHeight: headerHeight, - minUnit: minUnit, - timeSteps: timeSteps - } - - return React.Children.map(childArray, child => - React.cloneElement(child, childProps) - ) - } - - render() { - const { - items, - groups, - headerLabelGroupHeight, - headerLabelHeight, - sidebarWidth, - rightSidebarWidth, - timeSteps, - traditionalZoom - } = this.props - const { - draggingItem, - resizingItem, - width, - visibleTimeStart, - visibleTimeEnd, - canvasTimeStart - } = this.state - let { dimensionItems, height, groupHeights, groupTops } = this.state - - const zoom = visibleTimeEnd - visibleTimeStart - const canvasTimeEnd = canvasTimeStart + zoom * 3 - const canvasWidth = width * 3 - const minUnit = getMinUnit(zoom, width, timeSteps) - const headerHeight = headerLabelGroupHeight + headerLabelHeight - - const isInteractingWithItem = !!draggingItem || !!resizingItem - - if (isInteractingWithItem) { - const stackResults = this.stackItems( - items, - groups, - canvasTimeStart, - visibleTimeStart, - visibleTimeEnd, - width - ) - dimensionItems = stackResults.dimensionItems - height = stackResults.height - groupHeights = stackResults.groupHeights - groupTops = stackResults.groupTops - } - - const outerComponentStyle = { - height: `${height}px` - } - - return ( - - -
(this.container = el)} - className="react-calendar-timeline" - > - {this.header( - canvasTimeStart, - canvasTimeEnd, - canvasWidth, - minUnit, - timeSteps, - headerLabelGroupHeight, - headerLabelHeight - )} -
- {sidebarWidth > 0 ? this.sidebar(height, groupHeights) : null} - { - this.props.scrollRef(el); - this.scrollComponent = el - }} - width={width} - height={height} - onZoom={this.changeZoom} - onWheelZoom={this.handleWheelZoom} - traditionalZoom={traditionalZoom} - onScroll={this.onScroll} - isInteractingWithItem={isInteractingWithItem} - > - - {this.items( - canvasTimeStart, - zoom, - canvasTimeEnd, - canvasWidth, - minUnit, - dimensionItems, - groupHeights, - groupTops - )} - {this.columns( - canvasTimeStart, - canvasTimeEnd, - canvasWidth, - minUnit, - timeSteps, - height, - headerHeight - )} - {this.rows(canvasWidth, groupHeights, groups)} - {this.infoLabel()} - {this.childrenWithProps( - canvasTimeStart, - canvasTimeEnd, - canvasWidth, - dimensionItems, - groupHeights, - groupTops, - height, - headerHeight, - visibleTimeStart, - visibleTimeEnd, - minUnit, - timeSteps - )} - - - {rightSidebarWidth > 0 - ? this.rightSidebar(height, groupHeights) - : null} -
-
-
-
- ) - } -} diff --git a/src/lib/items/Item.js b/src/lib/items/Item.js index a6ccd7d09..cbdeb2335 100644 --- a/src/lib/items/Item.js +++ b/src/lib/items/Item.js @@ -102,7 +102,7 @@ export default class Item extends Component { nextProps.canvasTimeStart !== this.props.canvasTimeStart || nextProps.canvasTimeEnd !== this.props.canvasTimeEnd || nextProps.canvasWidth !== this.props.canvasWidth || - (nextProps.order ? nextProps.order.idnex : undefined) !== + (nextProps.order ? nextProps.order.index : undefined) !== (this.props.order ? this.props.order.index : undefined) || nextProps.dragSnap !== this.props.dragSnap || nextProps.minResizeWidth !== this.props.minResizeWidth || diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index a7d1159bd..5a383438e 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -218,9 +218,10 @@ export function getGroupOrders(groups, keys) { */ function getGroupedItems(items, groupOrders) { var groupedItems = {} + var keys = Object.keys(groupOrders) // Initialize with result object for each group - for (let i = 0; i < Object.keys(groupOrders).length; i++) { - const groupOrder = groupOrders[Object.keys(groupOrders)[i]] + for (let i = 0; i < keys.length; i++) { + const groupOrder = groupOrders[keys[i]] groupedItems[i] = { index: groupOrder.index, group: groupOrder.group, From fbedb20b9a59907000935003c53e75b57b7375be Mon Sep 17 00:00:00 2001 From: Ahmad Ilaiwi Date: Mon, 12 Nov 2018 14:12:07 +0200 Subject: [PATCH 09/34] [WIP]ItemHeader --- src/lib/headers/ItemHeader.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/lib/headers/ItemHeader.js diff --git a/src/lib/headers/ItemHeader.js b/src/lib/headers/ItemHeader.js new file mode 100644 index 000000000..b48ba8865 --- /dev/null +++ b/src/lib/headers/ItemHeader.js @@ -0,0 +1,35 @@ +import React from 'react'; + + +class ItemHeader extends React.PureComponent { + render(){ + + } +} + + +const ItemHeaderWrapper = ({ + style, + className, + props, + }) => ( + + {({ getTimelineState }) => { + const timelineState = getTimelineState() + return ( + + ) + }} + + ) + + ItemHeaderWrapper.propTypes = { + style: PropTypes.object, + className: PropTypes.string, + props: PropTypes.object, + } + \ No newline at end of file From 8bea61543436bbf01a9a041ee4f438c1f58670bd Mon Sep 17 00:00:00 2001 From: ilaiwi Date: Mon, 12 Nov 2018 19:28:50 +0200 Subject: [PATCH 10/34] WIP --- .../components/Markers/CustomMarker.test.js | 4 +- __tests__/test-utility/marker-renderer.js | 4 +- demo/app/demo-headers/index.js | 14 +- src/index.js | 1 + src/lib/Timeline.js | 1 + src/lib/headers/ItemHeader.js | 133 ++++++++++++++---- src/lib/timeline/TimelineStateContext.js | 5 +- src/lib/utility/calendar.js | 4 +- 8 files changed, 125 insertions(+), 41 deletions(-) diff --git a/__tests__/components/Markers/CustomMarker.test.js b/__tests__/components/Markers/CustomMarker.test.js index 32929c2de..e307780c3 100644 --- a/__tests__/components/Markers/CustomMarker.test.js +++ b/__tests__/components/Markers/CustomMarker.test.js @@ -4,6 +4,7 @@ import 'jest-dom/extend-expect' import TimelineMarkers from 'lib/markers/public/TimelineMarkers' import CustomMarker from 'lib/markers/public/CustomMarker' import { RenderWrapper } from 'test-utility/marker-renderer' +import { defaultKeys } from '../../../src/lib/default-config'; describe('CustomMarker', () => { afterEach(cleanup) @@ -70,7 +71,8 @@ describe('CustomMarker', () => { canvasWidth, showPeriod: () => {}, timelineWidth: 1000, - timelineUnit: 'day' + timelineUnit: 'day', + keys: defaultKeys, } const markerDate = now + oneDay / 2 diff --git a/__tests__/test-utility/marker-renderer.js b/__tests__/test-utility/marker-renderer.js index 566792c6b..7fd787b01 100644 --- a/__tests__/test-utility/marker-renderer.js +++ b/__tests__/test-utility/marker-renderer.js @@ -2,6 +2,7 @@ import React from 'react' import TimelineMarkersRenderer from 'lib/markers/TimelineMarkersRenderer' import { TimelineMarkersProvider } from 'lib/markers/TimelineMarkersContext' import { TimelineStateProvider } from 'lib/timeline/TimelineStateContext' +import { defaultKeys } from '../../src/lib/default-config'; const oneDay = 1000 * 60 * 60 * 24 // eslint-disable-next-line @@ -18,7 +19,8 @@ export const RenderWrapper = ({ children, timelineState }) => { visibleWidth: 1000, showPeriod:()=>{}, timelineWidth:1000, - timelineUnit:'day' + timelineUnit:'day', + keys: defaultKeys } timelineState = timelineState != null ? timelineState : defaultTimelineState diff --git a/demo/app/demo-headers/index.js b/demo/app/demo-headers/index.js index bf06054b4..694225704 100644 --- a/demo/app/demo-headers/index.js +++ b/demo/app/demo-headers/index.js @@ -10,7 +10,8 @@ import Timeline, { SidebarHeader, CustomHeader, TimelineHeaders, - DateHeader + DateHeader, + ItemHeader, } from 'react-calendar-timeline' import generateFakeData from '../generate-fake-data' @@ -38,7 +39,9 @@ export default class App extends Component { constructor(props) { super(props) - const { groups, items } = generateFakeData() + const { groups, items } = generateFakeData(2, 5, 1) + const { groups: headerGroup, items: headerItems } = generateFakeData(1, 5, 1) + console.log(headerGroup) const defaultTimeStart = moment() .startOf('day') .toDate() @@ -53,7 +56,8 @@ export default class App extends Component { defaultTimeStart, defaultTimeEnd, format: false, - showHeaders: false + showHeaders: false, + headerItems, } } @@ -196,7 +200,6 @@ export default class App extends Component { {({ getRootProps }) => { - console.log('left') return
Left
}}
@@ -205,6 +208,7 @@ export default class App extends Component { return
Right
}} + { - console.log('props', props) return (
{intervals.map(interval => { @@ -335,7 +338,6 @@ export default class App extends Component { { getIntervalProps, intervalContext }, props ) => { - console.log('intervalRenderer props', props) return (
{intervalContext.intervalText} diff --git a/src/index.js b/src/index.js index 1c1233da9..33839f0d7 100644 --- a/src/index.js +++ b/src/index.js @@ -10,4 +10,5 @@ export { default as TimelineHeaders } from './lib/headers/TimelineHeaders' export {default as SidebarHeader} from './lib/headers/SidebarHeader' export {default as CustomHeader} from './lib/headers/CustomHeader' export {default as DateHeader} from './lib/headers/DateHeader' +export {default as ItemHeader} from './lib/headers/ItemHeader' export default Timeline diff --git a/src/lib/Timeline.js b/src/lib/Timeline.js index 59b34ffb0..0b3d7f5c7 100644 --- a/src/lib/Timeline.js +++ b/src/lib/Timeline.js @@ -983,6 +983,7 @@ export default class ReactCalendarTimeline extends Component { showPeriod={this.showPeriod} timelineUnit={minUnit} timelineWidth={this.state.width} + keys={this.props.keys} > + calculateDimensions({ + itemTimeStart: _get(item, this.props.keys.itemTimeStartKey), + itemTimeEnd: _get(item, this.props.keys.itemTimeEndKey), + canvasTimeStart: this.props.canvasTimeStart, + canvasTimeEnd: this.props.canvasTimeEnd, + canvasWidth: this.props.canvasWidth, + dragTime: null, + isDragging: false, + isResizing: false, + resizeTime: null, + resizingEdge: null + }) + ) + .map(item => ({ + id: _get(item, this.props.keys.itemIdKey), + dimensions: { + ...item, + order: 0, + top: null + } + })) -const ItemHeaderWrapper = ({ - style, - className, - props, - }) => ( - - {({ getTimelineState }) => { - const timelineState = getTimelineState() - return ( - - ) - }} - - ) - - ItemHeaderWrapper.propTypes = { - style: PropTypes.object, - className: PropTypes.string, - props: PropTypes.object, + const stackingMethod = true ? stack : nostack + //Get a new array of groupOrders holding the stacked items + const { height, groupHeights, groupTops } = stackingMethod( + itemDimensions, + order, + 60, + groups + ) + console.log(height, groupHeights, groupTops) + return ( + + {({ getRootProps }) => { + return
ahmad
+ }} +
+ ) } - \ No newline at end of file +} + +const ItemHeaderWrapper = ({ style, className, props, items }) => ( + + {({ getTimelineState }) => { + const timelineState = getTimelineState() + return ( + + ) + }} + +) + +ItemHeaderWrapper.propTypes = { + style: PropTypes.object, + className: PropTypes.string, + props: PropTypes.object, + items: PropTypes.arrayOf(PropTypes.object).isRequired +} + +export default ItemHeaderWrapper diff --git a/src/lib/timeline/TimelineStateContext.js b/src/lib/timeline/TimelineStateContext.js index 6b87520bb..94fc5fc76 100644 --- a/src/lib/timeline/TimelineStateContext.js +++ b/src/lib/timeline/TimelineStateContext.js @@ -43,9 +43,8 @@ export class TimelineStateProvider extends React.Component { canvasWidth: PropTypes.number.isRequired, showPeriod: PropTypes.func.isRequired, timelineUnit: PropTypes.string.isRequired, - showPeriod: PropTypes.func.isRequired, - timelineUnit: PropTypes.string.isRequired, timelineWidth: PropTypes.number.isRequired, + keys:PropTypes.object.isRequired, } constructor(props) { @@ -70,6 +69,7 @@ export class TimelineStateProvider extends React.Component { canvasWidth, timelineUnit, timelineWidth, + keys, } = this.props return { visibleTimeStart, @@ -79,6 +79,7 @@ export class TimelineStateProvider extends React.Component { canvasWidth, timelineUnit, timelineWidth, + keys, } // REVIEW, } diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 051d7fb3b..9fa392008 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -459,7 +459,6 @@ export function stackItems( }, []) const stackingMethod = stackItems ? stack : nostack - // Get a new array of groupOrders holding the stacked items const { height, groupHeights, groupTops } = stackingMethod( dimensionItems, @@ -467,7 +466,8 @@ export function stackItems( lineHeight, groups ) - + + console.log(dimensionItems, height, groupHeights, groupTops) return { dimensionItems, height, groupHeights, groupTops } } From 770206f423ba8860a433611928551afde20755ef Mon Sep 17 00:00:00 2001 From: ilaiwi Date: Mon, 12 Nov 2018 20:54:41 +0200 Subject: [PATCH 11/34] WIP --- demo/app/demo-headers/index.js | 3 +- src/lib/headers/ItemHeader.js | 52 ++++++++++++++++++---------------- src/lib/utility/calendar.js | 7 ++--- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/demo/app/demo-headers/index.js b/demo/app/demo-headers/index.js index 694225704..a62de9731 100644 --- a/demo/app/demo-headers/index.js +++ b/demo/app/demo-headers/index.js @@ -39,7 +39,7 @@ export default class App extends Component { constructor(props) { super(props) - const { groups, items } = generateFakeData(2, 5, 1) + const { groups, items } = generateFakeData(1, 5, 1) const { groups: headerGroup, items: headerItems } = generateFakeData(1, 5, 1) console.log(headerGroup) const defaultTimeStart = moment() @@ -179,7 +179,6 @@ export default class App extends Component { canSelect itemsSorted itemTouchSendsClick={false} - stackItems itemHeightRatio={0.75} defaultTimeStart={defaultTimeStart} defaultTimeEnd={defaultTimeEnd} diff --git a/src/lib/headers/ItemHeader.js b/src/lib/headers/ItemHeader.js index 8d9899a9b..b7372555f 100644 --- a/src/lib/headers/ItemHeader.js +++ b/src/lib/headers/ItemHeader.js @@ -32,42 +32,44 @@ class ItemHeader extends React.PureComponent { } render() { - const {keys, items} = this.props + const { keys, items } = this.props const order = getGroupOrders(groups, keys) - console.log(this.props.items, order) - const itemDimensions = this.props.items - .map(item => - calculateDimensions({ - itemTimeStart: _get(item, this.props.keys.itemTimeStartKey), - itemTimeEnd: _get(item, this.props.keys.itemTimeEndKey), - canvasTimeStart: this.props.canvasTimeStart, - canvasTimeEnd: this.props.canvasTimeEnd, - canvasWidth: this.props.canvasWidth, - dragTime: null, - isDragging: false, - isResizing: false, - resizeTime: null, - resizingEdge: null - }) - ) - .map(item => ({ - id: _get(item, this.props.keys.itemIdKey), + const itemDimensions = this.props.items.map(item => { + const itemDimension = calculateDimensions({ + itemTimeStart: _get(item, this.props.keys.itemTimeStartKey), + itemTimeEnd: _get(item, this.props.keys.itemTimeEndKey), + canvasTimeStart: this.props.canvasTimeStart, + canvasTimeEnd: this.props.canvasTimeEnd, + canvasWidth: this.props.canvasWidth, + dragTime: null, + isDragging: false, + isResizing: false, + resizeTime: null, + resizingEdge: null + }) + + return { + id: _get(item, keys.itemIdKey), dimensions: { - ...item, + ...itemDimension, order: 0, - top: null + top: null, + stack : false, + height : 30, + isDragging : false, } - })) + } + }) const stackingMethod = true ? stack : nostack //Get a new array of groupOrders holding the stacked items const { height, groupHeights, groupTops } = stackingMethod( itemDimensions, order, - 60, - groups + 30, + groups, ) - console.log(height, groupHeights, groupTops) + console.log(itemDimensions, height, groupHeights, groupTops) return ( {({ getRootProps }) => { diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 266ed945b..874a62d2a 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -256,7 +256,7 @@ export function stack(items, groupOrders, lineHeight, groups) { var groupTops = [] var groupedItems = getGroupedItems(items, groupOrders) - + console.log(items, groupOrders, lineHeight, groups, groupedItems) groupedItems.forEach(function(group) { var groupVal = groups[k++] @@ -418,7 +418,7 @@ export function stackItems( // Get the order of groups based on their id key const groupOrders = getGroupOrders(groups, keys) - + let dimensionItems = visibleItems.reduce((memo, item) => { const itemId = _get(item, keys.itemIdKey) const isDragging = itemId === draggingItem @@ -454,7 +454,7 @@ export function stackItems( return memo }, []) - + const stackingMethod = stackItems ? stack : nostack // Get a new array of groupOrders holding the stacked items const { height, groupHeights, groupTops } = stackingMethod( @@ -464,7 +464,6 @@ export function stackItems( groups ) - console.log(dimensionItems, height, groupHeights, groupTops) return { dimensionItems, height, groupHeights, groupTops } } From 13a4f2b1648b76c7695af3f063b406b0bb8813de Mon Sep 17 00:00:00 2001 From: Ahmad Ilaiwi Date: Tue, 13 Nov 2018 12:24:22 +0200 Subject: [PATCH 12/34] beta ready --- demo/app/demo-headers/index.js | 27 +++-- package.json | 3 +- src/lib/headers/ItemHeader.js | 180 ++++++++++++++++++++++++++++----- src/lib/row/GroupRows.js | 2 +- src/lib/utility/calendar.js | 10 +- webpack.config.js | 2 +- yarn.lock | 4 + 7 files changed, 190 insertions(+), 38 deletions(-) diff --git a/demo/app/demo-headers/index.js b/demo/app/demo-headers/index.js index a62de9731..ff8e8021a 100644 --- a/demo/app/demo-headers/index.js +++ b/demo/app/demo-headers/index.js @@ -11,7 +11,7 @@ import Timeline, { CustomHeader, TimelineHeaders, DateHeader, - ItemHeader, + ItemHeader } from 'react-calendar-timeline' import generateFakeData from '../generate-fake-data' @@ -40,8 +40,6 @@ export default class App extends Component { super(props) const { groups, items } = generateFakeData(1, 5, 1) - const { groups: headerGroup, items: headerItems } = generateFakeData(1, 5, 1) - console.log(headerGroup) const defaultTimeStart = moment() .startOf('day') .toDate() @@ -56,8 +54,7 @@ export default class App extends Component { defaultTimeStart, defaultTimeEnd, format: false, - showHeaders: false, - headerItems, + showHeaders: false } } @@ -195,6 +192,7 @@ export default class App extends Component { // moveResizeValidator={this.moveResizeValidator} rightSidebarWidth={150} rightSidebarContent={
Above The Right
} + stackItems > @@ -207,7 +205,24 @@ export default class App extends Component { return
Right
}}
- + { + return ( +
+ {item.title} +
+ ) + }} + /> + { + return ( +
+ {item.title} +
+ ) + } + } + + getStateAndHelpers = (props, item, itemDimensions) => { + const { + canvasWidth: timelineWidth, + visibleTimeStart, + visibleTimeEnd, + canvasTimeStart, + canvasTimeEnd, + itemHeight + } = props + return { + timelineContext: { + timelineWidth, + visibleTimeStart, + visibleTimeEnd, + canvasTimeStart, + canvasTimeEnd + }, + item, + itemContext: { + dimensions: itemDimensions, + width: itemDimensions.width + }, + itemHeight + } } render() { - const { keys, items } = this.props + const { + keys, + items: itemWithNoIds, + stackItems, + itemHeight, + itemRenderer + } = this.props + const items = itemWithNoIds.map(item => ({ ...item, group: '1' })) const order = getGroupOrders(groups, keys) const itemDimensions = this.props.items.map(item => { const itemDimension = calculateDimensions({ @@ -54,33 +113,104 @@ class ItemHeader extends React.PureComponent { ...itemDimension, order: 0, top: null, - stack : false, - height : 30, - isDragging : false, + stack: stackItems, + height: itemHeight, + isDragging: false } } }) - const stackingMethod = true ? stack : nostack + const stackingMethod = stackItems ? stack : nostack //Get a new array of groupOrders holding the stacked items - const { height, groupHeights, groupTops } = stackingMethod( - itemDimensions, - order, - 30, - groups, - ) - console.log(itemDimensions, height, groupHeights, groupTops) + const { height } = stackingMethod(itemDimensions, order, itemHeight, groups) + return ( {({ getRootProps }) => { - return
ahmad
+ return ( +
+ {items.map(item => { + const itemId = _get(item, keys.itemIdKey) + const dimensions = itemDimensions.find( + itemDimension => itemDimension.id === itemId + ).dimensions + return ( + + ) + })} +
+ ) }}
) } } -const ItemHeaderWrapper = ({ style, className, props, items }) => ( +class Item extends React.PureComponent { + static propTypes = { + item: PropTypes.object.isRequired, + timelineContext: PropTypes.objectOf({ + timelineWidth: PropTypes.number, + visibleTimeStart: PropTypes.number, + visibleTimeEnd: PropTypes.number, + canvasTimeStart: PropTypes.number, + canvasTimeEnd: PropTypes.number + }).isRequired, + itemContext: PropTypes.objectOf({ + dimensions: PropTypes.object, + width: PropTypes.number + }).isRequired, + itemRenderer: passThroughPropTypes['itemRenderer'], + itemHeight: passThroughPropTypes['itemHeight'] + } + + getStyles = (style = {}, dimensions, itemHeight) => { + return { + position: 'absolute', + left: dimensions.left, + top: dimensions.top, + width: dimensions.width, + height: itemHeight, + ...style + } + } + + getRootProps = (props = {}) => { + const { style, ...rest } = props + return { + style: this.getStyles( + style, + this.props.itemContext.dimensions, + this.props.itemHeight + ), + rest + } + } + + render() { + const { item, timelineContext, itemContext } = this.props + return this.props.itemRenderer({ + item, + timelineContext, + itemContext, + getRootProps: this.getRootProps + }) + } +} + +const ItemHeaderWrapper = ({ + style, + className, + props, + items, + stackItems, + itemHeight, + itemRenderer +}) => ( {({ getTimelineState }) => { const timelineState = getTimelineState() @@ -96,6 +226,9 @@ const ItemHeaderWrapper = ({ style, className, props, items }) => ( visibleTimeEnd={timelineState.visibleTimeEnd} canvasWidth={timelineState.canvasWidth} keys={timelineState.keys} + stackItems={stackItems} + itemHeight={itemHeight} + itemRenderer={itemRenderer} /> ) }} @@ -103,10 +236,7 @@ const ItemHeaderWrapper = ({ style, className, props, items }) => ( ) ItemHeaderWrapper.propTypes = { - style: PropTypes.object, - className: PropTypes.string, - props: PropTypes.object, - items: PropTypes.arrayOf(PropTypes.object).isRequired + ...passThroughPropTypes } export default ItemHeaderWrapper diff --git a/src/lib/row/GroupRows.js b/src/lib/row/GroupRows.js index 6f29a72b7..c600bddab 100644 --- a/src/lib/row/GroupRows.js +++ b/src/lib/row/GroupRows.js @@ -37,7 +37,7 @@ export default class GroupRows extends Component { onRowContextClick, } = this.props let lines = [] - + console.log("GroupRows",JSON.stringify(groupHeights)) for (let i = 0; i < lineCount; i++) { lines.push( Date: Tue, 13 Nov 2018 12:44:33 +0200 Subject: [PATCH 13/34] remove extra logs --- demo/app/demo-headers/index.js | 10 ++++++---- src/lib/row/GroupRows.js | 1 - src/lib/utility/calendar.js | 7 +++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/demo/app/demo-headers/index.js b/demo/app/demo-headers/index.js index ff8e8021a..65c479d0a 100644 --- a/demo/app/demo-headers/index.js +++ b/demo/app/demo-headers/index.js @@ -39,7 +39,8 @@ export default class App extends Component { constructor(props) { super(props) - const { groups, items } = generateFakeData(1, 5, 1) + const { groups, items } = generateFakeData() + const {items: headerItems } = generateFakeData(2, 5, 1) const defaultTimeStart = moment() .startOf('day') .toDate() @@ -54,7 +55,8 @@ export default class App extends Component { defaultTimeStart, defaultTimeEnd, format: false, - showHeaders: false + showHeaders: false, + headerItems, } } @@ -206,7 +208,7 @@ export default class App extends Component { }} { return (
- + Date: Wed, 14 Nov 2018 14:44:54 +0200 Subject: [PATCH 14/34] pass classname and styles --- demo/app/demo-headers/index.js | 4 ++++ src/lib/headers/ItemHeader.js | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/demo/app/demo-headers/index.js b/demo/app/demo-headers/index.js index 65c479d0a..b74e13974 100644 --- a/demo/app/demo-headers/index.js +++ b/demo/app/demo-headers/index.js @@ -208,6 +208,10 @@ export default class App extends Component { }} { return ( diff --git a/src/lib/headers/ItemHeader.js b/src/lib/headers/ItemHeader.js index 967a1f84b..b7c12bb78 100644 --- a/src/lib/headers/ItemHeader.js +++ b/src/lib/headers/ItemHeader.js @@ -128,7 +128,7 @@ class ItemHeader extends React.PureComponent { {({ getRootProps }) => { return ( -
+
{items.map(item => { const itemId = _get(item, keys.itemIdKey) const dimensions = itemDimensions.find( @@ -148,6 +148,13 @@ class ItemHeader extends React.PureComponent { ) } + + getRootStyles(height) { + return { + ...this.props.style, + height, + }; + } } class Item extends React.PureComponent { From 68e31b61a135fb0a19e26b86b5433f7219da8b6f Mon Sep 17 00:00:00 2001 From: Ahmad Ilaiwi Date: Sun, 18 Nov 2018 16:03:34 +0200 Subject: [PATCH 15/34] refactor 1: calculateItemDimensions --- demo/app/demo-headers/index.js | 6 ++-- .../{ItemHeader.js => ItemHeader/index.js} | 24 +++++++-------- src/lib/headers/ItemHeader/utils.js | 30 +++++++++++++++++++ src/lib/utility/calendar.js | 8 +++-- 4 files changed, 48 insertions(+), 20 deletions(-) rename src/lib/headers/{ItemHeader.js => ItemHeader/index.js} (92%) create mode 100644 src/lib/headers/ItemHeader/utils.js diff --git a/demo/app/demo-headers/index.js b/demo/app/demo-headers/index.js index b74e13974..530fe5139 100644 --- a/demo/app/demo-headers/index.js +++ b/demo/app/demo-headers/index.js @@ -39,7 +39,7 @@ export default class App extends Component { constructor(props) { super(props) - const { groups, items } = generateFakeData() + const { groups, items } = generateFakeData(2, 5, 1) const {items: headerItems } = generateFakeData(2, 5, 1) const defaultTimeStart = moment() .startOf('day') @@ -212,7 +212,7 @@ export default class App extends Component { style={{ backgroundColor: "blue" }} - items={this.state.headerItems} + items={this.state.items} itemRenderer={({ item, getRootProps }) => { return (
- + ({ ...item, group: '1' })) const order = getGroupOrders(groups, keys) const itemDimensions = this.props.items.map(item => { - const itemDimension = calculateDimensions({ + const itemDimension = calculateItemDimensions({ itemTimeStart: _get(item, this.props.keys.itemTimeStartKey), itemTimeEnd: _get(item, this.props.keys.itemTimeEndKey), canvasTimeStart: this.props.canvasTimeStart, canvasTimeEnd: this.props.canvasTimeEnd, canvasWidth: this.props.canvasWidth, - dragTime: null, - isDragging: false, - isResizing: false, - resizeTime: null, - resizingEdge: null }) return { @@ -120,6 +114,8 @@ class ItemHeader extends React.PureComponent { } }) + console.log(itemDimensions) + const stackingMethod = stackItems ? stack : nostack //Get a new array of groupOrders holding the stacked items const { height } = stackingMethod(itemDimensions, order, itemHeight, groups) @@ -160,14 +156,14 @@ class ItemHeader extends React.PureComponent { class Item extends React.PureComponent { static propTypes = { item: PropTypes.object.isRequired, - timelineContext: PropTypes.objectOf({ + timelineContext: PropTypes.shape({ timelineWidth: PropTypes.number, visibleTimeStart: PropTypes.number, visibleTimeEnd: PropTypes.number, canvasTimeStart: PropTypes.number, canvasTimeEnd: PropTypes.number }).isRequired, - itemContext: PropTypes.objectOf({ + itemContext: PropTypes.shape({ dimensions: PropTypes.object, width: PropTypes.number }).isRequired, diff --git a/src/lib/headers/ItemHeader/utils.js b/src/lib/headers/ItemHeader/utils.js new file mode 100644 index 000000000..6e7733649 --- /dev/null +++ b/src/lib/headers/ItemHeader/utils.js @@ -0,0 +1,30 @@ +import { calculateXPositionForTime } from '../../utility/calendar' +export function calculateItemDimensions({ + itemTimeStart, + itemTimeEnd, + canvasTimeStart, + canvasTimeEnd, + canvasWidth +}) { + const itemTimeRange = itemTimeEnd - itemTimeStart + const left = calculateXPositionForTime( + canvasTimeStart, + canvasTimeEnd, + canvasWidth, + itemTimeStart + ) + const right = calculateXPositionForTime( + canvasTimeStart, + canvasTimeEnd, + canvasWidth, + itemTimeEnd + ) + const dimensions = { + left: left, + width: Math.max(right - left, 3), + collisionLeft: itemTimeStart, + collisionWidth: itemTimeRange + } + + return dimensions +} diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 38003cc69..2d2c746d4 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -154,17 +154,19 @@ export function getNextUnit(unit) { return nextUnits[unit] || '' } + export function calculateDimensions({ itemTimeStart, itemTimeEnd, - isDragging, - isResizing, canvasTimeStart, canvasTimeEnd, canvasWidth, + //TODO: delete all the bellow dragTime, resizingEdge, - resizeTime + resizeTime, + isDragging, + isResizing, }) { const itemStart = isResizing && resizingEdge === 'left' ? resizeTime : itemTimeStart From fe7979d2af7516a52e4d793a5837338cbb16aafd Mon Sep 17 00:00:00 2001 From: ilaiwi Date: Sun, 18 Nov 2018 23:34:28 +0200 Subject: [PATCH 16/34] snapshots --- __fixtures__/groupOrderAndItemDimentions.js | 74 ++++++++++++++++++ __fixtures__/itemsAndGroups.js | 31 ++++++++ __fixtures__/stateAndProps.js | 24 ++++++ .../__snapshots__/get-group-orders.js.snap | 18 +++++ .../__snapshots__/get-grouped-items.js.snap | 78 +++++++++++++++++++ .../calendar/__snapshots__/stack-all.js.snap | 29 +++++++ .../__snapshots__/stack-items.js.snap | 74 ++++++++++++++++++ .../utils/calendar/calculate-scroll-canvas.js | 65 +--------------- __tests__/utils/calendar/get-group-orders.js | 8 +- __tests__/utils/calendar/get-grouped-items.js | 6 +- __tests__/utils/calendar/no-stack.js | 6 -- __tests__/utils/calendar/stack-all.js | 13 ++++ __tests__/utils/calendar/stack-items.js | 9 +++ __tests__/utils/calendar/stack.js | 6 -- src/lib/utility/calendar.js | 2 +- 15 files changed, 363 insertions(+), 80 deletions(-) create mode 100644 __fixtures__/groupOrderAndItemDimentions.js create mode 100644 __fixtures__/itemsAndGroups.js create mode 100644 __fixtures__/stateAndProps.js create mode 100644 __tests__/utils/calendar/__snapshots__/get-group-orders.js.snap create mode 100644 __tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap create mode 100644 __tests__/utils/calendar/__snapshots__/stack-all.js.snap create mode 100644 __tests__/utils/calendar/__snapshots__/stack-items.js.snap delete mode 100644 __tests__/utils/calendar/no-stack.js create mode 100644 __tests__/utils/calendar/stack-all.js create mode 100644 __tests__/utils/calendar/stack-items.js delete mode 100644 __tests__/utils/calendar/stack.js diff --git a/__fixtures__/groupOrderAndItemDimentions.js b/__fixtures__/groupOrderAndItemDimentions.js new file mode 100644 index 000000000..9ba18ee80 --- /dev/null +++ b/__fixtures__/groupOrderAndItemDimentions.js @@ -0,0 +1,74 @@ +export const orderedGroups = { + '1': { + group: { + id: '1' + }, + index: 0 + }, + '2': { + group: { + id: '2' + }, + index: 1 + } +} + +export const dimensionItems = [ + { + dimensions: { + collisionLeft: 1540540000000, + collisionWidth: 6803877, + height: 22.5, + isDragging: false, + left: 4347.222222222223, + order: { + group: { + id: '1' + }, + index: 0 + }, + stack: true, + top: 7.5, + width: 236.24572916666668 + }, + id: '0' + }, + { + dimensions: { + collisionLeft: 1540570000000, + collisionWidth: 14875919, + height: 22.5, + isDragging: false, + left: 5388.888888888889, + order: { + group: { + id: '1' + }, + index: 0 + }, + stack: true, + top: 7.5, + width: 516.5249652777778 + }, + id: '1' + }, + { + dimensions: { + collisionLeft: 1540620000000, + collisionWidth: 20397548, + height: 22.5, + isDragging: false, + left: 7125, + order: { + group: { + id: '1' + }, + index: 0 + }, + stack: true, + top: 7.5, + width: 708.2481944444445 + }, + id: '2' + } +] diff --git a/__fixtures__/itemsAndGroups.js b/__fixtures__/itemsAndGroups.js new file mode 100644 index 000000000..76a8ac020 --- /dev/null +++ b/__fixtures__/itemsAndGroups.js @@ -0,0 +1,31 @@ +import moment from 'moment'; + +export const items = [ + { + id: '0', + group: '1', + start_time: moment('2018-10-26T10:46:40.000').valueOf(), + end_time: moment('2018-10-26T12:40:03.877').valueOf(), + canMove: false, + canResize: false + }, + { + id: '1', + group: '1', + start_time: moment('2018-10-26T19:06:40.000').valueOf(), + end_time: moment('2018-10-26T23:14:35.919').valueOf(), + canMove: true, + canResize: 'both' + }, + { + id: '2', + group: '1', + start_time: moment('2018-10-27T08:00:00.000').valueOf(), + end_time: moment('2018-10-27T13:39:57.548').valueOf(), + canMove: false, + canResize: false, + className: '' + } + ] + + export const groups = [{ id: '1' }, { id: '2' }] \ No newline at end of file diff --git a/__fixtures__/stateAndProps.js b/__fixtures__/stateAndProps.js new file mode 100644 index 000000000..d8a75eda3 --- /dev/null +++ b/__fixtures__/stateAndProps.js @@ -0,0 +1,24 @@ +import { defaultKeys } from 'lib/default-config' +import moment from 'moment' + +export const props = { + keys: defaultKeys, + lineHeight: 30, + stackItems: true, + itemHeightRatio: 0.75 +} + +export const visibleTimeStart = moment('2018-10-26T00:00:00.000') +export const visibleTimeEnd = moment('2018-10-27T00:00:00.000') + +export const state = { + draggingItem: undefined, + dragTime: null, + resizingItem: null, + resizingEdge: null, + resizeTime: null, + newGroupOrder: null, + canvasTimeStart: moment('2018-10-25T00:00:00.000').valueOf(), + visibleTimeEnd: visibleTimeEnd.valueOf(), + visibleTimeStart: visibleTimeStart.valueOf() +} diff --git a/__tests__/utils/calendar/__snapshots__/get-group-orders.js.snap b/__tests__/utils/calendar/__snapshots__/get-group-orders.js.snap new file mode 100644 index 000000000..6725dacd9 --- /dev/null +++ b/__tests__/utils/calendar/__snapshots__/get-group-orders.js.snap @@ -0,0 +1,18 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`getGroupOrders works as expected 1`] = ` +Object { + "1": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "2": Object { + "group": Object { + "id": "2", + }, + "index": 1, + }, +} +`; diff --git a/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap b/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap new file mode 100644 index 000000000..ebc8741f8 --- /dev/null +++ b/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap @@ -0,0 +1,78 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`getGroupedItems works as expected 1`] = ` +Object { + "0": Object { + "group": Object { + "id": "1", + }, + "index": 0, + "items": Array [ + Object { + "dimensions": Object { + "collisionLeft": 1540540000000, + "collisionWidth": 6803877, + "height": 22.5, + "isDragging": false, + "left": 4347.222222222223, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 236.24572916666668, + }, + "id": "0", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540570000000, + "collisionWidth": 14875919, + "height": 22.5, + "isDragging": false, + "left": 5388.888888888889, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 516.5249652777778, + }, + "id": "1", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540620000000, + "collisionWidth": 20397548, + "height": 22.5, + "isDragging": false, + "left": 7125, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 708.2481944444445, + }, + "id": "2", + }, + ], + }, + "1": Object { + "group": Object { + "id": "2", + }, + "index": 1, + "items": Array [], + }, +} +`; diff --git a/__tests__/utils/calendar/__snapshots__/stack-all.js.snap b/__tests__/utils/calendar/__snapshots__/stack-all.js.snap new file mode 100644 index 000000000..1cd25f355 --- /dev/null +++ b/__tests__/utils/calendar/__snapshots__/stack-all.js.snap @@ -0,0 +1,29 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`stackAll works as expected not stacked 1`] = ` +Object { + "groupHeights": Array [ + 60, + 60, + ], + "groupTops": Array [ + 0, + 60, + ], + "height": 120, +} +`; + +exports[`stackAll works as expected stacked 1`] = ` +Object { + "groupHeights": Array [ + 60, + 60, + ], + "groupTops": Array [ + 0, + 60, + ], + "height": 120, +} +`; diff --git a/__tests__/utils/calendar/__snapshots__/stack-items.js.snap b/__tests__/utils/calendar/__snapshots__/stack-items.js.snap new file mode 100644 index 000000000..ae6701f26 --- /dev/null +++ b/__tests__/utils/calendar/__snapshots__/stack-items.js.snap @@ -0,0 +1,74 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`stackItems work as expected 1`] = ` +Object { + "dimensionItems": Array [ + Object { + "dimensions": Object { + "collisionLeft": 1540540000000, + "collisionWidth": 6803877, + "height": 22.5, + "isDragging": false, + "left": 4347.222222222223, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 236.24572916666668, + }, + "id": "0", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540570000000, + "collisionWidth": 14875919, + "height": 22.5, + "isDragging": false, + "left": 5388.888888888889, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 516.5249652777778, + }, + "id": "1", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540620000000, + "collisionWidth": 20397548, + "height": 22.5, + "isDragging": false, + "left": 7125, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 708.2481944444445, + }, + "id": "2", + }, + ], + "groupHeights": Array [ + 37.5, + 30, + ], + "groupTops": Array [ + 0, + 37.5, + ], + "height": 67.5, +} +`; diff --git a/__tests__/utils/calendar/calculate-scroll-canvas.js b/__tests__/utils/calendar/calculate-scroll-canvas.js index 6ab8e051a..2d9fbbe6b 100644 --- a/__tests__/utils/calendar/calculate-scroll-canvas.js +++ b/__tests__/utils/calendar/calculate-scroll-canvas.js @@ -1,68 +1,9 @@ import { calculateScrollCanvas } from 'lib/utility/calendar' +import {defaultKeys} from 'lib/default-config' import moment from 'moment' +import {items, groups} from '../../../__fixtures__/itemsAndGroups' +import {props, state, visibleTimeStart, visibleTimeEnd} from '../../../__fixtures__/stateAndProps' -const keys = { - groupIdKey: 'id', - groupTitleKey: 'title', - groupRightTitleKey: 'rightTitle', - itemIdKey: 'id', - itemTitleKey: 'title', - itemDivTitleKey: 'title', - itemGroupKey: 'group', - itemTimeStartKey: 'start', - itemTimeEndKey: 'end' -} -const props = { - keys, - lineHeight: 30, - stackItems: true, - itemHeightRatio: 0.75 -} - -const visibleTimeStart = moment('2018-10-26T00:00:00.000') -const visibleTimeEnd = moment('2018-10-27T00:00:00.000') - -const state = { - draggingItem: undefined, - dragTime: null, - resizingItem: null, - resizingEdge: null, - resizeTime: null, - newGroupOrder: null, - canvasTimeStart: moment('2018-10-25T00:00:00.000').valueOf(), - visibleTimeEnd: visibleTimeEnd.valueOf(), - visibleTimeStart: visibleTimeStart.valueOf() -} - -const items = [ - { - id: '0', - group: '1', - start: moment('2018-10-26T10:46:40.000').valueOf(), - end: moment('2018-10-26T12:40:03.877').valueOf(), - canMove: false, - canResize: false - }, - { - id: '1', - group: '1', - start: moment('2018-10-26T19:06:40.000').valueOf(), - end: moment('2018-10-26T23:14:35.919').valueOf(), - canMove: true, - canResize: 'both' - }, - { - id: '2', - group: '1', - start: moment('2018-10-27T08:00:00.000').valueOf(), - end: moment('2018-10-27T13:39:57.548').valueOf(), - canMove: false, - canResize: false, - className: '' - } -] - -const groups = [{ id: '1' }, { id: '2' }] describe('calculateScrollCanvas', () => { it('should calculate new scroll state', () => { diff --git a/__tests__/utils/calendar/get-group-orders.js b/__tests__/utils/calendar/get-group-orders.js index c00addbac..6a2d4a459 100644 --- a/__tests__/utils/calendar/get-group-orders.js +++ b/__tests__/utils/calendar/get-group-orders.js @@ -1,6 +1,8 @@ -/* eslint-disable */ import { getGroupOrders } from 'lib/utility/calendar' - +import { groups} from '../../../__fixtures__/itemsAndGroups' +import {defaultKeys} from 'lib/default-config' describe('getGroupOrders', () => { - xit('WRITE UNIT TEST HERE', () => {}) + it('works as expected', () => { + expect(getGroupOrders(groups, defaultKeys)).toMatchSnapshot() + }) }) diff --git a/__tests__/utils/calendar/get-grouped-items.js b/__tests__/utils/calendar/get-grouped-items.js index e9ad1ac6a..e9bf0957f 100644 --- a/__tests__/utils/calendar/get-grouped-items.js +++ b/__tests__/utils/calendar/get-grouped-items.js @@ -1,6 +1,8 @@ -/* eslint-disable */ import { getGroupedItems } from 'lib/utility/calendar' +import {orderedGroups, dimensionItems} from '../../../__fixtures__/groupOrderAndItemDimentions' describe('getGroupedItems', () => { - xit('WRITE UNIT TEST HERE', () => {}) + it('works as expected', () => { + expect(getGroupedItems(dimensionItems,orderedGroups)).toMatchSnapshot() + }) }) diff --git a/__tests__/utils/calendar/no-stack.js b/__tests__/utils/calendar/no-stack.js deleted file mode 100644 index 178c28983..000000000 --- a/__tests__/utils/calendar/no-stack.js +++ /dev/null @@ -1,6 +0,0 @@ -/* eslint-disable */ -import { nostack } from 'lib/utility/calendar' - -describe('nostack', () => { - xit('WRITE UNIT TEST HERE', () => {}) -}) diff --git a/__tests__/utils/calendar/stack-all.js b/__tests__/utils/calendar/stack-all.js new file mode 100644 index 000000000..7d2ba07d1 --- /dev/null +++ b/__tests__/utils/calendar/stack-all.js @@ -0,0 +1,13 @@ +import { stackAll } from 'lib/utility/calendar' +import {orderedGroups, dimensionItems} from '../../../__fixtures__/groupOrderAndItemDimentions' + +const lineHeight = 60 + +describe('stackAll', () => { + it('works as expected stacked', () => { + expect(stackAll(dimensionItems, orderedGroups, lineHeight, true)).toMatchSnapshot() + }) + it('works as expected not stacked', () => { + expect(stackAll(dimensionItems, orderedGroups, lineHeight, false)).toMatchSnapshot() + }) +}) diff --git a/__tests__/utils/calendar/stack-items.js b/__tests__/utils/calendar/stack-items.js new file mode 100644 index 000000000..c820303da --- /dev/null +++ b/__tests__/utils/calendar/stack-items.js @@ -0,0 +1,9 @@ +import {stackItems} from 'lib/utility/calendar' +import {items, groups} from '../../../__fixtures__/itemsAndGroups' +import {props, state} from '../../../__fixtures__/stateAndProps' +describe('stackItems', ()=>{ + it('work as expected', ()=>{ + const result = stackItems(items, groups, state.canvasTimeStart, state.visibleTimeStart, state.visibleTimeEnd, 3000, props, state); + expect(result).toMatchSnapshot() + }) +}) diff --git a/__tests__/utils/calendar/stack.js b/__tests__/utils/calendar/stack.js deleted file mode 100644 index 15c4e6e9d..000000000 --- a/__tests__/utils/calendar/stack.js +++ /dev/null @@ -1,6 +0,0 @@ -/* eslint-disable */ -import { stack } from 'lib/utility/calendar' - -describe('stack', () => { - xit('WRITE UNIT TEST HERE', () => {}) -}) diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 10d6f4fdc..f7e8a2b15 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -216,7 +216,7 @@ export function getGroupOrders(groups, keys) { * @param {*} items list of all items * @param {*} groupOrders the result of getGroupOrders */ -function getGroupedItems(items, groupOrders) { +export function getGroupedItems(items, groupOrders) { var groupedItems = {} var keys = Object.keys(groupOrders) // Initialize with result object for each group From 6090e8222f21b2f87d69849fa8af3a961399f503 Mon Sep 17 00:00:00 2001 From: Ahmad Ilaiwi Date: Mon, 19 Nov 2018 11:47:00 +0200 Subject: [PATCH 17/34] add tests for stackgroup and no stackgroup --- .../calendar/__snapshots__/group-no-stack.js.snap | 8 ++++++++ .../utils/calendar/__snapshots__/group-stack.js.snap | 8 ++++++++ __tests__/utils/calendar/group-no-stack.js | 11 +++++++++++ __tests__/utils/calendar/group-stack.js | 11 +++++++++++ src/lib/utility/calendar.js | 4 ++-- 5 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 __tests__/utils/calendar/__snapshots__/group-no-stack.js.snap create mode 100644 __tests__/utils/calendar/__snapshots__/group-stack.js.snap create mode 100644 __tests__/utils/calendar/group-no-stack.js create mode 100644 __tests__/utils/calendar/group-stack.js diff --git a/__tests__/utils/calendar/__snapshots__/group-no-stack.js.snap b/__tests__/utils/calendar/__snapshots__/group-no-stack.js.snap new file mode 100644 index 000000000..12bba58cb --- /dev/null +++ b/__tests__/utils/calendar/__snapshots__/group-no-stack.js.snap @@ -0,0 +1,8 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`groupNoStack works as expected 1`] = ` +Object { + "groupHeight": 0, + "verticalMargin": 0, +} +`; diff --git a/__tests__/utils/calendar/__snapshots__/group-stack.js.snap b/__tests__/utils/calendar/__snapshots__/group-stack.js.snap new file mode 100644 index 000000000..3c4067570 --- /dev/null +++ b/__tests__/utils/calendar/__snapshots__/group-stack.js.snap @@ -0,0 +1,8 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`groupStack works as expected 1`] = ` +Object { + "groupHeight": 0, + "verticalMargin": 37.5, +} +`; diff --git a/__tests__/utils/calendar/group-no-stack.js b/__tests__/utils/calendar/group-no-stack.js new file mode 100644 index 000000000..758927266 --- /dev/null +++ b/__tests__/utils/calendar/group-no-stack.js @@ -0,0 +1,11 @@ +import {groupNoStack} from 'lib/utility/calendar' +import {orderedGroups, dimensionItems} from '../../../__fixtures__/groupOrderAndItemDimentions' + +describe('groupNoStack', ()=>{ + it('works as expected', ()=>{ + const groupHeight = 0; + const totalHeight = 0; + const index = 0; + expect(groupNoStack(60, dimensionItems[index], groupHeight, totalHeight, index)).toMatchSnapshot() + }) +}) diff --git a/__tests__/utils/calendar/group-stack.js b/__tests__/utils/calendar/group-stack.js new file mode 100644 index 000000000..2abd4eea6 --- /dev/null +++ b/__tests__/utils/calendar/group-stack.js @@ -0,0 +1,11 @@ +import {groupStack} from 'lib/utility/calendar' +import {orderedGroups, dimensionItems} from '../../../__fixtures__/groupOrderAndItemDimentions' + +describe('groupStack', ()=>{ + it('works as expected', ()=>{ + const groupHeight = 0; + const totalHeight = 0; + const index = 0; + expect(groupStack(60, dimensionItems[index], dimensionItems, groupHeight, totalHeight, index)).toMatchSnapshot() + }) +}) diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index f7e8a2b15..6c294d40a 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -271,7 +271,7 @@ export function collision(a, b, lineHeight, collisionPadding = EPSILON) { * Calculate the position of a given item for a group that * is being stacked */ -function groupStack(lineHeight, item, group, groupHeight, totalHeight, i) { +export function groupStack(lineHeight, item, group, groupHeight, totalHeight, i) { // calculate non-overlapping positions let curHeight = groupHeight let verticalMargin = lineHeight - item.dimensions.height @@ -309,7 +309,7 @@ function groupStack(lineHeight, item, group, groupHeight, totalHeight, i) { } // Calculate the position of this item for a group that is not being stacked -function groupNoStack(lineHeight, item, groupHeight, totalHeight) { +export function groupNoStack(lineHeight, item, groupHeight, totalHeight) { let verticalMargin = (lineHeight - item.dimensions.height) / 2 if (item.dimensions.top === null) { item.dimensions.top = totalHeight + verticalMargin From 4be769bc5276d596248314a2c3675b333c8ccb03 Mon Sep 17 00:00:00 2001 From: Ahmad Ilaiwi Date: Mon, 19 Nov 2018 14:18:45 +0200 Subject: [PATCH 18/34] refactor calculate dimensions + add tests cases for stack items --- __fixtures__/stateAndProps.js | 40 +++- .../__snapshots__/stack-items.js.snap | 225 +++++++++++++++++- .../utils/calendar/calculate-dimensions.js | 133 +---------- .../calculate-interaction-new-times.js | 57 +++++ __tests__/utils/calendar/stack-items.js | 74 +++++- src/lib/utility/calendar.js | 110 ++++++--- 6 files changed, 465 insertions(+), 174 deletions(-) create mode 100644 __tests__/utils/calendar/calculate-interaction-new-times.js diff --git a/__fixtures__/stateAndProps.js b/__fixtures__/stateAndProps.js index d8a75eda3..1edf642e5 100644 --- a/__fixtures__/stateAndProps.js +++ b/__fixtures__/stateAndProps.js @@ -1,6 +1,6 @@ import { defaultKeys } from 'lib/default-config' import moment from 'moment' - +import {items} from './itemsAndGroups' export const props = { keys: defaultKeys, lineHeight: 30, @@ -22,3 +22,41 @@ export const state = { visibleTimeEnd: visibleTimeEnd.valueOf(), visibleTimeStart: visibleTimeStart.valueOf() } + +//offset 1 hour +const timeOffset = 1 * 60 *60 *1000 + +export const stateMoveItem = { + draggingItem: items[0].id, + dragTime: items[0].start_time+timeOffset, + resizingItem: null, + resizingEdge: null, + resizeTime: null, + newGroupOrder: 0, + canvasTimeStart: moment('2018-10-25T00:00:00.000').valueOf(), + visibleTimeEnd: visibleTimeEnd.valueOf(), + visibleTimeStart: visibleTimeStart.valueOf() +} +export const stateResizeItemLeft = { + draggingItem: undefined, + dragTime: null, + resizingItem: items[0].id, + resizingEdge: 'left', + resizeTime: items[0].start_time+timeOffset, + newGroupOrder: 0, + canvasTimeStart: moment('2018-10-25T00:00:00.000').valueOf(), + visibleTimeEnd: visibleTimeEnd.valueOf(), + visibleTimeStart: visibleTimeStart.valueOf() +} + +export const stateResizeItemRight = { + draggingItem: undefined, + dragTime: null, + resizingItem: items[0].id, + resizingEdge: 'right', + resizeTime: items[0].end_time+timeOffset, + newGroupOrder: 0, + canvasTimeStart: moment('2018-10-25T00:00:00.000').valueOf(), + visibleTimeEnd: visibleTimeEnd.valueOf(), + visibleTimeStart: visibleTimeStart.valueOf() +} \ No newline at end of file diff --git a/__tests__/utils/calendar/__snapshots__/stack-items.js.snap b/__tests__/utils/calendar/__snapshots__/stack-items.js.snap index ae6701f26..84e1a1d66 100644 --- a/__tests__/utils/calendar/__snapshots__/stack-items.js.snap +++ b/__tests__/utils/calendar/__snapshots__/stack-items.js.snap @@ -1,5 +1,224 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`stackItems should stack items while moving an item 1`] = ` +Object { + "dimensionItems": Array [ + Object { + "dimensions": Object { + "collisionLeft": 1540543600000, + "collisionWidth": 6803877, + "height": 22.5, + "isDragging": true, + "left": 4472.222222222223, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 236.24572916666602, + }, + "id": "0", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540570000000, + "collisionWidth": 14875919, + "height": 22.5, + "isDragging": false, + "left": 5388.888888888889, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 516.5249652777784, + }, + "id": "1", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540620000000, + "collisionWidth": 20397548, + "height": 22.5, + "isDragging": false, + "left": 7125, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 708.2481944444444, + }, + "id": "2", + }, + ], + "groupHeights": Array [ + 37.5, + 30, + ], + "groupTops": Array [ + 0, + 37.5, + ], + "height": 67.5, +} +`; + +exports[`stackItems should stack items while resize item left 1`] = ` +Object { + "dimensionItems": Array [ + Object { + "dimensions": Object { + "collisionLeft": 1540543600000, + "collisionWidth": 3203877, + "height": 22.5, + "isDragging": false, + "left": 4472.222222222223, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 111.24572916666602, + }, + "id": "0", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540570000000, + "collisionWidth": 14875919, + "height": 22.5, + "isDragging": false, + "left": 5388.888888888889, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 516.5249652777784, + }, + "id": "1", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540620000000, + "collisionWidth": 20397548, + "height": 22.5, + "isDragging": false, + "left": 7125, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 708.2481944444444, + }, + "id": "2", + }, + ], + "groupHeights": Array [ + 37.5, + 30, + ], + "groupTops": Array [ + 0, + 37.5, + ], + "height": 67.5, +} +`; + +exports[`stackItems should stack items while resize item right 1`] = ` +Object { + "dimensionItems": Array [ + Object { + "dimensions": Object { + "collisionLeft": 1540540000000, + "collisionWidth": 10403877, + "height": 22.5, + "isDragging": false, + "left": 4347.222222222223, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 361.245729166666, + }, + "id": "0", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540570000000, + "collisionWidth": 14875919, + "height": 22.5, + "isDragging": false, + "left": 5388.888888888889, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 516.5249652777784, + }, + "id": "1", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540620000000, + "collisionWidth": 20397548, + "height": 22.5, + "isDragging": false, + "left": 7125, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 708.2481944444444, + }, + "id": "2", + }, + ], + "groupHeights": Array [ + 37.5, + 30, + ], + "groupTops": Array [ + 0, + 37.5, + ], + "height": 67.5, +} +`; + exports[`stackItems work as expected 1`] = ` Object { "dimensionItems": Array [ @@ -18,7 +237,7 @@ Object { }, "stack": true, "top": 7.5, - "width": 236.24572916666668, + "width": 236.24572916666602, }, "id": "0", }, @@ -37,7 +256,7 @@ Object { }, "stack": true, "top": 7.5, - "width": 516.5249652777778, + "width": 516.5249652777784, }, "id": "1", }, @@ -56,7 +275,7 @@ Object { }, "stack": true, "top": 7.5, - "width": 708.2481944444445, + "width": 708.2481944444444, }, "id": "2", }, diff --git a/__tests__/utils/calendar/calculate-dimensions.js b/__tests__/utils/calendar/calculate-dimensions.js index 8de052f50..5b5a18e58 100644 --- a/__tests__/utils/calendar/calculate-dimensions.js +++ b/__tests__/utils/calendar/calculate-dimensions.js @@ -27,48 +27,15 @@ describe('calculateDimensions', () => { }) }) - it('the item is moved and snapped to the grid', () => { - const dimension = calculateDimensions({ - itemTimeStart: 200, - itemTimeEnd: 300, - isDragging: true, - isResizing: false, - canvasTimeStart: 0, - canvasTimeEnd: 500, - canvasWidth: 500, - dragSnap: 10, - dragTime: 192, - resizingItem: false, - resizingEdge: false, - resizeTime: false, // we are not resizing right now - visibleTimeStart: 0, - visibleTimeEnd: 500 - }) - - expect(dimension).toMatchObject({ - collisionLeft: 192, - collisionWidth: 100, - left: 192, - width: 100 - }) - }) - it('items timeStart is less than canvasTimeStart', () => { let example = { itemTimeStart: 0, itemTimeEnd: 300, - isDragging: false, - isResizing: false, canvasTimeStart: 100, canvasTimeEnd: 500, - canvasWidth: 400, - dragSnap: 0, - dragTime: false, // we are not draging right now - resizingItem: false, - resizingEdge: false, - resizeTime: false, // we are not resizing right now visibleTimeStart: 100, - visibleTimeEnd: 500 + visibleTimeEnd: 500, + canvasWidth: 400, } expect(calculateDimensions(example)).toMatchObject({ @@ -83,18 +50,11 @@ describe('calculateDimensions', () => { let example = { itemTimeStart: 400, itemTimeEnd: 700, - isDragging: false, - isResizing: false, canvasTimeStart: 100, canvasTimeEnd: 500, - canvasWidth: 400, - dragSnap: 0, - dragTime: false, // we are not draging right now - resizingItem: false, - resizingEdge: false, - resizeTime: false, // we are not resizing right now visibleTimeStart: 100, - visibleTimeEnd: 500 + visibleTimeEnd: 500, + canvasWidth: 400, } expect(calculateDimensions(example)).toMatchObject({ @@ -108,18 +68,11 @@ describe('calculateDimensions', () => { let example = { itemTimeStart: 0, // item range extends before and after canvas itemTimeEnd: 600, - isDragging: false, - isResizing: false, canvasTimeStart: 100, canvasTimeEnd: 500, canvasWidth: 400, - dragSnap: 0, - dragTime: false, // we are not draging right now - resizingItem: false, - resizingEdge: false, - resizeTime: false, // we are not resizing right now visibleTimeStart: 100, - visibleTimeEnd: 500 + visibleTimeEnd: 500, } expect(calculateDimensions(example)).toMatchObject({ @@ -129,80 +82,4 @@ describe('calculateDimensions', () => { width: 400 }) }) - - it('the item is dragged', () => { - const dimension = calculateDimensions({ - itemTimeStart: 200, - itemTimeEnd: 300, - isDragging: true, - isResizing: false, - canvasTimeStart: 0, - canvasTimeEnd: 500, - canvasWidth: 500, - dragSnap: 0, - dragTime: 300, - resizingItem: false, - resizingEdge: false, - resizeTime: false, // we are not resizing right now - visibleTimeStart: 0, - visibleTimeEnd: 500 - }) - - expect(dimension).toMatchObject({ - collisionLeft: 300, - collisionWidth: 100, - left: 300, - width: 100 - }) - }) - - it('the item is resized right', () => { - const dimension = calculateDimensions({ - itemTimeStart: 200, - itemTimeEnd: 300, - isDragging: false, - isResizing: true, - canvasTimeStart: 0, - canvasTimeEnd: 500, - canvasWidth: 500, - dragSnap: 0, - dragTime: false, // we are not draging right now - resizingItem: true, - resizingEdge: 'right', - resizeTime: 250 - }) - - expect(dimension).toMatchObject({ - collisionLeft: 200, - collisionWidth: 50, - left: 200, - width: 50 - }) - }) - - it('the item is resized left', () => { - const dimension = calculateDimensions({ - itemTimeStart: 200, - itemTimeEnd: 300, - isDragging: false, - isResizing: true, - canvasTimeStart: 0, - canvasTimeEnd: 500, - canvasWidth: 500, - dragSnap: 0, - dragTime: false, // we are not draging right now - resizingItem: true, - resizingEdge: 'left', - resizeTime: 210, - visibleTimeStart: 0, - visibleTimeEnd: 500 - }) - - expect(dimension).toMatchObject({ - collisionLeft: 210, - collisionWidth: 90, - left: 210, - width: 90 - }) - }) }) diff --git a/__tests__/utils/calendar/calculate-interaction-new-times.js b/__tests__/utils/calendar/calculate-interaction-new-times.js new file mode 100644 index 000000000..5d7cbe804 --- /dev/null +++ b/__tests__/utils/calendar/calculate-interaction-new-times.js @@ -0,0 +1,57 @@ +import { calculateInteractionNewTimes } from 'lib/utility/calendar' + +describe('calculateInteractionNewTimes', () => { + it('should return the original time start and end if no interaction', () => { + expect( + calculateInteractionNewTimes({ + itemTimeStart: 200, + itemTimeEnd: 300, + dragTime: false, + isDragging: false, + isResizing: false, + resizingEdge: false, + resizeTime: false + }) + ).toMatchObject([200, 300]) + }) + it('should calculate new time start and end if being moved', () => { + expect( + calculateInteractionNewTimes({ + itemTimeStart: 200, + itemTimeEnd: 300, + dragTime: 192, + isDragging: true, + isResizing: false, + resizingEdge: false, + resizeTime: false + }) + ).toMatchObject([192, 292]) + }) + it('should calculate new time start and end if being resized right', () => { + expect( + calculateInteractionNewTimes({ + itemTimeStart: 200, + itemTimeEnd: 300, + dragTime: false, + isDragging: false, + isResizing: true, + resizingEdge: 'right', + resizeTime: 250 + }) + ).toMatchObject([200, 250]) + }) + it('should calculate new time start and end if being resized left', () => { + expect( + calculateInteractionNewTimes({ + itemTimeStart: 200, + itemTimeEnd: 300, + dragTime: false, + isDragging: false, + isResizing: true, + resizingEdge: 'left', + resizeTime: 210 + }) + ).toMatchObject([210, 300]) + }) + xit('the item is moved and snapped to the grid', () => {}) +}) diff --git a/__tests__/utils/calendar/stack-items.js b/__tests__/utils/calendar/stack-items.js index c820303da..80f40fe9e 100644 --- a/__tests__/utils/calendar/stack-items.js +++ b/__tests__/utils/calendar/stack-items.js @@ -1,9 +1,67 @@ -import {stackItems} from 'lib/utility/calendar' -import {items, groups} from '../../../__fixtures__/itemsAndGroups' -import {props, state} from '../../../__fixtures__/stateAndProps' -describe('stackItems', ()=>{ - it('work as expected', ()=>{ - const result = stackItems(items, groups, state.canvasTimeStart, state.visibleTimeStart, state.visibleTimeEnd, 3000, props, state); - expect(result).toMatchSnapshot() - }) +import { stackItems } from 'lib/utility/calendar' +import { items, groups } from '../../../__fixtures__/itemsAndGroups' +import { + props, + state, + stateMoveItem, + stateResizeItemLeft, + stateResizeItemRight, +} from '../../../__fixtures__/stateAndProps' +describe('stackItems', () => { + it('work as expected', () => { + expect( + stackItems( + items, + groups, + state.canvasTimeStart, + state.visibleTimeStart, + state.visibleTimeEnd, + 3000, + props, + state + ) + ).toMatchSnapshot() + }) + it('should stack items while moving an item', () => { + expect( + stackItems( + items, + groups, + state.canvasTimeStart, + stateMoveItem.visibleTimeStart, + stateMoveItem.visibleTimeEnd, + 3000, + props, + stateMoveItem + ) + ).toMatchSnapshot() + }) + it('should stack items while resize item left', () => { + expect( + stackItems( + items, + groups, + state.canvasTimeStart, + stateMoveItem.visibleTimeStart, + stateMoveItem.visibleTimeEnd, + 3000, + props, + stateResizeItemLeft + ) + ).toMatchSnapshot() + }) + it('should stack items while resize item right', () => { + expect( + stackItems( + items, + groups, + state.canvasTimeStart, + stateMoveItem.visibleTimeStart, + stateMoveItem.visibleTimeEnd, + 3000, + props, + stateResizeItemRight + ) + ).toMatchSnapshot() + }) }) diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 6c294d40a..943b63661 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -64,7 +64,7 @@ export function iterateTimes(start, end, unit, timeSteps, callback) { if (timeSteps[unit] && timeSteps[unit] > 1) { let value = time.get(unit) - time.set(unit, value - (value % timeSteps[unit])) + time.set(unit, value - value % timeSteps[unit]) } while (time.valueOf() < end) { @@ -154,39 +154,69 @@ export function getNextUnit(unit) { return nextUnits[unit] || '' } -export function calculateDimensions({ +/** + * get the new start and new end time of item that is being + * dragged or resized + * @param {*} itemTimeStart original item time in milliseconds + * @param {*} itemTimeEnd original item time in milliseconds + * @param {*} dragTime new start time if item is dragged in milliseconds + * @param {*} isDragging is item being dragged + * @param {*} isResizing is item being resized + * @param {`right` or `left`} resizingEdge resize edge + * @param {*} resizeTime new resize time in milliseconds + */ +export function calculateInteractionNewTimes({ itemTimeStart, itemTimeEnd, + dragTime, isDragging, isResizing, - canvasTimeStart, - canvasTimeEnd, - canvasWidth, - dragTime, resizingEdge, resizeTime }) { + const originalItemRange = itemTimeEnd - itemTimeStart const itemStart = isResizing && resizingEdge === 'left' ? resizeTime : itemTimeStart const itemEnd = isResizing && resizingEdge === 'right' ? resizeTime : itemTimeEnd + return [ + isDragging ? dragTime : itemStart, + isDragging ? dragTime + originalItemRange : itemEnd + ] +} - const itemTimeRange = itemEnd - itemStart +export function calculateDimensions({ + itemTimeStart, + itemTimeEnd, + canvasTimeStart, + canvasTimeEnd, + canvasWidth, +}) { - let newItemStart = isDragging ? dragTime : itemStart + const itemTimeRange = itemTimeEnd - itemTimeStart - const ratio = - 1 / coordinateToTimeRatio(canvasTimeStart, canvasTimeEnd, canvasWidth) + // restrict startTime and endTime to be bounded by canvasTimeStart and canvasTimeEnd + const effectiveStartTime = Math.max(itemTimeStart, canvasTimeStart) + const effectiveEndTime = Math.min(itemTimeEnd, canvasTimeEnd) - // restrict startTime and endTime to be bounded by canvasTimeStart and canasTimeEnd - const effectiveStartTime = Math.max(itemStart, canvasTimeStart) - const effectiveEndTime = Math.min(itemEnd, canvasTimeEnd) - const itemWidth = (effectiveEndTime - effectiveStartTime) * ratio + const left = calculateXPositionForTime( + canvasTimeStart, + canvasTimeEnd, + canvasWidth, + effectiveStartTime + ) + const right = calculateXPositionForTime( + canvasTimeStart, + canvasTimeEnd, + canvasWidth, + effectiveEndTime + ) + const itemWidth = right - left const dimensions = { - left: Math.max(newItemStart - canvasTimeStart, 0) * ratio, + left: left, width: Math.max(itemWidth, 3), - collisionLeft: newItemStart, + collisionLeft: itemTimeStart, collisionWidth: itemTimeRange } @@ -205,7 +235,7 @@ export function getGroupOrders(groups, keys) { let groupOrders = {} for (let i = 0; i < groups.length; i++) { - groupOrders[_get(groups[i], groupIdKey)] = { index: i, group: groups[i] } + groupOrders[_get(groups[i], groupIdKey)] = { index: i, group: groups[i] } } return groupOrders @@ -271,7 +301,14 @@ export function collision(a, b, lineHeight, collisionPadding = EPSILON) { * Calculate the position of a given item for a group that * is being stacked */ -export function groupStack(lineHeight, item, group, groupHeight, totalHeight, i) { +export function groupStack( + lineHeight, + item, + group, + groupHeight, + totalHeight, + i +) { // calculate non-overlapping positions let curHeight = groupHeight let verticalMargin = lineHeight - item.dimensions.height @@ -281,7 +318,7 @@ export function groupStack(lineHeight, item, group, groupHeight, totalHeight, i) do { var collidingItem = null //Items are placed from i=0 onwards, only check items with index < i - for (var j = i-1, jj = 0; j >= jj; j--) { + for (var j = i - 1, jj = 0; j >= jj; j--) { var other = group[j] if ( other.dimensions.top !== null && @@ -305,7 +342,7 @@ export function groupStack(lineHeight, item, group, groupHeight, totalHeight, i) } } while (collidingItem) } - return {groupHeight: curHeight, verticalMargin} + return { groupHeight: curHeight, verticalMargin } } // Calculate the position of this item for a group that is not being stacked @@ -315,14 +352,14 @@ export function groupNoStack(lineHeight, item, groupHeight, totalHeight) { item.dimensions.top = totalHeight + verticalMargin groupHeight = Math.max(groupHeight, lineHeight) } - return {groupHeight, verticalMargin: 0} + return { groupHeight, verticalMargin: 0 } } /** * Stack all groups * @param {*} items items to be stacked * @param {*} groupOrders the groupOrders object - * @param {*} lineHeight + * @param {*} lineHeight * @param {*} stackItems should items be stacked? */ export function stackAll(items, groupOrders, lineHeight, stackItems) { @@ -336,11 +373,12 @@ export function stackAll(items, groupOrders, lineHeight, stackItems) { for (var index in groupedItems) { const groupItems = groupedItems[index] - const {items, group} = groupItems + const { items, group } = groupItems groupTops.push(totalHeight) - + // Is group being stacked? - const isGroupStacked = group.stackItems !== undefined ? group.stackItems : stackItems + const isGroupStacked = + group.stackItems !== undefined ? group.stackItems : stackItems var groupHeight = 0 var verticalMargin = 0 // Find positions for each item in group @@ -353,7 +391,6 @@ export function stackAll(items, groupOrders, lineHeight, stackItems) { } groupHeight = r.groupHeight verticalMargin = r.verticalMargin - } // If group height is overridden, push new height @@ -395,6 +432,7 @@ export function stackItems( props, state ) { + // if there are no groups return an empty array of dimensions if (groups.length === 0) { return { @@ -431,30 +469,34 @@ export function stackItems( // Get the order of groups based on their id key const groupOrders = getGroupOrders(groups, keys) - let dimensionItems = visibleItems.reduce((memo, item) => { const itemId = _get(item, keys.itemIdKey) const isDragging = itemId === draggingItem const isResizing = itemId === resizingItem - let dimension = calculateDimensions({ + const [itemTimeStart,itemTimeEnd] = calculateInteractionNewTimes({ itemTimeStart: _get(item, keys.itemTimeStartKey), itemTimeEnd: _get(item, keys.itemTimeEndKey), isDragging, isResizing, - canvasTimeStart, - canvasTimeEnd, - canvasWidth, dragTime, resizingEdge, resizeTime }) + let dimension = calculateDimensions({ + itemTimeStart, + itemTimeEnd, + canvasTimeStart, + canvasTimeEnd, + canvasWidth, + }) + if (dimension) { dimension.top = null - dimension.order = isDragging ? - { index: newGroupOrder, group: groups[newGroupOrder] } : - groupOrders[_get(item, keys.itemGroupKey)] + dimension.order = isDragging + ? { index: newGroupOrder, group: groups[newGroupOrder] } + : groupOrders[_get(item, keys.itemGroupKey)] dimension.stack = !item.isOverlay dimension.height = lineHeight * itemHeightRatio dimension.isDragging = isDragging From d570d2c1b04ce0ef7c3f8a376469eb403d770568 Mon Sep 17 00:00:00 2001 From: Ahmad Ilaiwi Date: Mon, 19 Nov 2018 15:48:48 +0200 Subject: [PATCH 19/34] [WIP] refacor calculate dimentions --- .../__snapshots__/stack-items.js.snap | 12 -- src/lib/utility/calendar.js | 151 +++++++++++++----- 2 files changed, 115 insertions(+), 48 deletions(-) diff --git a/__tests__/utils/calendar/__snapshots__/stack-items.js.snap b/__tests__/utils/calendar/__snapshots__/stack-items.js.snap index 84e1a1d66..6b2524220 100644 --- a/__tests__/utils/calendar/__snapshots__/stack-items.js.snap +++ b/__tests__/utils/calendar/__snapshots__/stack-items.js.snap @@ -8,7 +8,6 @@ Object { "collisionLeft": 1540543600000, "collisionWidth": 6803877, "height": 22.5, - "isDragging": true, "left": 4472.222222222223, "order": Object { "group": Object { @@ -27,7 +26,6 @@ Object { "collisionLeft": 1540570000000, "collisionWidth": 14875919, "height": 22.5, - "isDragging": false, "left": 5388.888888888889, "order": Object { "group": Object { @@ -46,7 +44,6 @@ Object { "collisionLeft": 1540620000000, "collisionWidth": 20397548, "height": 22.5, - "isDragging": false, "left": 7125, "order": Object { "group": Object { @@ -81,7 +78,6 @@ Object { "collisionLeft": 1540543600000, "collisionWidth": 3203877, "height": 22.5, - "isDragging": false, "left": 4472.222222222223, "order": Object { "group": Object { @@ -100,7 +96,6 @@ Object { "collisionLeft": 1540570000000, "collisionWidth": 14875919, "height": 22.5, - "isDragging": false, "left": 5388.888888888889, "order": Object { "group": Object { @@ -119,7 +114,6 @@ Object { "collisionLeft": 1540620000000, "collisionWidth": 20397548, "height": 22.5, - "isDragging": false, "left": 7125, "order": Object { "group": Object { @@ -154,7 +148,6 @@ Object { "collisionLeft": 1540540000000, "collisionWidth": 10403877, "height": 22.5, - "isDragging": false, "left": 4347.222222222223, "order": Object { "group": Object { @@ -173,7 +166,6 @@ Object { "collisionLeft": 1540570000000, "collisionWidth": 14875919, "height": 22.5, - "isDragging": false, "left": 5388.888888888889, "order": Object { "group": Object { @@ -192,7 +184,6 @@ Object { "collisionLeft": 1540620000000, "collisionWidth": 20397548, "height": 22.5, - "isDragging": false, "left": 7125, "order": Object { "group": Object { @@ -227,7 +218,6 @@ Object { "collisionLeft": 1540540000000, "collisionWidth": 6803877, "height": 22.5, - "isDragging": false, "left": 4347.222222222223, "order": Object { "group": Object { @@ -246,7 +236,6 @@ Object { "collisionLeft": 1540570000000, "collisionWidth": 14875919, "height": 22.5, - "isDragging": false, "left": 5388.888888888889, "order": Object { "group": Object { @@ -265,7 +254,6 @@ Object { "collisionLeft": 1540620000000, "collisionWidth": 20397548, "height": 22.5, - "isDragging": false, "left": 7125, "order": Object { "group": Object { diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 943b63661..d43fe566c 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -190,9 +190,8 @@ export function calculateDimensions({ itemTimeEnd, canvasTimeStart, canvasTimeEnd, - canvasWidth, + canvasWidth }) { - const itemTimeRange = itemTimeEnd - itemTimeStart // restrict startTime and endTime to be bounded by canvasTimeStart and canvasTimeEnd @@ -432,7 +431,6 @@ export function stackItems( props, state ) { - // if there are no groups return an empty array of dimensions if (groups.length === 0) { return { @@ -469,56 +467,137 @@ export function stackItems( // Get the order of groups based on their id key const groupOrders = getGroupOrders(groups, keys) - let dimensionItems = visibleItems.reduce((memo, item) => { - const itemId = _get(item, keys.itemIdKey) - const isDragging = itemId === draggingItem - const isResizing = itemId === resizingItem - - const [itemTimeStart,itemTimeEnd] = calculateInteractionNewTimes({ - itemTimeStart: _get(item, keys.itemTimeStartKey), - itemTimeEnd: _get(item, keys.itemTimeEndKey), - isDragging, - isResizing, + let dimensionItems = getItemsDimensions({ + items: visibleItems, + keys, + draggingItem, + resizingItem, + dragTime, + resizingEdge, + resizeTime, + canvasTimeStart, + canvasTimeEnd, + canvasWidth, + newGroupOrder, + groups, + groupOrders, + lineHeight, + itemHeightRatio + }) + + // Get a new array of groupOrders holding the stacked items + const { height, groupHeights, groupTops } = stackAll( + dimensionItems, + groupOrders, + lineHeight, + stackItems + ) + + return { dimensionItems, height, groupHeights, groupTops } +} + +/** + * + * @param {*} items + * @param {*} keys + * @param {*} draggingItem + * @param {*} resizingItem + * @param {*} dragTime + * @param {*} resizingEdge + * @param {*} resizeTime + * @param {*} canvasTimeStart + * @param {*} canvasTimeEnd + * @param {*} canvasWidth + * @param {*} newGroupOrder + * @param {*} groups + * @param {*} groupOrders + * @param {*} lineHeight + * @param {*} itemHeightRatio + */ +function getItemsDimensions({ + items, + keys, + canvasTimeStart, + canvasTimeEnd, + canvasWidth, + lineHeight, + itemHeightRatio, + groups, + groupOrders, + //TODO: to be removed + draggingItem, + resizingItem, + dragTime, + resizingEdge, + resizeTime, + newGroupOrder +}) { + return items.reduce((memo, item) => { + const newItem = getItemWithInteractions( + item, + keys, + draggingItem, + resizingItem, dragTime, resizingEdge, - resizeTime - }) - + resizeTime, + groups, + newGroupOrder + ) + const itemId = _get(item, keys.itemIdKey) let dimension = calculateDimensions({ - itemTimeStart, - itemTimeEnd, + itemTimeStart: _get(newItem, keys.itemTimeStartKey), + itemTimeEnd: _get(newItem, keys.itemTimeEndKey), canvasTimeStart, canvasTimeEnd, - canvasWidth, + canvasWidth }) - if (dimension) { dimension.top = null - dimension.order = isDragging - ? { index: newGroupOrder, group: groups[newGroupOrder] } - : groupOrders[_get(item, keys.itemGroupKey)] - dimension.stack = !item.isOverlay + dimension.order = groupOrders[_get(newItem, keys.itemGroupKey)] + dimension.stack = !newItem.isOverlay dimension.height = lineHeight * itemHeightRatio - dimension.isDragging = isDragging - memo.push({ id: itemId, dimensions: dimension }) } - return memo }, []) +} - // Get a new array of groupOrders holding the stacked items - const { height, groupHeights, groupTops } = stackAll( - dimensionItems, - groupOrders, - lineHeight, - stackItems - ) - - return { dimensionItems, height, groupHeights, groupTops } +function getItemWithInteractions( + item, + keys, + draggingItem, + resizingItem, + dragTime, + resizingEdge, + resizeTime, + groups, + newGroupOrder +) { + const itemId = _get(item, keys.itemIdKey) + const isDragging = itemId === draggingItem + const isResizing = itemId === resizingItem + const [itemTimeStart, itemTimeEnd] = calculateInteractionNewTimes({ + itemTimeStart: _get(item, keys.itemTimeStartKey), + itemTimeEnd: _get(item, keys.itemTimeEndKey), + isDragging, + isResizing, + dragTime, + resizingEdge, + resizeTime + }) + const newItem = { + ...item, + [keys.itemTimeStartKey]: itemTimeStart, + [keys.itemTimeEndKey]: itemTimeEnd, + [keys.itemGroupKey]: isDragging + ? _get(groups[newGroupOrder], keys.groupIdKey) + : _get(item, keys.itemGroupKey) + } + return newItem } /** From 7765b5fb2af11ec24718f573cf1303b58adca462 Mon Sep 17 00:00:00 2001 From: Ahmad Ilaiwi Date: Tue, 20 Nov 2018 09:29:02 +0200 Subject: [PATCH 20/34] test getItemWithInteractions --- .../calendar/get-item-with-interactions.js | 110 ++++++++++++++++ src/lib/utility/calendar.js | 120 ++++++------------ 2 files changed, 150 insertions(+), 80 deletions(-) create mode 100644 __tests__/utils/calendar/get-item-with-interactions.js diff --git a/__tests__/utils/calendar/get-item-with-interactions.js b/__tests__/utils/calendar/get-item-with-interactions.js new file mode 100644 index 000000000..f0c17067d --- /dev/null +++ b/__tests__/utils/calendar/get-item-with-interactions.js @@ -0,0 +1,110 @@ +import { getItemWithInteractions } from 'lib/utility/calendar' +import { items, groups } from '../../../__fixtures__/itemsAndGroups' +import { defaultKeys } from 'lib/default-config' + +describe('getItemWithInteractions', () => { + it('should return the same item if no interaction occurred', () => { + const item = items[0] + expect( + getItemWithInteractions({ + item, + keys: defaultKeys, + draggingItem: undefined, + resizingItem: undefined, + dragTime: false, + resizingEdge: false, + resizeTime: false, + groups, + newGroupOrder: 0 + }) + ).toBe(item) + }) + it('should return new item with new start and end time if dragged with no changed group', () => { + const item = items[0] + //moved 1 hour + const dragOffset = 60 * 60 * 1000 + expect( + getItemWithInteractions({ + item, + keys: defaultKeys, + draggingItem: item.id, + resizingItem: undefined, + dragTime: item.start_time + dragOffset, + resizingEdge: false, + resizeTime: false, + groups, + newGroupOrder: 0 + }) + ).toMatchObject({ + ...item, + start_time: item.start_time + dragOffset, + end_time: item.end_time + dragOffset, + group: item.group + }) + }) + it('should return new item with new start and end time if dragged with changed group', () => { + const item = items[0] + //moved 1 hour + const dragOffset = 60 * 60 * 1000 + expect( + getItemWithInteractions({ + item, + keys: defaultKeys, + draggingItem: item.id, + resizingItem: undefined, + dragTime: item.start_time + dragOffset, + resizingEdge: false, + resizeTime: false, + groups, + newGroupOrder: 1 + }) + ).toMatchObject({ + ...item, + start_time: item.start_time + dragOffset, + end_time: item.end_time + dragOffset, + group: groups[1].id + }) + }) + it('should return new item with new start time if resized left', () => { + const item = items[0] + //moved 1 hour + const dragOffset = 60 * 60 * 1000 + expect( + getItemWithInteractions({ + item, + keys: defaultKeys, + draggingItem: undefined, + resizingItem: item.id, + dragTime: undefined, + resizingEdge: 'left', + resizeTime: item.start_time + dragOffset, + groups, + newGroupOrder: 0 + }) + ).toMatchObject({ + ...item, + start_time: item.start_time + dragOffset, + }) + }) + it('should return new item with end start time if resized right', () => { + const item = items[0] + //moved 1 hour + const dragOffset = 60 * 60 * 1000 + expect( + getItemWithInteractions({ + item, + keys: defaultKeys, + draggingItem: undefined, + resizingItem: item.id, + dragTime: undefined, + resizingEdge: 'right', + resizeTime: item.end_time + dragOffset, + groups, + newGroupOrder: 0 + }) + ).toMatchObject({ + ...item, + end_time: item.end_time + dragOffset, + }) + }) +}) diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index d43fe566c..3d8e15ea0 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -467,23 +467,39 @@ export function stackItems( // Get the order of groups based on their id key const groupOrders = getGroupOrders(groups, keys) - let dimensionItems = getItemsDimensions({ - items: visibleItems, - keys, - draggingItem, - resizingItem, - dragTime, - resizingEdge, - resizeTime, - canvasTimeStart, - canvasTimeEnd, - canvasWidth, - newGroupOrder, - groups, - groupOrders, - lineHeight, - itemHeightRatio - }) + let dimensionItems = visibleItems + .map(item => { + const newItem = getItemWithInteractions({ + item, + keys, + draggingItem, + resizingItem, + dragTime, + resizingEdge, + resizeTime, + groups, + newGroupOrder + }) + const itemId = _get(item, keys.itemIdKey) + let dimension = calculateDimensions({ + itemTimeStart: _get(newItem, keys.itemTimeStartKey), + itemTimeEnd: _get(newItem, keys.itemTimeEndKey), + canvasTimeStart, + canvasTimeEnd, + canvasWidth + }) + if (dimension) { + dimension.top = null + dimension.order = groupOrders[_get(newItem, keys.itemGroupKey)] + dimension.stack = !newItem.isOverlay + dimension.height = lineHeight * itemHeightRatio + return { + id: itemId, + dimensions: dimension + } + } + }) + .filter(item => !!item) // Get a new array of groupOrders holding the stacked items const { height, groupHeights, groupTops } = stackAll( @@ -497,76 +513,19 @@ export function stackItems( } /** - * - * @param {*} items + * get new item with changed `itemTimeStart` , `itemTimeEnd` and `itemGroupKey` according to user interaction + * user interaction is dragging an item and resize left and right + * @param {*} item * @param {*} keys * @param {*} draggingItem * @param {*} resizingItem * @param {*} dragTime * @param {*} resizingEdge * @param {*} resizeTime - * @param {*} canvasTimeStart - * @param {*} canvasTimeEnd - * @param {*} canvasWidth - * @param {*} newGroupOrder * @param {*} groups - * @param {*} groupOrders - * @param {*} lineHeight - * @param {*} itemHeightRatio + * @param {*} newGroupOrder */ -function getItemsDimensions({ - items, - keys, - canvasTimeStart, - canvasTimeEnd, - canvasWidth, - lineHeight, - itemHeightRatio, - groups, - groupOrders, - //TODO: to be removed - draggingItem, - resizingItem, - dragTime, - resizingEdge, - resizeTime, - newGroupOrder -}) { - return items.reduce((memo, item) => { - const newItem = getItemWithInteractions( - item, - keys, - draggingItem, - resizingItem, - dragTime, - resizingEdge, - resizeTime, - groups, - newGroupOrder - ) - const itemId = _get(item, keys.itemIdKey) - let dimension = calculateDimensions({ - itemTimeStart: _get(newItem, keys.itemTimeStartKey), - itemTimeEnd: _get(newItem, keys.itemTimeEndKey), - canvasTimeStart, - canvasTimeEnd, - canvasWidth - }) - if (dimension) { - dimension.top = null - dimension.order = groupOrders[_get(newItem, keys.itemGroupKey)] - dimension.stack = !newItem.isOverlay - dimension.height = lineHeight * itemHeightRatio - memo.push({ - id: itemId, - dimensions: dimension - }) - } - return memo - }, []) -} - -function getItemWithInteractions( +export function getItemWithInteractions({ item, keys, draggingItem, @@ -576,7 +535,8 @@ function getItemWithInteractions( resizeTime, groups, newGroupOrder -) { +}) { + if(!resizingItem && !draggingItem) return item const itemId = _get(item, keys.itemIdKey) const isDragging = itemId === draggingItem const isResizing = itemId === resizingItem From dae499623afd4f92b04c3ab64366b1fbf306aedf Mon Sep 17 00:00:00 2001 From: Ahmad Ilaiwi Date: Tue, 20 Nov 2018 11:14:14 +0200 Subject: [PATCH 21/34] test getItemDimensions --- __fixtures__/groupOrderAndItemDimentions.js | 3 - .../__snapshots__/get-grouped-items.js.snap | 3 - .../__snapshots__/get-item-dimensions.js.snap | 22 +++++ .../utils/calendar/get-item-dimensions.js | 22 +++++ src/lib/utility/calendar.js | 92 +++++++++++++------ 5 files changed, 108 insertions(+), 34 deletions(-) create mode 100644 __tests__/utils/calendar/__snapshots__/get-item-dimensions.js.snap create mode 100644 __tests__/utils/calendar/get-item-dimensions.js diff --git a/__fixtures__/groupOrderAndItemDimentions.js b/__fixtures__/groupOrderAndItemDimentions.js index 9ba18ee80..27e416efb 100644 --- a/__fixtures__/groupOrderAndItemDimentions.js +++ b/__fixtures__/groupOrderAndItemDimentions.js @@ -19,7 +19,6 @@ export const dimensionItems = [ collisionLeft: 1540540000000, collisionWidth: 6803877, height: 22.5, - isDragging: false, left: 4347.222222222223, order: { group: { @@ -38,7 +37,6 @@ export const dimensionItems = [ collisionLeft: 1540570000000, collisionWidth: 14875919, height: 22.5, - isDragging: false, left: 5388.888888888889, order: { group: { @@ -57,7 +55,6 @@ export const dimensionItems = [ collisionLeft: 1540620000000, collisionWidth: 20397548, height: 22.5, - isDragging: false, left: 7125, order: { group: { diff --git a/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap b/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap index ebc8741f8..95053d9ba 100644 --- a/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap +++ b/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap @@ -13,7 +13,6 @@ Object { "collisionLeft": 1540540000000, "collisionWidth": 6803877, "height": 22.5, - "isDragging": false, "left": 4347.222222222223, "order": Object { "group": Object { @@ -32,7 +31,6 @@ Object { "collisionLeft": 1540570000000, "collisionWidth": 14875919, "height": 22.5, - "isDragging": false, "left": 5388.888888888889, "order": Object { "group": Object { @@ -51,7 +49,6 @@ Object { "collisionLeft": 1540620000000, "collisionWidth": 20397548, "height": 22.5, - "isDragging": false, "left": 7125, "order": Object { "group": Object { diff --git a/__tests__/utils/calendar/__snapshots__/get-item-dimensions.js.snap b/__tests__/utils/calendar/__snapshots__/get-item-dimensions.js.snap new file mode 100644 index 000000000..b945fb7ea --- /dev/null +++ b/__tests__/utils/calendar/__snapshots__/get-item-dimensions.js.snap @@ -0,0 +1,22 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`getItemDimensions should evaluate dimensions for an item 1`] = ` +Object { + "dimensions": Object { + "collisionLeft": 1540540000000, + "collisionWidth": 6803877, + "height": 60, + "left": NaN, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": null, + "width": NaN, + }, + "id": "0", +} +`; diff --git a/__tests__/utils/calendar/get-item-dimensions.js b/__tests__/utils/calendar/get-item-dimensions.js new file mode 100644 index 000000000..4a47aa021 --- /dev/null +++ b/__tests__/utils/calendar/get-item-dimensions.js @@ -0,0 +1,22 @@ +import { getItemDimensions } from 'lib/utility/calendar' +import {items} from '../../../__fixtures__/itemsAndGroups' +import {state} from '../../../__fixtures__/stateAndProps' +import { defaultKeys } from 'lib/default-config' +import {orderedGroups} from '../../../__fixtures__/groupOrderAndItemDimentions' + +describe('getItemDimensions', () => { + it("should evaluate dimensions for an item", ()=>{ + const item = items[0] + const {canvasTimeStart, canvasTimeEnd} = state + expect(getItemDimensions({ + item, + keys: defaultKeys, + canvasTimeStart, + canvasTimeEnd, + canvasWidth: 3000, + groupOrders: orderedGroups, + lineHeight: 60, + itemHeightRatio: 1, + })).toMatchSnapshot() + }) +}) diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 3d8e15ea0..dd26fd58c 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -464,41 +464,36 @@ export function stackItems( keys ) + const visibleItemsWithInteraction = visibleItems.map(item => + getItemWithInteractions({ + item, + keys, + draggingItem, + resizingItem, + dragTime, + resizingEdge, + resizeTime, + groups, + newGroupOrder + }) + ) + // Get the order of groups based on their id key const groupOrders = getGroupOrders(groups, keys) - let dimensionItems = visibleItems - .map(item => { - const newItem = getItemWithInteractions({ + let dimensionItems = visibleItemsWithInteraction + .map(item => + getItemDimensions({ item, keys, - draggingItem, - resizingItem, - dragTime, - resizingEdge, - resizeTime, - groups, - newGroupOrder - }) - const itemId = _get(item, keys.itemIdKey) - let dimension = calculateDimensions({ - itemTimeStart: _get(newItem, keys.itemTimeStartKey), - itemTimeEnd: _get(newItem, keys.itemTimeEndKey), canvasTimeStart, canvasTimeEnd, - canvasWidth + canvasWidth, + groupOrders, + lineHeight, + itemHeightRatio }) - if (dimension) { - dimension.top = null - dimension.order = groupOrders[_get(newItem, keys.itemGroupKey)] - dimension.stack = !newItem.isOverlay - dimension.height = lineHeight * itemHeightRatio - return { - id: itemId, - dimensions: dimension - } - } - }) + ) .filter(item => !!item) // Get a new array of groupOrders holding the stacked items @@ -512,6 +507,47 @@ export function stackItems( return { dimensionItems, height, groupHeights, groupTops } } +/** + * get item's position, dimensions and collisions + * @param {*} item + * @param {*} keys + * @param {*} canvasTimeStart + * @param {*} canvasTimeEnd + * @param {*} canvasWidth + * @param {*} groupOrders + * @param {*} lineHeight + * @param {*} itemHeightRatio + */ +export function getItemDimensions({ + item, + keys, + canvasTimeStart, + canvasTimeEnd, + canvasWidth, + groupOrders, + lineHeight, + itemHeightRatio +}) { + const itemId = _get(item, keys.itemIdKey) + let dimension = calculateDimensions({ + itemTimeStart: _get(item, keys.itemTimeStartKey), + itemTimeEnd: _get(item, keys.itemTimeEndKey), + canvasTimeStart, + canvasTimeEnd, + canvasWidth + }) + if (dimension) { + dimension.top = null + dimension.order = groupOrders[_get(item, keys.itemGroupKey)] + dimension.stack = !item.isOverlay + dimension.height = lineHeight * itemHeightRatio + return { + id: itemId, + dimensions: dimension + } + } +} + /** * get new item with changed `itemTimeStart` , `itemTimeEnd` and `itemGroupKey` according to user interaction * user interaction is dragging an item and resize left and right @@ -536,7 +572,7 @@ export function getItemWithInteractions({ groups, newGroupOrder }) { - if(!resizingItem && !draggingItem) return item + if (!resizingItem && !draggingItem) return item const itemId = _get(item, keys.itemIdKey) const isDragging = itemId === draggingItem const isResizing = itemId === resizingItem From 38841076626820000e5d47bb4962faa7189f8c66 Mon Sep 17 00:00:00 2001 From: ilaiwi Date: Wed, 21 Nov 2018 09:45:37 +0200 Subject: [PATCH 22/34] add canvasTimeStart to state --- __fixtures__/stateAndProps.js | 22 +-- .../calculate-scroll-canvas.js.snap | 149 ++++++++++++++++++ .../__snapshots__/get-item-dimensions.js.snap | 4 +- .../utils/calendar/calculate-scroll-canvas.js | 28 ++++ src/lib/Timeline.js | 25 ++- src/lib/utility/calendar.js | 29 +++- 6 files changed, 218 insertions(+), 39 deletions(-) create mode 100644 __tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap diff --git a/__fixtures__/stateAndProps.js b/__fixtures__/stateAndProps.js index 1edf642e5..0699c0076 100644 --- a/__fixtures__/stateAndProps.js +++ b/__fixtures__/stateAndProps.js @@ -20,43 +20,31 @@ export const state = { newGroupOrder: null, canvasTimeStart: moment('2018-10-25T00:00:00.000').valueOf(), visibleTimeEnd: visibleTimeEnd.valueOf(), - visibleTimeStart: visibleTimeStart.valueOf() + visibleTimeStart: visibleTimeStart.valueOf(), + canvasTimeEnd: 1540674000000 } //offset 1 hour const timeOffset = 1 * 60 *60 *1000 export const stateMoveItem = { + ...state, draggingItem: items[0].id, dragTime: items[0].start_time+timeOffset, - resizingItem: null, - resizingEdge: null, - resizeTime: null, newGroupOrder: 0, - canvasTimeStart: moment('2018-10-25T00:00:00.000').valueOf(), - visibleTimeEnd: visibleTimeEnd.valueOf(), - visibleTimeStart: visibleTimeStart.valueOf() } export const stateResizeItemLeft = { - draggingItem: undefined, - dragTime: null, + ...state, resizingItem: items[0].id, resizingEdge: 'left', resizeTime: items[0].start_time+timeOffset, newGroupOrder: 0, - canvasTimeStart: moment('2018-10-25T00:00:00.000').valueOf(), - visibleTimeEnd: visibleTimeEnd.valueOf(), - visibleTimeStart: visibleTimeStart.valueOf() } export const stateResizeItemRight = { - draggingItem: undefined, - dragTime: null, + ...state, resizingItem: items[0].id, resizingEdge: 'right', resizeTime: items[0].end_time+timeOffset, newGroupOrder: 0, - canvasTimeStart: moment('2018-10-25T00:00:00.000').valueOf(), - visibleTimeEnd: visibleTimeEnd.valueOf(), - visibleTimeStart: visibleTimeStart.valueOf() } \ No newline at end of file diff --git a/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap b/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap new file mode 100644 index 000000000..c88d05bb4 --- /dev/null +++ b/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap @@ -0,0 +1,149 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`calculateScrollCanvas should calculate new scroll state correctly 1`] = ` +Object { + "canvasTimeEnd": 1540720800000, + "canvasTimeStart": 1540461600000, + "dimensionItems": Array [ + Object { + "dimensions": Object { + "collisionLeft": 1540540000000, + "collisionWidth": 6803877, + "height": 22.5, + "left": NaN, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": NaN, + }, + "id": "0", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540570000000, + "collisionWidth": 14875919, + "height": 22.5, + "left": NaN, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": NaN, + }, + "id": "1", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540620000000, + "collisionWidth": 20397548, + "height": 22.5, + "left": NaN, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": NaN, + }, + "id": "2", + }, + ], + "groupHeights": Array [ + 37.5, + 30, + ], + "groupTops": Array [ + 0, + 37.5, + ], + "height": 67.5, + "visibleTimeEnd": 1540634400000, + "visibleTimeStart": 1540548000000, +} +`; + +exports[`calculateScrollCanvas should calculate new state if zoom changed correctly 1`] = ` +Object { + "canvasTimeEnd": 1540681200000, + "canvasTimeStart": 1540411200000, + "dimensionItems": Array [ + Object { + "dimensions": Object { + "collisionLeft": 1540540000000, + "collisionWidth": 6803877, + "height": 22.5, + "left": NaN, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": NaN, + }, + "id": "0", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540570000000, + "collisionWidth": 14875919, + "height": 22.5, + "left": NaN, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": NaN, + }, + "id": "1", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540620000000, + "collisionWidth": 20397548, + "height": 22.5, + "left": NaN, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": NaN, + }, + "id": "2", + }, + ], + "groupHeights": Array [ + 37.5, + 30, + ], + "groupTops": Array [ + 0, + 37.5, + ], + "height": 67.5, + "visibleTimeEnd": 1540591200000, + "visibleTimeStart": 1540501200000, +} +`; diff --git a/__tests__/utils/calendar/__snapshots__/get-item-dimensions.js.snap b/__tests__/utils/calendar/__snapshots__/get-item-dimensions.js.snap index b945fb7ea..06f90cb2d 100644 --- a/__tests__/utils/calendar/__snapshots__/get-item-dimensions.js.snap +++ b/__tests__/utils/calendar/__snapshots__/get-item-dimensions.js.snap @@ -6,7 +6,7 @@ Object { "collisionLeft": 1540540000000, "collisionWidth": 6803877, "height": 60, - "left": NaN, + "left": 1449.074074074074, "order": Object { "group": Object { "id": "1", @@ -15,7 +15,7 @@ Object { }, "stack": true, "top": null, - "width": NaN, + "width": 78.74857638888898, }, "id": "0", } diff --git a/__tests__/utils/calendar/calculate-scroll-canvas.js b/__tests__/utils/calendar/calculate-scroll-canvas.js index 2d9fbbe6b..ed5ee7048 100644 --- a/__tests__/utils/calendar/calculate-scroll-canvas.js +++ b/__tests__/utils/calendar/calculate-scroll-canvas.js @@ -22,6 +22,20 @@ describe('calculateScrollCanvas', () => { expect(result).toHaveProperty('visibleTimeEnd') expect(result).toHaveProperty('dimensionItems') }) + it('should calculate new scroll state correctly', () => { + const newStartTime = visibleTimeStart.clone().add(13, 'h') + const newEndTime = visibleTimeEnd.clone().add(13, 'h') + const result = calculateScrollCanvas( + newStartTime.valueOf(), + newEndTime.valueOf(), + false, + items, + groups, + props, + state + ) + expect(result).toMatchSnapshot() + }) it('should skip new calculation if new visible start and visible end in canvas', () => { const newStartTime = visibleTimeStart.clone().add(1, 'h') const newEndTime = visibleTimeEnd.clone().add(1, 'h') @@ -70,4 +84,18 @@ describe('calculateScrollCanvas', () => { expect(result).toHaveProperty('visibleTimeEnd') expect(result).toHaveProperty('dimensionItems') }) + it('should calculate new state if zoom changed correctly', () => { + const newStartTime = visibleTimeStart.clone() + const newEndTime = visibleTimeEnd.clone().add(1, 'h') + const result = calculateScrollCanvas( + newStartTime.valueOf(), + newEndTime.valueOf(), + false, + items, + groups, + props, + state + ) + expect(result).toMatchSnapshot() + }) }) diff --git a/src/lib/Timeline.js b/src/lib/Timeline.js index f73310cc1..2512f0396 100644 --- a/src/lib/Timeline.js +++ b/src/lib/Timeline.js @@ -18,7 +18,8 @@ import { getNextUnit, stackItems, calculateTimeForXPosition, - calculateScrollCanvas + calculateScrollCanvas, + getCanvasBoundariesFromVisibleTime, } from './utility/calendar' import { _get, _length } from './utility/generic' import { @@ -254,10 +255,9 @@ export default class ReactCalendarTimeline extends Component { width, visibleTimeStart, visibleTimeEnd, - canvasTimeStart + canvasTimeStart, + canvasTimeEnd, } = this.state - const zoom = visibleTimeEnd - visibleTimeStart - const canvasTimeEnd = canvasTimeStart + zoom * 3 return { timelineWidth: width, @@ -287,13 +287,15 @@ export default class ReactCalendarTimeline extends Component { ) } + const [canvasTimeStart, canvasTimeEnd] = getCanvasBoundariesFromVisibleTime(visibleTimeStart, visibleTimeEnd) + this.state = { width: 1000, visibleTimeStart: visibleTimeStart, visibleTimeEnd: visibleTimeEnd, - canvasTimeStart: visibleTimeStart - (visibleTimeEnd - visibleTimeStart), - + canvasTimeStart: canvasTimeStart, + canvasTimeEnd: canvasTimeEnd, selectedItem: null, dragTime: null, dragGroupTitle: null, @@ -594,17 +596,12 @@ export default class ReactCalendarTimeline extends Component { const { width, canvasTimeStart, - visibleTimeStart, - visibleTimeEnd + canvasTimeEnd, } = this.state // this gives us distance from left of row element, so event is in // context of the row element, not client or page const { offsetX } = e.nativeEvent - // FIXME: DRY up way to calculate canvasTimeEnd - const zoom = visibleTimeEnd - visibleTimeStart - const canvasTimeEnd = zoom * 3 + canvasTimeStart - let time = calculateTimeForXPosition( canvasTimeStart, canvasTimeEnd, @@ -950,12 +947,12 @@ export default class ReactCalendarTimeline extends Component { width, visibleTimeStart, visibleTimeEnd, - canvasTimeStart + canvasTimeStart, + canvasTimeEnd, } = this.state let { dimensionItems, height, groupHeights, groupTops } = this.state const zoom = visibleTimeEnd - visibleTimeStart - const canvasTimeEnd = canvasTimeStart + zoom * 3 const canvasWidth = width * 3 const minUnit = getMinUnit(zoom, width, timeSteps) const headerHeight = headerLabelGroupHeight + headerLabelHeight diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index dd26fd58c..96b888336 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -448,12 +448,12 @@ export function stackItems( resizingItem, resizingEdge, resizeTime, - newGroupOrder + newGroupOrder, + canvasTimeEnd, } = state - const zoom = visibleTimeEnd - visibleTimeStart - const canvasTimeEnd = canvasTimeStart + zoom * 3 const canvasWidth = width * 3 + // Find items that fit within canvasTimeStart and canvasTimeEnd // this is used when calculating the number of 'lines' each group // will use. @@ -596,6 +596,18 @@ export function getItemWithInteractions({ return newItem } +/** + * get canvas start and end time from visible start and end time + * @param {number} visibleTimeStart + * @param {number} visibleTimeEnd + */ +export function getCanvasBoundariesFromVisibleTime(visibleTimeStart, visibleTimeEnd) { + const zoom = visibleTimeEnd - visibleTimeStart + const canvasTimeStart = visibleTimeStart - (visibleTimeEnd - visibleTimeStart) + const canvasTimeEnd = canvasTimeStart + zoom * 3 + return [canvasTimeStart, canvasTimeEnd] +} + /** * Get the the canvas area for a given visible time * Will shift the start/end of the canvas if the visible time @@ -631,8 +643,13 @@ export function calculateScrollCanvas( visibleTimeEnd <= oldCanvasTimeStart + oldZoom * 2.5 if (!canKeepCanvas || forceUpdateDimensions) { - newState.canvasTimeStart = - visibleTimeStart - (visibleTimeEnd - visibleTimeStart) + const [canvasTimeStart, canvasTimeEnd] = getCanvasBoundariesFromVisibleTime(visibleTimeStart,visibleTimeEnd) + newState.canvasTimeStart = canvasTimeStart + newState.canvasTimeEnd = canvasTimeEnd + const mergedState = { + ...state, + ...newState, + } // The canvas cannot be kept, so calculate the new items position Object.assign( newState, @@ -644,7 +661,7 @@ export function calculateScrollCanvas( visibleTimeEnd, state.width, props, - state + mergedState, ) ) } From 9bb014c899e762eaeb52e6ca54d632d19fcebab3 Mon Sep 17 00:00:00 2001 From: ilaiwi Date: Thu, 22 Nov 2018 20:00:23 +0200 Subject: [PATCH 23/34] solve NaN issue in snapshot --- __fixtures__/stateAndProps.js | 3 ++- .../calculate-scroll-canvas.js.snap | 24 +++++++++---------- src/lib/utility/calendar.js | 2 +- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/__fixtures__/stateAndProps.js b/__fixtures__/stateAndProps.js index 0699c0076..8e08327ee 100644 --- a/__fixtures__/stateAndProps.js +++ b/__fixtures__/stateAndProps.js @@ -21,7 +21,8 @@ export const state = { canvasTimeStart: moment('2018-10-25T00:00:00.000').valueOf(), visibleTimeEnd: visibleTimeEnd.valueOf(), visibleTimeStart: visibleTimeStart.valueOf(), - canvasTimeEnd: 1540674000000 + canvasTimeEnd: 1540674000000, + width: 1000, } //offset 1 hour diff --git a/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap b/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap index c88d05bb4..ed8967726 100644 --- a/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap +++ b/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap @@ -10,7 +10,7 @@ Object { "collisionLeft": 1540540000000, "collisionWidth": 6803877, "height": 22.5, - "left": NaN, + "left": 907.4074074074074, "order": Object { "group": Object { "id": "1", @@ -19,7 +19,7 @@ Object { }, "stack": true, "top": 7.5, - "width": NaN, + "width": 78.74857638888886, }, "id": "0", }, @@ -28,7 +28,7 @@ Object { "collisionLeft": 1540570000000, "collisionWidth": 14875919, "height": 22.5, - "left": NaN, + "left": 1254.6296296296296, "order": Object { "group": Object { "id": "1", @@ -37,7 +37,7 @@ Object { }, "stack": true, "top": 7.5, - "width": NaN, + "width": 172.1749884259259, }, "id": "1", }, @@ -46,7 +46,7 @@ Object { "collisionLeft": 1540620000000, "collisionWidth": 20397548, "height": 22.5, - "left": NaN, + "left": 1833.3333333333333, "order": Object { "group": Object { "id": "1", @@ -55,7 +55,7 @@ Object { }, "stack": true, "top": 7.5, - "width": NaN, + "width": 236.08273148148123, }, "id": "2", }, @@ -84,7 +84,7 @@ Object { "collisionLeft": 1540540000000, "collisionWidth": 6803877, "height": 22.5, - "left": NaN, + "left": 1431.111111111111, "order": Object { "group": Object { "id": "1", @@ -93,7 +93,7 @@ Object { }, "stack": true, "top": 7.5, - "width": NaN, + "width": 75.59863333333351, }, "id": "0", }, @@ -102,7 +102,7 @@ Object { "collisionLeft": 1540570000000, "collisionWidth": 14875919, "height": 22.5, - "left": NaN, + "left": 1764.4444444444446, "order": Object { "group": Object { "id": "1", @@ -111,7 +111,7 @@ Object { }, "stack": true, "top": 7.5, - "width": NaN, + "width": 165.28798888888878, }, "id": "1", }, @@ -120,7 +120,7 @@ Object { "collisionLeft": 1540620000000, "collisionWidth": 20397548, "height": 22.5, - "left": NaN, + "left": 2320, "order": Object { "group": Object { "id": "1", @@ -129,7 +129,7 @@ Object { }, "stack": true, "top": 7.5, - "width": NaN, + "width": 226.6394222222225, }, "id": "2", }, diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 96b888336..ec1f7042b 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -659,7 +659,7 @@ export function calculateScrollCanvas( newState.canvasTimeStart, visibleTimeStart, visibleTimeEnd, - state.width, + mergedState.width, props, mergedState, ) From a4d78fe7b786cbe12555a08b5e2d588dde8e345a Mon Sep 17 00:00:00 2001 From: ilaiwi Date: Thu, 22 Nov 2018 20:45:46 +0200 Subject: [PATCH 24/34] getCanvasWidth --- __tests__/utils/calendar/stack-items.js | 19 +++++++++++++++++++ src/lib/Timeline.js | 10 +++++----- src/lib/utility/calendar.js | 11 ++++++++++- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/__tests__/utils/calendar/stack-items.js b/__tests__/utils/calendar/stack-items.js index 80f40fe9e..339dc411c 100644 --- a/__tests__/utils/calendar/stack-items.js +++ b/__tests__/utils/calendar/stack-items.js @@ -64,4 +64,23 @@ describe('stackItems', () => { ) ).toMatchSnapshot() }) + it("should return empty dimensions if groups are empty", ()=>{ + expect( + stackItems( + items, + [], + state.canvasTimeStart, + stateMoveItem.visibleTimeStart, + stateMoveItem.visibleTimeEnd, + 3000, + props, + stateResizeItemRight + ) + ).toMatchObject({ + dimensionItems: [], + height: 0, + groupHeights: [], + groupTops: [] + }) + }) }) diff --git a/src/lib/Timeline.js b/src/lib/Timeline.js index 2512f0396..84547a625 100644 --- a/src/lib/Timeline.js +++ b/src/lib/Timeline.js @@ -20,6 +20,7 @@ import { calculateTimeForXPosition, calculateScrollCanvas, getCanvasBoundariesFromVisibleTime, + getCanvasWidth, } from './utility/calendar' import { _get, _length } from './utility/generic' import { @@ -291,7 +292,6 @@ export default class ReactCalendarTimeline extends Component { this.state = { width: 1000, - visibleTimeStart: visibleTimeStart, visibleTimeEnd: visibleTimeEnd, canvasTimeStart: canvasTimeStart, @@ -420,7 +420,7 @@ export default class ReactCalendarTimeline extends Component { } = this.container.getBoundingClientRect() let width = containerWidth - props.sidebarWidth - props.rightSidebarWidth - + const { dimensionItems, height, groupHeights, groupTops } = stackItems( props.items, props.groups, @@ -440,7 +440,7 @@ export default class ReactCalendarTimeline extends Component { dimensionItems, height, groupHeights, - groupTops + groupTops, }) this.scrollComponent.scrollLeft = width @@ -605,7 +605,7 @@ export default class ReactCalendarTimeline extends Component { let time = calculateTimeForXPosition( canvasTimeStart, canvasTimeEnd, - width * 3, + getCanvasWidth(width), offsetX ) time = Math.floor(time / dragSnap) * dragSnap @@ -953,7 +953,7 @@ export default class ReactCalendarTimeline extends Component { let { dimensionItems, height, groupHeights, groupTops } = this.state const zoom = visibleTimeEnd - visibleTimeStart - const canvasWidth = width * 3 + const canvasWidth = getCanvasWidth(width) const minUnit = getMinUnit(zoom, width, timeSteps) const headerHeight = headerLabelGroupHeight + headerLabelHeight diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index ec1f7042b..0d5f89737 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -451,7 +451,7 @@ export function stackItems( newGroupOrder, canvasTimeEnd, } = state - const canvasWidth = width * 3 + const canvasWidth = getCanvasWidth(width) // Find items that fit within canvasTimeStart and canvasTimeEnd @@ -507,6 +507,15 @@ export function stackItems( return { dimensionItems, height, groupHeights, groupTops } } +/** + * get canvas width from visible width + * @param {*} width + * @param {*} buffer + */ +export function getCanvasWidth(width, buffer = 3) { + return width * buffer; +} + /** * get item's position, dimensions and collisions * @param {*} item From 6f0e116bda6ec55e3fe395eaa6882b9691273665 Mon Sep 17 00:00:00 2001 From: ilaiwi Date: Sat, 24 Nov 2018 12:35:04 +0200 Subject: [PATCH 25/34] refactor stackItems to stackTimelineItems --- __tests__/utils/calendar/stack-items.js | 123 +++++++++++++++-------- src/lib/Timeline.js | 95 ++++++++++++------ src/lib/utility/calendar.js | 128 +++++++++++++----------- 3 files changed, 212 insertions(+), 134 deletions(-) diff --git a/__tests__/utils/calendar/stack-items.js b/__tests__/utils/calendar/stack-items.js index 339dc411c..85e64bb5c 100644 --- a/__tests__/utils/calendar/stack-items.js +++ b/__tests__/utils/calendar/stack-items.js @@ -1,80 +1,115 @@ -import { stackItems } from 'lib/utility/calendar' +import { stackTimelineItems } from 'lib/utility/calendar' import { items, groups } from '../../../__fixtures__/itemsAndGroups' import { props, state, stateMoveItem, stateResizeItemLeft, - stateResizeItemRight, + stateResizeItemRight } from '../../../__fixtures__/stateAndProps' describe('stackItems', () => { it('work as expected', () => { expect( - stackItems( + stackTimelineItems( items, groups, + 9000, state.canvasTimeStart, - state.visibleTimeStart, - state.visibleTimeEnd, - 3000, - props, - state + state.canvasTimeEnd, + props.keys, + props.lineHeight, + props.itemHeightRatio, + props.stackItems, + state.draggingItem, + state.resizingItem, + state.dragTime, + state.resizingEdge, + state.resizeTime, + state.newGroupOrder ) ).toMatchSnapshot() }) it('should stack items while moving an item', () => { expect( - stackItems( + stackTimelineItems( items, groups, - state.canvasTimeStart, - stateMoveItem.visibleTimeStart, - stateMoveItem.visibleTimeEnd, - 3000, - props, - stateMoveItem + 9000, + stateMoveItem.canvasTimeStart, + stateMoveItem.canvasTimeEnd, + props.keys, + props.lineHeight, + props.itemHeightRatio, + props.stackItems, + stateMoveItem.draggingItem, + stateMoveItem.resizingItem, + stateMoveItem.dragTime, + stateMoveItem.resizingEdge, + stateMoveItem.resizeTime, + stateMoveItem.newGroupOrder ) ).toMatchSnapshot() }) it('should stack items while resize item left', () => { expect( - stackItems( - items, - groups, - state.canvasTimeStart, - stateMoveItem.visibleTimeStart, - stateMoveItem.visibleTimeEnd, - 3000, - props, - stateResizeItemLeft - ) - ).toMatchSnapshot() + stackTimelineItems( + items, + groups, + 9000, + stateResizeItemLeft.canvasTimeStart, + stateResizeItemLeft.canvasTimeEnd, + props.keys, + props.lineHeight, + props.itemHeightRatio, + props.stackItems, + stateResizeItemLeft.draggingItem, + stateResizeItemLeft.resizingItem, + stateResizeItemLeft.dragTime, + stateResizeItemLeft.resizingEdge, + stateResizeItemLeft.resizeTime, + stateResizeItemLeft.newGroupOrder + ) + ).toMatchSnapshot() }) it('should stack items while resize item right', () => { expect( - stackItems( - items, - groups, - state.canvasTimeStart, - stateMoveItem.visibleTimeStart, - stateMoveItem.visibleTimeEnd, - 3000, - props, - stateResizeItemRight - ) - ).toMatchSnapshot() + stackTimelineItems( + items, + groups, + 9000, + stateResizeItemRight.canvasTimeStart, + stateResizeItemRight.canvasTimeEnd, + props.keys, + props.lineHeight, + props.itemHeightRatio, + props.stackItems, + stateResizeItemRight.draggingItem, + stateResizeItemRight.resizingItem, + stateResizeItemRight.dragTime, + stateResizeItemRight.resizingEdge, + stateResizeItemRight.resizeTime, + stateResizeItemRight.newGroupOrder + ) + ).toMatchSnapshot() }) - it("should return empty dimensions if groups are empty", ()=>{ + it('should return empty dimensions if groups are empty', () => { expect( - stackItems( + stackTimelineItems( items, [], + 9000, state.canvasTimeStart, - stateMoveItem.visibleTimeStart, - stateMoveItem.visibleTimeEnd, - 3000, - props, - stateResizeItemRight + state.canvasTimeEnd, + props.keys, + props.lineHeight, + props.itemHeightRatio, + props.stackItems, + state.draggingItem, + state.resizingItem, + state.dragTime, + state.resizingEdge, + state.resizeTime, + state.newGroupOrder ) ).toMatchObject({ dimensionItems: [], diff --git a/src/lib/Timeline.js b/src/lib/Timeline.js index 84547a625..4d30fd4ff 100644 --- a/src/lib/Timeline.js +++ b/src/lib/Timeline.js @@ -16,11 +16,11 @@ import windowResizeDetector from '../resize-detector/window' import { getMinUnit, getNextUnit, - stackItems, calculateTimeForXPosition, calculateScrollCanvas, getCanvasBoundariesFromVisibleTime, getCanvasWidth, + stackTimelineItems, } from './utility/calendar' import { _get, _length } from './utility/generic' import { @@ -304,15 +304,24 @@ export default class ReactCalendarTimeline extends Component { resizingEdge: null } - const { dimensionItems, height, groupHeights, groupTops } = stackItems( - props.items, - props.groups, - this.state.canvasTimeStart, - this.state.visibleTimeStart, - this.state.visibleTimeEnd, - this.state.width, - this.props, - this.state + const canvasWidth= getCanvasWidth(this.state.width) + + const { dimensionItems, height, groupHeights, groupTops } = stackTimelineItems( + props.items, + props.groups, + canvasWidth, + this.state.canvasTimeStart, + this.state.canvasTimeEnd, + props.keys, + props.lineHeight, + props.itemHeightRatio, + props.stackItems, + this.state.draggingItem, + this.state.resizingItem, + this.state.dragTime, + this.state.resizingEdge, + this.state.resizeTime, + this.state.newGroupOrder ) /* eslint-disable react/no-direct-mutation-state */ @@ -374,15 +383,25 @@ export default class ReactCalendarTimeline extends Component { )) } else if (forceUpdate) { // Calculate new item stack position as canvas may have changed + const canvasWidth = getCanvasWidth(prevState.width) Object.assign(derivedState, - stackItems(items, - groups, + stackTimelineItems( + items, + groups, + canvasWidth, prevState.canvasTimeStart, - prevState.visibleTimeStart, - prevState.visibleTimeEnd, - prevState.width, - nextProps, - prevState)) + prevState.canvasTimeEnd, + nextProps.keys, + nextProps.lineHeight, + nextProps.itemHeightRatio, + nextProps.stackItems, + prevState.draggingItem, + prevState.resizingItem, + prevState.dragTime, + prevState.resizingEdge, + prevState.resizeTime, + prevState.newGroupOrder + )) } return derivedState @@ -420,16 +439,23 @@ export default class ReactCalendarTimeline extends Component { } = this.container.getBoundingClientRect() let width = containerWidth - props.sidebarWidth - props.rightSidebarWidth - - const { dimensionItems, height, groupHeights, groupTops } = stackItems( + const canvasWidth = getCanvasWidth(width) + const { dimensionItems, height, groupHeights, groupTops } = stackTimelineItems( props.items, props.groups, + canvasWidth, this.state.canvasTimeStart, - this.state.visibleTimeStart, - this.state.visibleTimeEnd, - width, - this.props, - this.state + this.state.canvasTimeEnd, + props.keys, + props.lineHeight, + props.itemHeightRatio, + props.stackItems, + this.state.draggingItem, + this.state.resizingItem, + this.state.dragTime, + this.state.resizingEdge, + this.state.resizeTime, + this.state.newGroupOrder ) // this is needed by dragItem since it uses pageY from the drag events @@ -960,15 +986,22 @@ export default class ReactCalendarTimeline extends Component { const isInteractingWithItem = !!draggingItem || !!resizingItem if (isInteractingWithItem) { - const stackResults = stackItems( + const stackResults = stackTimelineItems( items, groups, - canvasTimeStart, - visibleTimeStart, - visibleTimeEnd, - width, - this.props, - this.state + canvasWidth, + this.state.canvasTimeStart, + this.state.canvasTimeEnd, + this.props.keys, + this.props.lineHeight, + this.props.itemHeightRatio, + this.props.stackItems, + this.state.draggingItem, + this.state.resizingItem, + this.state.dragTime, + this.state.resizingEdge, + this.state.resizeTime, + this.state.newGroupOrder ) dimensionItems = stackResults.dimensionItems height = stackResults.height diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 0d5f89737..3923aee0e 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -414,56 +414,43 @@ export function stackAll(items, groupOrders, lineHeight, stackItems) { * within the canvas area * @param {item[]} items * @param {group[]} groups - * @param {number} canvasTimeStart - * @param {number} visibleTimeStart - * @param {number} visibleTimeEnd - * @param {number} width - * @param {*} props - * @param {*} state + * @param {number} canvasWidth + * @param {number} canvasTimeStart + * @param {number} canvasTimeEnd + * @param {*} keys + * @param {number} lineHeight + * @param {number} itemHeightRatio + * @param {boolean} stackItems + * @param {*} draggingItem + * @param {*} resizingItem + * @param {number} dragTime + * @param {left or right} resizingEdge + * @param {number} resizeTime + * @param {number} newGroupOrder */ -export function stackItems( +export function stackTimelineItems( items, groups, + canvasWidth, canvasTimeStart, - visibleTimeStart, - visibleTimeEnd, - width, - props, - state + canvasTimeEnd, + keys, + lineHeight, + itemHeightRatio, + stackItems, + draggingItem, + resizingItem, + dragTime, + resizingEdge, + resizeTime, + newGroupOrder, ) { - // if there are no groups return an empty array of dimensions - if (groups.length === 0) { - return { - dimensionItems: [], - height: 0, - groupHeights: [], - groupTops: [] - } - } - - const { keys, lineHeight, stackItems, itemHeightRatio } = props - const { - draggingItem, - dragTime, - resizingItem, - resizingEdge, - resizeTime, - newGroupOrder, - canvasTimeEnd, - } = state - const canvasWidth = getCanvasWidth(width) - - - // Find items that fit within canvasTimeStart and canvasTimeEnd - // this is used when calculating the number of 'lines' each group - // will use. const visibleItems = getVisibleItems( items, canvasTimeStart, canvasTimeEnd, keys ) - const visibleItemsWithInteraction = visibleItems.map(item => getItemWithInteractions({ item, @@ -478,9 +465,18 @@ export function stackItems( }) ) + // if there are no groups return an empty array of dimensions + if (groups.length === 0) { + return { + dimensionItems: [], + height: 0, + groupHeights: [], + groupTops: [] + } + } + // Get the order of groups based on their id key const groupOrders = getGroupOrders(groups, keys) - let dimensionItems = visibleItemsWithInteraction .map(item => getItemDimensions({ @@ -495,7 +491,6 @@ export function stackItems( }) ) .filter(item => !!item) - // Get a new array of groupOrders holding the stacked items const { height, groupHeights, groupTops } = stackAll( dimensionItems, @@ -503,21 +498,20 @@ export function stackItems( lineHeight, stackItems ) - - return { dimensionItems, height, groupHeights, groupTops } + return{ dimensionItems, height, groupHeights, groupTops } } /** * get canvas width from visible width - * @param {*} width - * @param {*} buffer + * @param {*} width + * @param {*} buffer */ export function getCanvasWidth(width, buffer = 3) { - return width * buffer; + return width * buffer } /** - * get item's position, dimensions and collisions + * get item's position, dimensions and collisions * @param {*} item * @param {*} keys * @param {*} canvasTimeStart @@ -607,10 +601,13 @@ export function getItemWithInteractions({ /** * get canvas start and end time from visible start and end time - * @param {number} visibleTimeStart - * @param {number} visibleTimeEnd + * @param {number} visibleTimeStart + * @param {number} visibleTimeEnd */ -export function getCanvasBoundariesFromVisibleTime(visibleTimeStart, visibleTimeEnd) { +export function getCanvasBoundariesFromVisibleTime( + visibleTimeStart, + visibleTimeEnd +) { const zoom = visibleTimeEnd - visibleTimeStart const canvasTimeStart = visibleTimeStart - (visibleTimeEnd - visibleTimeStart) const canvasTimeEnd = canvasTimeStart + zoom * 3 @@ -652,25 +649,38 @@ export function calculateScrollCanvas( visibleTimeEnd <= oldCanvasTimeStart + oldZoom * 2.5 if (!canKeepCanvas || forceUpdateDimensions) { - const [canvasTimeStart, canvasTimeEnd] = getCanvasBoundariesFromVisibleTime(visibleTimeStart,visibleTimeEnd) + const [canvasTimeStart, canvasTimeEnd] = getCanvasBoundariesFromVisibleTime( + visibleTimeStart, + visibleTimeEnd + ) newState.canvasTimeStart = canvasTimeStart newState.canvasTimeEnd = canvasTimeEnd const mergedState = { ...state, - ...newState, + ...newState } + + const canvasWidth = getCanvasWidth(mergedState.width) + // The canvas cannot be kept, so calculate the new items position Object.assign( newState, - stackItems( + stackTimelineItems( items, groups, - newState.canvasTimeStart, - visibleTimeStart, - visibleTimeEnd, - mergedState.width, - props, - mergedState, + canvasWidth, + mergedState.canvasTimeStart, + mergedState.canvasTimeEnd, + props.keys, + props.lineHeight, + props.itemHeightRatio, + props.stackItems, + mergedState.draggingItem, + mergedState.resizingItem, + mergedState.dragTime, + mergedState.resizingEdge, + mergedState.resizeTime, + mergedState.newGroupOrder, ) ) } From 1c5095096dd1444751def6ee7c9592625027b198 Mon Sep 17 00:00:00 2001 From: ilaiwi Date: Sat, 24 Nov 2018 13:43:41 +0200 Subject: [PATCH 26/34] add one more item and group --- __fixtures__/groupOrderAndItemDimentions.js | 30 ++++++- __fixtures__/itemsAndGroups.js | 11 ++- .../calculate-scroll-canvas.js.snap | 44 +++++++++- .../__snapshots__/get-group-orders.js.snap | 6 ++ .../__snapshots__/get-grouped-items.js.snap | 32 ++++++- .../calendar/__snapshots__/stack-all.js.snap | 8 +- .../__snapshots__/stack-items.js.snap | 88 ++++++++++++++++++- src/lib/utility/calendar.js | 2 +- 8 files changed, 205 insertions(+), 16 deletions(-) diff --git a/__fixtures__/groupOrderAndItemDimentions.js b/__fixtures__/groupOrderAndItemDimentions.js index 27e416efb..06ae117d4 100644 --- a/__fixtures__/groupOrderAndItemDimentions.js +++ b/__fixtures__/groupOrderAndItemDimentions.js @@ -10,6 +10,12 @@ export const orderedGroups = { id: '2' }, index: 1 + }, + '3': { + group: { + id: '3' + }, + index: 2 } } @@ -28,7 +34,7 @@ export const dimensionItems = [ }, stack: true, top: 7.5, - width: 236.24572916666668 + width: 236.24572916666602 }, id: '0' }, @@ -46,7 +52,7 @@ export const dimensionItems = [ }, stack: true, top: 7.5, - width: 516.5249652777778 + width: 516.5249652777784 }, id: '1' }, @@ -64,8 +70,26 @@ export const dimensionItems = [ }, stack: true, top: 7.5, - width: 708.2481944444445 + width: 708.2481944444444 }, id: '2' + }, + { + dimensions: { + collisionLeft: 1540656000000, + collisionWidth: 20397548, + height: 22.5, + left: 8375, + order: { + group: { + id: '3' + }, + index: 2 + }, + stack: true, + top: 75, + width: 625 + }, + id: '3' } ] diff --git a/__fixtures__/itemsAndGroups.js b/__fixtures__/itemsAndGroups.js index 76a8ac020..e51ac1a56 100644 --- a/__fixtures__/itemsAndGroups.js +++ b/__fixtures__/itemsAndGroups.js @@ -25,7 +25,16 @@ export const items = [ canMove: false, canResize: false, className: '' + }, + { + id: '3', + group: '3', + start_time: moment('2018-10-27T18:00:00.000').valueOf(), + end_time: moment('2018-10-27T23:39:57.548').valueOf(), + canMove: false, + canResize: false, + className: '' } ] - export const groups = [{ id: '1' }, { id: '2' }] \ No newline at end of file + export const groups = [{ id: '1' }, { id: '2' }, { id: '3' }] \ No newline at end of file diff --git a/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap b/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap index ed8967726..b74fa35e8 100644 --- a/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap +++ b/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap @@ -59,16 +59,36 @@ Object { }, "id": "2", }, + Object { + "dimensions": Object { + "collisionLeft": 1540656000000, + "collisionWidth": 20397548, + "height": 22.5, + "left": 2250, + "order": Object { + "group": Object { + "id": "3", + }, + "index": 2, + }, + "stack": true, + "top": 75, + "width": 236.08273148148146, + }, + "id": "3", + }, ], "groupHeights": Array [ 37.5, 30, + 37.5, ], "groupTops": Array [ 0, 37.5, + 67.5, ], - "height": 67.5, + "height": 105, "visibleTimeEnd": 1540634400000, "visibleTimeStart": 1540548000000, } @@ -133,16 +153,36 @@ Object { }, "id": "2", }, + Object { + "dimensions": Object { + "collisionLeft": 1540656000000, + "collisionWidth": 20397548, + "height": 22.5, + "left": 2720, + "order": Object { + "group": Object { + "id": "3", + }, + "index": 2, + }, + "stack": true, + "top": 75, + "width": 226.6394222222225, + }, + "id": "3", + }, ], "groupHeights": Array [ 37.5, 30, + 37.5, ], "groupTops": Array [ 0, 37.5, + 67.5, ], - "height": 67.5, + "height": 105, "visibleTimeEnd": 1540591200000, "visibleTimeStart": 1540501200000, } diff --git a/__tests__/utils/calendar/__snapshots__/get-group-orders.js.snap b/__tests__/utils/calendar/__snapshots__/get-group-orders.js.snap index 6725dacd9..08e41b54f 100644 --- a/__tests__/utils/calendar/__snapshots__/get-group-orders.js.snap +++ b/__tests__/utils/calendar/__snapshots__/get-group-orders.js.snap @@ -14,5 +14,11 @@ Object { }, "index": 1, }, + "3": Object { + "group": Object { + "id": "3", + }, + "index": 2, + }, } `; diff --git a/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap b/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap index 95053d9ba..fc94c343d 100644 --- a/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap +++ b/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap @@ -22,7 +22,7 @@ Object { }, "stack": true, "top": 7.5, - "width": 236.24572916666668, + "width": 236.24572916666602, }, "id": "0", }, @@ -40,7 +40,7 @@ Object { }, "stack": true, "top": 7.5, - "width": 516.5249652777778, + "width": 516.5249652777784, }, "id": "1", }, @@ -58,7 +58,7 @@ Object { }, "stack": true, "top": 7.5, - "width": 708.2481944444445, + "width": 708.2481944444444, }, "id": "2", }, @@ -71,5 +71,31 @@ Object { "index": 1, "items": Array [], }, + "2": Object { + "group": Object { + "id": "3", + }, + "index": 2, + "items": Array [ + Object { + "dimensions": Object { + "collisionLeft": 1540656000000, + "collisionWidth": 20397548, + "height": 22.5, + "left": 8375, + "order": Object { + "group": Object { + "id": "3", + }, + "index": 2, + }, + "stack": true, + "top": 75, + "width": 625, + }, + "id": "3", + }, + ], + }, } `; diff --git a/__tests__/utils/calendar/__snapshots__/stack-all.js.snap b/__tests__/utils/calendar/__snapshots__/stack-all.js.snap index 1cd25f355..7121386fb 100644 --- a/__tests__/utils/calendar/__snapshots__/stack-all.js.snap +++ b/__tests__/utils/calendar/__snapshots__/stack-all.js.snap @@ -5,12 +5,14 @@ Object { "groupHeights": Array [ 60, 60, + 60, ], "groupTops": Array [ 0, 60, + 120, ], - "height": 120, + "height": 180, } `; @@ -19,11 +21,13 @@ Object { "groupHeights": Array [ 60, 60, + 60, ], "groupTops": Array [ 0, 60, + 120, ], - "height": 120, + "height": 180, } `; diff --git a/__tests__/utils/calendar/__snapshots__/stack-items.js.snap b/__tests__/utils/calendar/__snapshots__/stack-items.js.snap index 6b2524220..5d522b546 100644 --- a/__tests__/utils/calendar/__snapshots__/stack-items.js.snap +++ b/__tests__/utils/calendar/__snapshots__/stack-items.js.snap @@ -57,16 +57,36 @@ Object { }, "id": "2", }, + Object { + "dimensions": Object { + "collisionLeft": 1540656000000, + "collisionWidth": 20397548, + "height": 22.5, + "left": 8375, + "order": Object { + "group": Object { + "id": "3", + }, + "index": 2, + }, + "stack": true, + "top": 75, + "width": 625, + }, + "id": "3", + }, ], "groupHeights": Array [ 37.5, 30, + 37.5, ], "groupTops": Array [ 0, 37.5, + 67.5, ], - "height": 67.5, + "height": 105, } `; @@ -127,16 +147,36 @@ Object { }, "id": "2", }, + Object { + "dimensions": Object { + "collisionLeft": 1540656000000, + "collisionWidth": 20397548, + "height": 22.5, + "left": 8375, + "order": Object { + "group": Object { + "id": "3", + }, + "index": 2, + }, + "stack": true, + "top": 75, + "width": 625, + }, + "id": "3", + }, ], "groupHeights": Array [ 37.5, 30, + 37.5, ], "groupTops": Array [ 0, 37.5, + 67.5, ], - "height": 67.5, + "height": 105, } `; @@ -197,16 +237,36 @@ Object { }, "id": "2", }, + Object { + "dimensions": Object { + "collisionLeft": 1540656000000, + "collisionWidth": 20397548, + "height": 22.5, + "left": 8375, + "order": Object { + "group": Object { + "id": "3", + }, + "index": 2, + }, + "stack": true, + "top": 75, + "width": 625, + }, + "id": "3", + }, ], "groupHeights": Array [ 37.5, 30, + 37.5, ], "groupTops": Array [ 0, 37.5, + 67.5, ], - "height": 67.5, + "height": 105, } `; @@ -267,15 +327,35 @@ Object { }, "id": "2", }, + Object { + "dimensions": Object { + "collisionLeft": 1540656000000, + "collisionWidth": 20397548, + "height": 22.5, + "left": 8375, + "order": Object { + "group": Object { + "id": "3", + }, + "index": 2, + }, + "stack": true, + "top": 75, + "width": 625, + }, + "id": "3", + }, ], "groupHeights": Array [ 37.5, 30, + 37.5, ], "groupTops": Array [ 0, 37.5, + 67.5, ], - "height": 67.5, + "height": 105, } `; diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 3923aee0e..53885f22c 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -370,7 +370,7 @@ export function stackAll(items, groupOrders, lineHeight, stackItems) { var groupedItems = getGroupedItems(items, groupOrders) - for (var index in groupedItems) { + for (var index in groupedItems) { const groupItems = groupedItems[index] const { items, group } = groupItems groupTops.push(totalHeight) From 42c5136f615fc3f4730a9edd03432b53d0f5f80f Mon Sep 17 00:00:00 2001 From: ilaiwi Date: Sat, 24 Nov 2018 19:37:20 +0200 Subject: [PATCH 27/34] WIP stackAll --- src/lib/utility/calendar.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 53885f22c..35dac61be 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -306,7 +306,7 @@ export function groupStack( group, groupHeight, totalHeight, - i + itemIndex ) { // calculate non-overlapping positions let curHeight = groupHeight @@ -317,7 +317,7 @@ export function groupStack( do { var collidingItem = null //Items are placed from i=0 onwards, only check items with index < i - for (var j = i - 1, jj = 0; j >= jj; j--) { + for (var j = itemIndex - 1, jj = 0; j >= jj; j--) { var other = group[j] if ( other.dimensions.top !== null && @@ -354,6 +354,10 @@ export function groupNoStack(lineHeight, item, groupHeight, totalHeight) { return { groupHeight, verticalMargin: 0 } } +function sum(arr=[]) { + return arr.reduce((acc, i)=> acc+i,0) +} + /** * Stack all groups * @param {*} items items to be stacked @@ -362,7 +366,7 @@ export function groupNoStack(lineHeight, item, groupHeight, totalHeight) { * @param {*} stackItems should items be stacked? */ export function stackAll(items, groupOrders, lineHeight, stackItems) { - var i, iMax + var itemIndex var totalHeight = 0 var groupHeights = [] @@ -373,7 +377,8 @@ export function stackAll(items, groupOrders, lineHeight, stackItems) { for (var index in groupedItems) { const groupItems = groupedItems[index] const { items, group } = groupItems - groupTops.push(totalHeight) + const nextHeight = sum(groupHeights) + groupTops.push(nextHeight) // Is group being stacked? const isGroupStacked = @@ -381,12 +386,12 @@ export function stackAll(items, groupOrders, lineHeight, stackItems) { var groupHeight = 0 var verticalMargin = 0 // Find positions for each item in group - for (i = 0, iMax = items.length; i < iMax; i++) { + for (itemIndex = 0; itemIndex < items.length; itemIndex++) { let r = {} if (isGroupStacked) { - r = groupStack(lineHeight, items[i], items, groupHeight, totalHeight, i) + r = groupStack(lineHeight, items[itemIndex], items, groupHeight, nextHeight, itemIndex) } else { - r = groupNoStack(lineHeight, items[i], groupHeight, totalHeight) + r = groupNoStack(lineHeight, items[itemIndex], groupHeight, nextHeight) } groupHeight = r.groupHeight verticalMargin = r.verticalMargin @@ -396,14 +401,12 @@ export function stackAll(items, groupOrders, lineHeight, stackItems) { // Do this late as item position still needs to be calculated if (group.height) { groupHeights.push(group.height) - totalHeight += group.height } else { groupHeights.push(Math.max(groupHeight + verticalMargin, lineHeight)) - totalHeight += Math.max(groupHeight + verticalMargin, lineHeight) } } return { - height: totalHeight, + height: sum(groupTops), groupHeights, groupTops } From 863d7b8ce7b70be370c0f97c088b13acffc80f8a Mon Sep 17 00:00:00 2001 From: ilaiwi Date: Sun, 25 Nov 2018 22:05:48 +0200 Subject: [PATCH 28/34] better items fixture --- __fixtures__/groupOrderAndItemDimentions.js | 144 +++++--- __fixtures__/itemsAndGroups.js | 18 + __fixtures__/stateAndProps.js | 5 + .../calculate-scroll-canvas.js.snap | 92 +++++- .../__snapshots__/get-grouped-items.js.snap | 56 +++- .../__snapshots__/group-no-stack.js.snap | 1 + .../__snapshots__/group-stack.js.snap | 1 + .../__snapshots__/stack-items.js.snap | 310 ++++++++++++++++-- __tests__/utils/calendar/stack-items.js | 24 +- src/lib/utility/calendar.js | 6 +- 10 files changed, 558 insertions(+), 99 deletions(-) diff --git a/__fixtures__/groupOrderAndItemDimentions.js b/__fixtures__/groupOrderAndItemDimentions.js index 06ae117d4..dbda31167 100644 --- a/__fixtures__/groupOrderAndItemDimentions.js +++ b/__fixtures__/groupOrderAndItemDimentions.js @@ -21,75 +21,111 @@ export const orderedGroups = { export const dimensionItems = [ { - dimensions: { - collisionLeft: 1540540000000, - collisionWidth: 6803877, - height: 22.5, - left: 4347.222222222223, - order: { - group: { - id: '1' + "dimensions": { + "collisionLeft": 1540540000000, + "collisionWidth": 6803877, + "height": 22.5, + "left": 907.4074074074074, + "order": { + "group": { + "id": "1", }, - index: 0 + "index": 0, }, - stack: true, - top: 7.5, - width: 236.24572916666602 + "stack": true, + "top": 7.5, + "width": 78.74857638888886, }, - id: '0' + "id": "0", }, { - dimensions: { - collisionLeft: 1540570000000, - collisionWidth: 14875919, - height: 22.5, - left: 5388.888888888889, - order: { - group: { - id: '1' + "dimensions": { + "collisionLeft": 1540532800000, + "collisionWidth": 21203877, + "height": 22.5, + "left": 824.074074074074, + "order": { + "group": { + "id": "1", }, - index: 0 + "index": 0, }, - stack: true, - top: 7.5, - width: 516.5249652777784 + "stack": true, + "top": 37.5, + "width": 245.4152430555556, }, - id: '1' + "id": "5", }, { - dimensions: { - collisionLeft: 1540620000000, - collisionWidth: 20397548, - height: 22.5, - left: 7125, - order: { - group: { - id: '1' + "dimensions": { + "collisionLeft": 1540550800000, + "collisionWidth": 24803877, + "height": 22.5, + "left": 1032.4074074074074, + "order": { + "group": { + "id": "1", }, - index: 0 + "index": 0, }, - stack: true, - top: 7.5, - width: 708.2481944444444 + "stack": true, + "top": 7.5, + "width": 287.08190972222224, }, - id: '2' + "id": "6", }, { - dimensions: { - collisionLeft: 1540656000000, - collisionWidth: 20397548, - height: 22.5, - left: 8375, - order: { - group: { - id: '3' + "dimensions": { + "collisionLeft": 1540570000000, + "collisionWidth": 14875919, + "height": 22.5, + "left": 1254.6296296296296, + "order": { + "group": { + "id": "1", }, - index: 2 + "index": 0, }, - stack: true, - top: 75, - width: 625 + "stack": true, + "top": 37.5, + "width": 172.1749884259259, }, - id: '3' - } -] + "id": "1", + }, + { + "dimensions": { + "collisionLeft": 1540620000000, + "collisionWidth": 20397548, + "height": 22.5, + "left": 1833.3333333333333, + "order": { + "group": { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 236.08273148148123, + }, + "id": "2", + }, + { + "dimensions": { + "collisionLeft": 1540656000000, + "collisionWidth": 20397548, + "height": 22.5, + "left": 2250, + "order": { + "group": { + "id": "3", + }, + "index": 2, + }, + "stack": true, + "top": 105, + "width": 236.08273148148146, + }, + "id": "3", + }, +] \ No newline at end of file diff --git a/__fixtures__/itemsAndGroups.js b/__fixtures__/itemsAndGroups.js index e51ac1a56..676d3a30c 100644 --- a/__fixtures__/itemsAndGroups.js +++ b/__fixtures__/itemsAndGroups.js @@ -9,6 +9,24 @@ export const items = [ canMove: false, canResize: false }, + { + id: '5', + group: '1', + start_time: moment('2018-10-26T08:46:40.000').valueOf(), + end_time: moment('2018-10-26T14:40:03.877').valueOf(), + canMove: false, + canResize: false, + className: '' + }, + { + id: '6', + group: '1', + start_time: moment('2018-10-26T13:46:40.000').valueOf(), + end_time: moment('2018-10-26T20:40:03.877').valueOf(), + canMove: false, + canResize: false, + className: '' + }, { id: '1', group: '1', diff --git a/__fixtures__/stateAndProps.js b/__fixtures__/stateAndProps.js index 8e08327ee..c343c4905 100644 --- a/__fixtures__/stateAndProps.js +++ b/__fixtures__/stateAndProps.js @@ -8,6 +8,11 @@ export const props = { itemHeightRatio: 0.75 } +export const propsNoStack = { + ...props, + stackItems: false, +} + export const visibleTimeStart = moment('2018-10-26T00:00:00.000') export const visibleTimeEnd = moment('2018-10-27T00:00:00.000') diff --git a/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap b/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap index b74fa35e8..cf4b29ce3 100644 --- a/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap +++ b/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap @@ -23,6 +23,42 @@ Object { }, "id": "0", }, + Object { + "dimensions": Object { + "collisionLeft": 1540532800000, + "collisionWidth": 21203877, + "height": 22.5, + "left": 824.074074074074, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 37.5, + "width": 245.4152430555556, + }, + "id": "5", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540550800000, + "collisionWidth": 24803877, + "height": 22.5, + "left": 1032.4074074074074, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 287.08190972222224, + }, + "id": "6", + }, Object { "dimensions": Object { "collisionLeft": 1540570000000, @@ -36,7 +72,7 @@ Object { "index": 0, }, "stack": true, - "top": 7.5, + "top": 37.5, "width": 172.1749884259259, }, "id": "1", @@ -72,23 +108,23 @@ Object { "index": 2, }, "stack": true, - "top": 75, + "top": 105, "width": 236.08273148148146, }, "id": "3", }, ], "groupHeights": Array [ - 37.5, + 67.5, 30, 37.5, ], "groupTops": Array [ 0, - 37.5, 67.5, + 97.5, ], - "height": 105, + "height": 165, "visibleTimeEnd": 1540634400000, "visibleTimeStart": 1540548000000, } @@ -117,6 +153,42 @@ Object { }, "id": "0", }, + Object { + "dimensions": Object { + "collisionLeft": 1540532800000, + "collisionWidth": 21203877, + "height": 22.5, + "left": 1351.111111111111, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 37.5, + "width": 235.5986333333335, + }, + "id": "5", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540550800000, + "collisionWidth": 24803877, + "height": 22.5, + "left": 1551.111111111111, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 275.5986333333335, + }, + "id": "6", + }, Object { "dimensions": Object { "collisionLeft": 1540570000000, @@ -130,7 +202,7 @@ Object { "index": 0, }, "stack": true, - "top": 7.5, + "top": 37.5, "width": 165.28798888888878, }, "id": "1", @@ -166,23 +238,23 @@ Object { "index": 2, }, "stack": true, - "top": 75, + "top": 105, "width": 226.6394222222225, }, "id": "3", }, ], "groupHeights": Array [ - 37.5, + 67.5, 30, 37.5, ], "groupTops": Array [ 0, - 37.5, 67.5, + 97.5, ], - "height": 105, + "height": 165, "visibleTimeEnd": 1540591200000, "visibleTimeStart": 1540501200000, } diff --git a/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap b/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap index fc94c343d..b4a4b264b 100644 --- a/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap +++ b/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap @@ -13,7 +13,7 @@ Object { "collisionLeft": 1540540000000, "collisionWidth": 6803877, "height": 22.5, - "left": 4347.222222222223, + "left": 907.4074074074074, "order": Object { "group": Object { "id": "1", @@ -22,16 +22,52 @@ Object { }, "stack": true, "top": 7.5, - "width": 236.24572916666602, + "width": 78.74857638888886, }, "id": "0", }, + Object { + "dimensions": Object { + "collisionLeft": 1540532800000, + "collisionWidth": 21203877, + "height": 22.5, + "left": 824.074074074074, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 37.5, + "width": 245.4152430555556, + }, + "id": "5", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540550800000, + "collisionWidth": 24803877, + "height": 22.5, + "left": 1032.4074074074074, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 287.08190972222224, + }, + "id": "6", + }, Object { "dimensions": Object { "collisionLeft": 1540570000000, "collisionWidth": 14875919, "height": 22.5, - "left": 5388.888888888889, + "left": 1254.6296296296296, "order": Object { "group": Object { "id": "1", @@ -39,8 +75,8 @@ Object { "index": 0, }, "stack": true, - "top": 7.5, - "width": 516.5249652777784, + "top": 37.5, + "width": 172.1749884259259, }, "id": "1", }, @@ -49,7 +85,7 @@ Object { "collisionLeft": 1540620000000, "collisionWidth": 20397548, "height": 22.5, - "left": 7125, + "left": 1833.3333333333333, "order": Object { "group": Object { "id": "1", @@ -58,7 +94,7 @@ Object { }, "stack": true, "top": 7.5, - "width": 708.2481944444444, + "width": 236.08273148148123, }, "id": "2", }, @@ -82,7 +118,7 @@ Object { "collisionLeft": 1540656000000, "collisionWidth": 20397548, "height": 22.5, - "left": 8375, + "left": 2250, "order": Object { "group": Object { "id": "3", @@ -90,8 +126,8 @@ Object { "index": 2, }, "stack": true, - "top": 75, - "width": 625, + "top": 105, + "width": 236.08273148148146, }, "id": "3", }, diff --git a/__tests__/utils/calendar/__snapshots__/group-no-stack.js.snap b/__tests__/utils/calendar/__snapshots__/group-no-stack.js.snap index 12bba58cb..90095e18b 100644 --- a/__tests__/utils/calendar/__snapshots__/group-no-stack.js.snap +++ b/__tests__/utils/calendar/__snapshots__/group-no-stack.js.snap @@ -3,6 +3,7 @@ exports[`groupNoStack works as expected 1`] = ` Object { "groupHeight": 0, + "itemTop": 7.5, "verticalMargin": 0, } `; diff --git a/__tests__/utils/calendar/__snapshots__/group-stack.js.snap b/__tests__/utils/calendar/__snapshots__/group-stack.js.snap index 3c4067570..6f22034d7 100644 --- a/__tests__/utils/calendar/__snapshots__/group-stack.js.snap +++ b/__tests__/utils/calendar/__snapshots__/group-stack.js.snap @@ -3,6 +3,7 @@ exports[`groupStack works as expected 1`] = ` Object { "groupHeight": 0, + "itemTop": 7.5, "verticalMargin": 37.5, } `; diff --git a/__tests__/utils/calendar/__snapshots__/stack-items.js.snap b/__tests__/utils/calendar/__snapshots__/stack-items.js.snap index 5d522b546..a5dbc090f 100644 --- a/__tests__/utils/calendar/__snapshots__/stack-items.js.snap +++ b/__tests__/utils/calendar/__snapshots__/stack-items.js.snap @@ -21,6 +21,42 @@ Object { }, "id": "0", }, + Object { + "dimensions": Object { + "collisionLeft": 1540532800000, + "collisionWidth": 21203877, + "height": 22.5, + "left": 4097.222222222223, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 37.5, + "width": 736.245729166666, + }, + "id": "5", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540550800000, + "collisionWidth": 24803877, + "height": 22.5, + "left": 4722.222222222223, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 861.245729166666, + }, + "id": "6", + }, Object { "dimensions": Object { "collisionLeft": 1540570000000, @@ -34,7 +70,7 @@ Object { "index": 0, }, "stack": true, - "top": 7.5, + "top": 37.5, "width": 516.5249652777784, }, "id": "1", @@ -70,23 +106,23 @@ Object { "index": 2, }, "stack": true, - "top": 75, + "top": 105, "width": 625, }, "id": "3", }, ], "groupHeights": Array [ - 37.5, + 67.5, 30, 37.5, ], "groupTops": Array [ 0, - 37.5, 67.5, + 97.5, ], - "height": 105, + "height": 165, } `; @@ -111,6 +147,42 @@ Object { }, "id": "0", }, + Object { + "dimensions": Object { + "collisionLeft": 1540532800000, + "collisionWidth": 21203877, + "height": 22.5, + "left": 4097.222222222223, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 37.5, + "width": 736.245729166666, + }, + "id": "5", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540550800000, + "collisionWidth": 24803877, + "height": 22.5, + "left": 4722.222222222223, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 861.245729166666, + }, + "id": "6", + }, Object { "dimensions": Object { "collisionLeft": 1540570000000, @@ -124,7 +196,7 @@ Object { "index": 0, }, "stack": true, - "top": 7.5, + "top": 37.5, "width": 516.5249652777784, }, "id": "1", @@ -160,23 +232,23 @@ Object { "index": 2, }, "stack": true, - "top": 75, + "top": 105, "width": 625, }, "id": "3", }, ], "groupHeights": Array [ - 37.5, + 67.5, 30, 37.5, ], "groupTops": Array [ 0, - 37.5, 67.5, + 97.5, ], - "height": 105, + "height": 165, } `; @@ -201,6 +273,42 @@ Object { }, "id": "0", }, + Object { + "dimensions": Object { + "collisionLeft": 1540532800000, + "collisionWidth": 21203877, + "height": 22.5, + "left": 4097.222222222223, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 37.5, + "width": 736.245729166666, + }, + "id": "5", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540550800000, + "collisionWidth": 24803877, + "height": 22.5, + "left": 4722.222222222223, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 861.245729166666, + }, + "id": "6", + }, Object { "dimensions": Object { "collisionLeft": 1540570000000, @@ -214,7 +322,7 @@ Object { "index": 0, }, "stack": true, - "top": 7.5, + "top": 37.5, "width": 516.5249652777784, }, "id": "1", @@ -250,23 +358,23 @@ Object { "index": 2, }, "stack": true, - "top": 75, + "top": 105, "width": 625, }, "id": "3", }, ], "groupHeights": Array [ - 37.5, + 67.5, 30, 37.5, ], "groupTops": Array [ 0, - 37.5, 67.5, + 97.5, ], - "height": 105, + "height": 165, } `; @@ -291,6 +399,42 @@ Object { }, "id": "0", }, + Object { + "dimensions": Object { + "collisionLeft": 1540532800000, + "collisionWidth": 21203877, + "height": 22.5, + "left": 4097.222222222223, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 37.5, + "width": 736.245729166666, + }, + "id": "5", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540550800000, + "collisionWidth": 24803877, + "height": 22.5, + "left": 4722.222222222223, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 7.5, + "width": 861.245729166666, + }, + "id": "6", + }, Object { "dimensions": Object { "collisionLeft": 1540570000000, @@ -304,7 +448,7 @@ Object { "index": 0, }, "stack": true, - "top": 7.5, + "top": 37.5, "width": 516.5249652777784, }, "id": "1", @@ -340,22 +484,148 @@ Object { "index": 2, }, "stack": true, - "top": 75, + "top": 105, "width": 625, }, "id": "3", }, ], "groupHeights": Array [ - 37.5, + 67.5, 30, 37.5, ], "groupTops": Array [ 0, - 37.5, 67.5, + 97.5, + ], + "height": 165, +} +`; + +exports[`stackItems work as expected no stack 1`] = ` +Object { + "dimensionItems": Array [ + Object { + "dimensions": Object { + "collisionLeft": 1540540000000, + "collisionWidth": 6803877, + "height": 22.5, + "left": 4347.222222222223, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 3.75, + "width": 236.24572916666602, + }, + "id": "0", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540532800000, + "collisionWidth": 21203877, + "height": 22.5, + "left": 4097.222222222223, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 3.75, + "width": 736.245729166666, + }, + "id": "5", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540550800000, + "collisionWidth": 24803877, + "height": 22.5, + "left": 4722.222222222223, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 3.75, + "width": 861.245729166666, + }, + "id": "6", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540570000000, + "collisionWidth": 14875919, + "height": 22.5, + "left": 5388.888888888889, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 3.75, + "width": 516.5249652777784, + }, + "id": "1", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540620000000, + "collisionWidth": 20397548, + "height": 22.5, + "left": 7125, + "order": Object { + "group": Object { + "id": "1", + }, + "index": 0, + }, + "stack": true, + "top": 3.75, + "width": 708.2481944444444, + }, + "id": "2", + }, + Object { + "dimensions": Object { + "collisionLeft": 1540656000000, + "collisionWidth": 20397548, + "height": 22.5, + "left": 8375, + "order": Object { + "group": Object { + "id": "3", + }, + "index": 2, + }, + "stack": true, + "top": 63.75, + "width": 625, + }, + "id": "3", + }, + ], + "groupHeights": Array [ + 30, + 30, + 30, + ], + "groupTops": Array [ + 0, + 30, + 60, ], - "height": 105, + "height": 90, } `; diff --git a/__tests__/utils/calendar/stack-items.js b/__tests__/utils/calendar/stack-items.js index 85e64bb5c..fb3f07ff5 100644 --- a/__tests__/utils/calendar/stack-items.js +++ b/__tests__/utils/calendar/stack-items.js @@ -5,7 +5,8 @@ import { state, stateMoveItem, stateResizeItemLeft, - stateResizeItemRight + stateResizeItemRight, + propsNoStack, } from '../../../__fixtures__/stateAndProps' describe('stackItems', () => { it('work as expected', () => { @@ -29,6 +30,27 @@ describe('stackItems', () => { ) ).toMatchSnapshot() }) + it('work as expected no stack', () => { + expect( + stackTimelineItems( + items, + groups, + 9000, + state.canvasTimeStart, + state.canvasTimeEnd, + propsNoStack.keys, + propsNoStack.lineHeight, + propsNoStack.itemHeightRatio, + propsNoStack.stackItems, + state.draggingItem, + state.resizingItem, + state.dragTime, + state.resizingEdge, + state.resizeTime, + state.newGroupOrder + ) + ).toMatchSnapshot() + }) it('should stack items while moving an item', () => { expect( stackTimelineItems( diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 35dac61be..9f7dbecdc 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -341,7 +341,7 @@ export function groupStack( } } while (collidingItem) } - return { groupHeight: curHeight, verticalMargin } + return { groupHeight: curHeight, verticalMargin, itemTop: item.dimensions.top} } // Calculate the position of this item for a group that is not being stacked @@ -351,7 +351,7 @@ export function groupNoStack(lineHeight, item, groupHeight, totalHeight) { item.dimensions.top = totalHeight + verticalMargin groupHeight = Math.max(groupHeight, lineHeight) } - return { groupHeight, verticalMargin: 0 } + return { groupHeight, verticalMargin: 0, itemTop: item.dimensions.top} } function sum(arr=[]) { @@ -367,7 +367,6 @@ function sum(arr=[]) { */ export function stackAll(items, groupOrders, lineHeight, stackItems) { var itemIndex - var totalHeight = 0 var groupHeights = [] var groupTops = [] @@ -396,7 +395,6 @@ export function stackAll(items, groupOrders, lineHeight, stackItems) { groupHeight = r.groupHeight verticalMargin = r.verticalMargin } - // If group height is overridden, push new height // Do this late as item position still needs to be calculated if (group.height) { From 0ab2a09923830c0c22e16ee00b5e055053f36d25 Mon Sep 17 00:00:00 2001 From: ilaiwi Date: Sun, 25 Nov 2018 22:11:55 +0200 Subject: [PATCH 29/34] format --- __fixtures__/groupOrderAndItemDimentions.js | 160 ++++++++++---------- __fixtures__/itemsAndGroups.js | 112 +++++++------- 2 files changed, 136 insertions(+), 136 deletions(-) diff --git a/__fixtures__/groupOrderAndItemDimentions.js b/__fixtures__/groupOrderAndItemDimentions.js index dbda31167..4637688eb 100644 --- a/__fixtures__/groupOrderAndItemDimentions.js +++ b/__fixtures__/groupOrderAndItemDimentions.js @@ -21,111 +21,111 @@ export const orderedGroups = { export const dimensionItems = [ { - "dimensions": { - "collisionLeft": 1540540000000, - "collisionWidth": 6803877, - "height": 22.5, - "left": 907.4074074074074, - "order": { - "group": { - "id": "1", + dimensions: { + collisionLeft: 1540540000000, + collisionWidth: 6803877, + height: 22.5, + left: 907.4074074074074, + order: { + group: { + id: '1' }, - "index": 0, + index: 0 }, - "stack": true, - "top": 7.5, - "width": 78.74857638888886, + stack: true, + top: 7.5, + width: 78.74857638888886 }, - "id": "0", + id: '0' }, { - "dimensions": { - "collisionLeft": 1540532800000, - "collisionWidth": 21203877, - "height": 22.5, - "left": 824.074074074074, - "order": { - "group": { - "id": "1", + dimensions: { + collisionLeft: 1540532800000, + collisionWidth: 21203877, + height: 22.5, + left: 824.074074074074, + order: { + group: { + id: '1' }, - "index": 0, + index: 0 }, - "stack": true, - "top": 37.5, - "width": 245.4152430555556, + stack: true, + top: 37.5, + width: 245.4152430555556 }, - "id": "5", + id: '5' }, { - "dimensions": { - "collisionLeft": 1540550800000, - "collisionWidth": 24803877, - "height": 22.5, - "left": 1032.4074074074074, - "order": { - "group": { - "id": "1", + dimensions: { + collisionLeft: 1540550800000, + collisionWidth: 24803877, + height: 22.5, + left: 1032.4074074074074, + order: { + group: { + id: '1' }, - "index": 0, + index: 0 }, - "stack": true, - "top": 7.5, - "width": 287.08190972222224, + stack: true, + top: 7.5, + width: 287.08190972222224 }, - "id": "6", + id: '6' }, { - "dimensions": { - "collisionLeft": 1540570000000, - "collisionWidth": 14875919, - "height": 22.5, - "left": 1254.6296296296296, - "order": { - "group": { - "id": "1", + dimensions: { + collisionLeft: 1540570000000, + collisionWidth: 14875919, + height: 22.5, + left: 1254.6296296296296, + order: { + group: { + id: '1' }, - "index": 0, + index: 0 }, - "stack": true, - "top": 37.5, - "width": 172.1749884259259, + stack: true, + top: 37.5, + width: 172.1749884259259 }, - "id": "1", + id: '1' }, { - "dimensions": { - "collisionLeft": 1540620000000, - "collisionWidth": 20397548, - "height": 22.5, - "left": 1833.3333333333333, - "order": { - "group": { - "id": "1", + dimensions: { + collisionLeft: 1540620000000, + collisionWidth: 20397548, + height: 22.5, + left: 1833.3333333333333, + order: { + group: { + id: '1' }, - "index": 0, + index: 0 }, - "stack": true, - "top": 7.5, - "width": 236.08273148148123, + stack: true, + top: 7.5, + width: 236.08273148148123 }, - "id": "2", + id: '2' }, { - "dimensions": { - "collisionLeft": 1540656000000, - "collisionWidth": 20397548, - "height": 22.5, - "left": 2250, - "order": { - "group": { - "id": "3", + dimensions: { + collisionLeft: 1540656000000, + collisionWidth: 20397548, + height: 22.5, + left: 2250, + order: { + group: { + id: '3' }, - "index": 2, + index: 2 }, - "stack": true, - "top": 105, - "width": 236.08273148148146, + stack: true, + top: 105, + width: 236.08273148148146 }, - "id": "3", - }, -] \ No newline at end of file + id: '3' + } +] diff --git a/__fixtures__/itemsAndGroups.js b/__fixtures__/itemsAndGroups.js index 676d3a30c..0ad6371d2 100644 --- a/__fixtures__/itemsAndGroups.js +++ b/__fixtures__/itemsAndGroups.js @@ -1,58 +1,58 @@ -import moment from 'moment'; +import moment from 'moment' export const items = [ - { - id: '0', - group: '1', - start_time: moment('2018-10-26T10:46:40.000').valueOf(), - end_time: moment('2018-10-26T12:40:03.877').valueOf(), - canMove: false, - canResize: false - }, - { - id: '5', - group: '1', - start_time: moment('2018-10-26T08:46:40.000').valueOf(), - end_time: moment('2018-10-26T14:40:03.877').valueOf(), - canMove: false, - canResize: false, - className: '' - }, - { - id: '6', - group: '1', - start_time: moment('2018-10-26T13:46:40.000').valueOf(), - end_time: moment('2018-10-26T20:40:03.877').valueOf(), - canMove: false, - canResize: false, - className: '' - }, - { - id: '1', - group: '1', - start_time: moment('2018-10-26T19:06:40.000').valueOf(), - end_time: moment('2018-10-26T23:14:35.919').valueOf(), - canMove: true, - canResize: 'both' - }, - { - id: '2', - group: '1', - start_time: moment('2018-10-27T08:00:00.000').valueOf(), - end_time: moment('2018-10-27T13:39:57.548').valueOf(), - canMove: false, - canResize: false, - className: '' - }, - { - id: '3', - group: '3', - start_time: moment('2018-10-27T18:00:00.000').valueOf(), - end_time: moment('2018-10-27T23:39:57.548').valueOf(), - canMove: false, - canResize: false, - className: '' - } - ] - - export const groups = [{ id: '1' }, { id: '2' }, { id: '3' }] \ No newline at end of file + { + id: '0', + group: '1', + start_time: moment('2018-10-26T10:46:40.000').valueOf(), + end_time: moment('2018-10-26T12:40:03.877').valueOf(), + canMove: false, + canResize: false + }, + { + id: '5', + group: '1', + start_time: moment('2018-10-26T08:46:40.000').valueOf(), + end_time: moment('2018-10-26T14:40:03.877').valueOf(), + canMove: false, + canResize: false, + className: '' + }, + { + id: '6', + group: '1', + start_time: moment('2018-10-26T13:46:40.000').valueOf(), + end_time: moment('2018-10-26T20:40:03.877').valueOf(), + canMove: false, + canResize: false, + className: '' + }, + { + id: '1', + group: '1', + start_time: moment('2018-10-26T19:06:40.000').valueOf(), + end_time: moment('2018-10-26T23:14:35.919').valueOf(), + canMove: true, + canResize: 'both' + }, + { + id: '2', + group: '1', + start_time: moment('2018-10-27T08:00:00.000').valueOf(), + end_time: moment('2018-10-27T13:39:57.548').valueOf(), + canMove: false, + canResize: false, + className: '' + }, + { + id: '3', + group: '3', + start_time: moment('2018-10-27T18:00:00.000').valueOf(), + end_time: moment('2018-10-27T23:39:57.548').valueOf(), + canMove: false, + canResize: false, + className: '' + } +] + +export const groups = [{ id: '1' }, { id: '2' }, { id: '3' }] From ccab9b440fc48a2c6cf7564a0f25e49dd994eb78 Mon Sep 17 00:00:00 2001 From: ilaiwi Date: Sun, 25 Nov 2018 23:52:42 +0200 Subject: [PATCH 30/34] stack groups --- .../__snapshots__/stack-group.js.snap | 15 +++ __tests__/utils/calendar/stack-group.js | 11 ++ src/lib/utility/calendar.js | 118 +++++++++++------- 3 files changed, 98 insertions(+), 46 deletions(-) create mode 100644 __tests__/utils/calendar/__snapshots__/stack-group.js.snap create mode 100644 __tests__/utils/calendar/stack-group.js diff --git a/__tests__/utils/calendar/__snapshots__/stack-group.js.snap b/__tests__/utils/calendar/__snapshots__/stack-group.js.snap new file mode 100644 index 000000000..bbe832509 --- /dev/null +++ b/__tests__/utils/calendar/__snapshots__/stack-group.js.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`stackGroup should not stack list of items 1`] = ` +Object { + "groupHeight": 0, + "verticalMargin": 0, +} +`; + +exports[`stackGroup should stack list of items 1`] = ` +Object { + "groupHeight": 0, + "verticalMargin": 7.5, +} +`; diff --git a/__tests__/utils/calendar/stack-group.js b/__tests__/utils/calendar/stack-group.js new file mode 100644 index 000000000..be91fa399 --- /dev/null +++ b/__tests__/utils/calendar/stack-group.js @@ -0,0 +1,11 @@ +import { stackGroup } from 'lib/utility/calendar' +import { dimensionItems } from '../../../__fixtures__/groupOrderAndItemDimentions' + +describe('stackGroup', ()=>{ + it('should stack list of items', ()=>{ + expect(stackGroup(dimensionItems, true, 30, 0)).toMatchSnapshot() + }) + it('should not stack list of items', ()=>{ + expect(stackGroup(dimensionItems, false, 30, 0)).toMatchSnapshot() + }) +}) \ No newline at end of file diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 9f7dbecdc..59a1a5442 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -305,14 +305,14 @@ export function groupStack( item, group, groupHeight, - totalHeight, + groupTop, itemIndex ) { // calculate non-overlapping positions let curHeight = groupHeight let verticalMargin = lineHeight - item.dimensions.height if (item.dimensions.stack && item.dimensions.top === null) { - item.dimensions.top = totalHeight + verticalMargin + item.dimensions.top = groupTop + verticalMargin curHeight = Math.max(curHeight, lineHeight) do { var collidingItem = null @@ -336,26 +336,30 @@ export function groupStack( item.dimensions.top = collidingItem.dimensions.top + lineHeight curHeight = Math.max( curHeight, - item.dimensions.top + item.dimensions.height - totalHeight + item.dimensions.top + item.dimensions.height - groupTop ) } } while (collidingItem) } - return { groupHeight: curHeight, verticalMargin, itemTop: item.dimensions.top} + return { + groupHeight: curHeight, + verticalMargin, + itemTop: item.dimensions.top + } } // Calculate the position of this item for a group that is not being stacked -export function groupNoStack(lineHeight, item, groupHeight, totalHeight) { +export function groupNoStack(lineHeight, item, groupHeight, groupTop) { let verticalMargin = (lineHeight - item.dimensions.height) / 2 if (item.dimensions.top === null) { - item.dimensions.top = totalHeight + verticalMargin + item.dimensions.top = groupTop + verticalMargin groupHeight = Math.max(groupHeight, lineHeight) } - return { groupHeight, verticalMargin: 0, itemTop: item.dimensions.top} + return { groupHeight, verticalMargin: 0, itemTop: item.dimensions.top } } -function sum(arr=[]) { - return arr.reduce((acc, i)=> acc+i,0) +function sum(arr = []) { + return arr.reduce((acc, i) => acc + i, 0) } /** @@ -365,38 +369,29 @@ function sum(arr=[]) { * @param {*} lineHeight * @param {*} stackItems should items be stacked? */ -export function stackAll(items, groupOrders, lineHeight, stackItems) { - var itemIndex - +export function stackAll(itemsDimensions, groupOrders, lineHeight, stackItems) { var groupHeights = [] var groupTops = [] - var groupedItems = getGroupedItems(items, groupOrders) + var groupedItems = getGroupedItems(itemsDimensions, groupOrders) - for (var index in groupedItems) { + for (var index in groupedItems) { const groupItems = groupedItems[index] - const { items, group } = groupItems - const nextHeight = sum(groupHeights) - groupTops.push(nextHeight) + const { items: itemsDimensions, group } = groupItems + const groupTop = sum(groupHeights) // Is group being stacked? const isGroupStacked = group.stackItems !== undefined ? group.stackItems : stackItems - var groupHeight = 0 - var verticalMargin = 0 - // Find positions for each item in group - for (itemIndex = 0; itemIndex < items.length; itemIndex++) { - let r = {} - if (isGroupStacked) { - r = groupStack(lineHeight, items[itemIndex], items, groupHeight, nextHeight, itemIndex) - } else { - r = groupNoStack(lineHeight, items[itemIndex], groupHeight, nextHeight) - } - groupHeight = r.groupHeight - verticalMargin = r.verticalMargin - } + const { groupHeight, verticalMargin } = stackGroup( + itemsDimensions, + isGroupStacked, + lineHeight, + groupTop + ) // If group height is overridden, push new height // Do this late as item position still needs to be calculated + groupTops.push(groupTop) if (group.height) { groupHeights.push(group.height) } else { @@ -410,24 +405,55 @@ export function stackAll(items, groupOrders, lineHeight, stackItems) { } } +/** + * + * @param {*} itemsDimensions + * @param {*} isGroupStacked + * @param {*} lineHeight + * @param {*} groupTop + */ +export function stackGroup(itemsDimensions, isGroupStacked, lineHeight, groupTop) { + var groupHeight = 0 + var verticalMargin = 0 + // Find positions for each item in group + for (let itemIndex = 0; itemIndex < itemsDimensions.length; itemIndex++) { + let r = {} + if (isGroupStacked) { + r = groupStack( + lineHeight, + itemsDimensions[itemIndex], + itemsDimensions, + groupHeight, + groupTop, + itemIndex + ) + } else { + r = groupNoStack(lineHeight, itemsDimensions[itemIndex], groupHeight, groupTop) + } + groupHeight = r.groupHeight + verticalMargin = r.verticalMargin + } + return { groupHeight, verticalMargin } +} + /** * Stack the items that will be visible * within the canvas area * @param {item[]} items * @param {group[]} groups - * @param {number} canvasWidth - * @param {number} canvasTimeStart - * @param {number} canvasTimeEnd - * @param {*} keys - * @param {number} lineHeight - * @param {number} itemHeightRatio - * @param {boolean} stackItems - * @param {*} draggingItem - * @param {*} resizingItem - * @param {number} dragTime - * @param {left or right} resizingEdge - * @param {number} resizeTime - * @param {number} newGroupOrder + * @param {number} canvasWidth + * @param {number} canvasTimeStart + * @param {number} canvasTimeEnd + * @param {*} keys + * @param {number} lineHeight + * @param {number} itemHeightRatio + * @param {boolean} stackItems + * @param {*} draggingItem + * @param {*} resizingItem + * @param {number} dragTime + * @param {left or right} resizingEdge + * @param {number} resizeTime + * @param {number} newGroupOrder */ export function stackTimelineItems( items, @@ -444,7 +470,7 @@ export function stackTimelineItems( dragTime, resizingEdge, resizeTime, - newGroupOrder, + newGroupOrder ) { const visibleItems = getVisibleItems( items, @@ -499,7 +525,7 @@ export function stackTimelineItems( lineHeight, stackItems ) - return{ dimensionItems, height, groupHeights, groupTops } + return { dimensionItems, height, groupHeights, groupTops } } /** @@ -681,7 +707,7 @@ export function calculateScrollCanvas( mergedState.dragTime, mergedState.resizingEdge, mergedState.resizeTime, - mergedState.newGroupOrder, + mergedState.newGroupOrder ) ) } From 324698e83148c97edadb478b24f39e6d7ab243b9 Mon Sep 17 00:00:00 2001 From: ilaiwi Date: Tue, 27 Nov 2018 19:39:50 +0200 Subject: [PATCH 31/34] fix bug with stackAll --- .../__snapshots__/calculate-scroll-canvas.js.snap | 4 ++-- .../utils/calendar/__snapshots__/stack-items.js.snap | 8 ++++---- src/lib/utility/calendar.js | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap b/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap index cf4b29ce3..0d4c752b1 100644 --- a/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap +++ b/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap @@ -124,7 +124,7 @@ Object { 67.5, 97.5, ], - "height": 165, + "height": 135, "visibleTimeEnd": 1540634400000, "visibleTimeStart": 1540548000000, } @@ -254,7 +254,7 @@ Object { 67.5, 97.5, ], - "height": 165, + "height": 135, "visibleTimeEnd": 1540591200000, "visibleTimeStart": 1540501200000, } diff --git a/__tests__/utils/calendar/__snapshots__/stack-items.js.snap b/__tests__/utils/calendar/__snapshots__/stack-items.js.snap index a5dbc090f..8d27dc42d 100644 --- a/__tests__/utils/calendar/__snapshots__/stack-items.js.snap +++ b/__tests__/utils/calendar/__snapshots__/stack-items.js.snap @@ -122,7 +122,7 @@ Object { 67.5, 97.5, ], - "height": 165, + "height": 135, } `; @@ -248,7 +248,7 @@ Object { 67.5, 97.5, ], - "height": 165, + "height": 135, } `; @@ -374,7 +374,7 @@ Object { 67.5, 97.5, ], - "height": 165, + "height": 135, } `; @@ -500,7 +500,7 @@ Object { 67.5, 97.5, ], - "height": 165, + "height": 135, } `; diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js index 59a1a5442..4c5b888ec 100644 --- a/src/lib/utility/calendar.js +++ b/src/lib/utility/calendar.js @@ -399,7 +399,7 @@ export function stackAll(itemsDimensions, groupOrders, lineHeight, stackItems) { } } return { - height: sum(groupTops), + height: sum(groupHeights), groupHeights, groupTops } From ccd635a62d4d5ec6cf1a1fc68570c5bf85b1dc96 Mon Sep 17 00:00:00 2001 From: ilaiwi Date: Tue, 27 Nov 2018 20:10:48 +0200 Subject: [PATCH 32/34] remove group --- src/lib/headers/ItemHeader/index.js | 37 ++++++++--------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/src/lib/headers/ItemHeader/index.js b/src/lib/headers/ItemHeader/index.js index a33a12444..9f67db1ef 100644 --- a/src/lib/headers/ItemHeader/index.js +++ b/src/lib/headers/ItemHeader/index.js @@ -3,17 +3,10 @@ import { TimelineStateConsumer } from '../../timeline/TimelineStateContext' import CustomHeader from '../CustomHeader' import PropTypes from 'prop-types' import { - stackAll, - getGroupOrders, - getItemDimensions + getItemDimensions, + stackGroup } from '../../utility/calendar' import { _get } from '../../utility/generic' -import { calculateItemDimensions } from './utils' -const groups = [ - { - id: '1' - } -] const passThroughPropTypes = { style: PropTypes.object, @@ -85,7 +78,7 @@ class ItemHeader extends React.PureComponent { render() { const { keys, - items: itemWithNoIds, + items, itemHeight, itemRenderer, canvasTimeStart, @@ -93,35 +86,25 @@ class ItemHeader extends React.PureComponent { canvasWidth, stackItems } = this.props - const items = itemWithNoIds.map(item => ({ ...item, group: '1' })) - const order = getGroupOrders(groups, keys) const itemDimensions = items.map(item => { - console.log( - JSON.stringify({ - item, - keys, - canvasTimeStart, - canvasTimeEnd, - canvasWidth, - groupOrders: order, - itemHeight, - itemHeightRatio: 1 - }) - ) return getItemDimensions({ item, keys, canvasTimeStart, canvasTimeEnd, canvasWidth, - groupOrders: order, + groupOrders: {}, lineHeight: itemHeight, itemHeightRatio: 1 }) }) - const result = stackAll(itemDimensions, order, itemHeight, stackItems) - const { height } = result + const { groupHeight: height } = stackGroup( + itemDimensions, + stackItems, + itemHeight, + 0 + ) return ( {({ getRootProps }) => { From 2cd3bd0dd5ee29575e8382cfa25eeb53cff42a69 Mon Sep 17 00:00:00 2001 From: ilaiwi Date: Tue, 27 Nov 2018 20:32:25 +0200 Subject: [PATCH 33/34] add readme + final refactor --- README.md | 116 +++++++++++++++++- demo/app/demo-headers/index.js | 6 +- .../{ItemHeader/index.js => ItemHeader.js} | 19 +-- src/lib/headers/ItemHeader/utils.js | 30 ----- 4 files changed, 129 insertions(+), 42 deletions(-) rename src/lib/headers/{ItemHeader/index.js => ItemHeader.js} (91%) delete mode 100644 src/lib/headers/ItemHeader/utils.js diff --git a/README.md b/README.md index 9555557a6..5ad25df48 100644 --- a/README.md +++ b/README.md @@ -1043,9 +1043,123 @@ import Timeline, { ``` +### `ItemHeader` + + +Responsible for rendering group of items in the header. + +#### props + +| Prop | type | description| +| ----------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `style`| `object`| applied to the root of the header | +| `className` | `string`| applied to the root of the header| +| `itemHeight`| `number` | item height | +| `stackItems` | `boolean` (`false` by default) | optionally stack items in header | +| `itemRenderer`| `Function`| render prop to render each interval in the header | +| `props` | `object` | pass extra props to itemRenderer | + +#### itemRenderer + +Render prop function used to render a customized item. The function provides multiple parameters that can be used to render each item. + +Paramters provided to the function has two types: context params which have the state of the item and timeline, and prop getters functions + +##### item + +The object of the item to render + +##### timelineContext + +timeline context + +##### itemContext + +item context + +##### Prop getters functions + +Rather than applying props on the element yourself and to avoid your props being overridden (or overriding the props returned). You can pass an object to the prop getters to avoid any problems. This object will only accept some properties that our component manage so the component make sure to combine them correctly. + +| property | type | description| +| ---------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| `getRootProps` | `function(props={})` | returns the props you should apply to the root div element.| + +* `getRootProps` The returned props are: + + * style: inline object style + + These properties can be extended using the prop argument with properties: + + * style: extra inline styles to be applied to the component + +#### example + +```jsx +import Timeline, { + TimelineHeaders, + SidebarHeader, + DateHeader +} from 'react-calendar-timeline' + +const items = [ + { + id: 1, + title: 'item 1', + start_time: moment(), + end_time: moment().add(1, 'hour') + }, + { + id: 2, + title: 'item 2', + start_time: moment().add(-0.5, 'hour'), + end_time: moment().add(0.5, 'hour') + }, + { + id: 3, + title: 'item 3', + start_time: moment().add(2, 'hour'), + end_time: moment().add(3, 'hour') + } +] + + + + + {({ getRootProps }) => { + return
Left
+ }} +
+ { + return ( +
+ {item.title} +
+ ) + }} + /> + + +
+
+``` + ### `CustomHeader` -Responsible for rendering the headers above calendar part of the timeline. This is the base component for `DateHeader` and offers more control with less features. +Responsible for rendering the headers above calendar part of the timeline. This is the base component for `DateHeader` and `ItemHeader`. This offers more control with less features. #### props diff --git a/demo/app/demo-headers/index.js b/demo/app/demo-headers/index.js index 530fe5139..b74e13974 100644 --- a/demo/app/demo-headers/index.js +++ b/demo/app/demo-headers/index.js @@ -39,7 +39,7 @@ export default class App extends Component { constructor(props) { super(props) - const { groups, items } = generateFakeData(2, 5, 1) + const { groups, items } = generateFakeData() const {items: headerItems } = generateFakeData(2, 5, 1) const defaultTimeStart = moment() .startOf('day') @@ -212,7 +212,7 @@ export default class App extends Component { style={{ backgroundColor: "blue" }} - items={this.state.items} + items={this.state.headerItems} itemRenderer={({ item, getRootProps }) => { return (
- + ) @@ -156,7 +157,8 @@ class Item extends React.PureComponent { width: PropTypes.number }).isRequired, itemRenderer: passThroughPropTypes['itemRenderer'], - itemHeight: passThroughPropTypes['itemHeight'] + itemHeight: passThroughPropTypes['itemHeight'], + props: PropTypes.object, } getStyles = (style = {}, dimensions, itemHeight) => { @@ -183,12 +185,13 @@ class Item extends React.PureComponent { } render() { - const { item, timelineContext, itemContext } = this.props + const { item, timelineContext, itemContext, props } = this.props return this.props.itemRenderer({ item, timelineContext, itemContext, - getRootProps: this.getRootProps + getRootProps: this.getRootProps, + props, }) } } diff --git a/src/lib/headers/ItemHeader/utils.js b/src/lib/headers/ItemHeader/utils.js deleted file mode 100644 index 6e7733649..000000000 --- a/src/lib/headers/ItemHeader/utils.js +++ /dev/null @@ -1,30 +0,0 @@ -import { calculateXPositionForTime } from '../../utility/calendar' -export function calculateItemDimensions({ - itemTimeStart, - itemTimeEnd, - canvasTimeStart, - canvasTimeEnd, - canvasWidth -}) { - const itemTimeRange = itemTimeEnd - itemTimeStart - const left = calculateXPositionForTime( - canvasTimeStart, - canvasTimeEnd, - canvasWidth, - itemTimeStart - ) - const right = calculateXPositionForTime( - canvasTimeStart, - canvasTimeEnd, - canvasWidth, - itemTimeEnd - ) - const dimensions = { - left: left, - width: Math.max(right - left, 3), - collisionLeft: itemTimeStart, - collisionWidth: itemTimeRange - } - - return dimensions -} From fd1c6faadef09890e4544a07e725743c06add54c Mon Sep 17 00:00:00 2001 From: Ilaiwi Date: Wed, 28 Nov 2018 08:36:56 +0200 Subject: [PATCH 34/34] add min height for ItemHeader --- demo/app/demo-headers/index.js | 1 + src/lib/headers/ItemHeader.js | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/demo/app/demo-headers/index.js b/demo/app/demo-headers/index.js index b74e13974..0fafd2e29 100644 --- a/demo/app/demo-headers/index.js +++ b/demo/app/demo-headers/index.js @@ -229,6 +229,7 @@ export default class App extends Component { }} /> + {({ getRootProps }) => {