diff --git a/Jakefile.js b/Jakefile.js index bb43714b..483716dd 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -55,7 +55,6 @@ task('build', {async: true}, function () { './src/shim.js', './src/util.js', './src/events.js', - './src/EventBus.js', './src/DataSet.js', './src/DataView.js', @@ -82,7 +81,6 @@ task('build', {async: true}, function () { './src/graph/Popup.js', './src/graph/Groups.js', './src/graph/Images.js', - './src/graph/manipulationMixin.js', './src/graph/SectorsMixin.js', './src/graph/ClusterMixin.js', './src/graph/SelectionMixin.js', diff --git a/src/EventBus.js b/src/EventBus.js deleted file mode 100644 index 017739b1..00000000 --- a/src/EventBus.js +++ /dev/null @@ -1,89 +0,0 @@ -/** - * An event bus can be used to emit events, and to subscribe to events - * @constructor EventBus - */ -function EventBus() { - this.subscriptions = []; -} - -/** - * Subscribe to an event - * @param {String | RegExp} event The event can be a regular expression, or - * a string with wildcards, like 'server.*'. - * @param {function} callback. Callback are called with three parameters: - * {String} event, {*} [data], {*} [source] - * @param {*} [target] - * @returns {String} id A subscription id - */ -EventBus.prototype.on = function (event, callback, target) { - var regexp = (event instanceof RegExp) ? - event : - new RegExp(event.replace('*', '\\w+')); - - var subscription = { - id: util.randomUUID(), - event: event, - regexp: regexp, - callback: (typeof callback === 'function') ? callback : null, - target: target - }; - - this.subscriptions.push(subscription); - - return subscription.id; -}; - -/** - * Unsubscribe from an event - * @param {String | Object} filter Filter for subscriptions to be removed - * Filter can be a string containing a - * subscription id, or an object containing - * one or more of the fields id, event, - * callback, and target. - */ -EventBus.prototype.off = function (filter) { - var i = 0; - while (i < this.subscriptions.length) { - var subscription = this.subscriptions[i]; - - var match = true; - if (filter instanceof Object) { - // filter is an object. All fields must match - for (var prop in filter) { - if (filter.hasOwnProperty(prop)) { - if (filter[prop] !== subscription[prop]) { - match = false; - } - } - } - } - else { - // filter is a string, filter on id - match = (subscription.id == filter); - } - - if (match) { - this.subscriptions.splice(i, 1); - } - else { - i++; - } - } -}; - -/** - * Emit an event - * @param {String} event - * @param {*} [data] - * @param {*} [source] - */ -EventBus.prototype.emit = function (event, data, source) { - for (var i =0; i < this.subscriptions.length; i++) { - var subscription = this.subscriptions[i]; - if (subscription.regexp.test(event)) { - if (subscription.callback) { - subscription.callback(event, data, source); - } - } - } -}; diff --git a/src/module/exports.js b/src/module/exports.js index e4c70cbf..ef4c8ac2 100644 --- a/src/module/exports.js +++ b/src/module/exports.js @@ -11,7 +11,6 @@ var vis = { Range: Range, Stack: Stack, TimeStep: TimeStep, - EventBus: EventBus, components: { items: { diff --git a/src/timeline/Controller.js b/src/timeline/Controller.js index ebb3e494..ed683220 100644 --- a/src/timeline/Controller.js +++ b/src/timeline/Controller.js @@ -1,14 +1,54 @@ /** * @constructor Controller * - * A Controller controls the reflows and repaints of all visual components + * A Controller controls the reflows and repaints of all components, + * and is used as an event bus for all components. */ function Controller () { + var me = this; + this.id = util.randomUUID(); this.components = {}; - this.repaintTimer = undefined; - this.reflowTimer = undefined; + /** + * Listen for a 'request-reflow' event. The controller will schedule a reflow + * @param {Boolean} [force] If true, an immediate reflow is forced. Default + * is false. + */ + var reflowTimer = null; + this.on('request-reflow', function requestReflow(force) { + if (force) { + me.reflow(); + } + else { + if (!reflowTimer) { + reflowTimer = setTimeout(function () { + reflowTimer = null; + me.reflow(); + }, 0); + } + } + }); + + /** + * Request a repaint. The controller will schedule a repaint + * @param {Boolean} [force] If true, an immediate repaint is forced. Default + * is false. + */ + var repaintTimer = null; + this.on('request-repaint', function requestRepaint(force) { + if (force) { + me.repaint(); + } + else { + if (!repaintTimer) { + repaintTimer = setTimeout(function () { + repaintTimer = null; + me.repaint(); + }, 0); + } + } + }); } // Extend controller with Emitter mixin @@ -56,48 +96,6 @@ Controller.prototype.remove = function remove(component) { } }; -/** - * Request a reflow. The controller will schedule a reflow - * @param {Boolean} [force] If true, an immediate reflow is forced. Default - * is false. - */ -// TODO: change requestReflow into an event -Controller.prototype.requestReflow = function requestReflow(force) { - if (force) { - this.reflow(); - } - else { - if (!this.reflowTimer) { - var me = this; - this.reflowTimer = setTimeout(function () { - me.reflowTimer = undefined; - me.reflow(); - }, 0); - } - } -}; - -/** - * Request a repaint. The controller will schedule a repaint - * @param {Boolean} [force] If true, an immediate repaint is forced. Default - * is false. - */ -// TODO: change requestReflow into an event -Controller.prototype.requestRepaint = function requestRepaint(force) { - if (force) { - this.repaint(); - } - else { - if (!this.repaintTimer) { - var me = this; - this.repaintTimer = setTimeout(function () { - me.repaintTimer = undefined; - me.repaint(); - }, 0); - } - } -}; - /** * Repaint all components */ diff --git a/src/timeline/Stack.js b/src/timeline/Stack.js index 16ac34b7..1d014207 100644 --- a/src/timeline/Stack.js +++ b/src/timeline/Stack.js @@ -63,10 +63,8 @@ Stack.prototype.update = function update() { }; /** - * Order the items. The items are ordered by width first, and by left position - * second. - * If a custom order function has been provided via the options, then this will - * be used. + * Order the items. If a custom order function has been provided via the options, + * then this will be used. * @private */ Stack.prototype._order = function _order () { diff --git a/src/timeline/Timeline.js b/src/timeline/Timeline.js index 664bc20c..7b4cbf31 100644 --- a/src/timeline/Timeline.js +++ b/src/timeline/Timeline.js @@ -96,12 +96,12 @@ function Timeline (container, items, options) { this.range.subscribe(this.controller, this.rootPanel, 'zoom', 'horizontal'); this.range.on('rangechange', function (properties) { var force = true; - me.controller.requestReflow(force); + me.controller.emit('request-reflow', force); me.emit('rangechange', properties); }); this.range.on('rangechanged', function (properties) { var force = true; - me.controller.requestReflow(force); + me.controller.emit('request-reflow', force); me.emit('rangechanged', properties); }); diff --git a/src/timeline/component/Component.js b/src/timeline/component/Component.js index c7c8cd3c..ff6c9310 100644 --- a/src/timeline/component/Component.js +++ b/src/timeline/component/Component.js @@ -20,7 +20,6 @@ function Component () { * set. * @param {Object} options Available parameters: * {String | function} [className] - * {EventBus} [eventBus] * {String | Number | function} [left] * {String | Number | function} [top] * {String | Number | function} [width] @@ -143,7 +142,7 @@ Component.prototype.show = function show() { */ Component.prototype.requestRepaint = function requestRepaint() { if (this.controller) { - this.controller.requestRepaint(); + this.controller.emit('request-repaint'); } else { throw new Error('Cannot request a repaint: no controller configured'); @@ -156,7 +155,7 @@ Component.prototype.requestRepaint = function requestRepaint() { */ Component.prototype.requestReflow = function requestReflow() { if (this.controller) { - this.controller.requestReflow(); + this.controller.emit('request-reflow'); } else { throw new Error('Cannot request a reflow: no controller configured'); diff --git a/src/timeline/component/ItemSet.js b/src/timeline/component/ItemSet.js index e44d4c87..1c15ab0a 100644 --- a/src/timeline/component/ItemSet.js +++ b/src/timeline/component/ItemSet.js @@ -677,8 +677,7 @@ ItemSet.prototype.toScreen = function toScreen(time) { * @private */ ItemSet.prototype._onDragStart = function (event) { - var itemSet = ItemSet.itemSetFromTarget(event), - item = ItemSet.itemFromTarget(event), + var item = ItemSet.itemFromTarget(event), me = this; if (item && item.selected) { @@ -704,6 +703,8 @@ ItemSet.prototype._onDrag = function (event) { item.setOffset(deltaX); }); + // TODO: stacking on dragend changes the order. (stacking orders by start date, which isn't yet changed) + // TODO: implement snapping to nice dates // TODO: implement dragging from one group to another