Skip to content
This repository was archived by the owner on Jul 29, 2019. It is now read-only.
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
300 changes: 158 additions & 142 deletions lib/timeline/component/Group.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,158 +206,174 @@ Group.prototype.getLabelWidth = function() {
return this.props.label.width;
};

Group.prototype._didMarkerHeightChange = function() {
var markerHeight = this.dom.marker.clientHeight;
if (markerHeight != this.lastMarkerHeight) {
this.lastMarkerHeight = markerHeight;
util.forEach(this.items, function (item) {
item.dirty = true;
if (item.displayed) item.redraw();
});
return true;
}
}

Group.prototype._calculateGroupSizeAndPosition = function() {
var foreground = this.dom.foreground;
this.top = foreground.offsetTop;
this.right = foreground.offsetLeft;
this.width = foreground.offsetWidth;
}

Group.prototype._redrawItems = function(forceRestack, lastIsVisible, margin, range) {
var restack = forceRestack || this.stackDirty || this.isVisible && !lastIsVisible;

// 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
var me = this;
var limitSize = false;
util.forEach(this.items, function (item) {
if (!item.displayed) {
item.redraw();
me.visibleItems.push(item);
}
item.repositionX(limitSize);
});

// order all items and force a restacking
var customOrderedItems = this.orderedItems.byStart.slice().sort(function (a, b) {
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);

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;
}
}

Group.prototype._didResize = function(resized, height) {
resized = util.updateProperty(this, 'height', height) || resized;
// recalculate size of label
var labelWidth = this.dom.inner.clientWidth;
var labelHeight = this.dom.inner.clientHeight;
resized = util.updateProperty(this.props.label, 'width', labelWidth) || resized;
resized = util.updateProperty(this.props.label, 'height', labelHeight) || resized;
return resized

Choose a reason for hiding this comment

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

;

}

Group.prototype._applyGroupHeight = function(height) {
this.dom.background.style.height = height + 'px';
this.dom.foreground.style.height = height + 'px';
this.dom.label.style.height = height + 'px';
}

Group.prototype._updateItemsVerticalPosition = function(resized, margin) {
// update vertical position of items after they are re-stacked and the height of the group is calculated

Choose a reason for hiding this comment

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

Might be better as function header comment

for (var i = 0, ii = this.visibleItems.length; i < ii; i++) {
var item = this.visibleItems[i];
item.repositionY(margin);
if (!this.isVisible && this.groupId != "__background__") {
if (item.displayed) item.hide();
}
}

if (!this.isVisible && this.height) {
return resized = false;

Choose a reason for hiding this comment

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

Why this construct? I think return false would be enough here

}

return resized;
}

/**
* Repaint this group
* @param {{start: number, end: number}} range
* @param {{item: {horizontal: number, vertical: number}, axis: number}} margin
* @param {boolean} [forceRestack=false] Force restacking of all items
* @param {boolean} [returnQueue=false] return the queue or the result
* @param {boolean} [returnQueue=false] return the queue or if the group resized
* @return {boolean} Returns true if the group is resized or the redraw queue if returnQueue=true
*/
Group.prototype.redraw = function(range, margin, forceRestack, returnQueue) {
var queue = [];

queue.push((function () {
// 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;
if (markerHeight != this.lastMarkerHeight) {
this.lastMarkerHeight = markerHeight;
util.forEach(this.items, function (item) {
item.dirty = true;
if (item.displayed) item.redraw();
});

forceRestack = true;
}
}).bind(this));

queue.push((function () {
// recalculate the height of the subgroups
this._updateSubGroupHeights(margin);
}).bind(this));

queue.push((function () {
// calculate actual size and position
var foreground = this.dom.foreground;
this.top = foreground.offsetTop;
this.right = foreground.offsetLeft;
this.width = foreground.offsetWidth;
}).bind(this));

var resized;
var lastIsVisible;

queue.push((function () {
resized = false;
lastIsVisible = this.isVisible;
this.isVisible = this._isGroupVisible(range, margin);
}).bind(this));

queue.push((function () {
var restack = forceRestack || this.stackDirty || this.isVisible && !lastIsVisible;

// 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
var me = this;
var limitSize = false;
util.forEach(this.items, function (item) {
if (!item.displayed) {
item.redraw();
me.visibleItems.push(item);
}
item.repositionX(limitSize);
});

// order all items and force a restacking
var customOrderedItems = this.orderedItems.byStart.slice().sort(function (a, b) {
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);

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;
}
}).bind(this));

var height;

queue.push((function () {
this._updateSubgroupsSizes();
}).bind(this));

queue.push((function () {
// recalculate the height of the group
height = this._calculateHeight(margin);
}).bind(this));

queue.push((function () {
// calculate actual size and position
var foreground = this.dom.foreground;
this.top = foreground.offsetTop;
this.right = foreground.offsetLeft;
this.width = foreground.offsetWidth;
}).bind(this));

queue.push((function () {
resized = util.updateProperty(this, 'height', height) || resized;
// recalculate size of label
resized = util.updateProperty(this.props.label, 'width', this.dom.inner.clientWidth) || resized;
resized = util.updateProperty(this.props.label, 'height', this.dom.inner.clientHeight) || resized;
}).bind(this));

queue.push((function () {
// apply new height
this.dom.background.style.height = height + 'px';
this.dom.foreground.style.height = height + 'px';
this.dom.label.style.height = height + 'px';
}).bind(this));

queue.push((function () {
// update vertical position of items after they are re-stacked and the height of the group is calculated
for (var i = 0, ii = this.visibleItems.length; i < ii; i++) {
var item = this.visibleItems[i];
item.repositionY(margin);
if (!this.isVisible && this.groupId != "__background__") {
if (item.displayed) item.hide();
}
}

if (!this.isVisible && this.height) {
return resized = false;
}

return resized;
}).bind(this));
var resized = false;
var lastIsVisible = this.isVisible;
var height;

if (returnQueue) {
return queue;
} else {
var result;
queue.forEach(function (fn) {
result = fn();
});
return result;
}
};
var queue = [
// 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)
(function () {
forceRestack = this._didMarkerHeightChange.bind(this);
}).bind(this),

// recalculate the height of the subgroups
this._updateSubGroupHeights.bind(this, margin),

// calculate actual size and position
this._calculateGroupSizeAndPosition.bind(this),

// check if group is visible
(function() {
this.isVisible = this._isGroupVisible.bind(this)(range, margin);
}).bind(this),

// redraw Items if needed
(function() {
this._redrawItems.bind(this)(forceRestack, lastIsVisible, margin, range)
}).bind(this),

// update subgroups
this._updateSubgroupsSizes.bind(this),

// recalculate the height of the group
(function() {
height = this._calculateHeight.bind(this)(margin);
}).bind(this),

// calculate actual size and position again
this._calculateGroupSizeAndPosition.bind(this),

// check if resized
(function() {
resized = this._didResize.bind(this)(resized, height)
}).bind(this),

// apply group height
(function() {
this._applyGroupHeight.bind(this)(height)
}).bind(this),

// update vertical position of items after they are re-stacked and the height of the group is calculated
(function() {
return resized = this._updateItemsVerticalPosition.bind(this)(resized, margin)

Choose a reason for hiding this comment

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

For my understanding: this is the last function in the queue and it returns something. The return value is collected here. Is this the intention?

Choose a reason for hiding this comment

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

I suppose the assignment to resize isn't really necessary for the return, but it's kept in for completeness. I guess this is OK (I would probably do the same).

}).bind(this)
]

if (returnQueue) {
return queue;
} else {
var result;
queue.forEach(function (fn) {
result = fn();
});
return result;
}
};

/**
* recalculate the height of the subgroups
Expand Down