Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature - Ungrouped Area #1796

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions lib/timeline/Core.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,23 @@ class Core {
me.emit('release', event);
});

/**
*
* @param {HtmlElement} element
* @returns {boolean}
*/
function isInBottomPanel(element) {
if (element.parentElement === me.body.dom.root) {
return false;
}

if (element.parentElement === me.body.dom.bottom) {
return true;
}

return isInBottomPanel(element.parentElement);
}

/**
*
* @param {WheelEvent} event
Expand Down Expand Up @@ -243,7 +260,7 @@ class Core {
const current = this.props.scrollTop;
const adjusted = current + deltaY;

if (this.isActive()) {
if (this.isActive() && event.target !== this.body.dom.bottom && !isInBottomPanel(event.target)) {
const newScrollTop = this._setScrollTop(adjusted);

if (newScrollTop !== current) {
Expand Down Expand Up @@ -725,7 +742,7 @@ class Core {
* @returns {Array} The ids of the visible groups
*/
getVisibleGroups() {
return this.itemSet && this.itemSet.getVisibleGroups() || [];
return (this.itemSet && this.itemSet.getVisibleGroups()) || [];
}

/**
Expand Down Expand Up @@ -979,8 +996,8 @@ class Core {

// calculate heights of the content panels
props.root.height = dom.root.offsetHeight;
props.background.height = props.root.height;
const containerHeight = props.root.height - props.top.height - props.bottom.height;
props.background.height = containerHeight;
props.centerContainer.height = containerHeight;
props.leftContainer.height = containerHeight;
props.rightContainer.height = props.leftContainer.height;
Expand Down Expand Up @@ -1114,7 +1131,8 @@ class Core {
dom.backgroundHorizontal.style.width = `${props.background.width}px`;
dom.centerContainer.style.width = `${props.center.width}px`;
dom.top.style.width = `${props.top.width}px`;
dom.bottom.style.width = `${props.bottom.width}px`;
dom.bottom.style.width = "100%";
dom.bottom.style.overflowY = "scroll";

// reposition the panels
dom.background.style.left = '0';
Expand All @@ -1131,8 +1149,7 @@ class Core {
dom.rightContainer.style.top = `${props.top.height}px`;
dom.top.style.left = `${props.left.width}px`;
dom.top.style.top = '0';
dom.bottom.style.left = `${props.left.width}px`;
dom.bottom.style.top = `${props.top.height + props.centerContainer.height}px`;
dom.bottom.style.bottom = 0
dom.center.style.left = '0';
dom.left.style.left = '0';
dom.right.style.left = '0';
Expand Down
5 changes: 4 additions & 1 deletion lib/timeline/Timeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ export default class Timeline extends Core {
if (options.onInitialDrawComplete) { this.options.onInitialDrawComplete = options.onInitialDrawComplete; }
if (options.onTimeout) { this.options.onTimeout = options.onTimeout; }
if (options.loadingScreenTemplate) { this.options.loadingScreenTemplate = options.loadingScreenTemplate; }
if (options.showUngroupedItems) { this.options.showUngroupedItems = options.showUngroupedItems; }
if (options.ungroupedHeaderTemplate) { this.options.ungroupedHeaderTemplate = options.ungroupedHeaderTemplate; }
}

// Prepare loading screen
Expand Down Expand Up @@ -127,7 +129,8 @@ export default class Timeline extends Core {
toGlobalScreen: me._toGlobalScreen.bind(me), // this refers to the root.width
toTime: me._toTime.bind(me),
toGlobalTime : me._toGlobalTime.bind(me)
}
},
redrawTimeline: this._redraw.bind(this),
};

// range
Expand Down
25 changes: 20 additions & 5 deletions lib/timeline/component/Group.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ class Group {
foreground['vis-group'] = this;
this.dom.foreground = foreground;

const ungrouped = document.createElement('div');
ungrouped.className = 'vis-group';
ungrouped['vis-group'] = this;
this.dom.ungrouped = ungrouped;

this.dom.background = document.createElement('div');
this.dom.background.className = 'vis-group';

Expand Down Expand Up @@ -159,6 +164,10 @@ class Group {
}
}

if (this.itemSet.options && this.itemSet.options.showUngroupedItems && this.groupId === UNGROUPED) {
this.dom.label.style.display = "none";
}

if (this.itemSet.options && this.itemSet.options.groupTemplate) {
templateFunction = this.itemSet.options.groupTemplate.bind(this);
content = templateFunction(data, this.dom.inner);
Expand Down Expand Up @@ -307,7 +316,7 @@ class Group {
* @param {number} pixels
*/
_calculateGroupSizeAndPosition() {
const { offsetTop, offsetLeft, offsetWidth } = this.dom.foreground;
const { offsetTop, offsetLeft, offsetWidth } = this.groupId === UNGROUPED ? this.dom.ungrouped : this.dom.foreground;
this.top = offsetTop;
this.right = offsetLeft;
this.width = offsetWidth;
Expand Down Expand Up @@ -604,7 +613,9 @@ class Group {
* @private
*/
_isGroupVisible(range, margin) {
return (this.top <= range.body.domProps.centerContainer.height - range.body.domProps.scrollTop + margin.axis)
return (this.groupId === UNGROUPED &&
this.itemSet.dom.ungrouped.clientHeight > 0) ||
(this.top <= range.body.domProps.centerContainer.height - range.body.domProps.scrollTop + margin.axis)
&& (this.top + this.height + margin.axis >= - range.body.domProps.scrollTop);
}

Expand Down Expand Up @@ -650,7 +661,7 @@ class Group {
else {
height = 0 || this.props.label.height;
}
return height;
return this.groupId === UNGROUPED ? 0 : height;
}

/**
Expand All @@ -661,14 +672,18 @@ class Group {
this.itemSet.dom.labelSet.appendChild(this.dom.label);
}

if (!this.dom.foreground.parentNode) {
if (!this.dom.foreground.parentNode && this.groupId !== UNGROUPED) {
this.itemSet.dom.foreground.appendChild(this.dom.foreground);
}

if (!this.dom.background.parentNode) {
this.itemSet.dom.background.appendChild(this.dom.background);
}

if (!this.dom.ungrouped.parentNode && this.groupId === UNGROUPED) {
this.itemSet.dom.ungrouped.appendChild(this.dom.ungrouped);
}

if (!this.dom.axis.parentNode) {
this.itemSet.dom.axis.appendChild(this.dom.axis);
}
Expand Down Expand Up @@ -1046,7 +1061,7 @@ class Group {
* @private
*/
_checkIfVisible(item, visibleItems, range) {
if (item.isVisible(range)) {
if (item.isVisible(range) || this.groupId === UNGROUPED) {
if (!item.displayed) item.show();
// reposition item horizontally
item.repositionX();
Expand Down
84 changes: 79 additions & 5 deletions lib/timeline/component/ItemSet.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ class ItemSet extends Component {
this.options = util.extend({}, this.defaultOptions);
this.options.rtl = options.rtl;
this.options.onTimeout = options.onTimeout;
this.options.showUngroupedItems = options.showUngroupedItems;

this.conversion = {
toScreen: body.util.toScreen,
Expand Down Expand Up @@ -221,6 +222,8 @@ class ItemSet extends Component {
group: null,
isDragging: false
};

this.options.ungroupedHeaderTemplate = options.ungroupedHeaderTemplate;

// create the HTML DOM
this._create();
Expand Down Expand Up @@ -260,6 +263,15 @@ class ItemSet extends Component {
labelSet.className = 'vis-labelset';
this.dom.labelSet = labelSet;

// create foreground panel
const ungrouped = document.createElement("div");
ungrouped.className = "vis-ungrouped vis-foreground";
this.dom.ungrouped = ungrouped;

const ungroupedHeader = document.createElement("div");
ungroupedHeader.className = "vis-ungrouped-header";
this.dom.ungroupedHeader = ungroupedHeader;

// create ungrouped Group
this._updateUngrouped();

Expand Down Expand Up @@ -584,6 +596,54 @@ class ItemSet extends Component {
this.body.dom.center.appendChild(this.dom.frame);
}

if (!this.dom.ungrouped.parentNode && this.options.showUngroupedItems) {
this.dom.ungroupedHeader.style.position = "sticky";
this.dom.ungroupedHeader.style.top = "0";
this.dom.ungroupedHeader.style.left = "0";
this.dom.ungroupedHeader.style.zIndex = "99";

if (this.options.ungroupedHeaderTemplate) {
const templateFunction =
this.options.ungroupedHeaderTemplate.bind(this);
const content = templateFunction(this.dom.ungroupedHeader);

if (content instanceof Element) {
while (this.dom.ungroupedHeader.firstChild) {
this.dom.ungroupedHeader.removeChild(
this.dom.ungroupedHeader.firstChild
);
}
this.dom.ungroupedHeader.appendChild(content);
} else if (content instanceof Object && content.isReactComponent) {
// Do nothing. Component was rendered into the node be ReactDOM.render.
// That branch is necessary for evasion of a second call templateFunction.
// Supports only React < 16(due to the asynchronous nature of React 16).
} else if (content instanceof Object) {
templateFunction(this.dom.ungroupedHeader);
} else if (content !== undefined && content !== null) {
this.dom.ungroupedHeader.innerHTML = util.xss(content);
} else {
this.dom.ungroupedHeader.innerHTML = util.xss(this.groupId || ""); // groupId can be null
}
} else {
this.dom.ungroupedHeader.innerHTML = "Ungrouped Items";
this.dom.ungroupedHeader.style.padding = "8px";
this.dom.ungroupedHeader.style.backgroundColor = "white";
this.dom.ungroupedHeader.addEventListener("click", (e) => {
if (!this.dom.ungrouped.style.height) {
this.dom.ungrouped.style.height = "250px";
} else {
this.dom.ungrouped.style.height = "";
}
this.body.redrawTimeline();
});
}

this.body.dom.bottom.appendChild(this.dom.ungroupedHeader);

this.body.dom.bottom.appendChild(this.dom.ungrouped);
}

// show axis with dots
if (!this.dom.axis.parentNode) {
this.body.dom.backgroundVertical.appendChild(this.dom.axis);
Expand Down Expand Up @@ -809,14 +869,17 @@ class ItemSet extends Component {
const orientation = options.orientation.item;
let resized = false;
const frame = this.dom.frame;
const ungrouped = this.dom.ungrouped;

// recalculate absolute position (before redrawing groups)
this.props.top = this.body.domProps.top.height + this.body.domProps.border.top;

if (this.options.rtl) {
this.props.right = this.body.domProps.right.width + this.body.domProps.border.right;
ungrouped.style.paddingRight = `${this.props.right}px`
} else {
this.props.left = this.body.domProps.left.width + this.body.domProps.border.left;
ungrouped.style.paddingLeft = `${this.props.left}px`
}

// update class name
Expand Down Expand Up @@ -944,14 +1007,15 @@ class ItemSet extends Component {
if (this.groupsData) {
// remove the group holding all ungrouped items
if (ungrouped) {
ungrouped.dispose();
delete this.groups[UNGROUPED];
// I think this is not needed anymore
// ungrouped.dispose();
// delete this.groups[UNGROUPED];

for (itemId in this.items) {
if (this.items.hasOwnProperty(itemId)) {
item = this.items[itemId];
item.parent && item.parent.remove(item);
const groupId = this.getGroupId(item.data);
const groupId = this.getGroupId(item.data) || UNGROUPED;
const group = this.groups[groupId];
group && group.add(item) || item.hide();
}
Expand All @@ -961,7 +1025,7 @@ class ItemSet extends Component {
else {
// create a group holding all (unfiltered) items
if (!ungrouped) {
const id = null;
const id = UNGROUPED;
const data = null;
ungrouped = new Group(id, data, this);
this.groups[UNGROUPED] = ungrouped;
Expand Down Expand Up @@ -2609,7 +2673,17 @@ class ItemSet extends Component {
order: this.options.groupOrder
});
}


const ungrouped = this.dom.ungrouped;
const ungroupedRect = ungrouped.getBoundingClientRect();

if (
clientY >= ungroupedRect.top &&
clientY < ungroupedRect.top + ungrouped.offsetHeight
) {
return this.groups[UNGROUPED];
}

for (let i = 0; i < groupIds.length; i++) {
const groupId = groupIds[i];
const group = this.groups[groupId];
Expand Down
7 changes: 4 additions & 3 deletions lib/timeline/component/item/RangeItem.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ReservedGroupIds } from '../Group';
import Item from './Item';

/**
Expand Down Expand Up @@ -91,11 +92,11 @@ class RangeItem extends Item {
throw new Error('Cannot redraw item: no parent attached');
}
if (!this.dom.box.parentNode) {
const foreground = this.parent.dom.foreground;
if (!foreground) {
const container = this.parent.groupId === ReservedGroupIds.UNGROUPED ? this.parent.dom.ungrouped : this.parent.dom.foreground;
if (!container) {
throw new Error('Cannot redraw item: parent has no foreground container element');
}
foreground.appendChild(this.dom.box);
container.appendChild(this.dom.box);
}
this.displayed = true;
}
Expand Down
2 changes: 2 additions & 0 deletions lib/timeline/optionsTimeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,11 @@ let allOptions = {
},
snap: {'function': 'function', 'null': 'null'},
start: {date, number, string, moment},
showUngroupedItems: {'boolean': bool},
template: {'function': 'function'},
loadingScreenTemplate: {'function': 'function'},
groupTemplate: {'function': 'function'},
ungroupedHeaderTemplate: {'function': 'function'},
visibleFrameTemplate: {string, 'function': 'function'},
showTooltips: { 'boolean': bool},
tooltip: {
Expand Down