|
@ -57,31 +57,6 @@ Stack.prototype.setOptions = function setOptions (options) { |
|
|
// TODO: register on data changes at the connected itemset, and update the changed part only and immediately
|
|
|
// TODO: register on data changes at the connected itemset, and update the changed part only and immediately
|
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Stack the items such that they don't overlap. The items will have a minimal |
|
|
|
|
|
* distance equal to options.margin.item. |
|
|
|
|
|
*/ |
|
|
|
|
|
Stack.prototype.update = function update() { |
|
|
|
|
|
this._order(); |
|
|
|
|
|
this._stack(this.ordered); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Order the items. If a custom order function has been provided via the options, |
|
|
|
|
|
* then this will be used. |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
Stack.prototype._order = function _order () { |
|
|
|
|
|
var items = this.itemset.items; |
|
|
|
|
|
if (!items) { |
|
|
|
|
|
throw new Error('Cannot stack items: ItemSet does not contain items'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// TODO: use sorted items instead of ordering every time
|
|
|
|
|
|
|
|
|
|
|
|
this.ordered = this.order(items); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Order a map with items |
|
|
* Order a map with items |
|
|
* @param {Object<String, Item>} items |
|
|
* @param {Object<String, Item>} items |
|
@ -105,75 +80,6 @@ Stack.prototype.order = function order(items) { |
|
|
return ordered; |
|
|
return ordered; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Adjust vertical positions of the events such that they don't overlap each |
|
|
|
|
|
* other. |
|
|
|
|
|
* @param {Item[]} items |
|
|
|
|
|
* @private |
|
|
|
|
|
*/ |
|
|
|
|
|
Stack.prototype._stack = function _stack (items) { |
|
|
|
|
|
var i, |
|
|
|
|
|
iMax, |
|
|
|
|
|
options = this.options, |
|
|
|
|
|
orientation = options.orientation || this.defaultOptions.orientation, |
|
|
|
|
|
axisOnTop = (orientation == 'top'), |
|
|
|
|
|
margin, |
|
|
|
|
|
parentHeight = this.itemset.height; // TODO: should use the height of the itemsets parent
|
|
|
|
|
|
|
|
|
|
|
|
if (options.margin && options.margin.item !== undefined) { |
|
|
|
|
|
margin = options.margin.item; |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
margin = this.defaultOptions.margin.item |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// initialize top position
|
|
|
|
|
|
for (i = 0, iMax = items.length; i < iMax; i++) { |
|
|
|
|
|
var item = items[i]; |
|
|
|
|
|
|
|
|
|
|
|
//*
|
|
|
|
|
|
if (orientation == 'top') { |
|
|
|
|
|
item.top = margin; |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
// default or 'bottom'
|
|
|
|
|
|
item.top = parentHeight - item.height - 2 * margin; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// calculate new, non-overlapping positions
|
|
|
|
|
|
for (i = 0, iMax = items.length; i < iMax; i++) { |
|
|
|
|
|
var item = items[i]; |
|
|
|
|
|
var collidingItem = null; |
|
|
|
|
|
|
|
|
|
|
|
/* TODO: cleanup |
|
|
|
|
|
// initialize top position
|
|
|
|
|
|
if (orientation == 'top') { |
|
|
|
|
|
item.top = margin; |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
// default or 'bottom'
|
|
|
|
|
|
item.top = parentHeight - item.height - 2 * margin; |
|
|
|
|
|
} |
|
|
|
|
|
//*/
|
|
|
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
|
// TODO: optimize checking for overlap. when there is a gap without items,
|
|
|
|
|
|
// you only need to check for items from the next item on, not from zero
|
|
|
|
|
|
collidingItem = this._checkOverlap (items, i, 0, i - 1, margin); |
|
|
|
|
|
if (collidingItem != null) { |
|
|
|
|
|
// There is a collision. Reposition the event above the colliding element
|
|
|
|
|
|
if (axisOnTop) { |
|
|
|
|
|
item.top = collidingItem.top + collidingItem.height + margin; |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
item.top = collidingItem.top - item.height - margin; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} while (collidingItem); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Adjust vertical positions of the events such that they don't overlap each |
|
|
* Adjust vertical positions of the events such that they don't overlap each |
|
|
* other. |
|
|
* other. |
|
@ -209,11 +115,18 @@ Stack.prototype.stack = function stack (items) { |
|
|
item.top = parentHeight - item.height - 2 * margin; |
|
|
item.top = parentHeight - item.height - 2 * margin; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var collidingItem; |
|
|
|
|
|
do { |
|
|
do { |
|
|
// TODO: optimize checking for overlap. when there is a gap without items,
|
|
|
// TODO: optimize checking for overlap. when there is a gap without items,
|
|
|
// you only need to check for items from the next item on, not from zero
|
|
|
// you only need to check for items from the next item on, not from zero
|
|
|
collidingItem = this.checkOverlap (item, items, margin); |
|
|
|
|
|
|
|
|
var collidingItem = null; |
|
|
|
|
|
for (var j = 0, jj = items.length; j < jj; j++) { |
|
|
|
|
|
var other = items[j]; |
|
|
|
|
|
if (other.top !== null && other !== item && this.collision(item, other, margin)) { |
|
|
|
|
|
collidingItem = other; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (collidingItem != null) { |
|
|
if (collidingItem != null) { |
|
|
// There is a collision. Reposition the event above the colliding element
|
|
|
// There is a collision. Reposition the event above the colliding element
|
|
|
if (axisOnTop) { |
|
|
if (axisOnTop) { |
|
@ -228,62 +141,6 @@ Stack.prototype.stack = function stack (items) { |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Check if the destiny position of given item overlaps with any |
|
|
|
|
|
* of the other items from index itemStart to itemEnd. |
|
|
|
|
|
* @param {Item} item item to be checked |
|
|
|
|
|
* @param {Item[]} items Array with items |
|
|
|
|
|
* @return {Object | null} colliding item, or undefined when no collisions |
|
|
|
|
|
* @param {Number} margin A minimum required margin. |
|
|
|
|
|
* If margin is provided, the two items will be |
|
|
|
|
|
* marked colliding when they overlap or |
|
|
|
|
|
* when the margin between the two is smaller than |
|
|
|
|
|
* the requested margin. |
|
|
|
|
|
*/ |
|
|
|
|
|
Stack.prototype.checkOverlap = function checkOverlap (item, items, margin) { |
|
|
|
|
|
for (var i = 0, ii = items.length; i < ii; i++) { |
|
|
|
|
|
var b = items[i]; |
|
|
|
|
|
if (b.top !== null && b !== item && this.collision(item, b, margin)) { |
|
|
|
|
|
return b; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Check if the destiny position of given item overlaps with any |
|
|
|
|
|
* of the other items from index itemStart to itemEnd. |
|
|
|
|
|
* @param {Array} items Array with items |
|
|
|
|
|
* @param {int} itemIndex Number of the item to be checked for overlap |
|
|
|
|
|
* @param {int} itemStart First item to be checked. |
|
|
|
|
|
* @param {int} itemEnd Last item to be checked. |
|
|
|
|
|
* @return {Object | null} colliding item, or undefined when no collisions |
|
|
|
|
|
* @param {Number} margin A minimum required margin. |
|
|
|
|
|
* If margin is provided, the two items will be |
|
|
|
|
|
* marked colliding when they overlap or |
|
|
|
|
|
* when the margin between the two is smaller than |
|
|
|
|
|
* the requested margin. |
|
|
|
|
|
*/ |
|
|
|
|
|
Stack.prototype._checkOverlap = function _checkOverlap (items, itemIndex, |
|
|
|
|
|
itemStart, itemEnd, margin) { |
|
|
|
|
|
var collision = this.collision; |
|
|
|
|
|
|
|
|
|
|
|
// we loop from end to start, as we suppose that the chance of a
|
|
|
|
|
|
// collision is larger for items at the end, so check these first.
|
|
|
|
|
|
var a = items[itemIndex]; |
|
|
|
|
|
for (var i = itemEnd; i >= itemStart; i--) { |
|
|
|
|
|
var b = items[i]; |
|
|
|
|
|
if (collision(a, b, margin)) { |
|
|
|
|
|
if (i != itemIndex) { |
|
|
|
|
|
return b; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Test if the two provided items collide |
|
|
* Test if the two provided items collide |
|
|
* The items must have parameters left, width, top, and height. |
|
|
* The items must have parameters left, width, top, and height. |
|
|