Browse Source

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

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

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

@ -14,6 +14,9 @@ function Component () {
this.height = 0; 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 parameters for the frame. Parameters will be merged in current parameter
* set. * set.
@ -72,9 +75,11 @@ Component.prototype.getFrame = function getFrame() {
/** /**
* Repaint the component * Repaint the component
* @return {boolean} Returns true if the component is resized
*/ */
Component.prototype.repaint = function repaint() { Component.prototype.repaint = function repaint() {
// should be implemented by the component // should be implemented by the component
return false;
}; };
/** /**
@ -104,3 +109,18 @@ Component.prototype.show = function show() {
return false; 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 * Repaint the component
* @return {Boolean} changed
* @return {boolean} Returns true if the component is resized
*/ */
CurrentTime.prototype.repaint = function () { CurrentTime.prototype.repaint = function () {
var bar = this.frame, var bar = this.frame,

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

@ -20,8 +20,6 @@ function CustomTime (options) {
CustomTime.prototype = new Component(); CustomTime.prototype = new Component();
Emitter(CustomTime.prototype);
CustomTime.prototype.setOptions = Component.prototype.setOptions; CustomTime.prototype.setOptions = Component.prototype.setOptions;
/** /**
@ -35,7 +33,7 @@ CustomTime.prototype.getContainer = function () {
/** /**
* Repaint the component * Repaint the component
* @return {Boolean} changed
* @return {boolean} Returns true if the component is resized
*/ */
CustomTime.prototype.repaint = function () { CustomTime.prototype.repaint = function () {
var bar = this.frame, 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); var itemSetOptions = Object.create(this.options);
this.itemSet = new ItemSet(itemSetOptions); 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); if (this.range) this.itemSet.setRange(this.range);
this.contentPanel.appendChild(this.itemSet); this.contentPanel.appendChild(this.itemSet);
@ -113,10 +114,10 @@ Group.prototype.getSelection = function getSelection() {
/** /**
* Repaint the group * Repaint the group
* @return {Boolean} changed
* @return {boolean} Returns true if the component is resized
*/ */
Group.prototype.repaint = function repaint() { Group.prototype.repaint = function repaint() {
this.itemSet.repaint();
var resized = this.itemSet.repaint();
this.top = this.itemSet ? this.itemSet.top : 0; this.top = this.itemSet ? this.itemSet.top : 0;
this.height = this.itemSet ? this.itemSet.height : 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.width = 0;
this.props.label.height = 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) { for (var id in this.groups) {
if (this.groups.hasOwnProperty(id)) { if (this.groups.hasOwnProperty(id)) {
var group = this.groups[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); group.setItems(items);
} }
} }
@ -147,6 +148,8 @@ GroupSet.prototype.setGroups = function setGroups(groups) {
ids = this.groupsData.getIds(); ids = this.groupsData.getIds();
this._onAdd(ids); this._onAdd(ids);
} }
this.emit('change');
}; };
/** /**
@ -244,6 +247,8 @@ GroupSet.prototype.repaint = function repaint() {
groups = this.groups, groups = this.groups,
groupsData = this.groupsData; groupsData = this.groupsData;
this.queue = {}; // clear old queue, we have a copy here
// show/hide added/changed/removed groups // show/hide added/changed/removed groups
var ids = Object.keys(queue); var ids = Object.keys(queue);
if (ids.length) { if (ids.length) {
@ -262,15 +267,18 @@ GroupSet.prototype.repaint = function repaint() {
}); });
group = new Group(me, me.labelPanel, id, groupOptions); group = new Group(me, me.labelPanel, id, groupOptions);
group.on('change', me.emit.bind(me, 'change')); // propagate change event
group.setRange(me.range); group.setRange(me.range);
group.setItems(me.itemsData); // attach items data group.setItems(me.itemsData); // attach items data
groups[id] = group; 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 // TODO: update group data
group.data = groupsData.get(id); group.data = groupsData.get(id);
delete queue[id];
break; break;
case 'remove': case 'remove':
@ -279,8 +287,6 @@ GroupSet.prototype.repaint = function repaint() {
delete groups[id]; delete groups[id];
} }
// update lists
delete queue[id];
break; break;
default: default:
@ -306,7 +312,7 @@ GroupSet.prototype.repaint = function repaint() {
// repaint all groups in order // repaint all groups in order
this.groupIds.forEach(function (id) { this.groupIds.forEach(function (id) {
group = groups[id].repaint();
groups[id].repaint();
}); });
// reposition the labels and calculate the maximum label width // reposition the labels and calculate the maximum label width
@ -479,6 +485,8 @@ GroupSet.prototype._toQueue = function _toQueue(ids, action) {
ids.forEach(function (id) { ids.forEach(function (id) {
queue[id] = action; 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.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(Object.create(this.options)); 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.conversion = null;
this.touchParams = {}; // stores properties while dragging this.touchParams = {}; // stores properties while dragging
@ -164,11 +165,9 @@ ItemSet.prototype._deselect = function _deselect(id) {
/** /**
* Repaint the component * 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, var asSize = util.option.asSize,
asString = util.option.asString, asString = util.option.asString,
options = this.options, options = this.options,
@ -225,7 +224,6 @@ ItemSet.prototype.repaint = function repaint(force) {
var visibleInterval = this.range.end - this.range.start; var visibleInterval = this.range.end - this.range.start;
var zoomed = (this.visibleInterval != visibleInterval); var zoomed = (this.visibleInterval != visibleInterval);
this.visibleInterval = visibleInterval; this.visibleInterval = visibleInterval;
force = force || zoomed;
/* TODO: implement+fix smarter way to update visible items /* TODO: implement+fix smarter way to update visible items
// find the first visible item // find the first visible item
@ -293,7 +291,9 @@ ItemSet.prototype.repaint = function repaint(force) {
// reposition visible items vertically // reposition visible items vertically
//this.stack.order(this.visibleItems); // TODO: solve ordering issue //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.stack.stack(this.visibleItems, force);
this.stackDirty = false;
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();
} }
@ -340,7 +340,7 @@ ItemSet.prototype.repaint = function repaint(force) {
this.dom.axis.style.top = (orientation == 'top') ? '0' : ''; this.dom.axis.style.top = (orientation == 'top') ? '0' : '';
this.dom.axis.style.bottom = (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._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) { if (count) {
var force = true; // force restacking of all items
this._order(); 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 // 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(); event.stopPropagation();
} }
@ -726,8 +728,9 @@ ItemSet.prototype._onDragEnd = function (event) {
// restore original values // restore original values
if ('start' in props) props.item.data.start = props.start; if ('start' in props) props.item.data.start = props.start;
if ('end' in props) props.item.data.end = props.end; 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 * Repaint the component
* @return {boolean} Returns true if the component was resized since previous repaint
*/ */
Panel.prototype.repaint = function () { Panel.prototype.repaint = function () {
var asString = util.option.asString, var asString = util.option.asString,
@ -97,20 +98,25 @@ Panel.prototype.repaint = function () {
frame.className = 'vpanel' + (options.className ? (' ' + asString(options.className)) : ''); frame.className = 'vpanel' + (options.className ? (' ' + asString(options.className)) : '');
// repaint the child components // repaint the child components
this._repaintChilds();
var childsResized = this._repaintChilds();
// update frame size // update frame size
this._updateSize(); this._updateSize();
return this._isResized() || childsResized;
}; };
/** /**
* Repaint all childs of the panel * Repaint all childs of the panel
* @return {boolean} Returns true if the component is resized
* @private * @private
*/ */
Panel.prototype._repaintChilds = function () { Panel.prototype._repaintChilds = function () {
var resized = false;
for (var i = 0, ii = this.childs.length; i < ii; i++) { 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(); RootPanel.prototype = new Panel();
// turn RootPanel into an event emitter
Emitter(RootPanel.prototype);
/** /**
* Set options. Will extend the current options. * Set options. Will extend the current options.
* @param {Object} [options] Available parameters: * @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 () { RootPanel.prototype.repaint = function () {
// create frame // create frame
@ -87,11 +84,18 @@ RootPanel.prototype.repaint = function () {
this.frame.className = className; this.frame.className = className;
// repaint the child components // repaint the child components
this._repaintChilds();
var childsResized = this._repaintChilds();
// update frame size // update frame size
this.frame.style.maxHeight = util.option.asSize(this.options.maxHeight, ''); this.frame.style.maxHeight = util.option.asSize(this.options.maxHeight, '');
this._updateSize(); 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 * Repaint the component
* @return {boolean} Returns true if the component is resized
*/ */
TimeAxis.prototype.repaint = function () { TimeAxis.prototype.repaint = function () {
var asSize = util.option.asSize, var asSize = util.option.asSize,
@ -137,6 +138,8 @@ TimeAxis.prototype.repaint = function () {
parent.appendChild(frame) parent.appendChild(frame)
} }
} }
return this._isResized();
}; };
/** /**

Loading…
Cancel
Save