diff --git a/lib/timeline/component/Group.js b/lib/timeline/component/Group.js index ae60270a..51761959 100644 --- a/lib/timeline/component/Group.js +++ b/lib/timeline/component/Group.js @@ -47,7 +47,11 @@ function Group (groupId, data, itemSet) { */ Group.prototype._create = function() { var label = document.createElement('div'); - label.className = 'vis-label'; + if (this.itemSet.options.groupEditable.order) { + label.className = 'vis-label draggable'; + } else { + label.className = 'vis-label'; + } this.dom.label = label; var inner = document.createElement('div'); diff --git a/lib/timeline/component/ItemSet.js b/lib/timeline/component/ItemSet.js index 46af2ec9..6e628473 100644 --- a/lib/timeline/component/ItemSet.js +++ b/lib/timeline/component/ItemSet.js @@ -35,20 +35,13 @@ function ItemSet(body, options) { align: 'auto', // alignment of box items stack: true, groupsDraggable: false, - moveBefore: function(draggedGroup, targetGroup, groups) { + groupOrderSwap: function(draggedGroup, targetGroup, groups) { var targetOrder = targetGroup.order; targetGroup.order = draggedGroup.order; draggedGroup.order = targetOrder; groups.update(draggedGroup); groups.update(targetGroup); }, -// groupOrder: function(a,b) { -// if (a.order != undefined && b.order != undefined) { -// return (a.order - b.order); -// } else { -// return 0; -// } -// }, groupOrder: 'order', selectable: true, @@ -308,7 +301,7 @@ ItemSet.prototype._create = function(){ ItemSet.prototype.setOptions = function(options) { if (options) { // copy all options that we know - var fields = ['type', 'align', 'order', 'stack', 'selectable', 'multiselect', 'groupOrder', 'dataAttributes', 'template', 'groupTemplate', 'hide', 'snap', 'moveBefore']; + var fields = ['type', 'align', 'order', 'stack', 'selectable', 'multiselect', 'groupOrder', 'dataAttributes', 'template', 'groupTemplate', 'hide', 'snap', 'groupOrderSwap']; util.selectiveExtend(fields, this.options, options); if ('orientation' in options) { @@ -1448,19 +1441,43 @@ ItemSet.prototype._onGroupDrag = function (event) { // drag from one group to another var group = this.groupFromTarget(event); + + // try to avoid toggling when groups differ in height + if (group && group.height != this.groupTouchParams.group.height) { + var movingUp = (group.top < this.groupTouchParams.group.top); + var clientY = event.center ? event.center.y : event.clientY; + var targetGroupTop = util.getAbsoluteTop(group.dom.foreground); + var draggedGroupHeight = this.groupTouchParams.group.height; + if (movingUp) { + // skip swapping the groups when the dragged group is not below clientY afterwards + if (targetGroupTop + draggedGroupHeight < clientY) { + return; + } + } else { + var targetGroupHeight = group.height; + // skip swapping the groups when the dragged group is not below clientY afterwards + if (targetGroupTop + targetGroupHeight - draggedGroupHeight > clientY) { + return; + } + } + } + if (group && group != this.groupTouchParams.group) { var groupsData = this.groupsData; var targetGroup = groupsData.get(group.groupId); var draggedGroup = groupsData.get(this.groupTouchParams.group.groupId); + // switch groups if (draggedGroup && targetGroup) { - this.options.moveBefore(draggedGroup, targetGroup, this.groupsData); + this.options.groupOrderSwap(draggedGroup, targetGroup, this.groupsData); } + // fetch current order of groups var newOrder = this.groupsData.getIds({ order: this.options.groupOrder }); + // in case of changes since _onGroupDragStart if (!util.equalArray(newOrder, this.groupTouchParams.originalOrder)) { var groupsData = this.groupsData; var origOrder = this.groupTouchParams.originalOrder; @@ -1482,18 +1499,24 @@ ItemSet.prototype._onGroupDrag = function (event) { break; } - // not all ok -> since we start from the first group, did we reach the dragged group? + // not all ok + // if dragged group was move upwards everything below should have an offset if (newOrder[curPos+newOffset] == draggedId) { newOffset = 1; continue; - } else if (origOrder[curPos+orgOffset] == draggedId) { + } + // if dragged group was move downwards everything above should have an offset + else if (origOrder[curPos+orgOffset] == draggedId) { orgOffset = 1; continue; - } else { + } + // found a group (apart from dragged group) that has the wrong position -> switch with the + // group at the position where other one should be, fix index arrays and continue + else { var slippedPosition = newOrder.indexOf(origOrder[curPos+orgOffset]) var switchGroup = groupsData.get(newOrder[curPos+newOffset]); var shouldBeGroup = groupsData.get(origOrder[curPos+orgOffset]); - this.options.moveBefore(switchGroup, shouldBeGroup, groupsData); + this.options.groupOrderSwap(switchGroup, shouldBeGroup, groupsData); var switchGroupId = newOrder[curPos+newOffset]; newOrder[curPos+newOffset] = origOrder[curPos+orgOffset]; @@ -1512,68 +1535,6 @@ ItemSet.prototype._onGroupDragEnd = function (event) { if (this.options.groupEditable.order && this.groupTouchParams.group) { event.stopPropagation(); - var newOrder = this.groupsData.getIds({ - order: this.options.groupOrder - }); - - if (!util.equalArray(newOrder, this.groupTouchParams.originalOrder)) { - var groupsData = this.groupsData; - var origOrder = this.groupTouchParams.originalOrder; - var draggedId = this.groupTouchParams.group.groupId; - var numGroups = Math.min(origOrder.length, newOrder.length); - var curPos = 0; - var newOffset = 0; - var orgOffset = 0; - while (curPos < numGroups) { - // as long as the groups are where they should be step down along the groups order - while ((curPos+newOffset) < numGroups - && (curPos+orgOffset) < numGroups - && newOrder[curPos+newOffset] == origOrder[curPos+orgOffset]) { - curPos++; - } - - // all ok - if (curPos+newOffset >= numGroups) { - break; - } - - // not all ok -> since we start from the first group, did we reach the dragged group? - if (newOrder[curPos+newOffset] == draggedId) { - newOffset = 1; - continue; - } else if (origOrder[curPos+orgOffset] == draggedId) { - orgOffset = 1; - continue; - } else { - var slippedPosition = newOrder.indexOf(origOrder[curPos+orgOffset]) - var switchGroup = groupsData.get(newOrder[curPos+newOffset]); - var shouldBeGroup = groupsData.get(origOrder[curPos+orgOffset]); - this.options.moveBefore(switchGroup, shouldBeGroup, groupsData); - - var switchGroupId = newOrder[curPos+newOffset]; - newOrder[curPos+newOffset] = origOrder[curPos+orgOffset]; - newOrder[slippedPosition] = switchGroupId; - - curPos++; - } - } - } - - -// // drag from one group to another -// var group = this.groupFromTarget(event); -// if (group && group != this.groupTouchParams.group) { -// var draggedGroup = groupsData.get(this.groupTouchParams.group.groupId); -// var targetGroup = groupsData.get(group.groupId); -// -// if (draggedGroup && targetGroup) { -// var targetOrder = targetGroup.order; -// targetGroup.order = draggedGroup.order; -// groupsData.update(targetGroup); -// draggedGroup.order = targetOrder; -// groupsData.update(draggedGroup); -// } -// } this.body.emitter.emit('groupDragged'); } } diff --git a/lib/timeline/component/css/labelset.css b/lib/timeline/component/css/labelset.css index c2690e97..3aeabd10 100644 --- a/lib/timeline/component/css/labelset.css +++ b/lib/timeline/component/css/labelset.css @@ -21,6 +21,10 @@ border-bottom: 1px solid #bfbfbf; } +.vis-labelset .vis-label.draggable { + cursor: pointer; +} + .vis-labelset .vis-label:last-child { border-bottom: none; } diff --git a/lib/timeline/optionsTimeline.js b/lib/timeline/optionsTimeline.js index 5d588d3b..ace9e714 100644 --- a/lib/timeline/optionsTimeline.js +++ b/lib/timeline/optionsTimeline.js @@ -69,7 +69,7 @@ let allOptions = { order: {boolean, 'undefined': 'undefined'}, __type__: {boolean, object} }, - moveBefore: {'function': 'function'}, + groupOrderSwap: {'function': 'function'}, height: {string, number}, hiddenDates: {object, array}, locale:{string},