diff --git a/lib/timeline/component/BackgroundGroup.js b/lib/timeline/component/BackgroundGroup.js index af1286d5..ae44551c 100644 --- a/lib/timeline/component/BackgroundGroup.js +++ b/lib/timeline/component/BackgroundGroup.js @@ -22,10 +22,10 @@ BackgroundGroup.prototype = Object.create(Group.prototype); * Repaint this group * @param {{start: number, end: number}} range * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin - * @param {boolean} [restack=false] Force restacking of all items + * @param {boolean} [forceRestack=false] Force restacking of all items * @return {boolean} Returns true if the group is resized */ -BackgroundGroup.prototype.redraw = function(range, margin, restack) { +BackgroundGroup.prototype.redraw = function(range, margin, forceRestack) { var resized = false; this.visibleItems = this._updateItemsInRange(this.orderedItems, this.visibleItems, range); diff --git a/lib/timeline/component/Group.js b/lib/timeline/component/Group.js index 58920dfa..095262ea 100644 --- a/lib/timeline/component/Group.js +++ b/lib/timeline/component/Group.js @@ -15,6 +15,7 @@ function Group (groupId, data, itemSet) { this.subgroupOrderer = data && data.subgroupOrder; this.itemSet = itemSet; this.isVisible = null; + this.stackDirty = true; // if true, items will be restacked on next redraw if (data && data.nestedGroups) { this.nestedGroups = data.nestedGroups; @@ -212,12 +213,12 @@ Group.prototype.getLabelWidth = function() { * Repaint this group * @param {{start: number, end: number}} range * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin - * @param {boolean} [restack=false] Force restacking of all items + * @param {boolean} [forceRestack=false] Force restacking of all items * @return {boolean} Returns true if the group is resized */ -Group.prototype.redraw = function(range, margin, restack) { +Group.prototype.redraw = function(range, margin, forceRestack) { var resized = false; - + // force recalculation of the height of the items when the marker height changed // (due to the Timeline being attached to the DOM or changed from display:none to visible) var markerHeight = this.dom.marker.clientHeight; @@ -228,9 +229,9 @@ Group.prototype.redraw = function(range, margin, restack) { if (item.displayed) item.redraw(); }); - restack = true; - } - + forceRestack = true; + } + // recalculate the height of the subgroups this._calculateSubGroupHeights(margin); @@ -240,12 +241,15 @@ Group.prototype.redraw = function(range, margin, restack) { this.right = foreground.offsetLeft; this.width = foreground.offsetWidth; + var lastIsVisible = this.isVisible; this.isVisible = this._isGroupVisible(range, margin); - // reposition visible items vertically - if (typeof this.itemSet.options.order === 'function') { - // a custom order function + + var restack = forceRestack || this.stackDirty || (this.isVisible && !lastIsVisible); - if (restack) { + // if restacking, reposition visible items vertically + if(restack) { + if (typeof this.itemSet.options.order === 'function') { + // a custom order function // brute force restack of all items // show all items @@ -264,23 +268,24 @@ Group.prototype.redraw = function(range, margin, restack) { return me.itemSet.options.order(a.data, b.data); }); stack.stack(customOrderedItems, margin, true /* restack=true */); - } - - this.visibleItems = this._updateItemsInRange(this.orderedItems, this.visibleItems, range); - } - else { - // no custom order function, lazy stacking + this.visibleItems = this._updateItemsInRange(this.orderedItems, this.visibleItems, range); - this.visibleItems = this._updateItemsInRange(this.orderedItems, this.visibleItems, range); - - if (this.itemSet.options.stack) { // TODO: ugly way to access options... - stack.stack(this.visibleItems, margin, restack); } - else { // no stacking - stack.nostack(this.visibleItems, margin, this.subgroups, this.itemSet.options.stackSubgroups); + else { + // no custom order function, lazy stacking + this.visibleItems = this._updateItemsInRange(this.orderedItems, this.visibleItems, range); + + if (this.itemSet.options.stack) { // TODO: ugly way to access options... + stack.stack(this.visibleItems, margin, true /* restack=true */); + } + else { // no stacking + stack.nostack(this.visibleItems, margin, this.subgroups, this.itemSet.options.stackSubgroups); + } } + + this.stackDirty = false; } - + this._updateSubgroupsSizes(); // recalculate the height of the group @@ -435,7 +440,7 @@ Group.prototype.hide = function() { Group.prototype.add = function(item) { this.items[item.id] = item; item.setParent(this); - + this.stackDirty = true; // add to if (item.data.subgroup !== undefined) { this._addToSubgroup(item); @@ -540,6 +545,7 @@ Group.prototype.resetSubgroups = function() { Group.prototype.remove = function(item) { delete this.items[item.id]; item.setParent(null); + this.stackDirty = true; // remove from visible items var index = this.visibleItems.indexOf(item); diff --git a/lib/timeline/component/ItemSet.js b/lib/timeline/component/ItemSet.js index 8971d396..230e8781 100644 --- a/lib/timeline/component/ItemSet.js +++ b/lib/timeline/component/ItemSet.js @@ -155,7 +155,6 @@ function ItemSet(body, options) { this.groupIds = []; this.selection = []; // list with the ids of all selected nodes - this.stackDirty = true; // if true, all items will be restacked on next redraw this.popup = null; @@ -418,7 +417,6 @@ ItemSet.prototype.setOptions = function(options) { */ ItemSet.prototype.markDirty = function(options) { this.groupIds = []; - this.stackDirty = true; if (options && options.refreshItems) { util.forEach(this.items, function (item) { @@ -617,12 +615,11 @@ ItemSet.prototype.redraw = function() { var visibleInterval = range.end - range.start; var zoomed = (visibleInterval != this.lastVisibleInterval) || (this.props.width != this.props.lastWidth); var scrolled = range.start != this.lastRangeStart; - if (zoomed || scrolled) this.stackDirty = true; + var forceRestack = (zoomed || scrolled); this.lastVisibleInterval = visibleInterval; this.lastRangeStart = range.start; this.props.lastWidth = this.props.width; - var restack = this.stackDirty; var firstGroup = this._firstGroup(); var firstMargin = { item: margin.item, @@ -636,17 +633,16 @@ ItemSet.prototype.redraw = function() { var minHeight = margin.axis + margin.item.vertical; // redraw the background group - this.groups[BACKGROUND].redraw(range, nonFirstMargin, restack); + this.groups[BACKGROUND].redraw(range, nonFirstMargin, forceRestack); // redraw all regular groups util.forEach(this.groups, function (group) { var groupMargin = (group == firstGroup) ? firstMargin : nonFirstMargin; - var groupResized = group.redraw(range, groupMargin, restack); + var groupResized = group.redraw(range, groupMargin, forceRestack); resized = groupResized || resized; height += group.height; }); height = Math.max(height, minHeight); - this.stackDirty = false; // update frame height frame.style.height = asSize(height); @@ -978,7 +974,6 @@ ItemSet.prototype._onUpdate = function(ids) { }.bind(this)); this._order(); - this.stackDirty = true; // force re-stacking of all items next redraw this.body.emitter.emit('_change', {queue: true}); }; @@ -1008,7 +1003,6 @@ ItemSet.prototype._onRemove = function(ids) { if (count) { // update order this._order(); - this.stackDirty = true; // force re-stacking of all items next redraw this.body.emitter.emit('_change', {queue: true}); } }; @@ -1540,7 +1534,6 @@ ItemSet.prototype._onDrag = function (event) { //make sure we stay in bounds newOffset = Math.max(0, newOffset); newOffset = Math.min(me.groupIds.length-1, newOffset); - itemData.group = me.groupIds[newOffset]; } } @@ -1553,8 +1546,7 @@ ItemSet.prototype._onDrag = function (event) { } }.bind(this)); }.bind(this)); - - this.stackDirty = true; // force re-stacking of all items next redraw + this.body.emitter.emit('_change'); } }; @@ -1607,7 +1599,6 @@ ItemSet.prototype._onDragEnd = function (event) { } // force re-stacking of all items next redraw - me.stackDirty = true; me.body.emitter.emit('_change'); }); } @@ -1624,7 +1615,6 @@ ItemSet.prototype._onDragEnd = function (event) { // restore original values props.item.setData(props.data); - me.stackDirty = true; // force re-stacking of all items next redraw me.body.emitter.emit('_change'); } }); diff --git a/lib/timeline/component/item/Item.js b/lib/timeline/component/item/Item.js index 30c0bbc8..9bfa662d 100644 --- a/lib/timeline/component/item/Item.js +++ b/lib/timeline/component/item/Item.js @@ -64,6 +64,7 @@ Item.prototype.setData = function(data) { if (groupChanged && this.parent != null) { this.parent.itemSet._moveToGroup(this, data.group); } + this.parent.stackDirty = true; var subGroupChanged = data.subgroup != undefined && this.data.subgroup != data.subgroup; if (subGroupChanged && this.parent != null) { @@ -78,7 +79,7 @@ Item.prototype.setData = function(data) { /** * Set a parent for the item - * @param {ItemSet | Group} parent + * @param {Group} parent */ Item.prototype.setParent = function(parent) { if (this.displayed) {