Browse Source

Temporarily fixed stacking in a primitive way

css_transitions
josdejong 10 years ago
parent
commit
699c13d99b
9 changed files with 117 additions and 97 deletions
  1. +4
    -4
      src/timeline/Controller.js
  2. +21
    -40
      src/timeline/Stack.js
  3. +70
    -37
      src/timeline/component/ItemSet.js
  4. +0
    -10
      src/timeline/component/item/Item.js
  5. +1
    -1
      src/timeline/component/item/ItemBox.js
  6. +1
    -1
      src/timeline/component/item/ItemPoint.js
  7. +2
    -2
      src/timeline/component/item/ItemRange.js
  8. +2
    -2
      src/timeline/component/item/ItemRangeOverflow.js
  9. +16
    -0
      src/util.js

+ 4
- 4
src/timeline/Controller.js View File

@ -22,10 +22,10 @@ function Controller () {
} }
else { else {
if (!reflowTimer) { if (!reflowTimer) {
reflowTimer = setTimeout(function () {
reflowTimer = requestAnimationFrame(function () {
reflowTimer = null; reflowTimer = null;
me.reflow(); me.reflow();
}, 0);
});
} }
} }
}); });
@ -42,10 +42,10 @@ function Controller () {
} }
else { else {
if (!repaintTimer) { if (!repaintTimer) {
repaintTimer = setTimeout(function () {
repaintTimer = requestAnimationFrame(function () {
repaintTimer = null; repaintTimer = null;
me.repaint(); me.repaint();
}, 0);
});
} }
} }
}); });

+ 21
- 40
src/timeline/Stack.js View File

@ -55,59 +55,40 @@ Stack.prototype.setOptions = function setOptions (options) {
}; };
/** /**
* Order a map with items
* @param {Object<String, Item>} items
* @return {{asc: Item[], desc: Item[]}} sorted items
* Order an array with items using a predefined order function for items
* @param {Item[]} items
*/ */
Stack.prototype.order = function order(items) { Stack.prototype.order = function order(items) {
var ordered = [];
// convert map to array
for (var id in items) {
if (items.hasOwnProperty(id)) ordered.push(items[id]);
}
/* FIXME: fix option order
//order the items //order the items
var order = this.options.order || this.defaultOptions.order; var order = this.options.order || this.defaultOptions.order;
if (!(typeof order === 'function')) { if (!(typeof order === 'function')) {
throw new Error('Option order must be a function'); throw new Error('Option order must be a function');
} }
ordered.sort(order);
*/
// TODO: fix ordering, doesn't work correctly for ItemRange
ordered.sort(function (a, b) {
var aCenter = ('end' in a.data) ? (a.data.start + a.data.end) / 2 : a.data.start,
bCenter = ('end' in b.data) ? (b.data.start + b.data.end) / 2 : b.data.start;
return aCenter - bCenter;
});
/* TODO: cleanup
var asc = array.concat(),
desc= array.concat();
items.sort(order);
};
// sort ascending
asc.sort(function (a, b) {
/**
* Order items by their start data
* @param {Item[]} items
*/
Stack.prototype.orderByStart = function orderByStart(items) {
items.sort(function (a, b) {
return a.data.start - b.data.start; return a.data.start - b.data.start;
}); });
};
// sort descending
desc.sort(function (a, b) {
var aTime = 'end' in a.data ? a.data.end : a.data.start,
bTime = 'end' in b.data ? b.data.end : b.data.start;
/**
* Order items by their end date. If they have no end date, their start date
* is used.
* @param {Item[]} items
*/
Stack.prototype.orderByEnd = function orderByEnd(items) {
items.sort(function (a, b) {
var aTime = ('end' in a.data) ? a.data.end : a.data.start,
bTime = ('end' in b.data) ? b.data.end : b.data.start;
return bTime - aTime;
return aTime - bTime;
}); });
return {
asc: asc,
desc: desc
};
*/
return ordered;
}; };
/** /**

+ 70
- 37
src/timeline/component/ItemSet.js View File

@ -56,10 +56,13 @@ function ItemSet(parent, depends, options) {
}; };
this.items = {}; // object with an Item for every data item this.items = {}; // object with an Item for every data item
this.orderedItems = []; // ordered items
this.orderedItems = {
byStart: [],
byEnd: []
};
this.visibleItems = []; // visible, ordered items this.visibleItems = []; // visible, ordered items
this.visibleItemsStart = 0; // start index of visible items in this.orderedItems
this.visibleItemsEnd = 0; // start index of visible items in this.orderedItems
this.visibleItemsStart = 0; // start index of visible items in this.orderedItems // TODO: cleanup
this.visibleItemsEnd = 0; // start index of visible items in this.orderedItems // TODO: cleanup
this.selection = []; // list with the ids of all selected nodes this.selection = []; // list with the ids of all selected nodes
this.queue = {}; // queue with id/actions: 'add', 'update', 'delete' this.queue = {}; // queue with id/actions: 'add', 'update', 'delete'
this.stack = new Stack(this, Object.create(this.options)); this.stack = new Stack(this, Object.create(this.options));
@ -292,59 +295,80 @@ ItemSet.prototype.repaint = function repaint() {
changed += update(this.dom.axis.style, 'top', this.top + 'px'); changed += update(this.dom.axis.style, 'top', this.top + 'px');
} }
// find start of visible items
var start = Math.min(this.visibleItemsStart, Math.max(this.orderedItems.length - 1, 0));
var item = this.orderedItems[start];
while (item && item.isVisible(this.range) && start > 0) {
start--;
item = this.orderedItems[start];
}
while (item && !item.isVisible(this.range)) {
if (item.displayed) item.hide();
// check whether zoomed (in that case we need to re-stack everything)
var visibleInterval = this.range.end - this.range.start;
var zoomed = this.visibleInterval != visibleInterval;
this.visibleInterval = visibleInterval;
/*
// find the first visible item
// TODO: use faster search, not linear
var byEnd = this.orderedItems.byEnd;
var start = 0;
var item = null;
while ((item = byEnd[start]) &&
(('end' in item.data) ? item.data.end : item.data.start) < this.range.start) {
start++; start++;
item = this.orderedItems[start];
} }
this.visibleItemsStart = start;
// find end of visible items
var end = Math.max(Math.min(this.visibleItemsEnd, this.orderedItems.length), this.visibleItemsStart);
item = this.orderedItems[end];
while (item && item.isVisible(this.range)) {
// find the last visible item
// TODO: use faster search, not linear
var byStart = this.orderedItems.byStart;
var end = 0;
while ((item = byStart[end]) && item.data.start < this.range.end) {
end++; end++;
item = this.orderedItems[end];
} }
item = this.orderedItems[end - 1];
while (item && !item.isVisible(this.range) && end > 0) {
if (item.displayed) item.hide();
end--;
item = this.orderedItems[end - 1];
}
this.visibleItemsEnd = end;
console.log('visible items', start, end); // TODO: cleanup console.log('visible items', start, end); // TODO: cleanup
console.log('visible item ids', byStart[start] && byStart[start].id, byEnd[end-1] && byEnd[end-1].id); // TODO: cleanup
this.visibleItems = this.orderedItems.slice(start, end);
// check whether zoomed (in that case we need to re-stack everything)
var visibleInterval = this.range.end - this.range.start;
var zoomed = this.visibleInterval != visibleInterval;
this.visibleInterval = visibleInterval;
this.visibleItems = [];
var i = start;
item = byStart[i];
var lastItem = byEnd[end];
while (item && item !== lastItem) {
this.visibleItems.push(item);
item = byStart[++i];
}
this.stack.order(this.visibleItems);
// show visible items // show visible items
for (var i = 0, ii = this.visibleItems.length; i < ii; i++) { for (var i = 0, ii = this.visibleItems.length; i < ii; i++) {
var item = this.visibleItems[i];
item = this.visibleItems[i];
if (!item.displayed) item.show(); if (!item.displayed) item.show();
if (zoomed) item.top = null; // reset stacking position
item.top = null; // reset stacking position
// reposition item horizontally // reposition item horizontally
item.repositionX(); item.repositionX();
} }
*/
// simple, brute force calculation of visible items
// TODO: replace with a faster, more sophisticated solution
this.visibleItems = [];
for (var id in this.items) {
if (this.items.hasOwnProperty(id)) {
var item = this.items[id];
if (item.isVisible(this.range)) {
if (!item.displayed) item.show();
// reset stacking position
if (zoomed) item.top = null;
// reposition item horizontally
item.repositionX();
this.visibleItems.push(item);
}
else {
if (item.displayed) item.hide();
}
}
}
// reposition visible items vertically // reposition visible items vertically
// TODO: improve stacking, when moving the timeline to the right, update stacking in backward order
this.stack.order(this.visibleItems);
this.stack.stack(this.visibleItems); this.stack.stack(this.visibleItems);
for (var i = 0, ii = this.visibleItems.length; i < ii; i++) { for (var i = 0, ii = this.visibleItems.length; i < ii; i++) {
this.visibleItems[i].repositionY(); this.visibleItems[i].repositionY();
@ -630,8 +654,17 @@ ItemSet.prototype._onRemove = function _onRemove(ids) {
* @private * @private
*/ */
ItemSet.prototype._order = function _order() { ItemSet.prototype._order = function _order() {
var array = util.toArray(this.items);
this.orderedItems.byStart = array;
this.orderedItems.byEnd = [].concat(array);
// reorder the items // reorder the items
this.orderedItems = this.stack.order(this.items);
this.stack.orderByStart(this.orderedItems.byStart);
this.stack.orderByEnd(this.orderedItems.byEnd);
// TODO: cleanup
//console.log('byStart', this.orderedItems.byStart.map(function (item) {return item.id}))
//console.log('byEnd', this.orderedItems.byEnd.map(function (item) {return item.id}))
} }
/** /**

+ 0
- 10
src/timeline/component/item/Item.js View File

@ -22,7 +22,6 @@ function Item (parent, data, options, defaultOptions) {
this.left = null; this.left = null;
this.width = null; this.width = null;
this.height = null; this.height = null;
this.offset = 0; // TODO: is offset still used or redundant?
} }
/** /**
@ -90,15 +89,6 @@ Item.prototype.repositionY = function repositionY() {
// should be implemented by the item // should be implemented by the item
}; };
/**
* Give the item a display offset in pixels
* @param {Number} offset Offset on screen in pixels
*/
// TODO: is setOffset redundant?
Item.prototype.setOffset = function setOffset(offset) {
this.offset = offset;
};
/** /**
* Repaint a delete button on the top right of the item when the item is selected * Repaint a delete button on the top right of the item when the item is selected
* @param {HTMLElement} anchor * @param {HTMLElement} anchor

+ 1
- 1
src/timeline/component/item/ItemBox.js View File

@ -172,7 +172,7 @@ ItemBox.prototype.hide = function hide() {
* @Override * @Override
*/ */
ItemBox.prototype.repositionX = function repositionX() { ItemBox.prototype.repositionX = function repositionX() {
var start = this.parent.toScreen(this.data.start) + this.offset,
var start = this.parent.toScreen(this.data.start),
align = this.options.align || this.defaultOptions.align, align = this.options.align || this.defaultOptions.align,
left, left,
box = this.dom.box, box = this.dom.box,

+ 1
- 1
src/timeline/component/item/ItemPoint.js View File

@ -163,7 +163,7 @@ ItemPoint.prototype.hide = function hide() {
* @Override * @Override
*/ */
ItemPoint.prototype.repositionX = function repositionX() { ItemPoint.prototype.repositionX = function repositionX() {
var start = this.parent.toScreen(this.data.start) + this.offset;
var start = this.parent.toScreen(this.data.start);
this.left = start - this.props.dot.width / 2; this.left = start - this.props.dot.width / 2;

+ 2
- 2
src/timeline/component/item/ItemRange.js View File

@ -154,8 +154,8 @@ ItemRange.prototype.hide = function hide() {
ItemRange.prototype.repositionX = function repositionX() { ItemRange.prototype.repositionX = function repositionX() {
var props = this.props, var props = this.props,
parentWidth = this.parent.width, parentWidth = this.parent.width,
start = this.parent.toScreen(this.data.start) + this.offset,
end = this.parent.toScreen(this.data.end) + this.offset,
start = this.parent.toScreen(this.data.start),
end = this.parent.toScreen(this.data.end),
padding = 'padding' in this.options ? this.options.padding : this.defaultOptions.padding, padding = 'padding' in this.options ? this.options.padding : this.defaultOptions.padding,
contentLeft; contentLeft;

+ 2
- 2
src/timeline/component/item/ItemRangeOverflow.js View File

@ -29,8 +29,8 @@ ItemRangeOverflow.prototype.baseClassName = 'item rangeoverflow';
*/ */
ItemRangeOverflow.prototype.repositionX = function repositionX() { ItemRangeOverflow.prototype.repositionX = function repositionX() {
var parentWidth = this.parent.width, var parentWidth = this.parent.width,
start = this.parent.toScreen(this.data.start) + this.offset,
end = this.parent.toScreen(this.data.end) + this.offset,
start = this.parent.toScreen(this.data.start),
end = this.parent.toScreen(this.data.end),
padding = 'padding' in this.options ? this.options.padding : this.defaultOptions.padding, padding = 'padding' in this.options ? this.options.padding : this.defaultOptions.padding,
contentLeft; contentLeft;

+ 16
- 0
src/util.js View File

@ -440,6 +440,22 @@ util.forEach = function forEach (object, callback) {
} }
}; };
/**
* Convert an object into an array: all objects properties are put into the
* array. The resulting array is unordered.
* @param {Object} object
* @param {Array} array
*/
util.toArray = function toArray(object) {
var array = [];
for (var prop in object) {
if (object.hasOwnProperty(prop)) array.push(object[prop]);
}
return array;
}
/** /**
* Update a property in an object * Update a property in an object
* @param {Object} object * @param {Object} object

Loading…
Cancel
Save