vis-rails 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
};
|