Browse Source

Halfway implementing improved Timeline.fit()

flowchartTest
jos 9 years ago
parent
commit
1648604401
7 changed files with 169 additions and 15 deletions
  1. +12
    -7
      lib/timeline/Core.js
  2. +1
    -1
      lib/timeline/Graph2d.js
  3. +107
    -6
      lib/timeline/Timeline.js
  4. +16
    -0
      lib/timeline/component/item/BoxItem.js
  5. +16
    -0
      lib/timeline/component/item/Item.js
  6. +16
    -0
      lib/timeline/component/item/PointItem.js
  7. +1
    -1
      test/timeline.html

+ 12
- 7
lib/timeline/Core.js View File

@ -457,23 +457,28 @@ Core.prototype.getVisibleItems = function() {
* function is 'easeInOutQuad'.
*/
Core.prototype.fit = function(options) {
var range = this._getDataRange();
var range = this.getDataRange();
// skip range set if there is no start and end date
if (range.start === null && range.end === null) {
return;
}
// apply a margin of 1% left and right of the data
var interval = range.max - range.min;
var min = new Date(range.min.valueOf() - interval * 0.01);
var max = new Date(range.max.valueOf() + interval * 0.01);
var animation = (options && options.animation !== undefined) ? options.animation : true;
this.range.setRange(range.start, range.end, animation);
this.range.setRange(min, max, animation);
};
/**
* Calculate the data range of the items and applies a 5% window around it.
* @returns {{start: Date | null, end: Date | null}}
* Calculate the data range of the items start and end dates
* @returns {{min: Date | null, max: Date | null}}
* @protected
*/
Core.prototype._getDataRange = function() {
Core.prototype.getDataRange = function() {
// apply the data range as range
var dataRange = this.getItemRange();
@ -491,8 +496,8 @@ Core.prototype._getDataRange = function() {
}
return {
start: start,
end: end
start: null,
end: null
}
};

+ 1
- 1
lib/timeline/Graph2d.js View File

@ -242,7 +242,7 @@ Graph2d.prototype.isGroupVisible = function(groupId) {
* When no minimum is found, min==null
* When no maximum is found, max==null
*/
Graph2d.prototype.getItemRange = function() {
Graph2d.prototype.getDataRange = function() {
var min = null;
var max = null;

+ 107
- 6
lib/timeline/Timeline.js View File

@ -218,8 +218,6 @@ Timeline.prototype.setItems = function(items) {
this.setWindow(start, end, {animation: false});
}
else {
// call fit twice as
this.fit({animation: false});
this.fit({animation: false});
}
}
@ -345,12 +343,71 @@ Timeline.prototype.focus = function(id, options) {
}
};
/**
* Set Timeline window such that it fits all items
* @param {Object} [options] Available options:
* `animation: boolean | {duration: number, easingFunction: string}`
* If true (default), the range is animated
* smoothly to the new window. An object can be
* provided to specify duration and easing function.
* Default duration is 500 ms, and default easing
* function is 'easeInOutQuad'.
*/
Timeline.prototype.fit = function (options) {
// then, make sure all items are drawn and have a width, and fit the timeline window exactly.
var min = null;
var max = null;
var minItem = null;
var maxItem = null;
util.forEach(this.itemSet.items, function (item) {
item.show();
item.repositionX();
if (item.left < min) {
min = item.left;
minItem = item;
}
var right = item.left + item.width;
if (right > max) {
max = right;
maxItem = item;
}
});
if (minItem && maxItem) {
var start = util.convert(minItem.data.start, 'Date').valueOf();
var end = maxItem.data.end != undefined
? util.convert(maxItem.data.end, 'Date').valueOf()
: util.convert(maxItem.data.start, 'Date').valueOf();
var lhs = this._toScreen(start) - minItem.left - 10;
var rhs = maxItem.left + maxItem.width - this._toScreen(end) + 10;
var interval = end - start; // ms
if (interval <= 0) {interval = 10;}
var delta = this.props.center.width - lhs - rhs; // px
//console.log(start, end, lhs, rhs, delta)
if (delta > 0) {
start -= lhs * interval / delta; // ms
end += rhs * interval / delta; // ms
var animation = (options && options.animation !== undefined) ? options.animation : true;
this.range.setRange(start, end, animation);
}
}
};
/**
* Get the data range of the item set.
* @returns {{min: Date, max: Date}} range A range with a start and end Date.
* When no minimum is found, min==null
* When no maximum is found, max==null
*/
// TODO: remove this function
Timeline.prototype.getItemRange = function() {
var min = null;
var max = null;
@ -378,11 +435,26 @@ Timeline.prototype.getItemRange = function() {
var minItem = this.itemSet.items[minId];
var maxItem = this.itemSet.items[maxId];
if (minItem && minItem.width && maxItem && maxItem.width) {
var left = minItem.left;
var right = maxItem.left + maxItem.width;
//var left = minItem.left;
//var right = maxItem.left + maxItem.width;
//
//min = this._toTime(left - 10);
//max = this._toTime(right + 10);
var lhs = minItem.widthLhs(); // px
var rhs = maxItem.widthRhs(); // px
min = this._toTime(left - 10);
max = this._toTime(right + 10);
var interval = max - min; // ms
if (interval <= 0) {interval = 10;}
var delta = this.props.center.width - lhs - rhs; // px
console.log(minId, maxId, minItem.left, this._toScreen(min), this._toScreen(minItem.data.start), lhs, rhs, interval, delta)
if (delta > 0) {
min -= lhs * interval / delta; // ms
max += rhs * interval / delta; // ms
}
}
return {
@ -391,6 +463,35 @@ Timeline.prototype.getItemRange = function() {
};
};
/**
* Calculate the data range of the items start and end dates
* @returns {{min: Date | null, max: Date | null}}
* @protected
*/
Timeline.prototype.getDataRange = function() {
var min = null;
var max = null;
var dataset = this.itemsData && this.itemsData.getDataSet();
if (dataset) {
dataset.forEach(function (item) {
var start = util.convert(item.start, 'Date').valueOf();
var end = util.convert(item.end != undefined ? item.end : item.start, 'Date').valueOf();
if (min === null || start < min) {
min = start;
}
if (max === null || end > max) {
max = start;
}
});
}
return {
min: min,
max: max
}
};
/**
* Generate Timeline related information from an event
* @param {Event} event

+ 16
- 0
lib/timeline/component/item/BoxItem.js View File

@ -215,4 +215,20 @@ BoxItem.prototype.repositionY = function() {
dot.style.top = (-this.props.dot.height / 2) + 'px';
};
/**
* Return the width of the item left from its start date
* @return {number}
*/
BoxItem.prototype.widthLhs = function () {
return this.width / 2;
};
/**
* Return the width of the item right from its start date
* @return {number}
*/
BoxItem.prototype.widthRhs = function () {
return this.width / 2;
};
module.exports = BoxItem;

+ 16
- 0
lib/timeline/component/item/Item.js View File

@ -273,4 +273,20 @@ Item.prototype._contentToString = function (content) {
return content;
};
/**
* Return the width of the item left from its start date
* @return {number}
*/
Item.prototype.widthLhs = function () {
return 0;
};
/**
* Return the width of the item right from the max of its start and end date
* @return {number}
*/
Item.prototype.widthRhs = function () {
return 0;
};
module.exports = Item;

+ 16
- 0
lib/timeline/component/item/PointItem.js View File

@ -177,4 +177,20 @@ PointItem.prototype.repositionY = function() {
}
};
/**
* Return the width of the item left from its start date
* @return {number}
*/
PointItem.prototype.widthLhs = function () {
return this.props.dot.width / 2;
};
/**
* Return the width of the item right from its start date
* @return {number}
*/
PointItem.prototype.widthRhs = function () {
return this.width - this.props.dot.width / 2;
};
module.exports = PointItem;

+ 1
- 1
test/timeline.html View File

@ -170,7 +170,7 @@
//min: moment('2013-01-01'),
//max: moment('2013-12-31'),
//zoomMin: 1000 * 60 * 60 * 24, // 1 day
zoomMax: 1000 * 60 * 60 * 24 * 30 * 6 // 6 months
// zoomMax: 1000 * 60 * 60 * 24 * 30 * 6 // 6 months
};
console.timeEnd('create dataset');

Loading…
Cancel
Save