Browse Source

Halfway reworking the GroupSet

css_transitions
josdejong 10 years ago
parent
commit
2746149849
7 changed files with 85 additions and 130 deletions
  1. +4
    -6
      src/timeline/Timeline.js
  2. +3
    -4
      src/timeline/component/Group.js
  3. +51
    -90
      src/timeline/component/GroupSet.js
  4. +17
    -22
      src/timeline/component/ItemSet.js
  5. +1
    -8
      src/timeline/component/Panel.js
  6. +6
    -0
      src/timeline/component/css/groupset.css
  7. +3
    -0
      src/timeline/component/css/panel.css

+ 4
- 6
src/timeline/Timeline.js View File

@ -333,12 +333,10 @@ Timeline.prototype.setGroups = function(groups) {
var options = Object.create(this.options); var options = Object.create(this.options);
util.extend(options, { util.extend(options, {
top: function () { top: function () {
if (me.options.orientation == 'top') {
return me.timeaxis.height;
}
else {
return me.itemPanel.height - me.timeaxis.height - me.content.height;
}
return (me.options.orientation == 'top') ? (me.timeaxis.height + 'px') : '';
},
bottom: function () {
return (me.options.orientation == 'top') ? '' : (me.timeaxis.height + 'px');
}, },
left: null, left: null,
width: '100%', width: '100%',

+ 3
- 4
src/timeline/component/Group.js View File

@ -95,18 +95,17 @@ Group.prototype.getSelection = function getSelection() {
}; };
/** /**
* Repaint the item
* Repaint the group
* @return {Boolean} changed * @return {Boolean} changed
*/ */
Group.prototype.repaint = function repaint() { Group.prototype.repaint = function repaint() {
var update = util.updateProperty;
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;
// TODO: reckon with the height of the group label // TODO: reckon with the height of the group label
if (this.label) { if (this.label) {
// TODO: only update the labels width/height when the label is changed
var inner = this.label.firstChild; var inner = this.label.firstChild;
this.props.label.width = inner.clientWidth; this.props.label.width = inner.clientWidth;
this.props.label.height = inner.clientHeight; this.props.label.height = inner.clientHeight;

+ 51
- 90
src/timeline/component/GroupSet.js View File

@ -192,45 +192,35 @@ GroupSet.prototype.getSelection = function getSelection() {
/** /**
* Repaint the component * Repaint the component
* @return {Boolean} changed
*/ */
GroupSet.prototype.repaint = function repaint() { GroupSet.prototype.repaint = function repaint() {
var changed = 0,
i, id, group, label,
var i, id, group, label,
update = util.updateProperty, update = util.updateProperty,
asSize = util.option.asSize, asSize = util.option.asSize,
asString = util.option.asString,
asElement = util.option.asElement, asElement = util.option.asElement,
options = this.options, options = this.options,
orientation = this.getOption('orientation'),
frame = this.dom.frame, frame = this.dom.frame,
labels = this.dom.labels, labels = this.dom.labels,
labelSet = this.dom.labelSet; labelSet = this.dom.labelSet;
// create frame // create frame
if (!this.parent) {
throw new Error('Cannot repaint groupset: no parent attached');
}
var parentContainer = this.parent.getContainer();
if (!parentContainer) {
throw new Error('Cannot repaint groupset: parent has no container element');
}
if (!frame) { if (!frame) {
frame = document.createElement('div'); frame = document.createElement('div');
frame.className = 'groupset'; frame.className = 'groupset';
frame['timeline-groupset'] = this; frame['timeline-groupset'] = this;
this.dom.frame = frame; this.dom.frame = frame;
var className = options.className;
if (className) {
util.addClassName(frame, util.option.asString(className));
}
changed += 1;
}
if (!frame.parentNode) {
if (!this.parent) throw new Error('Cannot repaint groupset: no parent attached');
var parentContainer = this.parent.getContainer();
if (!parentContainer) throw new Error('Cannot repaint groupset: parent has no container element');
parentContainer.appendChild(frame); parentContainer.appendChild(frame);
changed += 1;
} }
// update classname
frame.className = 'groupset' + (options.className ? (' ' + asString(options.className)) : '');
// create labels // create labels
var labelContainer = asElement(options.labelContainer); var labelContainer = asElement(options.labelContainer);
if (!labelContainer) { if (!labelContainer) {
@ -254,16 +244,6 @@ GroupSet.prototype.repaint = function repaint() {
labelContainer.appendChild(labels); labelContainer.appendChild(labels);
} }
// reposition frame
changed += update(frame.style, 'height', asSize(options.height, this.height + 'px'));
changed += update(frame.style, 'top', asSize(options.top, '0px'));
changed += update(frame.style, 'left', asSize(options.left, '0px'));
changed += update(frame.style, 'width', asSize(options.width, '100%'));
// reposition labels
changed += update(labelSet.style, 'top', asSize(options.top, '0px'));
changed += update(labelSet.style, 'height', asSize(options.height, this.height + 'px'));
var me = this, var me = this,
queue = this.queue, queue = this.queue,
groups = this.groups, groups = this.groups,
@ -320,8 +300,6 @@ GroupSet.prototype.repaint = function repaint() {
// the groupset depends on each of the groups // the groupset depends on each of the groups
//this.depends = this.groups; // TODO: gives a circular reference through the parent //this.depends = this.groups; // TODO: gives a circular reference through the parent
// TODO: apply dependencies of the groupset
// update the top positions of the groups in the correct order // update the top positions of the groups in the correct order
var orderedGroups = this.groupsData.getIds({ var orderedGroups = this.groupsData.getIds({
order: this.options.groupOrder order: this.options.groupOrder
@ -350,13 +328,12 @@ GroupSet.prototype.repaint = function repaint() {
label = this._createLabel(id); label = this._createLabel(id);
labelSet.appendChild(label); labelSet.appendChild(label);
} }
changed++;
} }
// reposition the labels
// reposition the labels and calculate the maximum label width
// TODO: labels are not displayed correctly when orientation=='top' // TODO: labels are not displayed correctly when orientation=='top'
// TODO: width of labelPanel is not immediately updated on a change in groups // TODO: width of labelPanel is not immediately updated on a change in groups
var maxWidth = 0;
for (id in groups) { for (id in groups) {
if (groups.hasOwnProperty(id)) { if (groups.hasOwnProperty(id)) {
group = groups[id]; group = groups[id];
@ -364,11 +341,50 @@ GroupSet.prototype.repaint = function repaint() {
if (label) { if (label) {
label.style.top = group.top + 'px'; label.style.top = group.top + 'px';
label.style.height = group.height + 'px'; label.style.height = group.height + 'px';
var width = label.firstChild && label.firstChild.clientWidth || 0;
maxWidth = Math.max(maxWidth, width);
}
}
}
this.props.labels.width = maxWidth; // TODO: force redraw when width is changed?
// recalculate the height of the groupset
var fixedHeight = (asSize(options.height) != null);
var height;
if (!fixedHeight) {
// height is not specified, calculate the sum of the height of all groups
height = 0;
for (id in this.groups) {
if (this.groups.hasOwnProperty(id)) {
group = this.groups[id];
height += group.height;
} }
} }
} }
return (changed > 0);
// FIXME: right now maxHeight is only usable when fixedHeight == false
var maxHeight = util.option.asNumber(options.maxHeight);
if (maxHeight != null) {
height = Math.min(height, maxHeight);
}
// reposition frame
frame.style.height = fixedHeight ? asSize(options.height) : this.height + 'px';
frame.style.top = asSize(options.top, '0');
frame.style.left = asSize(options.left, '0');
frame.style.width = asSize(options.width, '100%');
// calculate actual size and position
this.top = frame.offsetTop;
this.left = frame.offsetLeft;
this.width = frame.offsetWidth;
this.height = fixedHeight ? frame.offsetHeight : height;
// reposition labels
labelSet.style.top = asSize(options.top, '0');
labelSet.style.height = fixedHeight ? asSize(options.height) : this.height + 'px';
}; };
/** /**
@ -419,61 +435,6 @@ GroupSet.prototype.getLabelsWidth = function getContainer() {
return this.props.labels.width; return this.props.labels.width;
}; };
/**
* Reflow the component
* @return {Boolean} resized
*/
GroupSet.prototype.reflow = function reflow() {
var changed = 0,
id, group,
options = this.options,
update = util.updateProperty,
asNumber = util.option.asNumber,
asSize = util.option.asSize,
frame = this.dom.frame;
if (frame) {
var maxHeight = asNumber(options.maxHeight);
var fixedHeight = (asSize(options.height) != null);
var height;
if (fixedHeight) {
height = frame.offsetHeight;
}
else {
// height is not specified, calculate the sum of the height of all groups
height = 0;
for (id in this.groups) {
if (this.groups.hasOwnProperty(id)) {
group = this.groups[id];
height += group.height;
}
}
}
if (maxHeight != null) {
height = Math.min(height, maxHeight);
}
changed += update(this, 'height', height);
changed += update(this, 'top', frame.offsetTop);
changed += update(this, 'left', frame.offsetLeft);
changed += update(this, 'width', frame.offsetWidth);
}
// calculate the maximum width of the labels
var width = 0;
for (id in this.groups) {
if (this.groups.hasOwnProperty(id)) {
group = this.groups[id];
var labelWidth = group.props && group.props.label && group.props.label.width || 0;
width = Math.max(width, labelWidth);
}
}
changed += update(this.props.labels, 'width', width);
return (changed > 0);
};
/** /**
* Hide the component from the DOM * Hide the component from the DOM
* @return {Boolean} changed * @return {Boolean} changed

+ 17
- 22
src/timeline/component/ItemSet.js View File

@ -346,17 +346,11 @@ ItemSet.prototype.repaint = function repaint() {
// recalculate the height of the itemset // recalculate the height of the itemset
var marginAxis = (options.margin && 'axis' in options.margin) ? options.margin.axis : this.itemOptions.margin.axis, var marginAxis = (options.margin && 'axis' in options.margin) ? options.margin.axis : this.itemOptions.margin.axis,
marginItem = (options.margin && 'item' in options.margin) ? options.margin.item : this.itemOptions.margin.item, marginItem = (options.margin && 'item' in options.margin) ? options.margin.item : this.itemOptions.margin.item,
maxHeight = asNumber(options.maxHeight),
fixedHeight = (asSize(options.height) != null), fixedHeight = (asSize(options.height) != null),
height; height;
// recalculate the frames size and position
// TODO: request frame's actual top, left, width only when size is changed (mark as dirty)
if (fixedHeight) {
height = frame.offsetHeight;
}
else {
// height is not specified, determine the height from the height and positioned items
// height is not specified, determine the height from the height and positioned items
if (!fixedHeight) {
var visibleItems = this.visibleItems; var visibleItems = this.visibleItems;
if (visibleItems.length) { if (visibleItems.length) {
var min = visibleItems[0].top; var min = visibleItems[0].top;
@ -371,30 +365,31 @@ ItemSet.prototype.repaint = function repaint() {
height = marginAxis + marginItem; height = marginAxis + marginItem;
} }
} }
// FIXME: right now maxHeight is only usable when fixedHeight == false
var maxHeight = asNumber(options.maxHeight);
if (maxHeight != null) { if (maxHeight != null) {
height = Math.min(height, maxHeight); height = Math.min(height, maxHeight);
} }
this.top = frame.offsetTop;
this.left = frame.offsetLeft;
this.width = frame.offsetWidth;
this.height = height;
// reposition frame // reposition frame
frame.style.left = asSize(options.left, '0px');
frame.style.left = asSize(options.left, '0');
frame.style.top = asSize(options.top, ''); frame.style.top = asSize(options.top, '');
frame.style.bottom = asSize(options.bottom, ''); frame.style.bottom = asSize(options.bottom, '');
frame.style.width = asSize(options.width, '100%'); frame.style.width = asSize(options.width, '100%');
frame.style.height = asSize(options.height, this.height + 'px');
frame.style.height = fixedHeight ? asSize(options.height) : height + 'px';
// calculate actual size and position
this.top = frame.offsetTop;
this.left = frame.offsetLeft;
this.width = frame.offsetWidth;
this.height = fixedHeight ? frame.offsetHeight : height;
// reposition axis // reposition axis
this.dom.axis.style.left = asSize(options.left, '0px');
this.dom.axis.style.width = asSize(options.width, '100%');
if (orientation == 'bottom') {
this.dom.axis.style.top = (this.top + this.height) + 'px';
}
else { // orientation == 'top'
this.dom.axis.style.top = this.top + 'px';
}
this.dom.axis.style.left = asSize(options.left, '0');
this.dom.axis.style.width = asSize(options.width, '100%');
this.dom.axis.style.top = (orientation == 'top' ? this.top : this.top + this.height) + 'px';
this.dom.axis.style.bottom = asSize(options.bottom, '');
return false; return false;
}; };

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

@ -53,25 +53,18 @@ Panel.prototype.repaint = function () {
// create frame // create frame
if (!frame) { if (!frame) {
frame = document.createElement('div'); frame = document.createElement('div');
this.frame = frame;
if (!this.parent) throw new Error('Cannot repaint panel: no parent attached'); if (!this.parent) throw new Error('Cannot repaint panel: no parent attached');
var parentContainer = this.parent.getContainer(); var parentContainer = this.parent.getContainer();
if (!parentContainer) throw new Error('Cannot repaint panel: parent has no container element'); if (!parentContainer) throw new Error('Cannot repaint panel: parent has no container element');
parentContainer.appendChild(frame); parentContainer.appendChild(frame);
this.frame = frame;
} }
// update className // update className
frame.className = 'vpanel' + (options.className ? (' ' + asSize(options.className)) : ''); frame.className = 'vpanel' + (options.className ? (' ' + asSize(options.className)) : '');
// update class name
var className = 'vis timeline rootpanel ' + options.orientation + (options.editable ? ' editable' : '');
if (options.className) className += ' ' + util.option.asString(className);
frame.className = className;
// update frame size // update frame size
this._updateSize(); this._updateSize();
}; };

+ 6
- 0
src/timeline/component/css/groupset.css View File

@ -31,6 +31,9 @@
border-top: none; border-top: none;
border-bottom: 1px solid #bfbfbf; border-bottom: 1px solid #bfbfbf;
-moz-box-sizing: border-box;
box-sizing: border-box;
} }
.vis.timeline .labels .label-set .vlabel { .vis.timeline .labels .label-set .vlabel {
@ -39,6 +42,9 @@
top: 0; top: 0;
width: 100%; width: 100%;
color: #4d4d4d; color: #4d4d4d;
-moz-box-sizing: border-box;
box-sizing: border-box;
} }
.vis.timeline.top .labels .label-set .vlabel, .vis.timeline.top .labels .label-set .vlabel,

+ 3
- 0
src/timeline/component/css/panel.css View File

@ -11,4 +11,7 @@
.vis.timeline .vpanel { .vis.timeline .vpanel {
position: absolute; position: absolute;
overflow: hidden; overflow: hidden;
-moz-box-sizing: border-box;
box-sizing: border-box;
} }

Loading…
Cancel
Save