|
|
@ -26,7 +26,7 @@ function Group (groupId, data, itemSet) { |
|
|
|
|
|
|
|
this.items = {}; // items filtered by groupId of this group
|
|
|
|
this.visibleItems = []; // items currently visible in window
|
|
|
|
this.orderedItems = { // items sorted by start and by end
|
|
|
|
this.orderedItems = { |
|
|
|
byStart: [], |
|
|
|
byEnd: [] |
|
|
|
}; |
|
|
@ -361,6 +361,7 @@ Group.prototype.remove = function(item) { |
|
|
|
// TODO: also remove from ordered items?
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Remove an item from the corresponding DataSet |
|
|
|
* @param {Item} item |
|
|
@ -369,35 +370,31 @@ Group.prototype.removeFromDataSet = function(item) { |
|
|
|
this.itemSet.removeItem(item.id); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Reorder the items |
|
|
|
*/ |
|
|
|
Group.prototype.order = function() { |
|
|
|
var array = util.toArray(this.items); |
|
|
|
this.orderedItems.byStart = array; |
|
|
|
this.orderedItems.byEnd = this._constructByEndArray(array); |
|
|
|
|
|
|
|
stack.orderByStart(this.orderedItems.byStart); |
|
|
|
stack.orderByEnd(this.orderedItems.byEnd); |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
|
* Create an array containing all items being a range (having an end date) |
|
|
|
* @param {Item[]} array |
|
|
|
* @returns {RangeItem[]} |
|
|
|
* @private |
|
|
|
*/ |
|
|
|
Group.prototype._constructByEndArray = function(array) { |
|
|
|
var startArray = []; |
|
|
|
var endArray = []; |
|
|
|
|
|
|
|
for (var i = 0; i < array.length; i++) { |
|
|
|
if (array[i] instanceof RangeItem) { |
|
|
|
if (array[i].data.end !== undefined) { |
|
|
|
endArray.push(array[i]); |
|
|
|
} |
|
|
|
startArray.push(array[i]); |
|
|
|
} |
|
|
|
return endArray; |
|
|
|
this.orderedItems = { |
|
|
|
byStart: startArray, |
|
|
|
byEnd: endArray |
|
|
|
}; |
|
|
|
|
|
|
|
stack.orderByStart(this.orderedItems.byStart); |
|
|
|
stack.orderByEnd(this.orderedItems.byEnd); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Update the visible items |
|
|
|
* @param {{byStart: Item[], byEnd: Item[]}} orderedItems All items ordered by start date and by end date |
|
|
@ -406,79 +403,111 @@ Group.prototype._constructByEndArray = function(array) { |
|
|
|
* @return {Item[]} visibleItems The new visible items. |
|
|
|
* @private |
|
|
|
*/ |
|
|
|
Group.prototype._updateVisibleItems = function(orderedItems, visibleItems, range) { |
|
|
|
var initialPosByStart, |
|
|
|
newVisibleItems = [], |
|
|
|
i; |
|
|
|
Group.prototype._updateVisibleItems = function(orderedItems, oldVisibleItems, range) { |
|
|
|
var visibleItems = []; |
|
|
|
var visibleItemsLookup = {}; |
|
|
|
var interval = (range.end - range.start) / 4; |
|
|
|
var lowerBound = range.start - interval; |
|
|
|
var upperBound = range.end + interval; |
|
|
|
var item, i; |
|
|
|
|
|
|
|
// this function is used to do the binary search.
|
|
|
|
var searchFunction = function (value) { |
|
|
|
if (value < lowerBound) {return -1;} |
|
|
|
else if (value >= lowerBound && value <= upperBound) {return 0;} |
|
|
|
else {return 1;} |
|
|
|
} |
|
|
|
|
|
|
|
// first check if the items that were in view previously are still in view.
|
|
|
|
// this handles the case for the RangeItem that is both before and after the current one.
|
|
|
|
if (visibleItems.length > 0) { |
|
|
|
for (i = 0; i < visibleItems.length; i++) { |
|
|
|
this._checkIfVisible(visibleItems[i], newVisibleItems, range); |
|
|
|
// IMPORTANT: this handles the case for the items with startdate before the window and enddate after the window!
|
|
|
|
// also cleans up invisible items.
|
|
|
|
if (oldVisibleItems.length > 0) { |
|
|
|
for (i = 0; i < oldVisibleItems.length; i++) { |
|
|
|
item = oldVisibleItems[i]; |
|
|
|
if (item.isVisible(range)) { |
|
|
|
visibleItems.push(item); |
|
|
|
visibleItemsLookup[item.id] = true; |
|
|
|
} |
|
|
|
else { |
|
|
|
if (item.displayed) item.hide(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// If there were no visible items previously, use binarySearch to find a visible PointItem or RangeItem (based on startTime)
|
|
|
|
if (newVisibleItems.length == 0) { |
|
|
|
initialPosByStart = util.binarySearch(orderedItems.byStart, range, 'data','start'); |
|
|
|
} |
|
|
|
else { |
|
|
|
initialPosByStart = orderedItems.byStart.indexOf(newVisibleItems[0]); |
|
|
|
} |
|
|
|
// we do a binary search for the items that have only start values.
|
|
|
|
var initialPosByStart = util.binarySearchCustom(orderedItems.byStart, searchFunction, 'data','start'); |
|
|
|
|
|
|
|
// use visible search to find a visible RangeItem (only based on endTime)
|
|
|
|
var initialPosByEnd = util.binarySearch(orderedItems.byEnd, range, 'data','end'); |
|
|
|
// we do a binary search for the items that have defined end times.
|
|
|
|
var initialPosByEnd = util.binarySearchCustom(orderedItems.byEnd, searchFunction, 'data','end'); |
|
|
|
|
|
|
|
// if we found a initial ID to use, trace it up and down until we meet an invisible item.
|
|
|
|
if (initialPosByStart != -1) { |
|
|
|
for (i = initialPosByStart; i >= 0; i--) { |
|
|
|
if (this._checkIfInvisible(orderedItems.byStart[i], newVisibleItems, range)) {break;} |
|
|
|
} |
|
|
|
for (i = initialPosByStart + 1; i < orderedItems.byStart.length; i++) { |
|
|
|
if (this._checkIfInvisible(orderedItems.byStart[i], newVisibleItems, range)) {break;} |
|
|
|
} |
|
|
|
} |
|
|
|
// trace the visible items from the inital start pos both ways until an invisible item is found, we only look at the start values.
|
|
|
|
this._traceVisible(initialPosByStart, orderedItems.byStart, visibleItems, visibleItemsLookup, function (item) { |
|
|
|
return (item.data.start < lowerBound || item.data.start > upperBound); |
|
|
|
}); |
|
|
|
|
|
|
|
// if we found a initial ID to use, trace it up and down until we meet an invisible item.
|
|
|
|
if (initialPosByEnd != -1) { |
|
|
|
for (i = initialPosByEnd; i >= 0; i--) { |
|
|
|
if (this._checkIfInvisible(orderedItems.byEnd[i], newVisibleItems, range)) {break;} |
|
|
|
} |
|
|
|
for (i = initialPosByEnd + 1; i < orderedItems.byEnd.length; i++) { |
|
|
|
if (this._checkIfInvisible(orderedItems.byEnd[i], newVisibleItems, range)) {break;} |
|
|
|
} |
|
|
|
// trace the visible items from the inital start pos both ways until an invisible item is found, we only look at the end values.
|
|
|
|
this._traceVisible(initialPosByEnd, orderedItems.byEnd, visibleItems, visibleItemsLookup, function (item) { |
|
|
|
return (item.data.end < lowerBound || item.data.end > upperBound); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// finally, we reposition all the visible items.
|
|
|
|
for (i = 0; i < visibleItems.length; i++) { |
|
|
|
item = visibleItems[i]; |
|
|
|
if (!item.displayed) item.show(); |
|
|
|
// reposition item horizontally
|
|
|
|
item.repositionX(); |
|
|
|
} |
|
|
|
|
|
|
|
return newVisibleItems; |
|
|
|
}; |
|
|
|
// debug
|
|
|
|
//console.log("new line")
|
|
|
|
//if (this.groupId == null) {
|
|
|
|
// for (i = 0; i < orderedItems.byStart.length; i++) {
|
|
|
|
// item = orderedItems.byStart[i].data;
|
|
|
|
// console.log('start',i,initialPosByStart, item.start.valueOf(), item.content, item.start >= lowerBound && item.start <= upperBound,i == initialPosByStart ? "<------------------- HEREEEE" : "")
|
|
|
|
// }
|
|
|
|
// for (i = 0; i < orderedItems.byEnd.length; i++) {
|
|
|
|
// item = orderedItems.byEnd[i].data;
|
|
|
|
// console.log('rangeEnd',i,initialPosByEnd, item.end.valueOf(), item.content, item.end >= range.start && item.end <= range.end,i == initialPosByEnd ? "<------------------- HEREEEE" : "")
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
|
|
|
|
return visibleItems; |
|
|
|
}; |
|
|
|
|
|
|
|
Group.prototype._traceVisible = function (initialPos, items, visibleItems, visibleItemsLookup, breakCondition) { |
|
|
|
var item; |
|
|
|
var i; |
|
|
|
|
|
|
|
/** |
|
|
|
* this function checks if an item is invisible. If it is NOT we make it visible |
|
|
|
* and add it to the global visible items. If it is, return true. |
|
|
|
* |
|
|
|
* @param {Item} item |
|
|
|
* @param {Item[]} visibleItems |
|
|
|
* @param {{start:number, end:number}} range |
|
|
|
* @returns {boolean} |
|
|
|
* @private |
|
|
|
*/ |
|
|
|
Group.prototype._checkIfInvisible = function(item, visibleItems, range) { |
|
|
|
if (item.isVisible(range)) { |
|
|
|
if (!item.displayed) item.show(); |
|
|
|
item.repositionX(); |
|
|
|
if (visibleItems.indexOf(item) == -1) { |
|
|
|
visibleItems.push(item); |
|
|
|
if (initialPos != -1) { |
|
|
|
for (i = initialPos; i >= 0; i--) { |
|
|
|
item = items[i]; |
|
|
|
if (breakCondition(item)) { |
|
|
|
break; |
|
|
|
} |
|
|
|
else { |
|
|
|
if (visibleItemsLookup[item.id] === undefined) { |
|
|
|
visibleItemsLookup[item.id] = true; |
|
|
|
visibleItems.push(item); |
|
|
|
} |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
else { |
|
|
|
if (item.displayed) item.hide(); |
|
|
|
return true; |
|
|
|
|
|
|
|
for (i = initialPos + 1; i < items.length; i++) { |
|
|
|
item = items[i]; |
|
|
|
if (breakCondition(item)) { |
|
|
|
break; |
|
|
|
} |
|
|
|
else { |
|
|
|
if (visibleItemsLookup[item.id] === undefined) { |
|
|
|
visibleItemsLookup[item.id] = true; |
|
|
|
visibleItems.push(item); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* this function is very similar to the _checkIfInvisible() but it does not |
|
|
@ -503,4 +532,6 @@ Group.prototype._checkIfVisible = function(item, visibleItems, range) { |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
module.exports = Group; |