diff --git a/Jakefile.js b/Jakefile.js index 4340aa5e..e4546709 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -38,7 +38,7 @@ task('build', {async: true}, function () { src: [ './src/timeline/component/css/timeline.css', './src/timeline/component/css/panel.css', - './src/timeline/component/css/groupset.css', + './src/timeline/component/css/labelset.css', './src/timeline/component/css/itemset.css', './src/timeline/component/css/item.css', './src/timeline/component/css/timeaxis.css', diff --git a/src/timeline/component/Group.js b/src/timeline/component/Group.js index 408cad52..c22ce385 100644 --- a/src/timeline/component/Group.js +++ b/src/timeline/component/Group.js @@ -1,14 +1,22 @@ /** * @constructor Group * @param {Number | String} groupId + * @param {Object} data * @param {ItemSet} itemSet */ -function Group (groupId, itemSet) { +function Group (groupId, data, itemSet) { this.groupId = groupId; this.itemSet = itemSet; this.dom = {}; + this.props = { + label: { + width: 0, + height: 0 + } + }; + this.items = {}; // items filtered by groupId of this group this.visibleItems = []; // items currently visible in window this.orderedItems = { // items sorted by start and by end @@ -17,6 +25,8 @@ function Group (groupId, itemSet) { }; this._create(); + + this.setData(data); } /** @@ -43,6 +53,30 @@ Group.prototype._create = function() { this.dom.axis = document.createElement('div'); }; +/** + * Set the group data for this group + * @param {Object} data Group data, can contain properties content and className + */ +Group.prototype.setData = function setData(data) { + // update contents + var content = data && data.content; + if (content instanceof Element) { + this.dom.inner.appendChild(content); + } + else if (content != undefined) { + this.dom.inner.innerHTML = content; + } + else { + this.dom.inner.innerHTML = this.groupId; + } + + // update className + var className = data && data.className; + if (className) { + util.addClassName(this.dom.label, className); + } +}; + /** * Get the foreground container element * @return {HTMLElement} foreground @@ -67,6 +101,15 @@ Group.prototype.getAxis = function getAxis() { return this.dom.axis; }; +/** + * Get the width of the group label + * @return {number} width + */ +Group.prototype.getLabelWidth = function getLabelWidth() { + return this.props.label.width; +}; + + /** * Repaint this group * @param {{start: number, end: number}} range @@ -75,6 +118,8 @@ Group.prototype.getAxis = function getAxis() { * @return {boolean} Returns true if the group is resized */ Group.prototype.repaint = function repaint(range, margin, restack) { + var resized; + if (typeof margin === 'number') { margin = { item: margin, @@ -94,8 +139,6 @@ Group.prototype.repaint = function repaint(range, margin, restack) { // recalculate the height of the group var height; - - // determine the height from the stacked items var visibleItems = this.visibleItems; if (visibleItems.length) { var min = visibleItems[0].top; @@ -109,8 +152,7 @@ Group.prototype.repaint = function repaint(range, margin, restack) { else { height = margin.axis + margin.item; } - - var resized = (this.height != height); + resized = (this.height != height); // calculate actual size and position var foreground = this.dom.foreground; @@ -119,8 +161,14 @@ Group.prototype.repaint = function repaint(range, margin, restack) { this.width = foreground.offsetWidth; this.height = height; + // recalculate size of label + // TODO: if changed, return resized=true + this.props.label.width = this.dom.inner.clientWidth; + this.props.label.height = this.dom.inner.clientHeight; + // apply new height foreground.style.height = height + 'px'; + this.dom.label.style.height = height + 'px'; return resized; }; diff --git a/src/timeline/component/ItemSet.js b/src/timeline/component/ItemSet.js index a9f2445a..a92fff7d 100644 --- a/src/timeline/component/ItemSet.js +++ b/src/timeline/component/ItemSet.js @@ -8,26 +8,21 @@ var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items * vertical lines of box items. * @param {Panel} axisPanel Panel on the axis where the dots of box-items * can be displayed. - * @param {Panel} labelPanel Left side panel holding labels + * @param {Panel} sidePanel Left side panel holding labels * @param {Object} [options] See ItemSet.setOptions for the available options. * @constructor ItemSet * @extends Panel */ -function ItemSet(backgroundPanel, axisPanel, labelPanel, options) { +function ItemSet(backgroundPanel, axisPanel, sidePanel, options) { this.id = util.randomUUID(); // one options object is shared by this itemset and all its items this.options = options || {}; this.backgroundPanel = backgroundPanel; this.axisPanel = axisPanel; - this.labelPanel = labelPanel; + this.sidePanel = sidePanel; this.itemOptions = Object.create(this.options); this.dom = {}; - this.props = { - labels: { - width: 0 - } - }; this.hammer = null; var me = this; @@ -110,6 +105,12 @@ ItemSet.prototype._create = function _create(){ this.dom.axis = axis; this.axisPanel.frame.appendChild(axis); + // create labelset + var labelSet = document.createElement('div'); + labelSet.className = 'labelset'; + this.dom.labelSet = labelSet; + this.sidePanel.frame.appendChild(labelSet); + // create ungrouped Group this._updateUngrouped(); @@ -166,6 +167,11 @@ ItemSet.prototype.hide = function hide() { if (this.dom.background.parentNode) { this.dom.background.parentNode.removeChild(this.dom.background); } + + // remove the labelset containing all group labels + if (this.dom.labelSet.parentNode) { + this.dom.labelSet.parentNode.removeChild(this.dom.labelSet); + } }; /** @@ -182,6 +188,11 @@ ItemSet.prototype.show = function show() { if (!this.dom.background.parentNode) { this.backgroundPanel.frame.appendChild(this.dom.background); } + + // show labelset containing labels + if (!this.dom.labelSet.parentNode) { + this.sidePanel.frame.appendChild(this.dom.labelSet); + } }; /** @@ -338,7 +349,8 @@ ItemSet.prototype._updateUngrouped = function _updateUngrouped() { // create a group holding all (unfiltered) items if (!ungrouped) { var id = null; - ungrouped = new Group(id, this, this.dom.background, this.dom.axis, this.labelPanel.frame); + var data = null; + ungrouped = new Group(id, data, this); this.groups[UNGROUPED] = ungrouped; for (var itemId in this.items) { @@ -381,7 +393,7 @@ ItemSet.prototype.getAxis = function getAxis() { * @return {HTMLElement} labelSet */ ItemSet.prototype.getLabelSet = function getLabelSet() { - return this.labelPanel.frame; + return this.dom.labelSet; }; /** @@ -631,7 +643,8 @@ ItemSet.prototype._onAddGroups = function _onAddGroups(ids) { height: null }); - group = new Group(id, me, me.dom.background, me.dom.axis, me.labelPanel.frame); + var data = me.groupsData.get(id); + group = new Group(id, data, me); me.groups[id] = group; // add items with this groupId to the new group @@ -763,7 +776,13 @@ ItemSet.prototype._constructByEndArray = function _constructByEndArray(array) { * @return {Number} width */ ItemSet.prototype.getLabelsWidth = function getLabelsWidth() { - return this.props.labels.width; + var width = 0; + + util.forEach(this.groups, function (group) { + width = Math.max(width, group.getLabelWidth()); + }); + + return width; }; /** diff --git a/src/timeline/component/css/itemset.css b/src/timeline/component/css/itemset.css index 7b75428d..0864aedf 100644 --- a/src/timeline/component/css/itemset.css +++ b/src/timeline/component/css/itemset.css @@ -25,6 +25,7 @@ .vis.timeline .group { position: relative; + box-sizing: border-box; } .vis.timeline.top .group { diff --git a/src/timeline/component/css/groupset.css b/src/timeline/component/css/labelset.css similarity index 76% rename from src/timeline/component/css/groupset.css rename to src/timeline/component/css/labelset.css index cbc501b9..0daa809f 100644 --- a/src/timeline/component/css/groupset.css +++ b/src/timeline/component/css/labelset.css @@ -20,14 +20,12 @@ box-sizing: border-box; } -.vis.timeline.bottom .labelset .vlabel, -.vis.timeline.top .vpanel.side-content { +.vis.timeline.top .labelset .vlabel { border-top: 1px solid #bfbfbf; border-bottom: none; } -.vis.timeline.top .labelset .vlabel, -.vis.timeline.bottom .vpanel.side-content { +.vis.timeline.bottom .labelset .vlabel { border-top: none; border-bottom: 1px solid #bfbfbf; }