Browse Source

repaint functions now return a `resized` variable used to determine whether another repaint is needed to settle

css_transitions
josdejong 10 years ago
parent
commit
7899d6dab4
10 changed files with 78 additions and 31 deletions
  1. +2
    -0
      src/timeline/Timeline.js
  2. +20
    -0
      src/timeline/component/Component.js
  3. +1
    -1
      src/timeline/component/CurrentTime.js
  4. +1
    -3
      src/timeline/component/CustomTime.js
  5. +5
    -2
      src/timeline/component/Group.js
  6. +13
    -5
      src/timeline/component/GroupSet.js
  7. +16
    -13
      src/timeline/component/ItemSet.js
  8. +8
    -2
      src/timeline/component/Panel.js
  9. +9
    -5
      src/timeline/component/RootPanel.js
  10. +3
    -0
      src/timeline/component/TimeAxis.js

+ 2
- 0
src/timeline/Timeline.js View File

@ -355,6 +355,7 @@ Timeline.prototype.setGroups = function(groups) {
// create new GroupSet
this.groupSet = new GroupSet(this.labelPanel, options);
this.groupSet.on('change', this.rootPanel.repaint.bind(this.rootPanel, 'changes'));
this.groupSet.setRange(this.range);
this.groupSet.setItems(this.itemsData);
this.groupSet.setGroups(this.groupsData);
@ -373,6 +374,7 @@ Timeline.prototype.setGroups = function(groups) {
this.itemSet = new ItemSet(options);
this.itemSet.setRange(this.range);
this.itemSet.setItems(this.itemsData);
this.itemSet.on('change', me.rootPanel.repaint.bind(me.rootPanel));
this.contentPanel.appendChild(this.itemSet);
}
};

+ 20
- 0
src/timeline/component/Component.js View File

@ -14,6 +14,9 @@ function Component () {
this.height = 0;
}
// Turn the Component into an event emitter
Emitter(Component.prototype);
/**
* Set parameters for the frame. Parameters will be merged in current parameter
* set.
@ -72,9 +75,11 @@ Component.prototype.getFrame = function getFrame() {
/**
* Repaint the component
* @return {boolean} Returns true if the component is resized
*/
Component.prototype.repaint = function repaint() {
// should be implemented by the component
return false;
};
/**
@ -104,3 +109,18 @@ Component.prototype.show = function show() {
return false;
}
};
/**
* Test whether the component is resized since the last time _isResized() was
* called.
* @return {Boolean} Returns true if the component is resized
* @private
*/
Component.prototype._isResized = function _isResized() {
var resized = (this._previousWidth !== this.width || this._previousHeight !== this.height);
this._previousWidth = this.width;
this._previousHeight = this.height;
return resized;
};

+ 1
- 1
src/timeline/component/CurrentTime.js View File

@ -32,7 +32,7 @@ CurrentTime.prototype.getContainer = function () {
/**
* Repaint the component
* @return {Boolean} changed
* @return {boolean} Returns true if the component is resized
*/
CurrentTime.prototype.repaint = function () {
var bar = this.frame,

+ 1
- 3
src/timeline/component/CustomTime.js View File

@ -20,8 +20,6 @@ function CustomTime (options) {
CustomTime.prototype = new Component();
Emitter(CustomTime.prototype);
CustomTime.prototype.setOptions = Component.prototype.setOptions;
/**
@ -35,7 +33,7 @@ CustomTime.prototype.getContainer = function () {
/**
* Repaint the component
* @return {Boolean} changed
* @return {boolean} Returns true if the component is resized
*/
CustomTime.prototype.repaint = function () {
var bar = this.frame,

+ 5
- 2
src/timeline/component/Group.js View File

@ -63,6 +63,7 @@ Group.prototype.setItems = function setItems(items) {
var itemSetOptions = Object.create(this.options);
this.itemSet = new ItemSet(itemSetOptions);
this.itemSet.on('change', this.emit.bind(this, 'change')); // propagate change event
if (this.range) this.itemSet.setRange(this.range);
this.contentPanel.appendChild(this.itemSet);
@ -113,10 +114,10 @@ Group.prototype.getSelection = function getSelection() {
/**
* Repaint the group
* @return {Boolean} changed
* @return {boolean} Returns true if the component is resized
*/
Group.prototype.repaint = function repaint() {
this.itemSet.repaint();
var resized = this.itemSet.repaint();
this.top = this.itemSet ? this.itemSet.top : 0;
this.height = this.itemSet ? this.itemSet.height : 0;
@ -133,4 +134,6 @@ Group.prototype.repaint = function repaint() {
this.props.label.width = 0;
this.props.label.height = 0;
}
return resized;
};

+ 13
- 5
src/timeline/component/GroupSet.js View File

@ -79,6 +79,7 @@ GroupSet.prototype.setItems = function setItems(items) {
for (var id in this.groups) {
if (this.groups.hasOwnProperty(id)) {
var group = this.groups[id];
// TODO: every group will emit a change event, causing a lot of unnecessary repaints. improve this.
group.setItems(items);
}
}
@ -147,6 +148,8 @@ GroupSet.prototype.setGroups = function setGroups(groups) {
ids = this.groupsData.getIds();
this._onAdd(ids);
}
this.emit('change');
};
/**
@ -244,6 +247,8 @@ GroupSet.prototype.repaint = function repaint() {
groups = this.groups,
groupsData = this.groupsData;
this.queue = {}; // clear old queue, we have a copy here
// show/hide added/changed/removed groups
var ids = Object.keys(queue);
if (ids.length) {
@ -262,15 +267,18 @@ GroupSet.prototype.repaint = function repaint() {
});
group = new Group(me, me.labelPanel, id, groupOptions);
group.on('change', me.emit.bind(me, 'change')); // propagate change event
group.setRange(me.range);
group.setItems(me.itemsData); // attach items data
groups[id] = group;
// Note: it is important to add the binding after group.setItems
// is executed, because that will start an infinite loop
// as this call will already triger a
}
// TODO: update group data
group.data = groupsData.get(id);
delete queue[id];
break;
case 'remove':
@ -279,8 +287,6 @@ GroupSet.prototype.repaint = function repaint() {
delete groups[id];
}
// update lists
delete queue[id];
break;
default:
@ -306,7 +312,7 @@ GroupSet.prototype.repaint = function repaint() {
// repaint all groups in order
this.groupIds.forEach(function (id) {
group = groups[id].repaint();
groups[id].repaint();
});
// reposition the labels and calculate the maximum label width
@ -479,6 +485,8 @@ GroupSet.prototype._toQueue = function _toQueue(ids, action) {
ids.forEach(function (id) {
queue[id] = action;
});
this.emit('change');
};
/**

+ 16
- 13
src/timeline/component/ItemSet.js View File

@ -45,6 +45,7 @@ function ItemSet(options) {
this.selection = []; // list with the ids of all selected nodes
this.queue = {}; // queue with id/actions: 'add', 'update', 'delete'
this.stack = new Stack(Object.create(this.options));
this.stackDirty = true; // if true, all items will be restacked on next repaint
this.conversion = null;
this.touchParams = {}; // stores properties while dragging
@ -164,11 +165,9 @@ ItemSet.prototype._deselect = function _deselect(id) {
/**
* Repaint the component
* @param {boolean} [force=false] If true, all items will be re-stacked.
* If false (default), only items having a
* top===null will be re-stacked
* @return {boolean} Returns true if the component is resized
*/
ItemSet.prototype.repaint = function repaint(force) {
ItemSet.prototype.repaint = function repaint() {
var asSize = util.option.asSize,
asString = util.option.asString,
options = this.options,
@ -225,7 +224,6 @@ ItemSet.prototype.repaint = function repaint(force) {
var visibleInterval = this.range.end - this.range.start;
var zoomed = (this.visibleInterval != visibleInterval);
this.visibleInterval = visibleInterval;
force = force || zoomed;
/* TODO: implement+fix smarter way to update visible items
// find the first visible item
@ -293,7 +291,9 @@ ItemSet.prototype.repaint = function repaint(force) {
// reposition visible items vertically
//this.stack.order(this.visibleItems); // TODO: solve ordering issue
var force = this.stackDirty || zoomed; // force re-stacking of all items if true
this.stack.stack(this.visibleItems, force);
this.stackDirty = false;
for (var i = 0, ii = this.visibleItems.length; i < ii; i++) {
this.visibleItems[i].repositionY();
}
@ -340,7 +340,7 @@ ItemSet.prototype.repaint = function repaint(force) {
this.dom.axis.style.top = (orientation == 'top') ? '0' : '';
this.dom.axis.style.bottom = (orientation == 'top') ? '' : '0';
return false;
return this._isResized();
};
/**
@ -505,7 +505,9 @@ ItemSet.prototype._onUpdate = function _onUpdate(ids) {
});
this._order();
this.repaint();
this.stackDirty = true; // force re-stacking of all items next repaint
this.emit('change');
};
/**
@ -534,9 +536,9 @@ ItemSet.prototype._onRemove = function _onRemove(ids) {
});
if (count) {
var force = true; // force restacking of all items
this._order();
this.repaint(force);
this.stackDirty = true; // force re-stacking of all items next repaint
this.emit('change');
}
};
@ -682,8 +684,8 @@ ItemSet.prototype._onDrag = function (event) {
// TODO: implement dragging from one group to another
var force = true; // force restacking of all items
this.repaint(force); // TODO: must repaint the rootPanel instead
this.stackDirty = true; // force re-stacking of all items next repaint
this.emit('change');
event.stopPropagation();
}
@ -726,8 +728,9 @@ ItemSet.prototype._onDragEnd = function (event) {
// restore original values
if ('start' in props) props.item.data.start = props.start;
if ('end' in props) props.item.data.end = props.end;
var force = true; // force restacking of all items
me.repaint(force);
this.stackDirty = true; // force re-stacking of all items next repaint
this.emit('change');
}
});
}

+ 8
- 2
src/timeline/component/Panel.js View File

@ -75,6 +75,7 @@ Panel.prototype.removeChild = function (child) {
/**
* Repaint the component
* @return {boolean} Returns true if the component was resized since previous repaint
*/
Panel.prototype.repaint = function () {
var asString = util.option.asString,
@ -97,20 +98,25 @@ Panel.prototype.repaint = function () {
frame.className = 'vpanel' + (options.className ? (' ' + asString(options.className)) : '');
// repaint the child components
this._repaintChilds();
var childsResized = this._repaintChilds();
// update frame size
this._updateSize();
return this._isResized() || childsResized;
};
/**
* Repaint all childs of the panel
* @return {boolean} Returns true if the component is resized
* @private
*/
Panel.prototype._repaintChilds = function () {
var resized = false;
for (var i = 0, ii = this.childs.length; i < ii; i++) {
this.childs[i].repaint();
resized = this.childs[i].repaint() || resized;
}
return resized;
};
/**

+ 9
- 5
src/timeline/component/RootPanel.js View File

@ -18,9 +18,6 @@ function RootPanel(container, options) {
RootPanel.prototype = new Panel();
// turn RootPanel into an event emitter
Emitter(RootPanel.prototype);
/**
* Set options. Will extend the current options.
* @param {Object} [options] Available parameters:
@ -48,7 +45,7 @@ RootPanel.prototype.setOptions = function (options) {
};
/**
* Repaint the component
* Repaint the root panel
*/
RootPanel.prototype.repaint = function () {
// create frame
@ -87,11 +84,18 @@ RootPanel.prototype.repaint = function () {
this.frame.className = className;
// repaint the child components
this._repaintChilds();
var childsResized = this._repaintChilds();
// update frame size
this.frame.style.maxHeight = util.option.asSize(this.options.maxHeight, '');
this._updateSize();
// if the root panel or any of its childs is resized, repaint again,
// as other components may need to be resized accordingly
var resized = this._isResized() || childsResized;
if (resized) {
setTimeout(this.repaint.bind(this), 0);
}
};
/**

+ 3
- 0
src/timeline/component/TimeAxis.js View File

@ -59,6 +59,7 @@ TimeAxis.prototype.setRange = function (range) {
/**
* Repaint the component
* @return {boolean} Returns true if the component is resized
*/
TimeAxis.prototype.repaint = function () {
var asSize = util.option.asSize,
@ -137,6 +138,8 @@ TimeAxis.prototype.repaint = function () {
parent.appendChild(frame)
}
}
return this._isResized();
};
/**

Loading…
Cancel
Save