diff --git a/src/timeline/Timeline.js b/src/timeline/Timeline.js index 5ffea046..321257f3 100644 --- a/src/timeline/Timeline.js +++ b/src/timeline/Timeline.js @@ -71,13 +71,6 @@ function Timeline (container, items, options) { this.options = {}; util.deepExtend(this.options, this.defaultOptions); - util.deepExtend(this.options, { - // FIXME: not nice passing these functions via the options - snap: null, // will be specified after timeaxis is created - - toScreen: me._toScreen.bind(me), - toTime: me._toTime.bind(me) - }); // Create the DOM, props, and emitter this._create(); @@ -92,7 +85,12 @@ function Timeline (container, items, options) { this.body = { dom: this.dom, props: this.props, - emitter: this + emitter: this, + util: { + snap: null, // will be specified after TimeAxis is created + toScreen: me._toScreen.bind(me), + toTime: me._toTime.bind(me) + } }; // range @@ -106,7 +104,7 @@ function Timeline (container, items, options) { // time axis this.timeAxis = new TimeAxis(this.body, this.options); this.components.push(this.timeAxis); - this.options.snap = this.timeAxis.snap.bind(this.timeAxis); // TODO: not nice adding snap to options + this.body.util.snap = this.timeAxis.snap.bind(this.timeAxis); // current time bar this.currentTime = new CurrentTime(this.body, this.options); diff --git a/src/timeline/component/Component.js b/src/timeline/component/Component.js index 5dfe5342..8e3a96e7 100644 --- a/src/timeline/component/Component.js +++ b/src/timeline/component/Component.js @@ -1,6 +1,6 @@ /** * Prototype for visual components - * @param {{dom: Object, props: Object, emitter: Emitter, range: Range}} body + * @param {{dom: Object, props: Object, emitter: Emitter, range: Range}} [body] * @param {Object} [options] */ function Component (body, options) { diff --git a/src/timeline/component/CurrentTime.js b/src/timeline/component/CurrentTime.js index ca0008f4..975ad45c 100644 --- a/src/timeline/component/CurrentTime.js +++ b/src/timeline/component/CurrentTime.js @@ -49,7 +49,7 @@ CurrentTime.prototype.redraw = function() { } var now = new Date(); - var x = this.options.toScreen(now); + var x = this.body.util.toScreen(now); this.bar.style.left = x + 'px'; this.bar.title = 'Current time: ' + now; diff --git a/src/timeline/component/CustomTime.js b/src/timeline/component/CustomTime.js index 4cd9e96d..e944ba5f 100644 --- a/src/timeline/component/CustomTime.js +++ b/src/timeline/component/CustomTime.js @@ -64,7 +64,7 @@ CustomTime.prototype.redraw = function () { parent.appendChild(this.bar); } - var x = this.options.toScreen(this.customTime); + var x = this.body.util.toScreen(this.customTime); this.bar.style.left = x + 'px'; this.bar.title = 'Time: ' + this.customTime; @@ -118,8 +118,8 @@ CustomTime.prototype._onDrag = function (event) { if (!this.eventParams.dragging) return; var deltaX = event.gesture.deltaX, - x = this.options.toScreen(this.eventParams.customTime) + deltaX, - time = this.options.toTime(x); + x = this.body.util.toScreen(this.eventParams.customTime) + deltaX, + time = this.body.util.toTime(x); this.setCustomTime(time); diff --git a/src/timeline/component/ItemSet.js b/src/timeline/component/ItemSet.js index 4b926c62..678606bd 100644 --- a/src/timeline/component/ItemSet.js +++ b/src/timeline/component/ItemSet.js @@ -15,6 +15,10 @@ function ItemSet(body, options) { // one options object is shared by this itemset and all its items this.options = options || {}; this.itemOptions = Object.create(this.options); + this.itemConversion = { + toScreen: body.util.toScreen, + toTime: body.util.toTime + }; this.dom = {}; this.props = {}; this.hammer = null; @@ -543,13 +547,11 @@ ItemSet.prototype.removeItem = function(id) { * @protected */ ItemSet.prototype._onUpdate = function(ids) { - var me = this, - items = this.items, - itemOptions = this.itemOptions; + var me = this; ids.forEach(function (id) { var itemData = me.itemsData.get(id), - item = items[id], + item = me.items[id], type = itemData.type || (itemData.start && itemData.end && 'range') || me.options.type || @@ -572,7 +574,7 @@ ItemSet.prototype._onUpdate = function(ids) { if (!item) { // create item if (constructor) { - item = new constructor(itemData, me.options, itemOptions); + item = new constructor(itemData, me.itemConversion, me.itemOptions); item.id = id; // TODO: not so nice setting id afterwards me._addItem(item); } @@ -913,7 +915,7 @@ ItemSet.prototype._onDragStart = function (event) { ItemSet.prototype._onDrag = function (event) { if (this.touchParams.itemProps) { var range = this.body.range, - snap = this.options.snap || null, + snap = this.body.util.snap || null, deltaX = event.gesture.deltaX, scale = (this.props.width / (range.end - range.start)), offset = deltaX / scale; @@ -1058,7 +1060,7 @@ ItemSet.prototype._onAddItem = function (event) { if (!this.options.editable.add) return; var me = this, - snap = this.options.snap || null, + snap = this.body.util.snap || null, item = ItemSet.itemFromTarget(event); if (item) { @@ -1076,7 +1078,7 @@ ItemSet.prototype._onAddItem = function (event) { // add item var xAbs = vis.util.getAbsoluteLeft(this.dom.frame); var x = event.gesture.center.pageX - xAbs; - var start = this.options.toTime(x); + var start = this.body.util.toTime(x); var newItem = { start: snap ? snap(start) : start, content: 'new item' @@ -1084,7 +1086,7 @@ ItemSet.prototype._onAddItem = function (event) { // when default type is a range, add a default end date to the new item if (this.options.type === 'range' || this.options.type == 'rangeoverflow') { - var end = this.options.toTime(x + this.props.width / 5); + var end = this.body.util.toTime(x + this.props.width / 5); newItem.end = snap ? snap(end) : end; } diff --git a/src/timeline/component/TimeAxis.js b/src/timeline/component/TimeAxis.js index a14591ad..3d1f268b 100644 --- a/src/timeline/component/TimeAxis.js +++ b/src/timeline/component/TimeAxis.js @@ -137,8 +137,8 @@ TimeAxis.prototype._repaintLabels = function () { // calculate range and step (step such that we have space for 7 characters per label) var start = util.convert(this.body.range.start, 'Number'), end = util.convert(this.body.range.end, 'Number'), - minimumStep = this.options.toTime((this.props.minorCharWidth || 10) * 7).valueOf() - -this.options.toTime(0).valueOf(); + minimumStep = this.body.util.toTime((this.props.minorCharWidth || 10) * 7).valueOf() + -this.body.util.toTime(0).valueOf(); var step = new TimeStep(new Date(start), new Date(end), minimumStep); this.step = step; @@ -161,7 +161,7 @@ TimeAxis.prototype._repaintLabels = function () { while (step.hasNext() && max < 1000) { max++; var cur = step.getCurrent(), - x = this.options.toScreen(cur), + x = this.body.util.toScreen(cur), isMajor = step.isMajor(); // TODO: lines must have a width, such that we can create css backgrounds @@ -188,7 +188,7 @@ TimeAxis.prototype._repaintLabels = function () { // create a major label on the left when needed if (this.getOption('showMajorLabels')) { - var leftTime = this.options.toTime(0), + var leftTime = this.body.util.toTime(0), leftText = step.getLabelMajor(leftTime), widthText = leftText.length * (this.props.majorCharWidth || 10) + 10; // upper bound estimation diff --git a/src/timeline/component/item/Item.js b/src/timeline/component/item/Item.js index 2522b49c..998f3bf8 100644 --- a/src/timeline/component/item/Item.js +++ b/src/timeline/component/item/Item.js @@ -2,17 +2,18 @@ * @constructor Item * @param {Object} data Object containing (optional) parameters type, * start, end, content, group, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options + * @param {{toScreen: function, toTime: function}} conversion + * Conversion functions from time to screen and vice versa + * @param {Object} options Configuration options * // TODO: describe available options */ -function Item (data, options, defaultOptions) { +function Item (data, conversion, options) { this.id = null; this.parent = null; this.data = data; this.dom = null; + this.conversion = conversion || {}; this.options = options || {}; - this.defaultOptions = defaultOptions || {}; this.selected = false; this.displayed = false; diff --git a/src/timeline/component/item/ItemBox.js b/src/timeline/component/item/ItemBox.js index 0ef92303..149b0da2 100644 --- a/src/timeline/component/item/ItemBox.js +++ b/src/timeline/component/item/ItemBox.js @@ -3,11 +3,12 @@ * @extends Item * @param {Object} data Object containing parameters start * content, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options + * @param {{toScreen: function, toTime: function}} conversion + * Conversion functions from time to screen and vice versa + * @param {Object} [options] Configuration options * // TODO: describe available options */ -function ItemBox (data, options, defaultOptions) { +function ItemBox (data, conversion, options) { this.props = { dot: { width: 0, @@ -26,10 +27,10 @@ function ItemBox (data, options, defaultOptions) { } } - Item.call(this, data, options, defaultOptions); + Item.call(this, data, conversion, options); } -ItemBox.prototype = new Item (null); +ItemBox.prototype = new Item (null, null, null); /** * Check whether this item is visible inside given range @@ -170,8 +171,8 @@ ItemBox.prototype.hide = function() { * @Override */ ItemBox.prototype.repositionX = function() { - var start = this.defaultOptions.toScreen(this.data.start), - align = this.options.align || this.defaultOptions.align, + var start = this.conversion.toScreen(this.data.start), + align = this.options.align, left, box = this.dom.box, line = this.dom.line, @@ -204,7 +205,7 @@ ItemBox.prototype.repositionX = function() { * @Override */ ItemBox.prototype.repositionY = function() { - var orientation = this.options.orientation || this.defaultOptions.orientation, + var orientation = this.options.orientation, box = this.dom.box, line = this.dom.line, dot = this.dom.dot; diff --git a/src/timeline/component/item/ItemPoint.js b/src/timeline/component/item/ItemPoint.js index 7c290cdd..9d1664ea 100644 --- a/src/timeline/component/item/ItemPoint.js +++ b/src/timeline/component/item/ItemPoint.js @@ -3,11 +3,12 @@ * @extends Item * @param {Object} data Object containing parameters start * content, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options + * @param {{toScreen: function, toTime: function}} conversion + * Conversion functions from time to screen and vice versa + * @param {Object} [options] Configuration options * // TODO: describe available options */ -function ItemPoint (data, options, defaultOptions) { +function ItemPoint (data, conversion, options) { this.props = { dot: { top: 0, @@ -27,10 +28,10 @@ function ItemPoint (data, options, defaultOptions) { } } - Item.call(this, data, options, defaultOptions); + Item.call(this, data, conversion, options); } -ItemPoint.prototype = new Item (null); +ItemPoint.prototype = new Item (null, null, null); /** * Check whether this item is visible inside given range @@ -164,7 +165,7 @@ ItemPoint.prototype.hide = function() { * @Override */ ItemPoint.prototype.repositionX = function() { - var start = this.defaultOptions.toScreen(this.data.start); + var start = this.conversion.toScreen(this.data.start); this.left = start - this.props.dot.width; @@ -177,7 +178,7 @@ ItemPoint.prototype.repositionX = function() { * @Override */ ItemPoint.prototype.repositionY = function() { - var orientation = this.options.orientation || this.defaultOptions.orientation, + var orientation = this.options.orientation, point = this.dom.point; if (orientation == 'top') { diff --git a/src/timeline/component/item/ItemRange.js b/src/timeline/component/item/ItemRange.js index 751e3471..859245b6 100644 --- a/src/timeline/component/item/ItemRange.js +++ b/src/timeline/component/item/ItemRange.js @@ -3,11 +3,12 @@ * @extends Item * @param {Object} data Object containing parameters start, end * content, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options - * // TODO: describe available options + * @param {{toScreen: function, toTime: function}} conversion + * Conversion functions from time to screen and vice versa + * @param {Object} [options] Configuration options + * // TODO: describe options */ -function ItemRange (data, options, defaultOptions) { +function ItemRange (data, conversion, options) { this.props = { content: { width: 0 @@ -24,10 +25,10 @@ function ItemRange (data, options, defaultOptions) { } } - Item.call(this, data, options, defaultOptions); + Item.call(this, data, conversion, options); } -ItemRange.prototype = new Item (null); +ItemRange.prototype = new Item (null, null, null); ItemRange.prototype.baseClassName = 'item range'; @@ -153,9 +154,9 @@ ItemRange.prototype.hide = function() { ItemRange.prototype.repositionX = function() { var props = this.props, parentWidth = this.parent.width, - start = this.defaultOptions.toScreen(this.data.start), - end = this.defaultOptions.toScreen(this.data.end), - padding = 'padding' in this.options ? this.options.padding : this.defaultOptions.padding, + start = this.conversion.toScreen(this.data.start), + end = this.conversion.toScreen(this.data.end), + padding = this.options.padding, contentLeft; // limit the width of the this, as browsers cannot draw very wide divs @@ -189,7 +190,7 @@ ItemRange.prototype.repositionX = function() { * @Override */ ItemRange.prototype.repositionY = function() { - var orientation = this.options.orientation || this.defaultOptions.orientation, + var orientation = this.options.orientation, box = this.dom.box; if (orientation == 'top') { diff --git a/src/timeline/component/item/ItemRangeOverflow.js b/src/timeline/component/item/ItemRangeOverflow.js index f94a7ff8..3d5d474e 100644 --- a/src/timeline/component/item/ItemRangeOverflow.js +++ b/src/timeline/component/item/ItemRangeOverflow.js @@ -3,11 +3,12 @@ * @extends ItemRange * @param {Object} data Object containing parameters start, end * content, className. - * @param {Object} [options] Options to set initial property values - * @param {Object} [defaultOptions] default options - * // TODO: describe available options + * @param {{toScreen: function, toTime: function}} conversion + * Conversion functions from time to screen and vice versa + * @param {Object} [options] Configuration options + * // TODO: describe options */ -function ItemRangeOverflow (data, options, defaultOptions) { +function ItemRangeOverflow (data, conversion, options) { this.props = { content: { left: 0, @@ -15,10 +16,10 @@ function ItemRangeOverflow (data, options, defaultOptions) { } }; - ItemRange.call(this, data, options, defaultOptions); + ItemRange.call(this, data, conversion, options); } -ItemRangeOverflow.prototype = new ItemRange (null); +ItemRangeOverflow.prototype = new ItemRange (null, null, null); ItemRangeOverflow.prototype.baseClassName = 'item rangeoverflow'; @@ -28,9 +29,8 @@ ItemRangeOverflow.prototype.baseClassName = 'item rangeoverflow'; */ ItemRangeOverflow.prototype.repositionX = function() { var parentWidth = this.parent.width, - start = this.defaultOptions.toScreen(this.data.start), - end = this.defaultOptions.toScreen(this.data.end), - padding = 'padding' in this.options ? this.options.padding : this.defaultOptions.padding, + start = this.conversion.toScreen(this.data.start), + end = this.conversion.toScreen(this.data.end), contentLeft; // limit the width of the this, as browsers cannot draw very wide divs