Browse Source

Merge branch 'alex_dev' of https://github.com/almende/vis into alex_dev

css_transitions
Alex de Mulder 10 years ago
parent
commit
3eaab04ebf
24 changed files with 356 additions and 159 deletions
  1. +4
    -4
      examples/graph/20_navigation.html
  2. +1
    -0
      package.json
  3. +0
    -0
      src/graph/graphMixins/physics/BarnesHut.js
  4. +0
    -0
      src/graph/graphMixins/physics/Repulsion.js
  5. +0
    -0
      src/graph/img/downArrow.png
  6. BIN
      src/graph/img/downarrow.png
  7. +0
    -0
      src/graph/img/leftArrow.png
  8. BIN
      src/graph/img/leftarrow.png
  9. +0
    -0
      src/graph/img/rightArrow.png
  10. BIN
      src/graph/img/rightarrow.png
  11. +0
    -0
      src/graph/img/upArrow.png
  12. BIN
      src/graph/img/uparrow.png
  13. +1
    -2
      src/module/imports.js
  14. +11
    -2
      src/timeline/Controller.js
  15. +38
    -17
      src/timeline/Range.js
  16. +7
    -7
      src/timeline/Stack.js
  17. +24
    -75
      src/timeline/Timeline.js
  18. +17
    -0
      src/timeline/component/Component.js
  19. +181
    -0
      src/timeline/component/ItemSet.js
  20. +57
    -46
      src/timeline/component/RootPanel.js
  21. +11
    -2
      src/timeline/component/item/Item.js
  22. +1
    -1
      src/timeline/component/item/ItemBox.js
  23. +1
    -1
      src/timeline/component/item/ItemPoint.js
  24. +2
    -2
      src/timeline/component/item/ItemRange.js

+ 4
- 4
examples/graph/20_navigation.html View File

@ -130,10 +130,10 @@
<table class="legend_table">
<tr>
<td>Icons: </td>
<td><div class="table_content"><img src="../../dist/img/uparrow.png" /> </div></td>
<td><div class="table_content"><img src="../../dist/img/downarrow.png" /> </div></td>
<td><div class="table_content"><img src="../../dist/img/leftarrow.png" /> </div></td>
<td><div class="table_content"><img src="../../dist/img/rightarrow.png" /> </div></td>
<td><div class="table_content"><img src="../../dist/img/upArrow.png" /> </div></td>
<td><div class="table_content"><img src="../../dist/img/downArrow.png" /> </div></td>
<td><div class="table_content"><img src="../../dist/img/leftArrow.png" /> </div></td>
<td><div class="table_content"><img src="../../dist/img/rightArrow.png" /> </div></td>
<td><div class="table_content"><img src="../../dist/img/plus.png" /> </div></td>
<td><div class="table_content"><img src="../../dist/img/minus.png" /> </div></td>
<td><div class="table_content"><img src="../../dist/img/zoomExtends.png" /> </div></td>

+ 1
- 0
package.json View File

@ -33,6 +33,7 @@
"moment": "latest",
"hammerjs": "1.0.5",
"mousetrap": "latest",
"emitter-component": "latest",
"node-watch": "latest"
}
}

src/graph/graphMixins/physics/barnesHut.js → src/graph/graphMixins/physics/BarnesHut.js View File


src/graph/graphMixins/physics/repulsion.js → src/graph/graphMixins/physics/Repulsion.js View File


dist/img/downarrow.png → src/graph/img/downArrow.png View File


BIN
src/graph/img/downarrow.png View File

Before After
Width: 30  |  Height: 30  |  Size: 4.4 KiB

dist/img/leftarrow.png → src/graph/img/leftArrow.png View File


BIN
src/graph/img/leftarrow.png View File

Before After
Width: 30  |  Height: 30  |  Size: 4.4 KiB

dist/img/rightarrow.png → src/graph/img/rightArrow.png View File


BIN
src/graph/img/rightarrow.png View File

Before After
Width: 30  |  Height: 30  |  Size: 4.4 KiB

dist/img/uparrow.png → src/graph/img/upArrow.png View File


BIN
src/graph/img/uparrow.png View File

Before After
Width: 30  |  Height: 30  |  Size: 4.4 KiB

+ 1
- 2
src/module/imports.js View File

@ -6,6 +6,7 @@
// If not available there, load via require.
var moment = (typeof window !== 'undefined') && window['moment'] || require('moment');
var Emitter = require('emitter-component');
var Hammer;
if (typeof window !== 'undefined') {
@ -28,5 +29,3 @@ else {
throw Error('mouseTrap is only available in a browser, not in node.js.');
}
}

+ 11
- 2
src/timeline/Controller.js View File

@ -11,6 +11,9 @@ function Controller () {
this.reflowTimer = undefined;
}
// Extend controller with Emitter mixin
Emitter(Controller.prototype);
/**
* Add a component to the controller
* @param {Component} component
@ -26,7 +29,7 @@ Controller.prototype.add = function add(component) {
}
// add the component
component.controller = this;
component.setController(this);
this.components[component.id] = component;
};
@ -38,13 +41,17 @@ Controller.prototype.remove = function remove(component) {
var id;
for (id in this.components) {
if (this.components.hasOwnProperty(id)) {
if (id == component || this.components[id] == component) {
if (id == component || this.components[id] === component) {
break;
}
}
}
if (id) {
// unregister the controller (gives the component the ability to unregister
// event listeners and clean up other stuff)
this.components[id].setController(null);
delete this.components[id];
}
};
@ -54,6 +61,7 @@ Controller.prototype.remove = function remove(component) {
* @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();
@ -74,6 +82,7 @@ Controller.prototype.requestReflow = function requestReflow(force) {
* @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();

+ 38
- 17
src/timeline/Range.js View File

@ -48,42 +48,48 @@ function validateDirection (direction) {
/**
* Add listeners for mouse and touch events to the component
* @param {Component} component
* @param {Controller} controller
* @param {Component} component Should be a rootpanel
* @param {String} event Available events: 'move', 'zoom'
* @param {String} direction Available directions: 'horizontal', 'vertical'
*/
Range.prototype.subscribe = function (component, event, direction) {
Range.prototype.subscribe = function (controller, component, event, direction) {
var me = this;
if (event == 'move') {
// drag start listener
component.on('dragstart', function (event) {
controller.on('dragstart', function (event) {
me._onDragStart(event, component);
});
// drag listener
component.on('drag', function (event) {
controller.on('drag', function (event) {
me._onDrag(event, component, direction);
});
// drag end listener
component.on('dragend', function (event) {
controller.on('dragend', function (event) {
me._onDragEnd(event, component);
});
// ignore dragging when holding
controller.on('hold', function (event) {
me._onHold();
});
}
else if (event == 'zoom') {
// mouse wheel
function mousewheel (event) {
me._onMouseWheel(event, component, direction);
}
component.on('mousewheel', mousewheel);
component.on('DOMMouseScroll', mousewheel); // For FF
controller.on('mousewheel', mousewheel);
controller.on('DOMMouseScroll', mousewheel); // For FF
// pinch
component.on('touch', function (event) {
me._onTouch();
controller.on('touch', function (event) {
me._onTouch(event);
});
component.on('pinch', function (event) {
controller.on('pinch', function (event) {
me._onPinch(event, component, direction);
});
}
@ -311,7 +317,7 @@ var touchParams = {};
Range.prototype._onDragStart = function(event, component) {
// refuse to drag when we where pinching to prevent the timeline make a jump
// when releasing the fingers in opposite order from the touch screen
if (touchParams.pinching) return;
if (touchParams.ignore) return;
touchParams.start = this.start;
touchParams.end = this.end;
@ -334,7 +340,7 @@ Range.prototype._onDrag = function (event, component, direction) {
// refuse to drag when we where pinching to prevent the timeline make a jump
// when releasing the fingers in opposite order from the touch screen
if (touchParams.pinching) return;
if (touchParams.ignore) return;
var delta = (direction == 'horizontal') ? event.gesture.deltaX : event.gesture.deltaY,
interval = (touchParams.end - touchParams.start),
@ -356,7 +362,7 @@ Range.prototype._onDrag = function (event, component, direction) {
Range.prototype._onDragEnd = function (event, component) {
// refuse to drag when we where pinching to prevent the timeline make a jump
// when releasing the fingers in opposite order from the touch screen
if (touchParams.pinching) return;
if (touchParams.ignore) return;
if (component.frame) {
component.frame.style.cursor = 'auto';
@ -417,14 +423,29 @@ Range.prototype._onMouseWheel = function(event, component, direction) {
};
/**
* On start of a touch gesture, initialize scale to 1
* Start of a touch gesture
* @private
*/
Range.prototype._onTouch = function () {
Range.prototype._onTouch = function (event) {
touchParams.start = this.start;
touchParams.end = this.end;
touchParams.pinching = false;
touchParams.ignore = false;
touchParams.center = null;
// don't move the range when dragging a selected event
// TODO: it's not so neat to have to know about the state of the ItemSet
var item = ItemSet.itemFromTarget(event);
if (item && item.selected) {
touchParams.ignore = true;
}
};
/**
* On start of a hold gesture
* @private
*/
Range.prototype._onHold = function () {
touchParams.ignore = true;
};
/**
@ -435,7 +456,7 @@ Range.prototype._onTouch = function () {
* @private
*/
Range.prototype._onPinch = function (event, component, direction) {
touchParams.pinching = true;
touchParams.ignore = true;
if (event.gesture.touches.length > 1) {
if (!touchParams.center) {

+ 7
- 7
src/timeline/Stack.js View File

@ -1,11 +1,11 @@
/**
* @constructor Stack
* Stacks items on top of each other.
* @param {ItemSet} parent
* @param {ItemSet} itemset
* @param {Object} [options]
*/
function Stack (parent, options) {
this.parent = parent;
function Stack (itemset, options) {
this.itemset = itemset;
this.options = options || {};
this.defaultOptions = {
@ -43,14 +43,14 @@ function Stack (parent, options) {
/**
* Set options for the stack
* @param {Object} options Available options:
* {ItemSet} parent
* {ItemSet} itemset
* {Number} margin
* {function} order Stacking order
*/
Stack.prototype.setOptions = function setOptions (options) {
util.extend(this.options, options);
// TODO: register on data changes at the connected parent itemset, and update the changed part only and immediately
// TODO: register on data changes at the connected itemset, and update the changed part only and immediately
};
/**
@ -70,9 +70,9 @@ Stack.prototype.update = function update() {
* @private
*/
Stack.prototype._order = function _order () {
var items = this.parent.items;
var items = this.itemset.items;
if (!items) {
throw new Error('Cannot stack items: parent does not contain items');
throw new Error('Cannot stack items: ItemSet does not contain items');
}
// TODO: store the sorted items, to have less work later on

+ 24
- 75
src/timeline/Timeline.js View File

@ -1,7 +1,7 @@
/**
* Create a timeline visualization
* @param {HTMLElement} container
* @param {vis.DataSet | Array | DataTable} [items]
* @param {vis.DataSet | Array | google.visualization.DataTable} [items]
* @param {Object} [options] See Timeline.setOptions for the available options.
* @constructor
*/
@ -45,6 +45,13 @@ function Timeline (container, items, options) {
this.rootPanel = new RootPanel(container, rootOptions);
this.controller.add(this.rootPanel);
// single select (or unselect) when tapping an item
// TODO: implement ctrl+click
this.controller.on('tap', this._onSelectItem.bind(this));
// multi select when holding mouse/touch, or on ctrl+click
this.controller.on('hold', this._onMultiSelectItem.bind(this));
// item panel
var itemOptions = Object.create(this.options);
itemOptions.left = function () {
@ -84,26 +91,20 @@ function Timeline (container, items, options) {
// TODO: reckon with options moveable and zoomable
// TODO: put the listeners in setOptions, be able to dynamically change with options moveable and zoomable
this.range.subscribe(this.rootPanel, 'move', 'horizontal');
this.range.subscribe(this.rootPanel, 'zoom', 'horizontal');
// TODO: enable moving again
this.range.subscribe(this.controller, this.rootPanel, 'move', 'horizontal');
this.range.subscribe(this.controller, this.rootPanel, 'zoom', 'horizontal');
this.range.on('rangechange', function (properties) {
var force = true;
me.controller.requestReflow(force);
me._trigger('rangechange', properties);
me.emit('rangechange', properties);
});
this.range.on('rangechanged', function (properties) {
var force = true;
me.controller.requestReflow(force);
me._trigger('rangechanged', properties);
me.emit('rangechanged', properties);
});
// single select (or unselect) when tapping an item
// TODO: implement ctrl+click
this.rootPanel.on('tap', this._onSelectItem.bind(this));
// multi select when holding mouse/touch, or on ctrl+click
this.rootPanel.on('hold', this._onMultiSelectItem.bind(this));
// time axis
var timeaxisOptions = Object.create(rootOptions);
timeaxisOptions.range = this.range;
@ -140,6 +141,9 @@ function Timeline (container, items, options) {
}
}
// extend Timeline with the Emitter mixin
Emitter(Timeline.prototype);
/**
* Set options
* @param {Object} options TODO: describe the available options
@ -173,7 +177,7 @@ Timeline.prototype.getCustomTime = function() {
/**
* Set items
* @param {vis.DataSet | Array | DataTable | null} items
* @param {vis.DataSet | Array | google.visualization.DataTable | null} items
*/
Timeline.prototype.setItems = function(items) {
var initialLoad = (this.itemsData == null);
@ -234,7 +238,7 @@ Timeline.prototype.setItems = function(items) {
/**
* Set groups
* @param {vis.DataSet | Array | DataTable} groups
* @param {vis.DataSet | Array | google.visualization.DataTable} groups
*/
Timeline.prototype.setGroups = function(groups) {
var me = this;
@ -367,56 +371,19 @@ Timeline.prototype.getSelection = function getSelection() {
return this.content ? this.content.getSelection() : [];
};
/**
* Add event listener
* @param {String} event Event name. Available events:
* 'rangechange', 'rangechanged', 'select'
* @param {function} callback Callback function, invoked as callback(properties)
* where properties is an optional object containing
* event specific properties.
*/
Timeline.prototype.on = function on (event, callback) {
var available = ['rangechange', 'rangechanged', 'select'];
if (available.indexOf(event) == -1) {
throw new Error('Unknown event "' + event + '". Choose from ' + available.join());
}
events.addListener(this, event, callback);
};
/**
* Remove an event listener
* @param {String} event Event name
* @param {function} callback Callback function
*/
Timeline.prototype.off = function off (event, callback) {
events.removeListener(this, event, callback);
};
/**
* Trigger an event
* @param {String} event Event name, available events: 'rangechange',
* 'rangechanged', 'select'
* @param {Object} [properties] Event specific properties
* @private
*/
Timeline.prototype._trigger = function _trigger(event, properties) {
events.trigger(this, event, properties || {});
};
/**
* Handle selecting/deselecting an item when tapping it
* @param {Event} event
* @private
*/
// TODO: move this function to ItemSet
Timeline.prototype._onSelectItem = function (event) {
var item = this._itemFromTarget(event);
var item = ItemSet.itemFromTarget(event);
var selection = item ? [item.id] : [];
this.setSelection(selection);
this._trigger('select', {
this.emit('select', {
items: this.getSelection()
});
@ -428,9 +395,10 @@ Timeline.prototype._onSelectItem = function (event) {
* @param {Event} event
* @private
*/
// TODO: move this function to ItemSet
Timeline.prototype._onMultiSelectItem = function (event) {
var selection,
item = this._itemFromTarget(event);
item = ItemSet.itemFromTarget(event);
if (!item) {
// do nothing...
@ -449,28 +417,9 @@ Timeline.prototype._onMultiSelectItem = function (event) {
}
this.setSelection(selection);
this._trigger('select', {
this.emit('select', {
items: this.getSelection()
});
event.stopPropagation();
};
/**
* Find an item from an event target:
* searches for the attribute 'timeline-item' in the event target's element tree
* @param {Event} event
* @return {Item | null| item
* @private
*/
Timeline.prototype._itemFromTarget = function _itemFromTarget (event) {
var target = event.target;
while (target) {
if (target.hasOwnProperty('timeline-item')) {
return target['timeline-item'];
}
target = target.parentNode;
}
return null;
};

+ 17
- 0
src/timeline/component/Component.js View File

@ -55,6 +55,23 @@ Component.prototype.getOption = function getOption(name) {
return value;
};
/**
* Set controller for this component, or remove current controller by passing
* null as parameter value.
* @param {Controller | null} controller
*/
Component.prototype.setController = function setController (controller) {
this.controller = controller || null;
};
/**
* Get controller of this component
* @return {Controller} controller
*/
Component.prototype.getController = function getController () {
return this.controller;
};
/**
* Get the container element of the component, which can be used by a child to
* add its own widgets. Not all components do have a container for childs, in

+ 181
- 0
src/timeline/component/ItemSet.js View File

@ -16,6 +16,13 @@ function ItemSet(parent, depends, options) {
this.parent = parent;
this.depends = depends;
// event listeners
this.eventListeners = {
dragstart: this._onDragStart.bind(this),
drag: this._onDrag.bind(this),
dragend: this._onDragEnd.bind(this)
};
// one options object is shared by this itemset and all its items
this.options = options || {};
this.defaultOptions = {
@ -35,6 +42,7 @@ function ItemSet(parent, depends, options) {
this.itemsData = null; // DataSet
this.range = null; // Range or Object {start: number, end: number}
// data change listeners
this.listeners = {
'add': function (event, params, senderId) {
if (senderId != me.id) {
@ -59,6 +67,8 @@ function ItemSet(parent, depends, options) {
this.stack = new Stack(this, Object.create(this.options));
this.conversion = null;
this.touchParams = {}; // stores properties while dragging
// TODO: ItemSet should also attach event listeners for rangechange and rangechanged, like timeaxis
}
@ -99,6 +109,55 @@ ItemSet.types = {
*/
ItemSet.prototype.setOptions = Component.prototype.setOptions;
/**
* Set controller for this component
* @param {Controller | null} controller
*/
ItemSet.prototype.setController = function setController (controller) {
var event;
// unregister old event listeners
if (this.controller) {
for (event in this.eventListeners) {
if (this.eventListeners.hasOwnProperty(event)) {
this.controller.off(event, this.eventListeners[event]);
}
}
}
this.controller = controller || null;
// register new event listeners
if (this.controller) {
for (event in this.eventListeners) {
if (this.eventListeners.hasOwnProperty(event)) {
this.controller.on(event, this.eventListeners[event]);
}
}
}
};
// attach event listeners for dragging items to the controller
(function (me) {
var _controller = null;
var _onDragStart = null;
var _onDrag = null;
var _onDragEnd = null;
Object.defineProperty(me, 'controller', {
get: function () {
return _controller;
},
set: function (controller) {
}
});
}) (this);
/**
* Set range (start and end).
* @param {Range | Object} range A Range or an object containing start and end.
@ -195,6 +254,7 @@ ItemSet.prototype.repaint = function repaint() {
if (!frame) {
frame = document.createElement('div');
frame.className = 'itemset';
frame['timeline-itemset'] = this;
var className = options.className;
if (className) {
@ -610,3 +670,124 @@ ItemSet.prototype.toScreen = function toScreen(time) {
var conversion = this.conversion;
return (time.valueOf() - conversion.offset) * conversion.scale;
};
/**
* Start dragging the selected events
* @param {Event} event
* @private
*/
ItemSet.prototype._onDragStart = function (event) {
var itemSet = ItemSet.itemSetFromTarget(event),
item = ItemSet.itemFromTarget(event),
me = this;
if (item && item.selected) {
this.touchParams.items = this.getSelection().map(function (id) {
return me.items[id];
});
event.stopPropagation();
}
};
/**
* Drag selected items
* @param {Event} event
* @private
*/
ItemSet.prototype._onDrag = function (event) {
if (this.touchParams.items) {
var deltaX = event.gesture.deltaX;
// adjust the offset of the items being dragged
this.touchParams.items.forEach(function (item) {
item.setOffset(deltaX);
});
// TODO: implement snapping to nice dates
// TODO: implement dragging from one group to another
this.requestReflow();
event.stopPropagation();
}
};
/**
* End of dragging selected items
* @param {Event} event
* @private
*/
ItemSet.prototype._onDragEnd = function (event) {
if (this.touchParams.items) {
var deltaX = event.gesture.deltaX,
scale = this.conversion.scale;
// prepare a changeset for the changed items
var changes = this.touchParams.items.map(function (item) {
item.setOffset(0);
var change = {
id: item.id
};
if ('start' in item.data) {
change.start = new Date(item.data.start.valueOf() + deltaX / scale);
}
if ('end' in item.data) {
change.end = new Date(item.data.end.valueOf() + deltaX / scale);
}
return change;
});
this.touchParams.items = null;
// find the root DataSet from our DataSet/DataView
var data = this.itemsData;
while (data instanceof DataView) {
data = data.data;
}
// apply the changes to the data
data.update(changes);
event.stopPropagation();
}
};
/**
* Find an item from an event target:
* searches for the attribute 'timeline-item' in the event target's element tree
* @param {Event} event
* @return {Item | null} item
*/
ItemSet.itemFromTarget = function itemFromTarget (event) {
var target = event.target;
while (target) {
if (target.hasOwnProperty('timeline-item')) {
return target['timeline-item'];
}
target = target.parentNode;
}
return null;
};
/**
* Find the ItemSet from an event target:
* searches for the attribute 'timeline-itemset' in the event target's element tree
* @param {Event} event
* @return {ItemSet | null} item
*/
ItemSet.itemSetFromTarget = function itemSetFromTarget (event) {
var target = event.target;
while (target) {
if (target.hasOwnProperty('timeline-itemset')) {
return target['timeline-itemset'];
}
target = target.parentNode;
}
return null;
};

+ 57
- 46
src/timeline/component/RootPanel.js View File

@ -10,12 +10,29 @@ function RootPanel(container, options) {
this.id = util.randomUUID();
this.container = container;
// create functions to be used as DOM event listeners
var me = this;
this.hammer = null;
// create listeners for all interesting events, these events will be emitted
// via the controller
var events = [
'touch', 'pinch', 'tap', 'hold',
'dragstart', 'drag', 'dragend',
'mousewheel', 'DOMMouseScroll' // DOMMouseScroll is for Firefox
];
this.listeners = {};
events.forEach(function (event) {
me.listeners[event] = function () {
var args = [event].concat(Array.prototype.slice.call(arguments, 0));
me.controller.emit.apply(me.controller, args);
};
});
this.options = options || {};
this.defaultOptions = {
autoResize: true
};
this.listeners = {}; // event listeners
}
RootPanel.prototype = new Panel();
@ -48,6 +65,8 @@ RootPanel.prototype.repaint = function () {
this.frame = frame;
this._registerListeners();
changed += 1;
}
if (!frame.parentNode) {
@ -69,7 +88,6 @@ RootPanel.prototype.repaint = function () {
changed += update(frame.style, 'width', asSize(options.width, '100%'));
changed += update(frame.style, 'height', asSize(options.height, '100%'));
this._updateEventEmitters();
this._updateWatch();
return (changed > 0);
@ -158,58 +176,51 @@ RootPanel.prototype._unwatch = function () {
};
/**
* Event handler
* @param {String} event name of the event, for example 'click', 'mousemove'
* @param {function} callback callback handler, invoked with the raw HTML Event
* as parameter.
* Set controller for this component, or remove current controller by passing
* null as parameter value.
* @param {Controller | null} controller
*/
RootPanel.prototype.on = function (event, callback) {
// register the listener at this component
var arr = this.listeners[event];
if (!arr) {
arr = [];
this.listeners[event] = arr;
}
arr.push(callback);
RootPanel.prototype.setController = function setController (controller) {
this.controller = controller || null;
this._updateEventEmitters();
if (this.controller) {
this._registerListeners();
}
else {
this._unregisterListeners();
}
};
/**
* Update the event listeners for all event emitters
* Register event emitters emitted by the rootpanel
* @private
*/
RootPanel.prototype._updateEventEmitters = function () {
if (this.listeners) {
var me = this;
util.forEach(this.listeners, function (listeners, event) {
if (!me.emitters) {
me.emitters = {};
RootPanel.prototype._registerListeners = function () {
if (this.frame && this.controller && !this.hammer) {
this.hammer = Hammer(this.frame, {
prevent_default: true
});
for (var event in this.listeners) {
if (this.listeners.hasOwnProperty(event)) {
this.hammer.on(event, this.listeners[event]);
}
if (!(event in me.emitters)) {
// create event
var frame = me.frame;
if (frame) {
//console.log('Created a listener for event ' + event + ' on component ' + me.id); // TODO: cleanup logging
var callback = function(event) {
listeners.forEach(function (listener) {
// TODO: filter on event target!
listener(event);
});
};
me.emitters[event] = callback;
if (!me.hammer) {
me.hammer = Hammer(frame, {
prevent_default: true
});
}
me.hammer.on(event, callback);
}
}
}
};
/**
* Unregister event emitters from the rootpanel
* @private
*/
RootPanel.prototype._unregisterListeners = function () {
if (this.hammer) {
for (var event in this.listeners) {
if (this.listeners.hasOwnProperty(event)) {
this.hammer.off(event, this.listeners[event]);
}
});
}
// TODO: be able to delete event listeners
// TODO: be able to move event listeners to a parent when available
this.hammer = null;
}
};

+ 11
- 2
src/timeline/component/item/Item.js View File

@ -20,6 +20,7 @@ function Item (parent, data, options, defaultOptions) {
this.left = 0;
this.width = 0;
this.height = 0;
this.offset = 0;
}
/**
@ -72,10 +73,18 @@ Item.prototype.reflow = function reflow() {
return false;
};
/**
* Give the item a display offset in pixels
* @param {Number} offset Offset on screen in pixels
*/
Item.prototype.setOffset = function setOffset(offset) {
this.offset = offset;
};
/**
* Return the items width
* @return {Integer} width
* @return {Number} width
*/
Item.prototype.getWidth = function getWidth() {
return this.width;
}
};

+ 1
- 1
src/timeline/component/item/ItemBox.js View File

@ -187,7 +187,7 @@ ItemBox.prototype.reflow = function reflow() {
update = util.updateProperty;
props = this.props;
options = this.options;
start = this.parent.toScreen(this.data.start);
start = this.parent.toScreen(this.data.start) + this.offset;
align = options.align || this.defaultOptions.align;
margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis;
orientation = options.orientation || this.defaultOptions.orientation;

+ 1
- 1
src/timeline/component/item/ItemPoint.js View File

@ -157,7 +157,7 @@ ItemPoint.prototype.reflow = function reflow() {
options = this.options;
orientation = options.orientation || this.defaultOptions.orientation;
margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis;
start = this.parent.toScreen(this.data.start);
start = this.parent.toScreen(this.data.start) + this.offset;
changed += update(this, 'width', dom.point.offsetWidth);
changed += update(this, 'height', dom.point.offsetHeight);

+ 2
- 2
src/timeline/component/item/ItemRange.js View File

@ -157,8 +157,8 @@ ItemRange.prototype.reflow = function reflow() {
props = this.props;
options = this.options;
parent = this.parent;
start = parent.toScreen(this.data.start);
end = parent.toScreen(this.data.end);
start = parent.toScreen(this.data.start) + this.offset;
end = parent.toScreen(this.data.end) + this.offset;
update = util.updateProperty;
box = dom.box;
parentWidth = parent.width;

Loading…
Cancel
Save