|
|
- // TODO: remove groupset
-
- /**
- * An GroupSet holds a set of groups
- * @param {Panel} contentPanel Panel where the ItemSets will be created
- * @param {Panel} labelPanel Panel where the labels will be created
- * @param {Panel} backgroundPanel Panel where the vertical lines of box
- * items are created
- * @param {Panel} axisPanel Panel on the axis where the dots of box
- * items will be created
- * @param {Object} [options] See GroupSet.setOptions for the available
- * options.
- * @constructor GroupSet
- * @extends Panel
- */
- function GroupSet(contentPanel, labelPanel, backgroundPanel, axisPanel, options) {
- this.id = util.randomUUID();
-
- this.contentPanel = contentPanel;
- this.labelPanel = labelPanel;
- this.backgroundPanel = backgroundPanel;
- this.axisPanel = axisPanel;
- this.options = options || {};
-
- this.range = null; // Range or Object {start: number, end: number}
- this.itemsData = null; // DataSet with items
- this.groupsData = null; // DataSet with groups
-
- this.groups = {}; // map with groups
- this.groupIds = []; // list with ordered group ids
-
- this.dom = {};
- this.props = {
- labels: {
- width: 0
- }
- };
-
- // TODO: implement right orientation of the labels (left/right)
-
- var me = this;
- this.listeners = {
- 'add': function (event, params) {
- me._onAdd(params.items);
- },
- 'update': function (event, params) {
- me._onUpdate(params.items);
- },
- 'remove': function (event, params) {
- me._onRemove(params.items);
- }
- };
-
- // create HTML DOM
- this._create();
- }
-
- GroupSet.prototype = new Panel();
-
- /**
- * Create the HTML DOM elements for the GroupSet
- * @private
- */
- GroupSet.prototype._create = function _create () {
- // TODO: reimplement groupSet DOM elements
- var frame = document.createElement('div');
- frame.className = 'groupset';
- frame['timeline-groupset'] = this;
- this.frame = frame;
-
- this.labelSet = new Panel({
- className: 'labelset',
- width: '100%',
- height: '100%'
- });
- this.labelPanel.appendChild(this.labelSet);
- };
-
- /**
- * Get the frame element of component
- * @returns {null} Get frame is not supported by GroupSet
- */
- GroupSet.prototype.getFrame = function getFrame() {
- return this.frame;
- };
-
- /**
- * Set options for the GroupSet. Existing options will be extended/overwritten.
- * @param {Object} [options] The following options are available:
- * {String | function} groupsOrder
- * TODO: describe options
- */
- GroupSet.prototype.setOptions = Component.prototype.setOptions;
-
- /**
- * Set range (start and end).
- * @param {Range | Object} range A Range or an object containing start and end.
- */
- GroupSet.prototype.setRange = function (range) {
- this.range = range;
-
- for (var id in this.groups) {
- if (this.groups.hasOwnProperty(id)) {
- this.groups[id].setRange(range);
- }
- }
- };
-
- /**
- * Set items
- * @param {vis.DataSet | null} items
- */
- GroupSet.prototype.setItems = function setItems(items) {
- this.itemsData = 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);
- }
- }
- };
-
- /**
- * Get items
- * @return {vis.DataSet | null} items
- */
- GroupSet.prototype.getItems = function getItems() {
- return this.itemsData;
- };
-
- /**
- * Set range (start and end).
- * @param {Range | Object} range A Range or an object containing start and end.
- */
- GroupSet.prototype.setRange = function setRange(range) {
- this.range = range;
- };
-
- /**
- * Set groups
- * @param {vis.DataSet} groups
- */
- GroupSet.prototype.setGroups = function setGroups(groups) {
- var me = this,
- ids;
-
- // unsubscribe from current dataset
- if (this.groupsData) {
- util.forEach(this.listeners, function (callback, event) {
- me.groupsData.unsubscribe(event, callback);
- });
-
- // remove all drawn groups
- ids = this.groupsData.getIds();
- this._onRemove(ids);
- }
-
- // replace the dataset
- if (!groups) {
- this.groupsData = null;
- }
- else if (groups instanceof DataSet) {
- this.groupsData = groups;
- }
- else {
- this.groupsData = new DataSet({
- convert: {
- start: 'Date',
- end: 'Date'
- }
- });
- this.groupsData.add(groups);
- }
-
- if (this.groupsData) {
- // subscribe to new dataset
- var id = this.id;
- util.forEach(this.listeners, function (callback, event) {
- me.groupsData.on(event, callback, id);
- });
-
- // draw all new groups
- ids = this.groupsData.getIds();
- this._onAdd(ids);
- }
-
- this.emit('change');
- };
-
- /**
- * Get groups
- * @return {vis.DataSet | null} groups
- */
- GroupSet.prototype.getGroups = function getGroups() {
- return this.groupsData;
- };
-
- /**
- * Set selected items by their id. Replaces the current selection.
- * Unknown id's are silently ignored.
- * @param {Array} [ids] An array with zero or more id's of the items to be
- * selected. If ids is an empty array, all items will be
- * unselected.
- */
- GroupSet.prototype.setSelection = function setSelection(ids) {
- var selection = [],
- groups = this.groups;
-
- // iterate over each of the groups
- for (var id in groups) {
- if (groups.hasOwnProperty(id)) {
- var group = groups[id];
- group.setSelection(ids);
- }
- }
-
- return selection;
- };
-
- /**
- * Get the selected items by their id
- * @return {Array} ids The ids of the selected items
- */
- GroupSet.prototype.getSelection = function getSelection() {
- var selection = [],
- groups = this.groups;
-
- // iterate over each of the groups
- for (var id in groups) {
- if (groups.hasOwnProperty(id)) {
- var group = groups[id];
- selection = selection.concat(group.getSelection());
- }
- }
-
- return selection;
- };
-
- /**
- * Repaint the component
- * @return {boolean} Returns true if the component was resized since previous repaint
- */
- GroupSet.prototype.repaint = function repaint() {
- var i, id, group,
- asSize = util.option.asSize,
- asString = util.option.asString,
- options = this.options,
- orientation = this.getOption('orientation'),
- frame = this.frame,
- resized = false,
- groups = this.groups;
-
- // repaint all groups in order
- this.groupIds.forEach(function (id) {
- var groupResized = groups[id].repaint();
- resized = resized || groupResized;
- });
-
- // reposition the labels and calculate the maximum label width
- var maxWidth = 0;
- for (id in groups) {
- if (groups.hasOwnProperty(id)) {
- group = groups[id];
- maxWidth = Math.max(maxWidth, group.props.label.width);
- }
- }
- resized = util.updateProperty(this.props.labels, 'width', maxWidth) || resized;
-
- // recalculate the height of the groupset, and recalculate top positions of the groups
- 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;
-
- this.groupIds.forEach(function (id) {
- var group = groups[id];
- group.top = height;
- if (group.itemSet) group.itemSet.top = group.top; // TODO: this is an ugly hack
- height += group.height;
- });
- }
-
- // update classname
- frame.className = 'groupset' + (options.className ? (' ' + asString(options.className)) : '');
-
- // calculate actual size and position
- this.top = frame.offsetTop;
- this.left = frame.offsetLeft;
- this.width = frame.offsetWidth;
- this.height = height;
-
- return resized;
- };
-
- /**
- * Update the groupIds. Requires a repaint afterwards
- * @private
- */
- GroupSet.prototype._updateGroupIds = function () {
- // reorder the groups
- this.groupIds = this.groupsData.getIds({
- order: this.options.groupOrder
- });
-
- // hide the groups now, they will be shown again in the next repaint
- // in correct order
- var groups = this.groups;
- this.groupIds.forEach(function (id) {
- groups[id].hide();
- });
- };
-
- /**
- * Get the width of the group labels
- * @return {Number} width
- */
- GroupSet.prototype.getLabelsWidth = function getLabelsWidth() {
- return this.props.labels.width;
- };
-
- /**
- * Hide the component from the DOM
- */
- GroupSet.prototype.hide = function hide() {
- // hide labelset
- this.labelPanel.removeChild(this.labelSet);
-
- // hide each of the groups
- for (var groupId in this.groups) {
- if (this.groups.hasOwnProperty(groupId)) {
- this.groups[groupId].hide();
- }
- }
- };
-
- /**
- * Show the component in the DOM (when not already visible).
- * @return {Boolean} changed
- */
- GroupSet.prototype.show = function show() {
- // show label set
- if (!this.labelPanel.hasChild(this.labelSet)) {
- this.labelPanel.removeChild(this.labelSet);
- }
-
- // show each of the groups
- for (var groupId in this.groups) {
- if (this.groups.hasOwnProperty(groupId)) {
- this.groups[groupId].show();
- }
- }
- };
-
- /**
- * Handle updated groups
- * @param {Number[]} ids
- * @private
- */
- GroupSet.prototype._onUpdate = function _onUpdate(ids) {
- this._onAdd(ids);
- };
-
- /**
- * Handle changed groups
- * @param {Number[]} ids
- * @private
- */
- GroupSet.prototype._onAdd = function _onAdd(ids) {
- var me = this;
-
- ids.forEach(function (id) {
- var group = me.groups[id];
- if (!group) {
- var groupOptions = Object.create(me.options);
- util.extend(groupOptions, {
- height: null
- });
-
- group = new Group(me, me.labelSet, me.backgroundPanel, me.axisPanel, id, groupOptions);
- group.on('change', me.emit.bind(me, 'change')); // propagate change event
- group.setRange(me.range);
- group.setItems(me.itemsData); // attach items data
- me.groups[id] = group;
- group.parent = me;
- }
-
- // update group data
- group.setData(me.groupsData.get(id));
- });
-
- this._updateGroupIds();
-
- this.emit('change');
- };
-
- /**
- * Handle removed groups
- * @param {Number[]} ids
- * @private
- */
- GroupSet.prototype._onRemove = function _onRemove(ids) {
- var groups = this.groups;
- ids.forEach(function (id) {
- var group = groups[id];
-
- if (group) {
- group.setItems(); // detach items data
- group.hide(); // FIXME: for some reason when doing setItems after hide, setItems again makes the label visible
- delete groups[id];
- }
- });
-
- this._updateGroupIds();
-
- this.emit('change');
- };
-
- /**
- * Find the GroupSet from an event target:
- * searches for the attribute 'timeline-groupset' in the event target's element
- * tree, then finds the right group in this groupset
- * @param {Event} event
- * @return {Group | null} group
- */
- GroupSet.groupSetFromTarget = function groupSetFromTarget (event) {
- var target = event.target;
- while (target) {
- if (target.hasOwnProperty('timeline-groupset')) {
- return target['timeline-groupset'];
- }
- target = target.parentNode;
- }
-
- return null;
- };
-
- /**
- * Find the Group from an event target:
- * searches for the two elements having attributes 'timeline-groupset' and
- * 'timeline-itemset' in the event target's element, then finds the right group.
- * @param {Event} event
- * @return {Group | null} group
- */
- GroupSet.groupFromTarget = function groupFromTarget (event) {
- // find the groupSet
- var groupSet = GroupSet.groupSetFromTarget(event);
-
- // find the ItemSet
- var itemSet = ItemSet.itemSetFromTarget(event);
-
- // find the right group
- if (groupSet && itemSet) {
- for (var groupId in groupSet.groups) {
- if (groupSet.groups.hasOwnProperty(groupId)) {
- var group = groupSet.groups[groupId];
- if (group.itemSet == itemSet) {
- return group;
- }
- }
- }
- }
-
- return null;
- };
|