vis-rails 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/lib/vis/rails/version.rb +1 -1
- data/vendor/assets/component/emitter.js +162 -0
- data/vendor/assets/javascripts/vis.js +1 -0
- data/vendor/assets/vis/DataSet.js +8 -2
- data/vendor/assets/vis/DataView.js +8 -4
- data/vendor/assets/vis/graph/Edge.js +210 -78
- data/vendor/assets/vis/graph/Graph.js +474 -652
- data/vendor/assets/vis/graph/Node.js +119 -82
- data/vendor/assets/vis/graph/css/graph-manipulation.css +128 -0
- data/vendor/assets/vis/graph/css/graph-navigation.css +62 -0
- data/vendor/assets/vis/graph/graphMixins/ClusterMixin.js +1141 -0
- data/vendor/assets/vis/graph/graphMixins/HierarchicalLayoutMixin.js +296 -0
- data/vendor/assets/vis/graph/graphMixins/ManipulationMixin.js +433 -0
- data/vendor/assets/vis/graph/graphMixins/MixinLoader.js +201 -0
- data/vendor/assets/vis/graph/graphMixins/NavigationMixin.js +173 -0
- data/vendor/assets/vis/graph/graphMixins/SectorsMixin.js +552 -0
- data/vendor/assets/vis/graph/graphMixins/SelectionMixin.js +558 -0
- data/vendor/assets/vis/graph/graphMixins/physics/BarnesHut.js +373 -0
- data/vendor/assets/vis/graph/graphMixins/physics/HierarchialRepulsion.js +64 -0
- data/vendor/assets/vis/graph/graphMixins/physics/PhysicsMixin.js +513 -0
- data/vendor/assets/vis/graph/graphMixins/physics/Repulsion.js +66 -0
- data/vendor/assets/vis/graph/img/acceptDeleteIcon.png +0 -0
- data/vendor/assets/vis/graph/img/addNodeIcon.png +0 -0
- data/vendor/assets/vis/graph/img/backIcon.png +0 -0
- data/vendor/assets/vis/graph/img/connectIcon.png +0 -0
- data/vendor/assets/vis/graph/img/cross.png +0 -0
- data/vendor/assets/vis/graph/img/cross2.png +0 -0
- data/vendor/assets/vis/graph/img/deleteIcon.png +0 -0
- data/vendor/assets/vis/graph/img/downArrow.png +0 -0
- data/vendor/assets/vis/graph/img/editIcon.png +0 -0
- data/vendor/assets/vis/graph/img/leftArrow.png +0 -0
- data/vendor/assets/vis/graph/img/rightArrow.png +0 -0
- data/vendor/assets/vis/graph/img/upArrow.png +0 -0
- data/vendor/assets/vis/module/exports.js +0 -2
- data/vendor/assets/vis/module/header.js +2 -2
- data/vendor/assets/vis/module/imports.js +1 -2
- data/vendor/assets/vis/timeline/Controller.js +56 -45
- data/vendor/assets/vis/timeline/Range.js +68 -62
- data/vendor/assets/vis/timeline/Stack.js +11 -13
- data/vendor/assets/vis/timeline/TimeStep.js +43 -38
- data/vendor/assets/vis/timeline/Timeline.js +215 -93
- data/vendor/assets/vis/timeline/component/Component.js +19 -3
- data/vendor/assets/vis/timeline/component/CurrentTime.js +1 -1
- data/vendor/assets/vis/timeline/component/CustomTime.js +39 -120
- data/vendor/assets/vis/timeline/component/GroupSet.js +35 -1
- data/vendor/assets/vis/timeline/component/ItemSet.js +272 -9
- data/vendor/assets/vis/timeline/component/RootPanel.js +59 -47
- data/vendor/assets/vis/timeline/component/TimeAxis.js +10 -0
- data/vendor/assets/vis/timeline/component/css/item.css +53 -22
- data/vendor/assets/vis/timeline/component/item/Item.js +40 -5
- data/vendor/assets/vis/timeline/component/item/ItemBox.js +3 -1
- data/vendor/assets/vis/timeline/component/item/ItemPoint.js +3 -1
- data/vendor/assets/vis/timeline/component/item/ItemRange.js +67 -3
- data/vendor/assets/vis/timeline/component/item/ItemRangeOverflow.js +37 -9
- data/vendor/assets/vis/timeline/img/delete.png +0 -0
- data/vendor/assets/vis/util.js +169 -30
- metadata +39 -12
@@ -20,7 +20,6 @@ function Component () {
|
|
20
20
|
* set.
|
21
21
|
* @param {Object} options Available parameters:
|
22
22
|
* {String | function} [className]
|
23
|
-
* {EventBus} [eventBus]
|
24
23
|
* {String | Number | function} [left]
|
25
24
|
* {String | Number | function} [top]
|
26
25
|
* {String | Number | function} [width]
|
@@ -55,6 +54,23 @@ Component.prototype.getOption = function getOption(name) {
|
|
55
54
|
return value;
|
56
55
|
};
|
57
56
|
|
57
|
+
/**
|
58
|
+
* Set controller for this component, or remove current controller by passing
|
59
|
+
* null as parameter value.
|
60
|
+
* @param {Controller | null} controller
|
61
|
+
*/
|
62
|
+
Component.prototype.setController = function setController (controller) {
|
63
|
+
this.controller = controller || null;
|
64
|
+
};
|
65
|
+
|
66
|
+
/**
|
67
|
+
* Get controller of this component
|
68
|
+
* @return {Controller} controller
|
69
|
+
*/
|
70
|
+
Component.prototype.getController = function getController () {
|
71
|
+
return this.controller;
|
72
|
+
};
|
73
|
+
|
58
74
|
/**
|
59
75
|
* Get the container element of the component, which can be used by a child to
|
60
76
|
* add its own widgets. Not all components do have a container for childs, in
|
@@ -126,7 +142,7 @@ Component.prototype.show = function show() {
|
|
126
142
|
*/
|
127
143
|
Component.prototype.requestRepaint = function requestRepaint() {
|
128
144
|
if (this.controller) {
|
129
|
-
this.controller.
|
145
|
+
this.controller.emit('request-repaint');
|
130
146
|
}
|
131
147
|
else {
|
132
148
|
throw new Error('Cannot request a repaint: no controller configured');
|
@@ -139,7 +155,7 @@ Component.prototype.requestRepaint = function requestRepaint() {
|
|
139
155
|
*/
|
140
156
|
Component.prototype.requestReflow = function requestReflow() {
|
141
157
|
if (this.controller) {
|
142
|
-
this.controller.
|
158
|
+
this.controller.emit('request-reflow');
|
143
159
|
}
|
144
160
|
else {
|
145
161
|
throw new Error('Cannot request a reflow: no controller configured');
|
@@ -19,12 +19,14 @@ function CustomTime (parent, depends, options) {
|
|
19
19
|
showCustomTime: false
|
20
20
|
};
|
21
21
|
|
22
|
-
this.listeners = [];
|
23
22
|
this.customTime = new Date();
|
23
|
+
this.eventParams = {}; // stores state parameters while dragging the bar
|
24
24
|
}
|
25
25
|
|
26
26
|
CustomTime.prototype = new Component();
|
27
27
|
|
28
|
+
Emitter(CustomTime.prototype);
|
29
|
+
|
28
30
|
CustomTime.prototype.setOptions = Component.prototype.setOptions;
|
29
31
|
|
30
32
|
/**
|
@@ -42,13 +44,13 @@ CustomTime.prototype.getContainer = function () {
|
|
42
44
|
*/
|
43
45
|
CustomTime.prototype.repaint = function () {
|
44
46
|
var bar = this.frame,
|
45
|
-
parent = this.parent
|
46
|
-
parentContainer = parent.parent.getContainer();
|
47
|
+
parent = this.parent;
|
47
48
|
|
48
49
|
if (!parent) {
|
49
50
|
throw new Error('Cannot repaint bar: no parent attached');
|
50
51
|
}
|
51
52
|
|
53
|
+
var parentContainer = parent.parent.getContainer();
|
52
54
|
if (!parentContainer) {
|
53
55
|
throw new Error('Cannot repaint bar: parent has no container element');
|
54
56
|
}
|
@@ -59,7 +61,7 @@ CustomTime.prototype.repaint = function () {
|
|
59
61
|
delete this.frame;
|
60
62
|
}
|
61
63
|
|
62
|
-
return;
|
64
|
+
return false;
|
63
65
|
}
|
64
66
|
|
65
67
|
if (!bar) {
|
@@ -81,7 +83,13 @@ CustomTime.prototype.repaint = function () {
|
|
81
83
|
|
82
84
|
this.frame = bar;
|
83
85
|
|
84
|
-
|
86
|
+
// attach event listeners
|
87
|
+
this.hammer = Hammer(bar, {
|
88
|
+
prevent_default: true
|
89
|
+
});
|
90
|
+
this.hammer.on('dragstart', this._onDragStart.bind(this));
|
91
|
+
this.hammer.on('drag', this._onDrag.bind(this));
|
92
|
+
this.hammer.on('dragend', this._onDragEnd.bind(this));
|
85
93
|
}
|
86
94
|
|
87
95
|
if (!parent.conversion) {
|
@@ -100,7 +108,7 @@ CustomTime.prototype.repaint = function () {
|
|
100
108
|
* Set custom time.
|
101
109
|
* @param {Date} time
|
102
110
|
*/
|
103
|
-
CustomTime.prototype.
|
111
|
+
CustomTime.prototype.setCustomTime = function(time) {
|
104
112
|
this.customTime = new Date(time.valueOf());
|
105
113
|
this.repaint();
|
106
114
|
};
|
@@ -109,147 +117,58 @@ CustomTime.prototype._setCustomTime = function(time) {
|
|
109
117
|
* Retrieve the current custom time.
|
110
118
|
* @return {Date} customTime
|
111
119
|
*/
|
112
|
-
CustomTime.prototype.
|
120
|
+
CustomTime.prototype.getCustomTime = function() {
|
113
121
|
return new Date(this.customTime.valueOf());
|
114
122
|
};
|
115
123
|
|
116
|
-
/**
|
117
|
-
* Add listeners for mouse and touch events to the component
|
118
|
-
* @param {Component} component
|
119
|
-
*/
|
120
|
-
CustomTime.prototype.subscribe = function (component, event) {
|
121
|
-
var me = this;
|
122
|
-
var listener = {
|
123
|
-
component: component,
|
124
|
-
event: event,
|
125
|
-
callback: function (event) {
|
126
|
-
me._onMouseDown(event, listener);
|
127
|
-
},
|
128
|
-
params: {}
|
129
|
-
};
|
130
|
-
|
131
|
-
component.on('mousedown', listener.callback);
|
132
|
-
me.listeners.push(listener);
|
133
|
-
|
134
|
-
};
|
135
|
-
|
136
|
-
/**
|
137
|
-
* Event handler
|
138
|
-
* @param {String} event name of the event, for example 'click', 'mousemove'
|
139
|
-
* @param {function} callback callback handler, invoked with the raw HTML Event
|
140
|
-
* as parameter.
|
141
|
-
*/
|
142
|
-
CustomTime.prototype.on = function (event, callback) {
|
143
|
-
var bar = this.frame;
|
144
|
-
if (!bar) {
|
145
|
-
throw new Error('Cannot add event listener: no parent attached');
|
146
|
-
}
|
147
|
-
|
148
|
-
events.addListener(this, event, callback);
|
149
|
-
util.addEventListener(bar, event, callback);
|
150
|
-
};
|
151
|
-
|
152
124
|
/**
|
153
125
|
* Start moving horizontally
|
154
126
|
* @param {Event} event
|
155
|
-
* @param {Object} listener Listener containing the component and params
|
156
127
|
* @private
|
157
128
|
*/
|
158
|
-
CustomTime.prototype.
|
159
|
-
|
160
|
-
var params = listener.params;
|
161
|
-
|
162
|
-
// only react on left mouse button down
|
163
|
-
var leftButtonDown = event.which ? (event.which == 1) : (event.button == 1);
|
164
|
-
if (!leftButtonDown) {
|
165
|
-
return;
|
166
|
-
}
|
167
|
-
|
168
|
-
// get mouse position
|
169
|
-
params.mouseX = util.getPageX(event);
|
170
|
-
params.moved = false;
|
171
|
-
|
172
|
-
params.customTime = this.customTime;
|
173
|
-
|
174
|
-
// add event listeners to handle moving the custom time bar
|
175
|
-
var me = this;
|
176
|
-
if (!params.onMouseMove) {
|
177
|
-
params.onMouseMove = function (event) {
|
178
|
-
me._onMouseMove(event, listener);
|
179
|
-
};
|
180
|
-
util.addEventListener(document, 'mousemove', params.onMouseMove);
|
181
|
-
}
|
182
|
-
if (!params.onMouseUp) {
|
183
|
-
params.onMouseUp = function (event) {
|
184
|
-
me._onMouseUp(event, listener);
|
185
|
-
};
|
186
|
-
util.addEventListener(document, 'mouseup', params.onMouseUp);
|
187
|
-
}
|
129
|
+
CustomTime.prototype._onDragStart = function(event) {
|
130
|
+
this.eventParams.customTime = this.customTime;
|
188
131
|
|
189
|
-
|
190
|
-
|
132
|
+
event.stopPropagation();
|
133
|
+
event.preventDefault();
|
191
134
|
};
|
192
135
|
|
193
136
|
/**
|
194
137
|
* Perform moving operating.
|
195
|
-
* This function activated from within the funcion CustomTime._onMouseDown().
|
196
138
|
* @param {Event} event
|
197
|
-
* @param {Object} listener
|
198
139
|
* @private
|
199
140
|
*/
|
200
|
-
CustomTime.prototype.
|
201
|
-
|
202
|
-
|
203
|
-
|
141
|
+
CustomTime.prototype._onDrag = function (event) {
|
142
|
+
var deltaX = event.gesture.deltaX,
|
143
|
+
x = this.parent.toScreen(this.eventParams.customTime) + deltaX,
|
144
|
+
time = this.parent.toTime(x);
|
204
145
|
|
205
|
-
|
206
|
-
var mouseX = util.getPageX(event);
|
207
|
-
|
208
|
-
if (params.mouseX === undefined) {
|
209
|
-
params.mouseX = mouseX;
|
210
|
-
}
|
211
|
-
|
212
|
-
var diff = mouseX - params.mouseX;
|
213
|
-
|
214
|
-
// if mouse movement is big enough, register it as a "moved" event
|
215
|
-
if (Math.abs(diff) >= 1) {
|
216
|
-
params.moved = true;
|
217
|
-
}
|
218
|
-
|
219
|
-
var x = parent.toScreen(params.customTime);
|
220
|
-
var xnew = x + diff;
|
221
|
-
var time = parent.toTime(xnew);
|
222
|
-
this._setCustomTime(time);
|
146
|
+
this.setCustomTime(time);
|
223
147
|
|
224
148
|
// fire a timechange event
|
225
|
-
|
149
|
+
if (this.controller) {
|
150
|
+
this.controller.emit('timechange', {
|
151
|
+
time: this.customTime
|
152
|
+
})
|
153
|
+
}
|
226
154
|
|
227
|
-
|
155
|
+
event.stopPropagation();
|
156
|
+
event.preventDefault();
|
228
157
|
};
|
229
158
|
|
230
159
|
/**
|
231
160
|
* Stop moving operating.
|
232
|
-
* This function activated from within the function CustomTime._onMouseDown().
|
233
161
|
* @param {event} event
|
234
|
-
* @param {Object} listener
|
235
162
|
* @private
|
236
163
|
*/
|
237
|
-
CustomTime.prototype.
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
util.removeEventListener(document, 'mousemove', params.onMouseMove);
|
244
|
-
params.onMouseMove = null;
|
245
|
-
}
|
246
|
-
if (params.onMouseUp) {
|
247
|
-
util.removeEventListener(document, 'mouseup', params.onMouseUp);
|
248
|
-
params.onMouseUp = null;
|
164
|
+
CustomTime.prototype._onDragEnd = function (event) {
|
165
|
+
// fire a timechanged event
|
166
|
+
if (this.controller) {
|
167
|
+
this.controller.emit('timechanged', {
|
168
|
+
time: this.customTime
|
169
|
+
})
|
249
170
|
}
|
250
171
|
|
251
|
-
|
252
|
-
|
253
|
-
events.trigger(this, 'timechanged', {customTime: this.customTime});
|
254
|
-
}
|
172
|
+
event.stopPropagation();
|
173
|
+
event.preventDefault();
|
255
174
|
};
|
@@ -132,7 +132,7 @@ GroupSet.prototype.setGroups = function setGroups(groups) {
|
|
132
132
|
// subscribe to new dataset
|
133
133
|
var id = this.id;
|
134
134
|
util.forEach(this.listeners, function (callback, event) {
|
135
|
-
me.groupsData.
|
135
|
+
me.groupsData.on(event, callback, id);
|
136
136
|
});
|
137
137
|
|
138
138
|
// draw all new groups
|
@@ -216,6 +216,7 @@ GroupSet.prototype.repaint = function repaint() {
|
|
216
216
|
if (!frame) {
|
217
217
|
frame = document.createElement('div');
|
218
218
|
frame.className = 'groupset';
|
219
|
+
frame['timeline-groupset'] = this;
|
219
220
|
this.dom.frame = frame;
|
220
221
|
|
221
222
|
var className = options.className;
|
@@ -544,3 +545,36 @@ GroupSet.prototype._toQueue = function _toQueue(ids, action) {
|
|
544
545
|
this.requestRepaint();
|
545
546
|
}
|
546
547
|
};
|
548
|
+
|
549
|
+
/**
|
550
|
+
* Find the Group from an event target:
|
551
|
+
* searches for the attribute 'timeline-groupset' in the event target's element
|
552
|
+
* tree, then finds the right group in this groupset
|
553
|
+
* @param {Event} event
|
554
|
+
* @return {Group | null} group
|
555
|
+
*/
|
556
|
+
GroupSet.groupFromTarget = function groupFromTarget (event) {
|
557
|
+
var groupset,
|
558
|
+
target = event.target;
|
559
|
+
|
560
|
+
while (target) {
|
561
|
+
if (target.hasOwnProperty('timeline-groupset')) {
|
562
|
+
groupset = target['timeline-groupset'];
|
563
|
+
break;
|
564
|
+
}
|
565
|
+
target = target.parentNode;
|
566
|
+
}
|
567
|
+
|
568
|
+
if (groupset) {
|
569
|
+
for (var groupId in groupset.groups) {
|
570
|
+
if (groupset.groups.hasOwnProperty(groupId)) {
|
571
|
+
var group = groupset.groups[groupId];
|
572
|
+
if (group.itemset && ItemSet.itemSetFromTarget(event) == group.itemset) {
|
573
|
+
return group;
|
574
|
+
}
|
575
|
+
}
|
576
|
+
}
|
577
|
+
}
|
578
|
+
|
579
|
+
return null;
|
580
|
+
};
|
@@ -16,6 +16,13 @@ function ItemSet(parent, depends, options) {
|
|
16
16
|
this.parent = parent;
|
17
17
|
this.depends = depends;
|
18
18
|
|
19
|
+
// event listeners
|
20
|
+
this.eventListeners = {
|
21
|
+
dragstart: this._onDragStart.bind(this),
|
22
|
+
drag: this._onDrag.bind(this),
|
23
|
+
dragend: this._onDragEnd.bind(this)
|
24
|
+
};
|
25
|
+
|
19
26
|
// one options object is shared by this itemset and all its items
|
20
27
|
this.options = options || {};
|
21
28
|
this.defaultOptions = {
|
@@ -35,6 +42,7 @@ function ItemSet(parent, depends, options) {
|
|
35
42
|
this.itemsData = null; // DataSet
|
36
43
|
this.range = null; // Range or Object {start: number, end: number}
|
37
44
|
|
45
|
+
// data change listeners
|
38
46
|
this.listeners = {
|
39
47
|
'add': function (event, params, senderId) {
|
40
48
|
if (senderId != me.id) {
|
@@ -59,6 +67,8 @@ function ItemSet(parent, depends, options) {
|
|
59
67
|
this.stack = new Stack(this, Object.create(this.options));
|
60
68
|
this.conversion = null;
|
61
69
|
|
70
|
+
this.touchParams = {}; // stores properties while dragging
|
71
|
+
|
62
72
|
// TODO: ItemSet should also attach event listeners for rangechange and rangechanged, like timeaxis
|
63
73
|
}
|
64
74
|
|
@@ -96,9 +106,61 @@ ItemSet.types = {
|
|
96
106
|
* {Number} padding
|
97
107
|
* Padding of the contents of an item in pixels.
|
98
108
|
* Must correspond with the items css. Default is 5.
|
109
|
+
* {Function} snap
|
110
|
+
* Function to let items snap to nice dates when
|
111
|
+
* dragging items.
|
99
112
|
*/
|
100
113
|
ItemSet.prototype.setOptions = Component.prototype.setOptions;
|
101
114
|
|
115
|
+
|
116
|
+
|
117
|
+
/**
|
118
|
+
* Set controller for this component
|
119
|
+
* @param {Controller | null} controller
|
120
|
+
*/
|
121
|
+
ItemSet.prototype.setController = function setController (controller) {
|
122
|
+
var event;
|
123
|
+
|
124
|
+
// unregister old event listeners
|
125
|
+
if (this.controller) {
|
126
|
+
for (event in this.eventListeners) {
|
127
|
+
if (this.eventListeners.hasOwnProperty(event)) {
|
128
|
+
this.controller.off(event, this.eventListeners[event]);
|
129
|
+
}
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
this.controller = controller || null;
|
134
|
+
|
135
|
+
// register new event listeners
|
136
|
+
if (this.controller) {
|
137
|
+
for (event in this.eventListeners) {
|
138
|
+
if (this.eventListeners.hasOwnProperty(event)) {
|
139
|
+
this.controller.on(event, this.eventListeners[event]);
|
140
|
+
}
|
141
|
+
}
|
142
|
+
}
|
143
|
+
};
|
144
|
+
|
145
|
+
// attach event listeners for dragging items to the controller
|
146
|
+
(function (me) {
|
147
|
+
var _controller = null;
|
148
|
+
var _onDragStart = null;
|
149
|
+
var _onDrag = null;
|
150
|
+
var _onDragEnd = null;
|
151
|
+
|
152
|
+
Object.defineProperty(me, 'controller', {
|
153
|
+
get: function () {
|
154
|
+
return _controller;
|
155
|
+
},
|
156
|
+
|
157
|
+
set: function (controller) {
|
158
|
+
|
159
|
+
}
|
160
|
+
});
|
161
|
+
}) (this);
|
162
|
+
|
163
|
+
|
102
164
|
/**
|
103
165
|
* Set range (start and end).
|
104
166
|
* @param {Range | Object} range A Range or an object containing start and end.
|
@@ -144,12 +206,6 @@ ItemSet.prototype.setSelection = function setSelection(ids) {
|
|
144
206
|
}
|
145
207
|
}
|
146
208
|
|
147
|
-
// trigger a select event
|
148
|
-
selection = this.selection.concat([]);
|
149
|
-
events.trigger(this, 'select', {
|
150
|
-
ids: selection
|
151
|
-
});
|
152
|
-
|
153
209
|
if (this.controller) {
|
154
210
|
this.requestRepaint();
|
155
211
|
}
|
@@ -195,6 +251,7 @@ ItemSet.prototype.repaint = function repaint() {
|
|
195
251
|
if (!frame) {
|
196
252
|
frame = document.createElement('div');
|
197
253
|
frame.className = 'itemset';
|
254
|
+
frame['timeline-itemset'] = this;
|
198
255
|
|
199
256
|
var className = options.className;
|
200
257
|
if (className) {
|
@@ -389,8 +446,8 @@ ItemSet.prototype.getAxis = function getAxis() {
|
|
389
446
|
ItemSet.prototype.reflow = function reflow () {
|
390
447
|
var changed = 0,
|
391
448
|
options = this.options,
|
392
|
-
marginAxis = options.margin && options.margin.axis
|
393
|
-
marginItem = options.margin && options.margin.item
|
449
|
+
marginAxis = (options.margin && 'axis' in options.margin) ? options.margin.axis : this.defaultOptions.margin.axis,
|
450
|
+
marginItem = (options.margin && 'item' in options.margin) ? options.margin.item : this.defaultOptions.margin.item,
|
394
451
|
update = util.updateProperty,
|
395
452
|
asNumber = util.option.asNumber,
|
396
453
|
asSize = util.option.asSize,
|
@@ -501,7 +558,7 @@ ItemSet.prototype.setItems = function setItems(items) {
|
|
501
558
|
// subscribe to new dataset
|
502
559
|
var id = this.id;
|
503
560
|
util.forEach(this.listeners, function (callback, event) {
|
504
|
-
me.itemsData.
|
561
|
+
me.itemsData.on(event, callback, id);
|
505
562
|
});
|
506
563
|
|
507
564
|
// draw all new items
|
@@ -518,6 +575,24 @@ ItemSet.prototype.getItems = function getItems() {
|
|
518
575
|
return this.itemsData;
|
519
576
|
};
|
520
577
|
|
578
|
+
/**
|
579
|
+
* Remove an item by its id
|
580
|
+
* @param {String | Number} id
|
581
|
+
*/
|
582
|
+
ItemSet.prototype.removeItem = function removeItem (id) {
|
583
|
+
var item = this.itemsData.get(id),
|
584
|
+
dataset = this._myDataSet();
|
585
|
+
|
586
|
+
if (item) {
|
587
|
+
// confirm deletion
|
588
|
+
this.options.onRemove(item, function (item) {
|
589
|
+
if (item) {
|
590
|
+
dataset.remove(item);
|
591
|
+
}
|
592
|
+
});
|
593
|
+
}
|
594
|
+
};
|
595
|
+
|
521
596
|
/**
|
522
597
|
* Handle updated items
|
523
598
|
* @param {Number[]} ids
|
@@ -610,3 +685,191 @@ ItemSet.prototype.toScreen = function toScreen(time) {
|
|
610
685
|
var conversion = this.conversion;
|
611
686
|
return (time.valueOf() - conversion.offset) * conversion.scale;
|
612
687
|
};
|
688
|
+
|
689
|
+
/**
|
690
|
+
* Start dragging the selected events
|
691
|
+
* @param {Event} event
|
692
|
+
* @private
|
693
|
+
*/
|
694
|
+
ItemSet.prototype._onDragStart = function (event) {
|
695
|
+
if (!this.options.editable) {
|
696
|
+
return;
|
697
|
+
}
|
698
|
+
|
699
|
+
var item = ItemSet.itemFromTarget(event),
|
700
|
+
me = this;
|
701
|
+
|
702
|
+
if (item && item.selected) {
|
703
|
+
var dragLeftItem = event.target.dragLeftItem;
|
704
|
+
var dragRightItem = event.target.dragRightItem;
|
705
|
+
|
706
|
+
if (dragLeftItem) {
|
707
|
+
this.touchParams.itemProps = [{
|
708
|
+
item: dragLeftItem,
|
709
|
+
start: item.data.start.valueOf()
|
710
|
+
}];
|
711
|
+
}
|
712
|
+
else if (dragRightItem) {
|
713
|
+
this.touchParams.itemProps = [{
|
714
|
+
item: dragRightItem,
|
715
|
+
end: item.data.end.valueOf()
|
716
|
+
}];
|
717
|
+
}
|
718
|
+
else {
|
719
|
+
this.touchParams.itemProps = this.getSelection().map(function (id) {
|
720
|
+
var item = me.items[id];
|
721
|
+
var props = {
|
722
|
+
item: item
|
723
|
+
};
|
724
|
+
|
725
|
+
if ('start' in item.data) {
|
726
|
+
props.start = item.data.start.valueOf()
|
727
|
+
}
|
728
|
+
if ('end' in item.data) {
|
729
|
+
props.end = item.data.end.valueOf()
|
730
|
+
}
|
731
|
+
|
732
|
+
return props;
|
733
|
+
});
|
734
|
+
}
|
735
|
+
|
736
|
+
event.stopPropagation();
|
737
|
+
}
|
738
|
+
};
|
739
|
+
|
740
|
+
/**
|
741
|
+
* Drag selected items
|
742
|
+
* @param {Event} event
|
743
|
+
* @private
|
744
|
+
*/
|
745
|
+
ItemSet.prototype._onDrag = function (event) {
|
746
|
+
if (this.touchParams.itemProps) {
|
747
|
+
var snap = this.options.snap || null,
|
748
|
+
deltaX = event.gesture.deltaX,
|
749
|
+
offset = deltaX / this.conversion.scale;
|
750
|
+
|
751
|
+
// move
|
752
|
+
this.touchParams.itemProps.forEach(function (props) {
|
753
|
+
if ('start' in props) {
|
754
|
+
var start = new Date(props.start + offset);
|
755
|
+
props.item.data.start = snap ? snap(start) : start;
|
756
|
+
}
|
757
|
+
if ('end' in props) {
|
758
|
+
var end = new Date(props.end + offset);
|
759
|
+
props.item.data.end = snap ? snap(end) : end;
|
760
|
+
}
|
761
|
+
});
|
762
|
+
|
763
|
+
// TODO: implement onMoving handler
|
764
|
+
|
765
|
+
// TODO: implement dragging from one group to another
|
766
|
+
|
767
|
+
this.requestReflow();
|
768
|
+
|
769
|
+
event.stopPropagation();
|
770
|
+
}
|
771
|
+
};
|
772
|
+
|
773
|
+
/**
|
774
|
+
* End of dragging selected items
|
775
|
+
* @param {Event} event
|
776
|
+
* @private
|
777
|
+
*/
|
778
|
+
ItemSet.prototype._onDragEnd = function (event) {
|
779
|
+
if (this.touchParams.itemProps) {
|
780
|
+
// prepare a change set for the changed items
|
781
|
+
var changes = [],
|
782
|
+
me = this,
|
783
|
+
dataset = this._myDataSet(),
|
784
|
+
type;
|
785
|
+
|
786
|
+
this.touchParams.itemProps.forEach(function (props) {
|
787
|
+
var id = props.item.id,
|
788
|
+
item = me.itemsData.get(id);
|
789
|
+
|
790
|
+
var changed = false;
|
791
|
+
if ('start' in props.item.data) {
|
792
|
+
changed = (props.start != props.item.data.start.valueOf());
|
793
|
+
item.start = util.convert(props.item.data.start, dataset.convert['start']);
|
794
|
+
}
|
795
|
+
if ('end' in props.item.data) {
|
796
|
+
changed = changed || (props.end != props.item.data.end.valueOf());
|
797
|
+
item.end = util.convert(props.item.data.end, dataset.convert['end']);
|
798
|
+
}
|
799
|
+
|
800
|
+
// only apply changes when start or end is actually changed
|
801
|
+
if (changed) {
|
802
|
+
me.options.onMove(item, function (item) {
|
803
|
+
if (item) {
|
804
|
+
// apply changes
|
805
|
+
changes.push(item);
|
806
|
+
}
|
807
|
+
else {
|
808
|
+
// restore original values
|
809
|
+
if ('start' in props) props.item.data.start = props.start;
|
810
|
+
if ('end' in props) props.item.data.end = props.end;
|
811
|
+
me.requestReflow();
|
812
|
+
}
|
813
|
+
});
|
814
|
+
}
|
815
|
+
});
|
816
|
+
this.touchParams.itemProps = null;
|
817
|
+
|
818
|
+
// apply the changes to the data (if there are changes)
|
819
|
+
if (changes.length) {
|
820
|
+
dataset.update(changes);
|
821
|
+
}
|
822
|
+
|
823
|
+
event.stopPropagation();
|
824
|
+
}
|
825
|
+
};
|
826
|
+
|
827
|
+
/**
|
828
|
+
* Find an item from an event target:
|
829
|
+
* searches for the attribute 'timeline-item' in the event target's element tree
|
830
|
+
* @param {Event} event
|
831
|
+
* @return {Item | null} item
|
832
|
+
*/
|
833
|
+
ItemSet.itemFromTarget = function itemFromTarget (event) {
|
834
|
+
var target = event.target;
|
835
|
+
while (target) {
|
836
|
+
if (target.hasOwnProperty('timeline-item')) {
|
837
|
+
return target['timeline-item'];
|
838
|
+
}
|
839
|
+
target = target.parentNode;
|
840
|
+
}
|
841
|
+
|
842
|
+
return null;
|
843
|
+
};
|
844
|
+
|
845
|
+
/**
|
846
|
+
* Find the ItemSet from an event target:
|
847
|
+
* searches for the attribute 'timeline-itemset' in the event target's element tree
|
848
|
+
* @param {Event} event
|
849
|
+
* @return {ItemSet | null} item
|
850
|
+
*/
|
851
|
+
ItemSet.itemSetFromTarget = function itemSetFromTarget (event) {
|
852
|
+
var target = event.target;
|
853
|
+
while (target) {
|
854
|
+
if (target.hasOwnProperty('timeline-itemset')) {
|
855
|
+
return target['timeline-itemset'];
|
856
|
+
}
|
857
|
+
target = target.parentNode;
|
858
|
+
}
|
859
|
+
|
860
|
+
return null;
|
861
|
+
};
|
862
|
+
|
863
|
+
/**
|
864
|
+
* Find the DataSet to which this ItemSet is connected
|
865
|
+
* @returns {null | DataSet} dataset
|
866
|
+
* @private
|
867
|
+
*/
|
868
|
+
ItemSet.prototype._myDataSet = function _myDataSet() {
|
869
|
+
// find the root DataSet
|
870
|
+
var dataset = this.itemsData;
|
871
|
+
while (dataset instanceof DataView) {
|
872
|
+
dataset = dataset.data;
|
873
|
+
}
|
874
|
+
return dataset;
|
875
|
+
};
|