Skip to content
This repository was archived by the owner on Jul 29, 2019. It is now read-only.

Hide vertically hidden ranged items in groups that are not visible #2062

Merged
merged 9 commits into from
Sep 13, 2016
122 changes: 122 additions & 0 deletions examples/timeline/groups/verticalItemsHide.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<html>
<head>
<title>Timeline | A lot of grouped data</title>

<script src="../../../docs/js/jquery.min.js"></script>
<script src="../../../dist/vis.js"></script>
<link href="../../../dist/vis.css" rel="stylesheet" type="text/css" />

<style type="text/css">
body {
color: #4D4D4D;
font: 10pt arial;
}
</style>
<script src="../../googleAnalytics.js"></script>
</head>

<body onresize="/*timeline.checkResize();*/">
<h1>Timeline vertical visibility</h1>


<button onclick="showVisibleItems()">Show current visible items</button>
<div>
<h2>visible items:</h2>
<h3 id="visibleItemsContainer"></h3>
</div>

<div id="mytimeline"></div>
<br>

<script>
function showVisibleItems() {
var a = timeline.getVisibleItems();
console.log(a);
document.getElementById("visibleItemsContainer").innerHTML = ""
document.getElementById("visibleItemsContainer").innerHTML += a;
};

// get selected item count from url parameter
var count = 1000;

// create groups
var groups = new vis.DataSet([
{id: 1, content: 'Truck&nbsp;1'},
{id: 2, content: 'Truck&nbsp;2'},
{id: 3, content: 'Truck&nbsp;3'},
{id: 4, content: 'Truck&nbsp;4'},
{id: 5, content: 'Truck&nbsp;5'},
{id: 6, content: 'Truck&nbsp;6'},
{id: 7, content: 'Truck&nbsp;7'},
{id: 8, content: 'Truck&nbsp;8'},
{id: 9, content: 'Truck&nbsp;9'},
{id: 10, content: 'Truck&nbsp;10'},
{id: 11, content: 'Truck&nbsp;11'},
{id: 12, content: 'Truck&nbsp;12'},
{id: 13, content: 'Truck&nbsp;13'},
{id: 14, content: 'Truck&nbsp;14'},
{id: 15, content: 'Truck&nbsp;15'},
{id: 16, content: 'Truck&nbsp;16'},
{id: 17, content: 'Truck&nbsp;17'},
{id: 18, content: 'Truck&nbsp;18'},
{id: 19, content: 'Truck&nbsp;19'},
{id: 20, content: 'Truck&nbsp;20'},
{id: 21, content: 'Truck&nbsp;21'},
{id: 22, content: 'Truck&nbsp;22'},
{id: 23, content: 'Truck&nbsp;23'},
{id: 24, content: 'Truck&nbsp;24'},
{id: 25, content: 'Truck&nbsp;25'},

]);

// create items
var items = new vis.DataSet();

var order = 1;
var truck = 1;
for (var j = 0; j < 25; j++) {
var date = new Date();
for (var i = 0; i < count/25; i++) {
date.setHours(date.getHours() + 4 * (Math.random() < 0.2));
var start = new Date(date);

date.setHours(date.getHours() + 2 + Math.floor(Math.random()*4));
var end = new Date(date);

items.add({
id: order,
group: truck,
start: start,
end: end,
content: 'Order ' + order
});

order++;
}
truck++;
}

// specify options
var options = {
stack: true,
maxHeight: 400,
start: new Date(),
end: new Date(1000*60*60*24 + (new Date()).valueOf()),
editable: true,
margin: {
item: 10, // minimal margin between items
axis: 5 // minimal margin between items and the axis
},
orientation: 'top'
};


// create a Timeline
var container = document.getElementById('mytimeline');
timeline = new vis.Timeline(container, null, options);
timeline.setGroups(groups);
timeline.setItems(items);
</script>

</body>
</html>
45 changes: 34 additions & 11 deletions lib/timeline/component/Group.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ function Group (groupId, data, itemSet) {
this.subgroupIndex = 0;
this.subgroupOrderer = data && data.subgroupOrder;
this.itemSet = itemSet;
this.isVisible = null;

this.dom = {};
this.props = {
Expand Down Expand Up @@ -180,6 +181,8 @@ Group.prototype.redraw = function(range, margin, restack) {
// recalculate the height of the subgroups
this._calculateSubGroupHeights();

this.isVisible = this._isGroupVisible(range, margin);

// reposition visible items vertically
if (typeof this.itemSet.options.order === 'function') {
// a custom order function
Expand Down Expand Up @@ -219,6 +222,10 @@ Group.prototype.redraw = function(range, margin, restack) {
}
}

if (!this.isVisible && this.height) {
return resized = false;
}

// recalculate the height of the group
var height = this._calculateHeight(margin);

Expand Down Expand Up @@ -265,6 +272,17 @@ Group.prototype._calculateSubGroupHeights = function () {
}
};

/**
* check if group is visible
* @private
*/
Group.prototype._isGroupVisible = function (range, margin) {
var isVisible =
(this.top <= range.body.domProps.centerContainer.height - range.body.domProps.scrollTop + margin.axis)
&& (this.top + this.height + margin.axis >= - range.body.domProps.scrollTop);
return isVisible;
}

/**
* recalculate the height of the group
* @param {{item: {horizontal: number, vertical: number}, axis: number}} margin
Expand Down Expand Up @@ -475,10 +493,18 @@ Group.prototype.order = function() {
Group.prototype._updateVisibleItems = function(orderedItems, oldVisibleItems, range) {
var visibleItems = [];
var visibleItemsLookup = {}; // we keep this to quickly look up if an item already exists in the list without using indexOf on visibleItems

if (!this.isVisible) {
Copy link
Member

@mojoaxel mojoaxel Sep 4, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the problem why examples with no groups are no longer working. Please rethink this lines again.

Copy link
Member Author

@yotamberk yotamberk Sep 4, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I solved it by add equals in the
Group.prototype._isGroupVisible = function (range) { var isVisible = (this.top <= range.body.domProps.centerContainer.height - range.body.domProps.scrollTop) && (this.top + this.height >= - range.body.domProps.scrollTop); return isVisible; }
So that when there are no groups, it will see it as one group with top 0 and we get 0==0 which leads to visible items.
This seems to solve the problem I caused. Examples now work well. Something doesn't sit well with me in this solution...

I think there should be a calculation of the initial group height and it should not be 0. It should calculate the height as if all the groups' items in the horizontal range are visible initially and then remove them if they aren't in the vertical range.
I'm working on a more elegant solution then the one supplied in this merge request.

for (var i = 0; i < oldVisibleItems.length; i++) {
var item = oldVisibleItems[i];
if (item.displayed) item.hide();
}
return visibleItems;
}

var interval = (range.end - range.start) / 4;
var lowerBound = range.start - interval;
var upperBound = range.end + interval;
var item, i;

// this function is used to do the binary search.
var searchFunction = function (value) {
Expand All @@ -491,7 +517,7 @@ Group.prototype._updateVisibleItems = function(orderedItems, oldVisibleItems, ra
// IMPORTANT: this handles the case for the items with startdate before the window and enddate after the window!
// also cleans up invisible items.
if (oldVisibleItems.length > 0) {
for (i = 0; i < oldVisibleItems.length; i++) {
for (var i = 0; i < oldVisibleItems.length; i++) {
this._checkIfVisibleWithReference(oldVisibleItems[i], visibleItems, visibleItemsLookup, range);
}
}
Expand Down Expand Up @@ -524,8 +550,8 @@ Group.prototype._updateVisibleItems = function(orderedItems, oldVisibleItems, ra


// finally, we reposition all the visible items.
for (i = 0; i < visibleItems.length; i++) {
item = visibleItems[i];
for (var i = 0; i < visibleItems.length; i++) {
var item = visibleItems[i];
if (!item.displayed) item.show();
// reposition item horizontally
item.repositionX();
Expand All @@ -548,12 +574,9 @@ Group.prototype._updateVisibleItems = function(orderedItems, oldVisibleItems, ra
};

Group.prototype._traceVisible = function (initialPos, items, visibleItems, visibleItemsLookup, breakCondition) {
var item;
var i;

if (initialPos != -1) {
for (i = initialPos; i >= 0; i--) {
item = items[i];
for (var i = initialPos; i >= 0; i--) {
var item = items[i];
if (breakCondition(item)) {
break;
}
Expand All @@ -565,8 +588,8 @@ Group.prototype._traceVisible = function (initialPos, items, visibleItems, visib
}
}

for (i = initialPos + 1; i < items.length; i++) {
item = items[i];
for (var i = initialPos + 1; i < items.length; i++) {
var item = items[i];
if (breakCondition(item)) {
break;
}
Expand Down
10 changes: 8 additions & 2 deletions lib/timeline/component/item/RangeItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,14 @@ RangeItem.prototype.baseClassName = 'vis-item vis-range';
*/
RangeItem.prototype.isVisible = function(range) {
// determine visibility
return (this.data.start < range.end) && (this.data.end > range.start);
};
var isVisible =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code formatting is broken here. Please check the indent of this function.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've fixed it

// determine horizontal visibillity
(this.data.start < range.end) &&
(this.data.end > range.start) &&
// determine vertical visibillity
(this.parent.top < range.body.domProps.centerContainer.height - range.body.domProps.scrollTop) &&
(this.parent.top + this.parent.height > - range.body.domProps.scrollTop)
return isVisible;};

/**
* Repaint the item
Expand Down