vis-rails 2.0.0 → 2.0.1
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 +4 -4
- data/lib/vis/rails/version.rb +1 -1
- data/vendor/assets/javascripts/vis.js +26 -26
- metadata +16 -85
- data/vendor/assets/vis/DataSet.js +0 -926
- data/vendor/assets/vis/DataView.js +0 -283
- data/vendor/assets/vis/graph/Edge.js +0 -957
- data/vendor/assets/vis/graph/Graph.js +0 -2291
- data/vendor/assets/vis/graph/Groups.js +0 -80
- data/vendor/assets/vis/graph/Images.js +0 -41
- data/vendor/assets/vis/graph/Node.js +0 -966
- data/vendor/assets/vis/graph/Popup.js +0 -132
- data/vendor/assets/vis/graph/css/graph-manipulation.css +0 -128
- data/vendor/assets/vis/graph/css/graph-navigation.css +0 -66
- data/vendor/assets/vis/graph/dotparser.js +0 -829
- data/vendor/assets/vis/graph/graphMixins/ClusterMixin.js +0 -1143
- data/vendor/assets/vis/graph/graphMixins/HierarchicalLayoutMixin.js +0 -311
- data/vendor/assets/vis/graph/graphMixins/ManipulationMixin.js +0 -576
- data/vendor/assets/vis/graph/graphMixins/MixinLoader.js +0 -199
- data/vendor/assets/vis/graph/graphMixins/NavigationMixin.js +0 -205
- data/vendor/assets/vis/graph/graphMixins/SectorsMixin.js +0 -552
- data/vendor/assets/vis/graph/graphMixins/SelectionMixin.js +0 -648
- data/vendor/assets/vis/graph/graphMixins/physics/BarnesHut.js +0 -398
- data/vendor/assets/vis/graph/graphMixins/physics/HierarchialRepulsion.js +0 -64
- data/vendor/assets/vis/graph/graphMixins/physics/PhysicsMixin.js +0 -697
- data/vendor/assets/vis/graph/graphMixins/physics/Repulsion.js +0 -66
- 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/minus.png +0 -0
- data/vendor/assets/vis/graph/img/plus.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/graph/img/zoomExtends.png +0 -0
- data/vendor/assets/vis/graph/shapes.js +0 -225
- data/vendor/assets/vis/graph3d/Graph3d.js +0 -3306
- data/vendor/assets/vis/module/exports.js +0 -65
- data/vendor/assets/vis/module/header.js +0 -24
- data/vendor/assets/vis/module/imports.js +0 -31
- data/vendor/assets/vis/shim.js +0 -252
- data/vendor/assets/vis/timeline/Range.js +0 -532
- data/vendor/assets/vis/timeline/TimeStep.js +0 -466
- data/vendor/assets/vis/timeline/Timeline.js +0 -851
- data/vendor/assets/vis/timeline/component/Component.js +0 -52
- data/vendor/assets/vis/timeline/component/CurrentTime.js +0 -128
- data/vendor/assets/vis/timeline/component/CustomTime.js +0 -182
- data/vendor/assets/vis/timeline/component/Group.js +0 -470
- data/vendor/assets/vis/timeline/component/ItemSet.js +0 -1332
- data/vendor/assets/vis/timeline/component/TimeAxis.js +0 -389
- data/vendor/assets/vis/timeline/component/css/animation.css +0 -33
- data/vendor/assets/vis/timeline/component/css/currenttime.css +0 -5
- data/vendor/assets/vis/timeline/component/css/customtime.css +0 -6
- data/vendor/assets/vis/timeline/component/css/item.css +0 -107
- data/vendor/assets/vis/timeline/component/css/itemset.css +0 -33
- data/vendor/assets/vis/timeline/component/css/labelset.css +0 -36
- data/vendor/assets/vis/timeline/component/css/panel.css +0 -71
- data/vendor/assets/vis/timeline/component/css/timeaxis.css +0 -48
- data/vendor/assets/vis/timeline/component/css/timeline.css +0 -2
- data/vendor/assets/vis/timeline/component/item/Item.js +0 -139
- data/vendor/assets/vis/timeline/component/item/ItemBox.js +0 -230
- data/vendor/assets/vis/timeline/component/item/ItemPoint.js +0 -190
- data/vendor/assets/vis/timeline/component/item/ItemRange.js +0 -262
- data/vendor/assets/vis/timeline/component/item/ItemRangeOverflow.js +0 -57
- data/vendor/assets/vis/timeline/img/delete.png +0 -0
- data/vendor/assets/vis/timeline/stack.js +0 -112
- data/vendor/assets/vis/util.js +0 -990
@@ -1,1332 +0,0 @@
|
|
1
|
-
var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items
|
2
|
-
|
3
|
-
/**
|
4
|
-
* An ItemSet holds a set of items and ranges which can be displayed in a
|
5
|
-
* range. The width is determined by the parent of the ItemSet, and the height
|
6
|
-
* is determined by the size of the items.
|
7
|
-
* @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} body
|
8
|
-
* @param {Object} [options] See ItemSet.setOptions for the available options.
|
9
|
-
* @constructor ItemSet
|
10
|
-
* @extends Component
|
11
|
-
*/
|
12
|
-
function ItemSet(body, options) {
|
13
|
-
this.body = body;
|
14
|
-
|
15
|
-
this.defaultOptions = {
|
16
|
-
type: 'box',
|
17
|
-
orientation: 'bottom', // 'top' or 'bottom'
|
18
|
-
align: 'center', // alignment of box items
|
19
|
-
stack: true,
|
20
|
-
groupOrder: null,
|
21
|
-
|
22
|
-
selectable: true,
|
23
|
-
editable: {
|
24
|
-
updateTime: false,
|
25
|
-
updateGroup: false,
|
26
|
-
add: false,
|
27
|
-
remove: false
|
28
|
-
},
|
29
|
-
|
30
|
-
onAdd: function (item, callback) {
|
31
|
-
callback(item);
|
32
|
-
},
|
33
|
-
onUpdate: function (item, callback) {
|
34
|
-
callback(item);
|
35
|
-
},
|
36
|
-
onMove: function (item, callback) {
|
37
|
-
callback(item);
|
38
|
-
},
|
39
|
-
onRemove: function (item, callback) {
|
40
|
-
callback(item);
|
41
|
-
},
|
42
|
-
|
43
|
-
margin: {
|
44
|
-
item: 10,
|
45
|
-
axis: 20
|
46
|
-
},
|
47
|
-
padding: 5
|
48
|
-
};
|
49
|
-
|
50
|
-
// options is shared by this ItemSet and all its items
|
51
|
-
this.options = util.extend({}, this.defaultOptions);
|
52
|
-
|
53
|
-
// options for getting items from the DataSet with the correct type
|
54
|
-
this.itemOptions = {
|
55
|
-
type: {start: 'Date', end: 'Date'}
|
56
|
-
};
|
57
|
-
|
58
|
-
this.conversion = {
|
59
|
-
toScreen: body.util.toScreen,
|
60
|
-
toTime: body.util.toTime
|
61
|
-
};
|
62
|
-
this.dom = {};
|
63
|
-
this.props = {};
|
64
|
-
this.hammer = null;
|
65
|
-
|
66
|
-
var me = this;
|
67
|
-
this.itemsData = null; // DataSet
|
68
|
-
this.groupsData = null; // DataSet
|
69
|
-
|
70
|
-
// listeners for the DataSet of the items
|
71
|
-
this.itemListeners = {
|
72
|
-
'add': function (event, params, senderId) {
|
73
|
-
me._onAdd(params.items);
|
74
|
-
},
|
75
|
-
'update': function (event, params, senderId) {
|
76
|
-
me._onUpdate(params.items);
|
77
|
-
},
|
78
|
-
'remove': function (event, params, senderId) {
|
79
|
-
me._onRemove(params.items);
|
80
|
-
}
|
81
|
-
};
|
82
|
-
|
83
|
-
// listeners for the DataSet of the groups
|
84
|
-
this.groupListeners = {
|
85
|
-
'add': function (event, params, senderId) {
|
86
|
-
me._onAddGroups(params.items);
|
87
|
-
},
|
88
|
-
'update': function (event, params, senderId) {
|
89
|
-
me._onUpdateGroups(params.items);
|
90
|
-
},
|
91
|
-
'remove': function (event, params, senderId) {
|
92
|
-
me._onRemoveGroups(params.items);
|
93
|
-
}
|
94
|
-
};
|
95
|
-
|
96
|
-
this.items = {}; // object with an Item for every data item
|
97
|
-
this.groups = {}; // Group object for every group
|
98
|
-
this.groupIds = [];
|
99
|
-
|
100
|
-
this.selection = []; // list with the ids of all selected nodes
|
101
|
-
this.stackDirty = true; // if true, all items will be restacked on next redraw
|
102
|
-
|
103
|
-
this.touchParams = {}; // stores properties while dragging
|
104
|
-
// create the HTML DOM
|
105
|
-
|
106
|
-
this._create();
|
107
|
-
|
108
|
-
this.setOptions(options);
|
109
|
-
}
|
110
|
-
|
111
|
-
ItemSet.prototype = new Component();
|
112
|
-
|
113
|
-
// available item types will be registered here
|
114
|
-
ItemSet.types = {
|
115
|
-
box: ItemBox,
|
116
|
-
range: ItemRange,
|
117
|
-
rangeoverflow: ItemRangeOverflow,
|
118
|
-
point: ItemPoint
|
119
|
-
};
|
120
|
-
|
121
|
-
/**
|
122
|
-
* Create the HTML DOM for the ItemSet
|
123
|
-
*/
|
124
|
-
ItemSet.prototype._create = function(){
|
125
|
-
var frame = document.createElement('div');
|
126
|
-
frame.className = 'itemset';
|
127
|
-
frame['timeline-itemset'] = this;
|
128
|
-
this.dom.frame = frame;
|
129
|
-
|
130
|
-
// create background panel
|
131
|
-
var background = document.createElement('div');
|
132
|
-
background.className = 'background';
|
133
|
-
frame.appendChild(background);
|
134
|
-
this.dom.background = background;
|
135
|
-
|
136
|
-
// create foreground panel
|
137
|
-
var foreground = document.createElement('div');
|
138
|
-
foreground.className = 'foreground';
|
139
|
-
frame.appendChild(foreground);
|
140
|
-
this.dom.foreground = foreground;
|
141
|
-
|
142
|
-
// create axis panel
|
143
|
-
var axis = document.createElement('div');
|
144
|
-
axis.className = 'axis';
|
145
|
-
this.dom.axis = axis;
|
146
|
-
|
147
|
-
// create labelset
|
148
|
-
var labelSet = document.createElement('div');
|
149
|
-
labelSet.className = 'labelset';
|
150
|
-
this.dom.labelSet = labelSet;
|
151
|
-
|
152
|
-
// create ungrouped Group
|
153
|
-
this._updateUngrouped();
|
154
|
-
|
155
|
-
// attach event listeners
|
156
|
-
// Note: we bind to the centerContainer for the case where the height
|
157
|
-
// of the center container is larger than of the ItemSet, so we
|
158
|
-
// can click in the empty area to create a new item or deselect an item.
|
159
|
-
this.hammer = Hammer(this.body.dom.centerContainer, {
|
160
|
-
prevent_default: true
|
161
|
-
});
|
162
|
-
|
163
|
-
// drag items when selected
|
164
|
-
this.hammer.on('touch', this._onTouch.bind(this));
|
165
|
-
this.hammer.on('dragstart', this._onDragStart.bind(this));
|
166
|
-
this.hammer.on('drag', this._onDrag.bind(this));
|
167
|
-
this.hammer.on('dragend', this._onDragEnd.bind(this));
|
168
|
-
|
169
|
-
// single select (or unselect) when tapping an item
|
170
|
-
this.hammer.on('tap', this._onSelectItem.bind(this));
|
171
|
-
|
172
|
-
// multi select when holding mouse/touch, or on ctrl+click
|
173
|
-
this.hammer.on('hold', this._onMultiSelectItem.bind(this));
|
174
|
-
|
175
|
-
// add item on doubletap
|
176
|
-
this.hammer.on('doubletap', this._onAddItem.bind(this));
|
177
|
-
|
178
|
-
// attach to the DOM
|
179
|
-
this.show();
|
180
|
-
};
|
181
|
-
|
182
|
-
/**
|
183
|
-
* Set options for the ItemSet. Existing options will be extended/overwritten.
|
184
|
-
* @param {Object} [options] The following options are available:
|
185
|
-
* {String} type
|
186
|
-
* Default type for the items. Choose from 'box'
|
187
|
-
* (default), 'point', or 'range'. The default
|
188
|
-
* Style can be overwritten by individual items.
|
189
|
-
* {String} align
|
190
|
-
* Alignment for the items, only applicable for
|
191
|
-
* ItemBox. Choose 'center' (default), 'left', or
|
192
|
-
* 'right'.
|
193
|
-
* {String} orientation
|
194
|
-
* Orientation of the item set. Choose 'top' or
|
195
|
-
* 'bottom' (default).
|
196
|
-
* {Function} groupOrder
|
197
|
-
* A sorting function for ordering groups
|
198
|
-
* {Boolean} stack
|
199
|
-
* If true (deafult), items will be stacked on
|
200
|
-
* top of each other.
|
201
|
-
* {Number} margin.axis
|
202
|
-
* Margin between the axis and the items in pixels.
|
203
|
-
* Default is 20.
|
204
|
-
* {Number} margin.item
|
205
|
-
* Margin between items in pixels. Default is 10.
|
206
|
-
* {Number} margin
|
207
|
-
* Set margin for both axis and items in pixels.
|
208
|
-
* {Number} padding
|
209
|
-
* Padding of the contents of an item in pixels.
|
210
|
-
* Must correspond with the items css. Default is 5.
|
211
|
-
* {Boolean} selectable
|
212
|
-
* If true (default), items can be selected.
|
213
|
-
* {Boolean} editable
|
214
|
-
* Set all editable options to true or false
|
215
|
-
* {Boolean} editable.updateTime
|
216
|
-
* Allow dragging an item to an other moment in time
|
217
|
-
* {Boolean} editable.updateGroup
|
218
|
-
* Allow dragging an item to an other group
|
219
|
-
* {Boolean} editable.add
|
220
|
-
* Allow creating new items on double tap
|
221
|
-
* {Boolean} editable.remove
|
222
|
-
* Allow removing items by clicking the delete button
|
223
|
-
* top right of a selected item.
|
224
|
-
* {Function(item: Item, callback: Function)} onAdd
|
225
|
-
* Callback function triggered when an item is about to be added:
|
226
|
-
* when the user double taps an empty space in the Timeline.
|
227
|
-
* {Function(item: Item, callback: Function)} onUpdate
|
228
|
-
* Callback function fired when an item is about to be updated.
|
229
|
-
* This function typically has to show a dialog where the user
|
230
|
-
* change the item. If not implemented, nothing happens.
|
231
|
-
* {Function(item: Item, callback: Function)} onMove
|
232
|
-
* Fired when an item has been moved. If not implemented,
|
233
|
-
* the move action will be accepted.
|
234
|
-
* {Function(item: Item, callback: Function)} onRemove
|
235
|
-
* Fired when an item is about to be deleted.
|
236
|
-
* If not implemented, the item will be always removed.
|
237
|
-
*/
|
238
|
-
ItemSet.prototype.setOptions = function(options) {
|
239
|
-
if (options) {
|
240
|
-
// copy all options that we know
|
241
|
-
var fields = ['type', 'align', 'orientation', 'padding', 'stack', 'selectable', 'groupOrder'];
|
242
|
-
util.selectiveExtend(fields, this.options, options);
|
243
|
-
|
244
|
-
if ('margin' in options) {
|
245
|
-
if (typeof options.margin === 'number') {
|
246
|
-
this.options.margin.axis = options.margin;
|
247
|
-
this.options.margin.item = options.margin;
|
248
|
-
}
|
249
|
-
else if (typeof options.margin === 'object'){
|
250
|
-
util.selectiveExtend(['axis', 'item'], this.options.margin, options.margin);
|
251
|
-
}
|
252
|
-
}
|
253
|
-
|
254
|
-
if ('editable' in options) {
|
255
|
-
if (typeof options.editable === 'boolean') {
|
256
|
-
this.options.editable.updateTime = options.editable;
|
257
|
-
this.options.editable.updateGroup = options.editable;
|
258
|
-
this.options.editable.add = options.editable;
|
259
|
-
this.options.editable.remove = options.editable;
|
260
|
-
}
|
261
|
-
else if (typeof options.editable === 'object') {
|
262
|
-
util.selectiveExtend(['updateTime', 'updateGroup', 'add', 'remove'], this.options.editable, options.editable);
|
263
|
-
}
|
264
|
-
}
|
265
|
-
|
266
|
-
// callback functions
|
267
|
-
var addCallback = (function (name) {
|
268
|
-
if (name in options) {
|
269
|
-
var fn = options[name];
|
270
|
-
if (!(fn instanceof Function) || fn.length != 2) {
|
271
|
-
throw new Error('option ' + name + ' must be a function ' + name + '(item, callback)');
|
272
|
-
}
|
273
|
-
this.options[name] = fn;
|
274
|
-
}
|
275
|
-
}).bind(this);
|
276
|
-
['onAdd', 'onUpdate', 'onRemove', 'onMove'].forEach(addCallback);
|
277
|
-
|
278
|
-
// force the itemSet to refresh: options like orientation and margins may be changed
|
279
|
-
this.markDirty();
|
280
|
-
}
|
281
|
-
};
|
282
|
-
|
283
|
-
/**
|
284
|
-
* Mark the ItemSet dirty so it will refresh everything with next redraw
|
285
|
-
*/
|
286
|
-
ItemSet.prototype.markDirty = function() {
|
287
|
-
this.groupIds = [];
|
288
|
-
this.stackDirty = true;
|
289
|
-
};
|
290
|
-
|
291
|
-
/**
|
292
|
-
* Destroy the ItemSet
|
293
|
-
*/
|
294
|
-
ItemSet.prototype.destroy = function() {
|
295
|
-
this.hide();
|
296
|
-
this.setItems(null);
|
297
|
-
this.setGroups(null);
|
298
|
-
|
299
|
-
this.hammer = null;
|
300
|
-
|
301
|
-
this.body = null;
|
302
|
-
this.conversion = null;
|
303
|
-
};
|
304
|
-
|
305
|
-
/**
|
306
|
-
* Hide the component from the DOM
|
307
|
-
*/
|
308
|
-
ItemSet.prototype.hide = function() {
|
309
|
-
// remove the frame containing the items
|
310
|
-
if (this.dom.frame.parentNode) {
|
311
|
-
this.dom.frame.parentNode.removeChild(this.dom.frame);
|
312
|
-
}
|
313
|
-
|
314
|
-
// remove the axis with dots
|
315
|
-
if (this.dom.axis.parentNode) {
|
316
|
-
this.dom.axis.parentNode.removeChild(this.dom.axis);
|
317
|
-
}
|
318
|
-
|
319
|
-
// remove the labelset containing all group labels
|
320
|
-
if (this.dom.labelSet.parentNode) {
|
321
|
-
this.dom.labelSet.parentNode.removeChild(this.dom.labelSet);
|
322
|
-
}
|
323
|
-
};
|
324
|
-
|
325
|
-
/**
|
326
|
-
* Show the component in the DOM (when not already visible).
|
327
|
-
* @return {Boolean} changed
|
328
|
-
*/
|
329
|
-
ItemSet.prototype.show = function() {
|
330
|
-
// show frame containing the items
|
331
|
-
if (!this.dom.frame.parentNode) {
|
332
|
-
this.body.dom.center.appendChild(this.dom.frame);
|
333
|
-
}
|
334
|
-
|
335
|
-
// show axis with dots
|
336
|
-
if (!this.dom.axis.parentNode) {
|
337
|
-
this.body.dom.backgroundVertical.appendChild(this.dom.axis);
|
338
|
-
}
|
339
|
-
|
340
|
-
// show labelset containing labels
|
341
|
-
if (!this.dom.labelSet.parentNode) {
|
342
|
-
this.body.dom.left.appendChild(this.dom.labelSet);
|
343
|
-
}
|
344
|
-
};
|
345
|
-
|
346
|
-
/**
|
347
|
-
* Set selected items by their id. Replaces the current selection
|
348
|
-
* Unknown id's are silently ignored.
|
349
|
-
* @param {Array} [ids] An array with zero or more id's of the items to be
|
350
|
-
* selected. If ids is an empty array, all items will be
|
351
|
-
* unselected.
|
352
|
-
*/
|
353
|
-
ItemSet.prototype.setSelection = function(ids) {
|
354
|
-
var i, ii, id, item;
|
355
|
-
|
356
|
-
if (ids) {
|
357
|
-
if (!Array.isArray(ids)) {
|
358
|
-
throw new TypeError('Array expected');
|
359
|
-
}
|
360
|
-
|
361
|
-
// unselect currently selected items
|
362
|
-
for (i = 0, ii = this.selection.length; i < ii; i++) {
|
363
|
-
id = this.selection[i];
|
364
|
-
item = this.items[id];
|
365
|
-
if (item) item.unselect();
|
366
|
-
}
|
367
|
-
|
368
|
-
// select items
|
369
|
-
this.selection = [];
|
370
|
-
for (i = 0, ii = ids.length; i < ii; i++) {
|
371
|
-
id = ids[i];
|
372
|
-
item = this.items[id];
|
373
|
-
if (item) {
|
374
|
-
this.selection.push(id);
|
375
|
-
item.select();
|
376
|
-
}
|
377
|
-
}
|
378
|
-
}
|
379
|
-
};
|
380
|
-
|
381
|
-
/**
|
382
|
-
* Get the selected items by their id
|
383
|
-
* @return {Array} ids The ids of the selected items
|
384
|
-
*/
|
385
|
-
ItemSet.prototype.getSelection = function() {
|
386
|
-
return this.selection.concat([]);
|
387
|
-
};
|
388
|
-
|
389
|
-
/**
|
390
|
-
* Deselect a selected item
|
391
|
-
* @param {String | Number} id
|
392
|
-
* @private
|
393
|
-
*/
|
394
|
-
ItemSet.prototype._deselect = function(id) {
|
395
|
-
var selection = this.selection;
|
396
|
-
for (var i = 0, ii = selection.length; i < ii; i++) {
|
397
|
-
if (selection[i] == id) { // non-strict comparison!
|
398
|
-
selection.splice(i, 1);
|
399
|
-
break;
|
400
|
-
}
|
401
|
-
}
|
402
|
-
};
|
403
|
-
|
404
|
-
/**
|
405
|
-
* Repaint the component
|
406
|
-
* @return {boolean} Returns true if the component is resized
|
407
|
-
*/
|
408
|
-
ItemSet.prototype.redraw = function() {
|
409
|
-
var margin = this.options.margin,
|
410
|
-
range = this.body.range,
|
411
|
-
asSize = util.option.asSize,
|
412
|
-
options = this.options,
|
413
|
-
orientation = options.orientation,
|
414
|
-
resized = false,
|
415
|
-
frame = this.dom.frame,
|
416
|
-
editable = options.editable.updateTime || options.editable.updateGroup;
|
417
|
-
|
418
|
-
// update class name
|
419
|
-
frame.className = 'itemset' + (editable ? ' editable' : '');
|
420
|
-
|
421
|
-
// reorder the groups (if needed)
|
422
|
-
resized = this._orderGroups() || resized;
|
423
|
-
|
424
|
-
// check whether zoomed (in that case we need to re-stack everything)
|
425
|
-
// TODO: would be nicer to get this as a trigger from Range
|
426
|
-
var visibleInterval = range.end - range.start;
|
427
|
-
var zoomed = (visibleInterval != this.lastVisibleInterval) || (this.props.width != this.props.lastWidth);
|
428
|
-
if (zoomed) this.stackDirty = true;
|
429
|
-
this.lastVisibleInterval = visibleInterval;
|
430
|
-
this.props.lastWidth = this.props.width;
|
431
|
-
|
432
|
-
// redraw all groups
|
433
|
-
var restack = this.stackDirty,
|
434
|
-
firstGroup = this._firstGroup(),
|
435
|
-
firstMargin = {
|
436
|
-
item: margin.item,
|
437
|
-
axis: margin.axis
|
438
|
-
},
|
439
|
-
nonFirstMargin = {
|
440
|
-
item: margin.item,
|
441
|
-
axis: margin.item / 2
|
442
|
-
},
|
443
|
-
height = 0,
|
444
|
-
minHeight = margin.axis + margin.item;
|
445
|
-
util.forEach(this.groups, function (group) {
|
446
|
-
var groupMargin = (group == firstGroup) ? firstMargin : nonFirstMargin;
|
447
|
-
var groupResized = group.redraw(range, groupMargin, restack);
|
448
|
-
resized = groupResized || resized;
|
449
|
-
height += group.height;
|
450
|
-
});
|
451
|
-
height = Math.max(height, minHeight);
|
452
|
-
this.stackDirty = false;
|
453
|
-
|
454
|
-
// update frame height
|
455
|
-
frame.style.height = asSize(height);
|
456
|
-
|
457
|
-
// calculate actual size and position
|
458
|
-
this.props.top = frame.offsetTop;
|
459
|
-
this.props.left = frame.offsetLeft;
|
460
|
-
this.props.width = frame.offsetWidth;
|
461
|
-
this.props.height = height;
|
462
|
-
|
463
|
-
// reposition axis
|
464
|
-
this.dom.axis.style.top = asSize((orientation == 'top') ?
|
465
|
-
(this.body.domProps.top.height + this.body.domProps.border.top) :
|
466
|
-
(this.body.domProps.top.height + this.body.domProps.centerContainer.height));
|
467
|
-
this.dom.axis.style.left = this.body.domProps.border.left + 'px';
|
468
|
-
|
469
|
-
// check if this component is resized
|
470
|
-
resized = this._isResized() || resized;
|
471
|
-
|
472
|
-
return resized;
|
473
|
-
};
|
474
|
-
|
475
|
-
/**
|
476
|
-
* Get the first group, aligned with the axis
|
477
|
-
* @return {Group | null} firstGroup
|
478
|
-
* @private
|
479
|
-
*/
|
480
|
-
ItemSet.prototype._firstGroup = function() {
|
481
|
-
var firstGroupIndex = (this.options.orientation == 'top') ? 0 : (this.groupIds.length - 1);
|
482
|
-
var firstGroupId = this.groupIds[firstGroupIndex];
|
483
|
-
var firstGroup = this.groups[firstGroupId] || this.groups[UNGROUPED];
|
484
|
-
|
485
|
-
return firstGroup || null;
|
486
|
-
};
|
487
|
-
|
488
|
-
/**
|
489
|
-
* Create or delete the group holding all ungrouped items. This group is used when
|
490
|
-
* there are no groups specified.
|
491
|
-
* @protected
|
492
|
-
*/
|
493
|
-
ItemSet.prototype._updateUngrouped = function() {
|
494
|
-
var ungrouped = this.groups[UNGROUPED];
|
495
|
-
|
496
|
-
if (this.groupsData) {
|
497
|
-
// remove the group holding all ungrouped items
|
498
|
-
if (ungrouped) {
|
499
|
-
ungrouped.hide();
|
500
|
-
delete this.groups[UNGROUPED];
|
501
|
-
}
|
502
|
-
}
|
503
|
-
else {
|
504
|
-
// create a group holding all (unfiltered) items
|
505
|
-
if (!ungrouped) {
|
506
|
-
var id = null;
|
507
|
-
var data = null;
|
508
|
-
ungrouped = new Group(id, data, this);
|
509
|
-
this.groups[UNGROUPED] = ungrouped;
|
510
|
-
|
511
|
-
for (var itemId in this.items) {
|
512
|
-
if (this.items.hasOwnProperty(itemId)) {
|
513
|
-
ungrouped.add(this.items[itemId]);
|
514
|
-
}
|
515
|
-
}
|
516
|
-
|
517
|
-
ungrouped.show();
|
518
|
-
}
|
519
|
-
}
|
520
|
-
};
|
521
|
-
|
522
|
-
/**
|
523
|
-
* Get the element for the labelset
|
524
|
-
* @return {HTMLElement} labelSet
|
525
|
-
*/
|
526
|
-
ItemSet.prototype.getLabelSet = function() {
|
527
|
-
return this.dom.labelSet;
|
528
|
-
};
|
529
|
-
|
530
|
-
/**
|
531
|
-
* Set items
|
532
|
-
* @param {vis.DataSet | null} items
|
533
|
-
*/
|
534
|
-
ItemSet.prototype.setItems = function(items) {
|
535
|
-
var me = this,
|
536
|
-
ids,
|
537
|
-
oldItemsData = this.itemsData;
|
538
|
-
|
539
|
-
// replace the dataset
|
540
|
-
if (!items) {
|
541
|
-
this.itemsData = null;
|
542
|
-
}
|
543
|
-
else if (items instanceof DataSet || items instanceof DataView) {
|
544
|
-
this.itemsData = items;
|
545
|
-
}
|
546
|
-
else {
|
547
|
-
throw new TypeError('Data must be an instance of DataSet or DataView');
|
548
|
-
}
|
549
|
-
|
550
|
-
if (oldItemsData) {
|
551
|
-
// unsubscribe from old dataset
|
552
|
-
util.forEach(this.itemListeners, function (callback, event) {
|
553
|
-
oldItemsData.off(event, callback);
|
554
|
-
});
|
555
|
-
|
556
|
-
// remove all drawn items
|
557
|
-
ids = oldItemsData.getIds();
|
558
|
-
this._onRemove(ids);
|
559
|
-
}
|
560
|
-
|
561
|
-
if (this.itemsData) {
|
562
|
-
// subscribe to new dataset
|
563
|
-
var id = this.id;
|
564
|
-
util.forEach(this.itemListeners, function (callback, event) {
|
565
|
-
me.itemsData.on(event, callback, id);
|
566
|
-
});
|
567
|
-
|
568
|
-
// add all new items
|
569
|
-
ids = this.itemsData.getIds();
|
570
|
-
this._onAdd(ids);
|
571
|
-
|
572
|
-
// update the group holding all ungrouped items
|
573
|
-
this._updateUngrouped();
|
574
|
-
}
|
575
|
-
};
|
576
|
-
|
577
|
-
/**
|
578
|
-
* Get the current items
|
579
|
-
* @returns {vis.DataSet | null}
|
580
|
-
*/
|
581
|
-
ItemSet.prototype.getItems = function() {
|
582
|
-
return this.itemsData;
|
583
|
-
};
|
584
|
-
|
585
|
-
/**
|
586
|
-
* Set groups
|
587
|
-
* @param {vis.DataSet} groups
|
588
|
-
*/
|
589
|
-
ItemSet.prototype.setGroups = function(groups) {
|
590
|
-
var me = this,
|
591
|
-
ids;
|
592
|
-
|
593
|
-
// unsubscribe from current dataset
|
594
|
-
if (this.groupsData) {
|
595
|
-
util.forEach(this.groupListeners, function (callback, event) {
|
596
|
-
me.groupsData.unsubscribe(event, callback);
|
597
|
-
});
|
598
|
-
|
599
|
-
// remove all drawn groups
|
600
|
-
ids = this.groupsData.getIds();
|
601
|
-
this.groupsData = null;
|
602
|
-
this._onRemoveGroups(ids); // note: this will cause a redraw
|
603
|
-
}
|
604
|
-
|
605
|
-
// replace the dataset
|
606
|
-
if (!groups) {
|
607
|
-
this.groupsData = null;
|
608
|
-
}
|
609
|
-
else if (groups instanceof DataSet || groups instanceof DataView) {
|
610
|
-
this.groupsData = groups;
|
611
|
-
}
|
612
|
-
else {
|
613
|
-
throw new TypeError('Data must be an instance of DataSet or DataView');
|
614
|
-
}
|
615
|
-
|
616
|
-
if (this.groupsData) {
|
617
|
-
// subscribe to new dataset
|
618
|
-
var id = this.id;
|
619
|
-
util.forEach(this.groupListeners, function (callback, event) {
|
620
|
-
me.groupsData.on(event, callback, id);
|
621
|
-
});
|
622
|
-
|
623
|
-
// draw all ms
|
624
|
-
ids = this.groupsData.getIds();
|
625
|
-
this._onAddGroups(ids);
|
626
|
-
}
|
627
|
-
|
628
|
-
// update the group holding all ungrouped items
|
629
|
-
this._updateUngrouped();
|
630
|
-
|
631
|
-
// update the order of all items in each group
|
632
|
-
this._order();
|
633
|
-
|
634
|
-
this.body.emitter.emit('change');
|
635
|
-
};
|
636
|
-
|
637
|
-
/**
|
638
|
-
* Get the current groups
|
639
|
-
* @returns {vis.DataSet | null} groups
|
640
|
-
*/
|
641
|
-
ItemSet.prototype.getGroups = function() {
|
642
|
-
return this.groupsData;
|
643
|
-
};
|
644
|
-
|
645
|
-
/**
|
646
|
-
* Remove an item by its id
|
647
|
-
* @param {String | Number} id
|
648
|
-
*/
|
649
|
-
ItemSet.prototype.removeItem = function(id) {
|
650
|
-
var item = this.itemsData.get(id),
|
651
|
-
dataset = this._myDataSet();
|
652
|
-
|
653
|
-
if (item) {
|
654
|
-
// confirm deletion
|
655
|
-
this.options.onRemove(item, function (item) {
|
656
|
-
if (item) {
|
657
|
-
// remove by id here, it is possible that an item has no id defined
|
658
|
-
// itself, so better not delete by the item itself
|
659
|
-
dataset.remove(id);
|
660
|
-
}
|
661
|
-
});
|
662
|
-
}
|
663
|
-
};
|
664
|
-
|
665
|
-
/**
|
666
|
-
* Handle updated items
|
667
|
-
* @param {Number[]} ids
|
668
|
-
* @protected
|
669
|
-
*/
|
670
|
-
ItemSet.prototype._onUpdate = function(ids) {
|
671
|
-
var me = this;
|
672
|
-
|
673
|
-
ids.forEach(function (id) {
|
674
|
-
var itemData = me.itemsData.get(id, me.itemOptions),
|
675
|
-
item = me.items[id],
|
676
|
-
type = itemData.type ||
|
677
|
-
(itemData.start && itemData.end && 'range') ||
|
678
|
-
me.options.type ||
|
679
|
-
'box';
|
680
|
-
|
681
|
-
var constructor = ItemSet.types[type];
|
682
|
-
|
683
|
-
if (item) {
|
684
|
-
// update item
|
685
|
-
if (!constructor || !(item instanceof constructor)) {
|
686
|
-
// item type has changed, delete the item and recreate it
|
687
|
-
me._removeItem(item);
|
688
|
-
item = null;
|
689
|
-
}
|
690
|
-
else {
|
691
|
-
me._updateItem(item, itemData);
|
692
|
-
}
|
693
|
-
}
|
694
|
-
|
695
|
-
if (!item) {
|
696
|
-
// create item
|
697
|
-
if (constructor) {
|
698
|
-
item = new constructor(itemData, me.conversion, me.options);
|
699
|
-
item.id = id; // TODO: not so nice setting id afterwards
|
700
|
-
me._addItem(item);
|
701
|
-
}
|
702
|
-
else {
|
703
|
-
throw new TypeError('Unknown item type "' + type + '"');
|
704
|
-
}
|
705
|
-
}
|
706
|
-
});
|
707
|
-
|
708
|
-
this._order();
|
709
|
-
this.stackDirty = true; // force re-stacking of all items next redraw
|
710
|
-
this.body.emitter.emit('change');
|
711
|
-
};
|
712
|
-
|
713
|
-
/**
|
714
|
-
* Handle added items
|
715
|
-
* @param {Number[]} ids
|
716
|
-
* @protected
|
717
|
-
*/
|
718
|
-
ItemSet.prototype._onAdd = ItemSet.prototype._onUpdate;
|
719
|
-
|
720
|
-
/**
|
721
|
-
* Handle removed items
|
722
|
-
* @param {Number[]} ids
|
723
|
-
* @protected
|
724
|
-
*/
|
725
|
-
ItemSet.prototype._onRemove = function(ids) {
|
726
|
-
var count = 0;
|
727
|
-
var me = this;
|
728
|
-
ids.forEach(function (id) {
|
729
|
-
var item = me.items[id];
|
730
|
-
if (item) {
|
731
|
-
count++;
|
732
|
-
me._removeItem(item);
|
733
|
-
}
|
734
|
-
});
|
735
|
-
|
736
|
-
if (count) {
|
737
|
-
// update order
|
738
|
-
this._order();
|
739
|
-
this.stackDirty = true; // force re-stacking of all items next redraw
|
740
|
-
this.body.emitter.emit('change');
|
741
|
-
}
|
742
|
-
};
|
743
|
-
|
744
|
-
/**
|
745
|
-
* Update the order of item in all groups
|
746
|
-
* @private
|
747
|
-
*/
|
748
|
-
ItemSet.prototype._order = function() {
|
749
|
-
// reorder the items in all groups
|
750
|
-
// TODO: optimization: only reorder groups affected by the changed items
|
751
|
-
util.forEach(this.groups, function (group) {
|
752
|
-
group.order();
|
753
|
-
});
|
754
|
-
};
|
755
|
-
|
756
|
-
/**
|
757
|
-
* Handle updated groups
|
758
|
-
* @param {Number[]} ids
|
759
|
-
* @private
|
760
|
-
*/
|
761
|
-
ItemSet.prototype._onUpdateGroups = function(ids) {
|
762
|
-
this._onAddGroups(ids);
|
763
|
-
};
|
764
|
-
|
765
|
-
/**
|
766
|
-
* Handle changed groups
|
767
|
-
* @param {Number[]} ids
|
768
|
-
* @private
|
769
|
-
*/
|
770
|
-
ItemSet.prototype._onAddGroups = function(ids) {
|
771
|
-
var me = this;
|
772
|
-
|
773
|
-
ids.forEach(function (id) {
|
774
|
-
var groupData = me.groupsData.get(id);
|
775
|
-
var group = me.groups[id];
|
776
|
-
|
777
|
-
if (!group) {
|
778
|
-
// check for reserved ids
|
779
|
-
if (id == UNGROUPED) {
|
780
|
-
throw new Error('Illegal group id. ' + id + ' is a reserved id.');
|
781
|
-
}
|
782
|
-
|
783
|
-
var groupOptions = Object.create(me.options);
|
784
|
-
util.extend(groupOptions, {
|
785
|
-
height: null
|
786
|
-
});
|
787
|
-
|
788
|
-
group = new Group(id, groupData, me);
|
789
|
-
me.groups[id] = group;
|
790
|
-
|
791
|
-
// add items with this groupId to the new group
|
792
|
-
for (var itemId in me.items) {
|
793
|
-
if (me.items.hasOwnProperty(itemId)) {
|
794
|
-
var item = me.items[itemId];
|
795
|
-
if (item.data.group == id) {
|
796
|
-
group.add(item);
|
797
|
-
}
|
798
|
-
}
|
799
|
-
}
|
800
|
-
|
801
|
-
group.order();
|
802
|
-
group.show();
|
803
|
-
}
|
804
|
-
else {
|
805
|
-
// update group
|
806
|
-
group.setData(groupData);
|
807
|
-
}
|
808
|
-
});
|
809
|
-
|
810
|
-
this.body.emitter.emit('change');
|
811
|
-
};
|
812
|
-
|
813
|
-
/**
|
814
|
-
* Handle removed groups
|
815
|
-
* @param {Number[]} ids
|
816
|
-
* @private
|
817
|
-
*/
|
818
|
-
ItemSet.prototype._onRemoveGroups = function(ids) {
|
819
|
-
var groups = this.groups;
|
820
|
-
ids.forEach(function (id) {
|
821
|
-
var group = groups[id];
|
822
|
-
|
823
|
-
if (group) {
|
824
|
-
group.hide();
|
825
|
-
delete groups[id];
|
826
|
-
}
|
827
|
-
});
|
828
|
-
|
829
|
-
this.markDirty();
|
830
|
-
|
831
|
-
this.body.emitter.emit('change');
|
832
|
-
};
|
833
|
-
|
834
|
-
/**
|
835
|
-
* Reorder the groups if needed
|
836
|
-
* @return {boolean} changed
|
837
|
-
* @private
|
838
|
-
*/
|
839
|
-
ItemSet.prototype._orderGroups = function () {
|
840
|
-
if (this.groupsData) {
|
841
|
-
// reorder the groups
|
842
|
-
var groupIds = this.groupsData.getIds({
|
843
|
-
order: this.options.groupOrder
|
844
|
-
});
|
845
|
-
|
846
|
-
var changed = !util.equalArray(groupIds, this.groupIds);
|
847
|
-
if (changed) {
|
848
|
-
// hide all groups, removes them from the DOM
|
849
|
-
var groups = this.groups;
|
850
|
-
groupIds.forEach(function (groupId) {
|
851
|
-
groups[groupId].hide();
|
852
|
-
});
|
853
|
-
|
854
|
-
// show the groups again, attach them to the DOM in correct order
|
855
|
-
groupIds.forEach(function (groupId) {
|
856
|
-
groups[groupId].show();
|
857
|
-
});
|
858
|
-
|
859
|
-
this.groupIds = groupIds;
|
860
|
-
}
|
861
|
-
|
862
|
-
return changed;
|
863
|
-
}
|
864
|
-
else {
|
865
|
-
return false;
|
866
|
-
}
|
867
|
-
};
|
868
|
-
|
869
|
-
/**
|
870
|
-
* Add a new item
|
871
|
-
* @param {Item} item
|
872
|
-
* @private
|
873
|
-
*/
|
874
|
-
ItemSet.prototype._addItem = function(item) {
|
875
|
-
this.items[item.id] = item;
|
876
|
-
|
877
|
-
// add to group
|
878
|
-
var groupId = this.groupsData ? item.data.group : UNGROUPED;
|
879
|
-
var group = this.groups[groupId];
|
880
|
-
if (group) group.add(item);
|
881
|
-
};
|
882
|
-
|
883
|
-
/**
|
884
|
-
* Update an existing item
|
885
|
-
* @param {Item} item
|
886
|
-
* @param {Object} itemData
|
887
|
-
* @private
|
888
|
-
*/
|
889
|
-
ItemSet.prototype._updateItem = function(item, itemData) {
|
890
|
-
var oldGroupId = item.data.group;
|
891
|
-
|
892
|
-
item.data = itemData;
|
893
|
-
if (item.displayed) {
|
894
|
-
item.redraw();
|
895
|
-
}
|
896
|
-
|
897
|
-
// update group
|
898
|
-
if (oldGroupId != item.data.group) {
|
899
|
-
var oldGroup = this.groups[oldGroupId];
|
900
|
-
if (oldGroup) oldGroup.remove(item);
|
901
|
-
|
902
|
-
var groupId = this.groupsData ? item.data.group : UNGROUPED;
|
903
|
-
var group = this.groups[groupId];
|
904
|
-
if (group) group.add(item);
|
905
|
-
}
|
906
|
-
};
|
907
|
-
|
908
|
-
/**
|
909
|
-
* Delete an item from the ItemSet: remove it from the DOM, from the map
|
910
|
-
* with items, and from the map with visible items, and from the selection
|
911
|
-
* @param {Item} item
|
912
|
-
* @private
|
913
|
-
*/
|
914
|
-
ItemSet.prototype._removeItem = function(item) {
|
915
|
-
// remove from DOM
|
916
|
-
item.hide();
|
917
|
-
|
918
|
-
// remove from items
|
919
|
-
delete this.items[item.id];
|
920
|
-
|
921
|
-
// remove from selection
|
922
|
-
var index = this.selection.indexOf(item.id);
|
923
|
-
if (index != -1) this.selection.splice(index, 1);
|
924
|
-
|
925
|
-
// remove from group
|
926
|
-
var groupId = this.groupsData ? item.data.group : UNGROUPED;
|
927
|
-
var group = this.groups[groupId];
|
928
|
-
if (group) group.remove(item);
|
929
|
-
};
|
930
|
-
|
931
|
-
/**
|
932
|
-
* Create an array containing all items being a range (having an end date)
|
933
|
-
* @param array
|
934
|
-
* @returns {Array}
|
935
|
-
* @private
|
936
|
-
*/
|
937
|
-
ItemSet.prototype._constructByEndArray = function(array) {
|
938
|
-
var endArray = [];
|
939
|
-
|
940
|
-
for (var i = 0; i < array.length; i++) {
|
941
|
-
if (array[i] instanceof ItemRange) {
|
942
|
-
endArray.push(array[i]);
|
943
|
-
}
|
944
|
-
}
|
945
|
-
return endArray;
|
946
|
-
};
|
947
|
-
|
948
|
-
/**
|
949
|
-
* Register the clicked item on touch, before dragStart is initiated.
|
950
|
-
*
|
951
|
-
* dragStart is initiated from a mousemove event, which can have left the item
|
952
|
-
* already resulting in an item == null
|
953
|
-
*
|
954
|
-
* @param {Event} event
|
955
|
-
* @private
|
956
|
-
*/
|
957
|
-
ItemSet.prototype._onTouch = function (event) {
|
958
|
-
// store the touched item, used in _onDragStart
|
959
|
-
this.touchParams.item = ItemSet.itemFromTarget(event);
|
960
|
-
};
|
961
|
-
|
962
|
-
/**
|
963
|
-
* Start dragging the selected events
|
964
|
-
* @param {Event} event
|
965
|
-
* @private
|
966
|
-
*/
|
967
|
-
ItemSet.prototype._onDragStart = function (event) {
|
968
|
-
if (!this.options.editable.updateTime && !this.options.editable.updateGroup) {
|
969
|
-
return;
|
970
|
-
}
|
971
|
-
|
972
|
-
var item = this.touchParams.item || null,
|
973
|
-
me = this,
|
974
|
-
props;
|
975
|
-
|
976
|
-
if (item && item.selected) {
|
977
|
-
var dragLeftItem = event.target.dragLeftItem;
|
978
|
-
var dragRightItem = event.target.dragRightItem;
|
979
|
-
|
980
|
-
if (dragLeftItem) {
|
981
|
-
props = {
|
982
|
-
item: dragLeftItem
|
983
|
-
};
|
984
|
-
|
985
|
-
if (me.options.editable.updateTime) {
|
986
|
-
props.start = item.data.start.valueOf();
|
987
|
-
}
|
988
|
-
if (me.options.editable.updateGroup) {
|
989
|
-
if ('group' in item.data) props.group = item.data.group;
|
990
|
-
}
|
991
|
-
|
992
|
-
this.touchParams.itemProps = [props];
|
993
|
-
}
|
994
|
-
else if (dragRightItem) {
|
995
|
-
props = {
|
996
|
-
item: dragRightItem
|
997
|
-
};
|
998
|
-
|
999
|
-
if (me.options.editable.updateTime) {
|
1000
|
-
props.end = item.data.end.valueOf();
|
1001
|
-
}
|
1002
|
-
if (me.options.editable.updateGroup) {
|
1003
|
-
if ('group' in item.data) props.group = item.data.group;
|
1004
|
-
}
|
1005
|
-
|
1006
|
-
this.touchParams.itemProps = [props];
|
1007
|
-
}
|
1008
|
-
else {
|
1009
|
-
this.touchParams.itemProps = this.getSelection().map(function (id) {
|
1010
|
-
var item = me.items[id];
|
1011
|
-
var props = {
|
1012
|
-
item: item
|
1013
|
-
};
|
1014
|
-
|
1015
|
-
if (me.options.editable.updateTime) {
|
1016
|
-
if ('start' in item.data) props.start = item.data.start.valueOf();
|
1017
|
-
if ('end' in item.data) props.end = item.data.end.valueOf();
|
1018
|
-
}
|
1019
|
-
if (me.options.editable.updateGroup) {
|
1020
|
-
if ('group' in item.data) props.group = item.data.group;
|
1021
|
-
}
|
1022
|
-
|
1023
|
-
return props;
|
1024
|
-
});
|
1025
|
-
}
|
1026
|
-
|
1027
|
-
event.stopPropagation();
|
1028
|
-
}
|
1029
|
-
};
|
1030
|
-
|
1031
|
-
/**
|
1032
|
-
* Drag selected items
|
1033
|
-
* @param {Event} event
|
1034
|
-
* @private
|
1035
|
-
*/
|
1036
|
-
ItemSet.prototype._onDrag = function (event) {
|
1037
|
-
if (this.touchParams.itemProps) {
|
1038
|
-
var range = this.body.range,
|
1039
|
-
snap = this.body.util.snap || null,
|
1040
|
-
deltaX = event.gesture.deltaX,
|
1041
|
-
scale = (this.props.width / (range.end - range.start)),
|
1042
|
-
offset = deltaX / scale;
|
1043
|
-
|
1044
|
-
// move
|
1045
|
-
this.touchParams.itemProps.forEach(function (props) {
|
1046
|
-
if ('start' in props) {
|
1047
|
-
var start = new Date(props.start + offset);
|
1048
|
-
props.item.data.start = snap ? snap(start) : start;
|
1049
|
-
}
|
1050
|
-
|
1051
|
-
if ('end' in props) {
|
1052
|
-
var end = new Date(props.end + offset);
|
1053
|
-
props.item.data.end = snap ? snap(end) : end;
|
1054
|
-
}
|
1055
|
-
|
1056
|
-
if ('group' in props) {
|
1057
|
-
// drag from one group to another
|
1058
|
-
var group = ItemSet.groupFromTarget(event);
|
1059
|
-
if (group && group.groupId != props.item.data.group) {
|
1060
|
-
var oldGroup = props.item.parent;
|
1061
|
-
oldGroup.remove(props.item);
|
1062
|
-
oldGroup.order();
|
1063
|
-
group.add(props.item);
|
1064
|
-
group.order();
|
1065
|
-
|
1066
|
-
props.item.data.group = group.groupId;
|
1067
|
-
}
|
1068
|
-
}
|
1069
|
-
});
|
1070
|
-
|
1071
|
-
// TODO: implement onMoving handler
|
1072
|
-
|
1073
|
-
this.stackDirty = true; // force re-stacking of all items next redraw
|
1074
|
-
this.body.emitter.emit('change');
|
1075
|
-
|
1076
|
-
event.stopPropagation();
|
1077
|
-
}
|
1078
|
-
};
|
1079
|
-
|
1080
|
-
/**
|
1081
|
-
* End of dragging selected items
|
1082
|
-
* @param {Event} event
|
1083
|
-
* @private
|
1084
|
-
*/
|
1085
|
-
ItemSet.prototype._onDragEnd = function (event) {
|
1086
|
-
if (this.touchParams.itemProps) {
|
1087
|
-
// prepare a change set for the changed items
|
1088
|
-
var changes = [],
|
1089
|
-
me = this,
|
1090
|
-
dataset = this._myDataSet();
|
1091
|
-
|
1092
|
-
this.touchParams.itemProps.forEach(function (props) {
|
1093
|
-
var id = props.item.id,
|
1094
|
-
itemData = me.itemsData.get(id, me.itemOptions);
|
1095
|
-
|
1096
|
-
var changed = false;
|
1097
|
-
if ('start' in props.item.data) {
|
1098
|
-
changed = (props.start != props.item.data.start.valueOf());
|
1099
|
-
itemData.start = util.convert(props.item.data.start,
|
1100
|
-
dataset._options.type && dataset._options.type.start || 'Date');
|
1101
|
-
}
|
1102
|
-
if ('end' in props.item.data) {
|
1103
|
-
changed = changed || (props.end != props.item.data.end.valueOf());
|
1104
|
-
itemData.end = util.convert(props.item.data.end,
|
1105
|
-
dataset._options.type && dataset._options.type.end || 'Date');
|
1106
|
-
}
|
1107
|
-
if ('group' in props.item.data) {
|
1108
|
-
changed = changed || (props.group != props.item.data.group);
|
1109
|
-
itemData.group = props.item.data.group;
|
1110
|
-
}
|
1111
|
-
|
1112
|
-
// only apply changes when start or end is actually changed
|
1113
|
-
if (changed) {
|
1114
|
-
me.options.onMove(itemData, function (itemData) {
|
1115
|
-
if (itemData) {
|
1116
|
-
// apply changes
|
1117
|
-
itemData[dataset._fieldId] = id; // ensure the item contains its id (can be undefined)
|
1118
|
-
changes.push(itemData);
|
1119
|
-
}
|
1120
|
-
else {
|
1121
|
-
// restore original values
|
1122
|
-
if ('start' in props) props.item.data.start = props.start;
|
1123
|
-
if ('end' in props) props.item.data.end = props.end;
|
1124
|
-
|
1125
|
-
me.stackDirty = true; // force re-stacking of all items next redraw
|
1126
|
-
me.body.emitter.emit('change');
|
1127
|
-
}
|
1128
|
-
});
|
1129
|
-
}
|
1130
|
-
});
|
1131
|
-
this.touchParams.itemProps = null;
|
1132
|
-
|
1133
|
-
// apply the changes to the data (if there are changes)
|
1134
|
-
if (changes.length) {
|
1135
|
-
dataset.update(changes);
|
1136
|
-
}
|
1137
|
-
|
1138
|
-
event.stopPropagation();
|
1139
|
-
}
|
1140
|
-
};
|
1141
|
-
|
1142
|
-
/**
|
1143
|
-
* Handle selecting/deselecting an item when tapping it
|
1144
|
-
* @param {Event} event
|
1145
|
-
* @private
|
1146
|
-
*/
|
1147
|
-
ItemSet.prototype._onSelectItem = function (event) {
|
1148
|
-
if (!this.options.selectable) return;
|
1149
|
-
|
1150
|
-
var ctrlKey = event.gesture.srcEvent && event.gesture.srcEvent.ctrlKey;
|
1151
|
-
var shiftKey = event.gesture.srcEvent && event.gesture.srcEvent.shiftKey;
|
1152
|
-
if (ctrlKey || shiftKey) {
|
1153
|
-
this._onMultiSelectItem(event);
|
1154
|
-
return;
|
1155
|
-
}
|
1156
|
-
|
1157
|
-
var oldSelection = this.getSelection();
|
1158
|
-
|
1159
|
-
var item = ItemSet.itemFromTarget(event);
|
1160
|
-
var selection = item ? [item.id] : [];
|
1161
|
-
this.setSelection(selection);
|
1162
|
-
|
1163
|
-
var newSelection = this.getSelection();
|
1164
|
-
|
1165
|
-
// emit a select event,
|
1166
|
-
// except when old selection is empty and new selection is still empty
|
1167
|
-
if (newSelection.length > 0 || oldSelection.length > 0) {
|
1168
|
-
this.body.emitter.emit('select', {
|
1169
|
-
items: this.getSelection()
|
1170
|
-
});
|
1171
|
-
}
|
1172
|
-
|
1173
|
-
event.stopPropagation();
|
1174
|
-
};
|
1175
|
-
|
1176
|
-
/**
|
1177
|
-
* Handle creation and updates of an item on double tap
|
1178
|
-
* @param event
|
1179
|
-
* @private
|
1180
|
-
*/
|
1181
|
-
ItemSet.prototype._onAddItem = function (event) {
|
1182
|
-
if (!this.options.selectable) return;
|
1183
|
-
if (!this.options.editable.add) return;
|
1184
|
-
|
1185
|
-
var me = this,
|
1186
|
-
snap = this.body.util.snap || null,
|
1187
|
-
item = ItemSet.itemFromTarget(event);
|
1188
|
-
|
1189
|
-
if (item) {
|
1190
|
-
// update item
|
1191
|
-
|
1192
|
-
// execute async handler to update the item (or cancel it)
|
1193
|
-
var itemData = me.itemsData.get(item.id); // get a clone of the data from the dataset
|
1194
|
-
this.options.onUpdate(itemData, function (itemData) {
|
1195
|
-
if (itemData) {
|
1196
|
-
me.itemsData.update(itemData);
|
1197
|
-
}
|
1198
|
-
});
|
1199
|
-
}
|
1200
|
-
else {
|
1201
|
-
// add item
|
1202
|
-
var xAbs = vis.util.getAbsoluteLeft(this.dom.frame);
|
1203
|
-
var x = event.gesture.center.pageX - xAbs;
|
1204
|
-
var start = this.body.util.toTime(x);
|
1205
|
-
var newItem = {
|
1206
|
-
start: snap ? snap(start) : start,
|
1207
|
-
content: 'new item'
|
1208
|
-
};
|
1209
|
-
|
1210
|
-
// when default type is a range, add a default end date to the new item
|
1211
|
-
if (this.options.type === 'range' || this.options.type == 'rangeoverflow') {
|
1212
|
-
var end = this.body.util.toTime(x + this.props.width / 5);
|
1213
|
-
newItem.end = snap ? snap(end) : end;
|
1214
|
-
}
|
1215
|
-
|
1216
|
-
newItem[this.itemsData.fieldId] = util.randomUUID();
|
1217
|
-
|
1218
|
-
var group = ItemSet.groupFromTarget(event);
|
1219
|
-
if (group) {
|
1220
|
-
newItem.group = group.groupId;
|
1221
|
-
}
|
1222
|
-
|
1223
|
-
// execute async handler to customize (or cancel) adding an item
|
1224
|
-
this.options.onAdd(newItem, function (item) {
|
1225
|
-
if (item) {
|
1226
|
-
me.itemsData.add(newItem);
|
1227
|
-
// TODO: need to trigger a redraw?
|
1228
|
-
}
|
1229
|
-
});
|
1230
|
-
}
|
1231
|
-
};
|
1232
|
-
|
1233
|
-
/**
|
1234
|
-
* Handle selecting/deselecting multiple items when holding an item
|
1235
|
-
* @param {Event} event
|
1236
|
-
* @private
|
1237
|
-
*/
|
1238
|
-
ItemSet.prototype._onMultiSelectItem = function (event) {
|
1239
|
-
if (!this.options.selectable) return;
|
1240
|
-
|
1241
|
-
var selection,
|
1242
|
-
item = ItemSet.itemFromTarget(event);
|
1243
|
-
|
1244
|
-
if (item) {
|
1245
|
-
// multi select items
|
1246
|
-
selection = this.getSelection(); // current selection
|
1247
|
-
var index = selection.indexOf(item.id);
|
1248
|
-
if (index == -1) {
|
1249
|
-
// item is not yet selected -> select it
|
1250
|
-
selection.push(item.id);
|
1251
|
-
}
|
1252
|
-
else {
|
1253
|
-
// item is already selected -> deselect it
|
1254
|
-
selection.splice(index, 1);
|
1255
|
-
}
|
1256
|
-
this.setSelection(selection);
|
1257
|
-
|
1258
|
-
this.body.emitter.emit('select', {
|
1259
|
-
items: this.getSelection()
|
1260
|
-
});
|
1261
|
-
|
1262
|
-
event.stopPropagation();
|
1263
|
-
}
|
1264
|
-
};
|
1265
|
-
|
1266
|
-
/**
|
1267
|
-
* Find an item from an event target:
|
1268
|
-
* searches for the attribute 'timeline-item' in the event target's element tree
|
1269
|
-
* @param {Event} event
|
1270
|
-
* @return {Item | null} item
|
1271
|
-
*/
|
1272
|
-
ItemSet.itemFromTarget = function(event) {
|
1273
|
-
var target = event.target;
|
1274
|
-
while (target) {
|
1275
|
-
if (target.hasOwnProperty('timeline-item')) {
|
1276
|
-
return target['timeline-item'];
|
1277
|
-
}
|
1278
|
-
target = target.parentNode;
|
1279
|
-
}
|
1280
|
-
|
1281
|
-
return null;
|
1282
|
-
};
|
1283
|
-
|
1284
|
-
/**
|
1285
|
-
* Find the Group from an event target:
|
1286
|
-
* searches for the attribute 'timeline-group' in the event target's element tree
|
1287
|
-
* @param {Event} event
|
1288
|
-
* @return {Group | null} group
|
1289
|
-
*/
|
1290
|
-
ItemSet.groupFromTarget = function(event) {
|
1291
|
-
var target = event.target;
|
1292
|
-
while (target) {
|
1293
|
-
if (target.hasOwnProperty('timeline-group')) {
|
1294
|
-
return target['timeline-group'];
|
1295
|
-
}
|
1296
|
-
target = target.parentNode;
|
1297
|
-
}
|
1298
|
-
|
1299
|
-
return null;
|
1300
|
-
};
|
1301
|
-
|
1302
|
-
/**
|
1303
|
-
* Find the ItemSet from an event target:
|
1304
|
-
* searches for the attribute 'timeline-itemset' in the event target's element tree
|
1305
|
-
* @param {Event} event
|
1306
|
-
* @return {ItemSet | null} item
|
1307
|
-
*/
|
1308
|
-
ItemSet.itemSetFromTarget = function(event) {
|
1309
|
-
var target = event.target;
|
1310
|
-
while (target) {
|
1311
|
-
if (target.hasOwnProperty('timeline-itemset')) {
|
1312
|
-
return target['timeline-itemset'];
|
1313
|
-
}
|
1314
|
-
target = target.parentNode;
|
1315
|
-
}
|
1316
|
-
|
1317
|
-
return null;
|
1318
|
-
};
|
1319
|
-
|
1320
|
-
/**
|
1321
|
-
* Find the DataSet to which this ItemSet is connected
|
1322
|
-
* @returns {null | DataSet} dataset
|
1323
|
-
* @private
|
1324
|
-
*/
|
1325
|
-
ItemSet.prototype._myDataSet = function() {
|
1326
|
-
// find the root DataSet
|
1327
|
-
var dataset = this.itemsData;
|
1328
|
-
while (dataset instanceof DataView) {
|
1329
|
-
dataset = dataset.data;
|
1330
|
-
}
|
1331
|
-
return dataset;
|
1332
|
-
};
|