vis-rails 1.0.2 → 2.0.0
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/CHANGELOG.md +1 -1
- data/README.md +2 -0
- data/lib/vis/rails/version.rb +1 -1
- data/vendor/assets/javascripts/module/exports-only-timeline.js +55 -0
- data/vendor/assets/javascripts/vis-only-timeline.js +23 -0
- data/vendor/assets/javascripts/vis.js +3 -3
- data/vendor/assets/stylesheets/vis-only-timeline.css +3 -0
- data/vendor/assets/vis/DataSet.js +106 -130
- data/vendor/assets/vis/DataView.js +35 -37
- data/vendor/assets/vis/graph/Edge.js +225 -45
- data/vendor/assets/vis/graph/Graph.js +120 -24
- data/vendor/assets/vis/graph/Node.js +16 -16
- data/vendor/assets/vis/graph/graphMixins/HierarchicalLayoutMixin.js +1 -1
- data/vendor/assets/vis/graph/graphMixins/ManipulationMixin.js +143 -0
- data/vendor/assets/vis/graph/graphMixins/SelectionMixin.js +81 -3
- data/vendor/assets/vis/graph3d/Graph3d.js +3306 -0
- data/vendor/assets/vis/module/exports.js +2 -3
- data/vendor/assets/vis/timeline/Range.js +93 -80
- data/vendor/assets/vis/timeline/Timeline.js +525 -428
- data/vendor/assets/vis/timeline/component/Component.js +19 -53
- data/vendor/assets/vis/timeline/component/CurrentTime.js +57 -25
- data/vendor/assets/vis/timeline/component/CustomTime.js +55 -19
- data/vendor/assets/vis/timeline/component/Group.js +47 -50
- data/vendor/assets/vis/timeline/component/ItemSet.js +402 -206
- data/vendor/assets/vis/timeline/component/TimeAxis.js +112 -169
- data/vendor/assets/vis/timeline/component/css/animation.css +33 -0
- data/vendor/assets/vis/timeline/component/css/currenttime.css +1 -1
- data/vendor/assets/vis/timeline/component/css/customtime.css +1 -1
- data/vendor/assets/vis/timeline/component/css/item.css +1 -11
- data/vendor/assets/vis/timeline/component/css/itemset.css +13 -18
- data/vendor/assets/vis/timeline/component/css/labelset.css +8 -6
- data/vendor/assets/vis/timeline/component/css/panel.css +56 -13
- data/vendor/assets/vis/timeline/component/css/timeaxis.css +15 -8
- data/vendor/assets/vis/timeline/component/item/Item.js +16 -15
- data/vendor/assets/vis/timeline/component/item/ItemBox.js +30 -30
- data/vendor/assets/vis/timeline/component/item/ItemPoint.js +20 -21
- data/vendor/assets/vis/timeline/component/item/ItemRange.js +23 -24
- data/vendor/assets/vis/timeline/component/item/ItemRangeOverflow.js +10 -10
- data/vendor/assets/vis/timeline/stack.js +5 -5
- data/vendor/assets/vis/util.js +81 -35
- metadata +7 -4
- data/vendor/assets/vis/timeline/component/Panel.js +0 -170
- data/vendor/assets/vis/timeline/component/RootPanel.js +0 -176
@@ -4,55 +4,92 @@ var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items
|
|
4
4
|
* An ItemSet holds a set of items and ranges which can be displayed in a
|
5
5
|
* range. The width is determined by the parent of the ItemSet, and the height
|
6
6
|
* is determined by the size of the items.
|
7
|
-
* @param {
|
8
|
-
* vertical lines of box items.
|
9
|
-
* @param {Panel} axisPanel Panel on the axis where the dots of box-items
|
10
|
-
* can be displayed.
|
11
|
-
* @param {Panel} sidePanel Left side panel holding labels
|
7
|
+
* @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} body
|
12
8
|
* @param {Object} [options] See ItemSet.setOptions for the available options.
|
13
9
|
* @constructor ItemSet
|
14
|
-
* @extends
|
10
|
+
* @extends Component
|
15
11
|
*/
|
16
|
-
function ItemSet(
|
17
|
-
this.
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
+
};
|
25
62
|
this.dom = {};
|
63
|
+
this.props = {};
|
26
64
|
this.hammer = null;
|
27
65
|
|
28
66
|
var me = this;
|
29
67
|
this.itemsData = null; // DataSet
|
30
68
|
this.groupsData = null; // DataSet
|
31
|
-
this.range = null; // Range or Object {start: number, end: number}
|
32
69
|
|
33
70
|
// listeners for the DataSet of the items
|
34
71
|
this.itemListeners = {
|
35
72
|
'add': function (event, params, senderId) {
|
36
|
-
|
73
|
+
me._onAdd(params.items);
|
37
74
|
},
|
38
75
|
'update': function (event, params, senderId) {
|
39
|
-
|
76
|
+
me._onUpdate(params.items);
|
40
77
|
},
|
41
78
|
'remove': function (event, params, senderId) {
|
42
|
-
|
79
|
+
me._onRemove(params.items);
|
43
80
|
}
|
44
81
|
};
|
45
82
|
|
46
83
|
// listeners for the DataSet of the groups
|
47
84
|
this.groupListeners = {
|
48
85
|
'add': function (event, params, senderId) {
|
49
|
-
|
86
|
+
me._onAddGroups(params.items);
|
50
87
|
},
|
51
88
|
'update': function (event, params, senderId) {
|
52
|
-
|
89
|
+
me._onUpdateGroups(params.items);
|
53
90
|
},
|
54
91
|
'remove': function (event, params, senderId) {
|
55
|
-
|
92
|
+
me._onRemoveGroups(params.items);
|
56
93
|
}
|
57
94
|
};
|
58
95
|
|
@@ -61,15 +98,17 @@ function ItemSet(backgroundPanel, axisPanel, sidePanel, options) {
|
|
61
98
|
this.groupIds = [];
|
62
99
|
|
63
100
|
this.selection = []; // list with the ids of all selected nodes
|
64
|
-
this.stackDirty = true; // if true, all items will be restacked on next
|
101
|
+
this.stackDirty = true; // if true, all items will be restacked on next redraw
|
65
102
|
|
66
103
|
this.touchParams = {}; // stores properties while dragging
|
67
104
|
// create the HTML DOM
|
68
105
|
|
69
106
|
this._create();
|
107
|
+
|
108
|
+
this.setOptions(options);
|
70
109
|
}
|
71
110
|
|
72
|
-
ItemSet.prototype = new
|
111
|
+
ItemSet.prototype = new Component();
|
73
112
|
|
74
113
|
// available item types will be registered here
|
75
114
|
ItemSet.types = {
|
@@ -82,15 +121,16 @@ ItemSet.types = {
|
|
82
121
|
/**
|
83
122
|
* Create the HTML DOM for the ItemSet
|
84
123
|
*/
|
85
|
-
ItemSet.prototype._create = function
|
124
|
+
ItemSet.prototype._create = function(){
|
86
125
|
var frame = document.createElement('div');
|
126
|
+
frame.className = 'itemset';
|
87
127
|
frame['timeline-itemset'] = this;
|
88
|
-
this.frame = frame;
|
128
|
+
this.dom.frame = frame;
|
89
129
|
|
90
130
|
// create background panel
|
91
131
|
var background = document.createElement('div');
|
92
132
|
background.className = 'background';
|
93
|
-
|
133
|
+
frame.appendChild(background);
|
94
134
|
this.dom.background = background;
|
95
135
|
|
96
136
|
// create foreground panel
|
@@ -103,33 +143,46 @@ ItemSet.prototype._create = function _create(){
|
|
103
143
|
var axis = document.createElement('div');
|
104
144
|
axis.className = 'axis';
|
105
145
|
this.dom.axis = axis;
|
106
|
-
this.axisPanel.frame.appendChild(axis);
|
107
146
|
|
108
147
|
// create labelset
|
109
148
|
var labelSet = document.createElement('div');
|
110
149
|
labelSet.className = 'labelset';
|
111
150
|
this.dom.labelSet = labelSet;
|
112
|
-
this.sidePanel.frame.appendChild(labelSet);
|
113
151
|
|
114
152
|
// create ungrouped Group
|
115
153
|
this._updateUngrouped();
|
116
154
|
|
117
155
|
// attach event listeners
|
118
|
-
//
|
119
|
-
|
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, {
|
120
160
|
prevent_default: true
|
121
161
|
});
|
162
|
+
|
163
|
+
// drag items when selected
|
164
|
+
this.hammer.on('touch', this._onTouch.bind(this));
|
122
165
|
this.hammer.on('dragstart', this._onDragStart.bind(this));
|
123
166
|
this.hammer.on('drag', this._onDrag.bind(this));
|
124
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();
|
125
180
|
};
|
126
181
|
|
127
182
|
/**
|
128
183
|
* Set options for the ItemSet. Existing options will be extended/overwritten.
|
129
184
|
* @param {Object} [options] The following options are available:
|
130
|
-
* {String
|
131
|
-
* class name for the itemset
|
132
|
-
* {String} [type]
|
185
|
+
* {String} type
|
133
186
|
* Default type for the items. Choose from 'box'
|
134
187
|
* (default), 'point', or 'range'. The default
|
135
188
|
* Style can be overwritten by individual items.
|
@@ -140,44 +193,129 @@ ItemSet.prototype._create = function _create(){
|
|
140
193
|
* {String} orientation
|
141
194
|
* Orientation of the item set. Choose 'top' or
|
142
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.
|
143
201
|
* {Number} margin.axis
|
144
202
|
* Margin between the axis and the items in pixels.
|
145
203
|
* Default is 20.
|
146
204
|
* {Number} margin.item
|
147
205
|
* Margin between items in pixels. Default is 10.
|
206
|
+
* {Number} margin
|
207
|
+
* Set margin for both axis and items in pixels.
|
148
208
|
* {Number} padding
|
149
209
|
* Padding of the contents of an item in pixels.
|
150
210
|
* Must correspond with the items css. Default is 5.
|
151
|
-
* {
|
152
|
-
*
|
153
|
-
*
|
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.
|
154
237
|
*/
|
155
|
-
ItemSet.prototype.setOptions = function
|
156
|
-
|
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
|
+
}
|
157
281
|
};
|
158
282
|
|
159
283
|
/**
|
160
|
-
* Mark the ItemSet dirty so it will refresh everything with next
|
284
|
+
* Mark the ItemSet dirty so it will refresh everything with next redraw
|
161
285
|
*/
|
162
|
-
ItemSet.prototype.markDirty = function
|
286
|
+
ItemSet.prototype.markDirty = function() {
|
163
287
|
this.groupIds = [];
|
164
288
|
this.stackDirty = true;
|
165
289
|
};
|
166
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
|
+
|
167
305
|
/**
|
168
306
|
* Hide the component from the DOM
|
169
307
|
*/
|
170
|
-
ItemSet.prototype.hide = function
|
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
|
+
|
171
314
|
// remove the axis with dots
|
172
315
|
if (this.dom.axis.parentNode) {
|
173
316
|
this.dom.axis.parentNode.removeChild(this.dom.axis);
|
174
317
|
}
|
175
318
|
|
176
|
-
// remove the background with vertical lines
|
177
|
-
if (this.dom.background.parentNode) {
|
178
|
-
this.dom.background.parentNode.removeChild(this.dom.background);
|
179
|
-
}
|
180
|
-
|
181
319
|
// remove the labelset containing all group labels
|
182
320
|
if (this.dom.labelSet.parentNode) {
|
183
321
|
this.dom.labelSet.parentNode.removeChild(this.dom.labelSet);
|
@@ -188,35 +326,23 @@ ItemSet.prototype.hide = function hide() {
|
|
188
326
|
* Show the component in the DOM (when not already visible).
|
189
327
|
* @return {Boolean} changed
|
190
328
|
*/
|
191
|
-
ItemSet.prototype.show = function
|
192
|
-
// show
|
193
|
-
if (!this.dom.
|
194
|
-
this.
|
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);
|
195
333
|
}
|
196
334
|
|
197
|
-
// show
|
198
|
-
if (!this.dom.
|
199
|
-
this.
|
335
|
+
// show axis with dots
|
336
|
+
if (!this.dom.axis.parentNode) {
|
337
|
+
this.body.dom.backgroundVertical.appendChild(this.dom.axis);
|
200
338
|
}
|
201
339
|
|
202
340
|
// show labelset containing labels
|
203
341
|
if (!this.dom.labelSet.parentNode) {
|
204
|
-
this.
|
342
|
+
this.body.dom.left.appendChild(this.dom.labelSet);
|
205
343
|
}
|
206
344
|
};
|
207
345
|
|
208
|
-
/**
|
209
|
-
* Set range (start and end).
|
210
|
-
* @param {Range | Object} range A Range or an object containing start and end.
|
211
|
-
*/
|
212
|
-
ItemSet.prototype.setRange = function setRange(range) {
|
213
|
-
if (!(range instanceof Range) && (!range || !range.start || !range.end)) {
|
214
|
-
throw new TypeError('Range must be an instance of Range, ' +
|
215
|
-
'or an object containing start and end.');
|
216
|
-
}
|
217
|
-
this.range = range;
|
218
|
-
};
|
219
|
-
|
220
346
|
/**
|
221
347
|
* Set selected items by their id. Replaces the current selection
|
222
348
|
* Unknown id's are silently ignored.
|
@@ -224,7 +350,7 @@ ItemSet.prototype.setRange = function setRange(range) {
|
|
224
350
|
* selected. If ids is an empty array, all items will be
|
225
351
|
* unselected.
|
226
352
|
*/
|
227
|
-
ItemSet.prototype.setSelection = function
|
353
|
+
ItemSet.prototype.setSelection = function(ids) {
|
228
354
|
var i, ii, id, item;
|
229
355
|
|
230
356
|
if (ids) {
|
@@ -256,7 +382,7 @@ ItemSet.prototype.setSelection = function setSelection(ids) {
|
|
256
382
|
* Get the selected items by their id
|
257
383
|
* @return {Array} ids The ids of the selected items
|
258
384
|
*/
|
259
|
-
ItemSet.prototype.getSelection = function
|
385
|
+
ItemSet.prototype.getSelection = function() {
|
260
386
|
return this.selection.concat([]);
|
261
387
|
};
|
262
388
|
|
@@ -265,7 +391,7 @@ ItemSet.prototype.getSelection = function getSelection() {
|
|
265
391
|
* @param {String | Number} id
|
266
392
|
* @private
|
267
393
|
*/
|
268
|
-
ItemSet.prototype._deselect = function
|
394
|
+
ItemSet.prototype._deselect = function(id) {
|
269
395
|
var selection = this.selection;
|
270
396
|
for (var i = 0, ii = selection.length; i < ii; i++) {
|
271
397
|
if (selection[i] == id) { // non-strict comparison!
|
@@ -275,51 +401,35 @@ ItemSet.prototype._deselect = function _deselect(id) {
|
|
275
401
|
}
|
276
402
|
};
|
277
403
|
|
278
|
-
/**
|
279
|
-
* Return the item sets frame
|
280
|
-
* @returns {HTMLElement} frame
|
281
|
-
*/
|
282
|
-
ItemSet.prototype.getFrame = function getFrame() {
|
283
|
-
return this.frame;
|
284
|
-
};
|
285
|
-
|
286
404
|
/**
|
287
405
|
* Repaint the component
|
288
406
|
* @return {boolean} Returns true if the component is resized
|
289
407
|
*/
|
290
|
-
ItemSet.prototype.
|
408
|
+
ItemSet.prototype.redraw = function() {
|
291
409
|
var margin = this.options.margin,
|
292
|
-
range = this.range,
|
410
|
+
range = this.body.range,
|
293
411
|
asSize = util.option.asSize,
|
294
|
-
asString = util.option.asString,
|
295
412
|
options = this.options,
|
296
|
-
orientation =
|
413
|
+
orientation = options.orientation,
|
297
414
|
resized = false,
|
298
|
-
frame = this.frame
|
299
|
-
|
300
|
-
// TODO: document this feature to specify one margin for both item and axis distance
|
301
|
-
if (typeof margin === 'number') {
|
302
|
-
margin = {
|
303
|
-
item: margin,
|
304
|
-
axis: margin
|
305
|
-
};
|
306
|
-
}
|
415
|
+
frame = this.dom.frame,
|
416
|
+
editable = options.editable.updateTime || options.editable.updateGroup;
|
307
417
|
|
308
|
-
// update
|
309
|
-
frame.className = 'itemset' + (
|
418
|
+
// update class name
|
419
|
+
frame.className = 'itemset' + (editable ? ' editable' : '');
|
310
420
|
|
311
421
|
// reorder the groups (if needed)
|
312
422
|
resized = this._orderGroups() || resized;
|
313
423
|
|
314
424
|
// check whether zoomed (in that case we need to re-stack everything)
|
315
425
|
// TODO: would be nicer to get this as a trigger from Range
|
316
|
-
var visibleInterval =
|
317
|
-
var zoomed = (visibleInterval != this.lastVisibleInterval) || (this.width != this.lastWidth);
|
426
|
+
var visibleInterval = range.end - range.start;
|
427
|
+
var zoomed = (visibleInterval != this.lastVisibleInterval) || (this.props.width != this.props.lastWidth);
|
318
428
|
if (zoomed) this.stackDirty = true;
|
319
429
|
this.lastVisibleInterval = visibleInterval;
|
320
|
-
this.lastWidth = this.width;
|
430
|
+
this.props.lastWidth = this.props.width;
|
321
431
|
|
322
|
-
//
|
432
|
+
// redraw all groups
|
323
433
|
var restack = this.stackDirty,
|
324
434
|
firstGroup = this._firstGroup(),
|
325
435
|
firstMargin = {
|
@@ -334,34 +444,27 @@ ItemSet.prototype.repaint = function repaint() {
|
|
334
444
|
minHeight = margin.axis + margin.item;
|
335
445
|
util.forEach(this.groups, function (group) {
|
336
446
|
var groupMargin = (group == firstGroup) ? firstMargin : nonFirstMargin;
|
337
|
-
|
447
|
+
var groupResized = group.redraw(range, groupMargin, restack);
|
448
|
+
resized = groupResized || resized;
|
338
449
|
height += group.height;
|
339
450
|
});
|
340
451
|
height = Math.max(height, minHeight);
|
341
452
|
this.stackDirty = false;
|
342
453
|
|
343
|
-
//
|
344
|
-
frame.style.left = asSize(options.left, '');
|
345
|
-
frame.style.right = asSize(options.right, '');
|
346
|
-
frame.style.top = asSize((orientation == 'top') ? '0' : '');
|
347
|
-
frame.style.bottom = asSize((orientation == 'top') ? '' : '0');
|
348
|
-
frame.style.width = asSize(options.width, '100%');
|
454
|
+
// update frame height
|
349
455
|
frame.style.height = asSize(height);
|
350
|
-
//frame.style.height = asSize('height' in options ? options.height : height); // TODO: reckon with height
|
351
456
|
|
352
457
|
// calculate actual size and position
|
353
|
-
this.top = frame.offsetTop;
|
354
|
-
this.left = frame.offsetLeft;
|
355
|
-
this.width = frame.offsetWidth;
|
356
|
-
this.height = height;
|
458
|
+
this.props.top = frame.offsetTop;
|
459
|
+
this.props.left = frame.offsetLeft;
|
460
|
+
this.props.width = frame.offsetWidth;
|
461
|
+
this.props.height = height;
|
357
462
|
|
358
463
|
// reposition axis
|
359
|
-
this.dom.axis.style.
|
360
|
-
|
361
|
-
|
362
|
-
this.dom.axis.style.
|
363
|
-
this.dom.axis.style.top = asSize((orientation == 'top') ? '0' : '');
|
364
|
-
this.dom.axis.style.bottom = asSize((orientation == 'top') ? '' : '0');
|
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';
|
365
468
|
|
366
469
|
// check if this component is resized
|
367
470
|
resized = this._isResized() || resized;
|
@@ -374,7 +477,7 @@ ItemSet.prototype.repaint = function repaint() {
|
|
374
477
|
* @return {Group | null} firstGroup
|
375
478
|
* @private
|
376
479
|
*/
|
377
|
-
ItemSet.prototype._firstGroup = function
|
480
|
+
ItemSet.prototype._firstGroup = function() {
|
378
481
|
var firstGroupIndex = (this.options.orientation == 'top') ? 0 : (this.groupIds.length - 1);
|
379
482
|
var firstGroupId = this.groupIds[firstGroupIndex];
|
380
483
|
var firstGroup = this.groups[firstGroupId] || this.groups[UNGROUPED];
|
@@ -387,7 +490,7 @@ ItemSet.prototype._firstGroup = function _firstGroup() {
|
|
387
490
|
* there are no groups specified.
|
388
491
|
* @protected
|
389
492
|
*/
|
390
|
-
ItemSet.prototype._updateUngrouped = function
|
493
|
+
ItemSet.prototype._updateUngrouped = function() {
|
391
494
|
var ungrouped = this.groups[UNGROUPED];
|
392
495
|
|
393
496
|
if (this.groupsData) {
|
@@ -416,35 +519,11 @@ ItemSet.prototype._updateUngrouped = function _updateUngrouped() {
|
|
416
519
|
}
|
417
520
|
};
|
418
521
|
|
419
|
-
/**
|
420
|
-
* Get the foreground container element
|
421
|
-
* @return {HTMLElement} foreground
|
422
|
-
*/
|
423
|
-
ItemSet.prototype.getForeground = function getForeground() {
|
424
|
-
return this.dom.foreground;
|
425
|
-
};
|
426
|
-
|
427
|
-
/**
|
428
|
-
* Get the background container element
|
429
|
-
* @return {HTMLElement} background
|
430
|
-
*/
|
431
|
-
ItemSet.prototype.getBackground = function getBackground() {
|
432
|
-
return this.dom.background;
|
433
|
-
};
|
434
|
-
|
435
|
-
/**
|
436
|
-
* Get the axis container element
|
437
|
-
* @return {HTMLElement} axis
|
438
|
-
*/
|
439
|
-
ItemSet.prototype.getAxis = function getAxis() {
|
440
|
-
return this.dom.axis;
|
441
|
-
};
|
442
|
-
|
443
522
|
/**
|
444
523
|
* Get the element for the labelset
|
445
524
|
* @return {HTMLElement} labelSet
|
446
525
|
*/
|
447
|
-
ItemSet.prototype.getLabelSet = function
|
526
|
+
ItemSet.prototype.getLabelSet = function() {
|
448
527
|
return this.dom.labelSet;
|
449
528
|
};
|
450
529
|
|
@@ -452,7 +531,7 @@ ItemSet.prototype.getLabelSet = function getLabelSet() {
|
|
452
531
|
* Set items
|
453
532
|
* @param {vis.DataSet | null} items
|
454
533
|
*/
|
455
|
-
ItemSet.prototype.setItems = function
|
534
|
+
ItemSet.prototype.setItems = function(items) {
|
456
535
|
var me = this,
|
457
536
|
ids,
|
458
537
|
oldItemsData = this.itemsData;
|
@@ -471,7 +550,7 @@ ItemSet.prototype.setItems = function setItems(items) {
|
|
471
550
|
if (oldItemsData) {
|
472
551
|
// unsubscribe from old dataset
|
473
552
|
util.forEach(this.itemListeners, function (callback, event) {
|
474
|
-
oldItemsData.
|
553
|
+
oldItemsData.off(event, callback);
|
475
554
|
});
|
476
555
|
|
477
556
|
// remove all drawn items
|
@@ -499,7 +578,7 @@ ItemSet.prototype.setItems = function setItems(items) {
|
|
499
578
|
* Get the current items
|
500
579
|
* @returns {vis.DataSet | null}
|
501
580
|
*/
|
502
|
-
ItemSet.prototype.getItems = function
|
581
|
+
ItemSet.prototype.getItems = function() {
|
503
582
|
return this.itemsData;
|
504
583
|
};
|
505
584
|
|
@@ -507,7 +586,7 @@ ItemSet.prototype.getItems = function getItems() {
|
|
507
586
|
* Set groups
|
508
587
|
* @param {vis.DataSet} groups
|
509
588
|
*/
|
510
|
-
ItemSet.prototype.setGroups = function
|
589
|
+
ItemSet.prototype.setGroups = function(groups) {
|
511
590
|
var me = this,
|
512
591
|
ids;
|
513
592
|
|
@@ -520,7 +599,7 @@ ItemSet.prototype.setGroups = function setGroups(groups) {
|
|
520
599
|
// remove all drawn groups
|
521
600
|
ids = this.groupsData.getIds();
|
522
601
|
this.groupsData = null;
|
523
|
-
this._onRemoveGroups(ids); // note: this will cause a
|
602
|
+
this._onRemoveGroups(ids); // note: this will cause a redraw
|
524
603
|
}
|
525
604
|
|
526
605
|
// replace the dataset
|
@@ -552,14 +631,14 @@ ItemSet.prototype.setGroups = function setGroups(groups) {
|
|
552
631
|
// update the order of all items in each group
|
553
632
|
this._order();
|
554
633
|
|
555
|
-
this.emit('change');
|
634
|
+
this.body.emitter.emit('change');
|
556
635
|
};
|
557
636
|
|
558
637
|
/**
|
559
638
|
* Get the current groups
|
560
639
|
* @returns {vis.DataSet | null} groups
|
561
640
|
*/
|
562
|
-
ItemSet.prototype.getGroups = function
|
641
|
+
ItemSet.prototype.getGroups = function() {
|
563
642
|
return this.groupsData;
|
564
643
|
};
|
565
644
|
|
@@ -567,7 +646,7 @@ ItemSet.prototype.getGroups = function getGroups() {
|
|
567
646
|
* Remove an item by its id
|
568
647
|
* @param {String | Number} id
|
569
648
|
*/
|
570
|
-
ItemSet.prototype.removeItem = function
|
649
|
+
ItemSet.prototype.removeItem = function(id) {
|
571
650
|
var item = this.itemsData.get(id),
|
572
651
|
dataset = this._myDataSet();
|
573
652
|
|
@@ -588,14 +667,12 @@ ItemSet.prototype.removeItem = function removeItem (id) {
|
|
588
667
|
* @param {Number[]} ids
|
589
668
|
* @protected
|
590
669
|
*/
|
591
|
-
ItemSet.prototype._onUpdate = function
|
592
|
-
var me = this
|
593
|
-
items = this.items,
|
594
|
-
itemOptions = this.itemOptions;
|
670
|
+
ItemSet.prototype._onUpdate = function(ids) {
|
671
|
+
var me = this;
|
595
672
|
|
596
673
|
ids.forEach(function (id) {
|
597
|
-
var itemData = me.itemsData.get(id),
|
598
|
-
item = items[id],
|
674
|
+
var itemData = me.itemsData.get(id, me.itemOptions),
|
675
|
+
item = me.items[id],
|
599
676
|
type = itemData.type ||
|
600
677
|
(itemData.start && itemData.end && 'range') ||
|
601
678
|
me.options.type ||
|
@@ -618,7 +695,7 @@ ItemSet.prototype._onUpdate = function _onUpdate(ids) {
|
|
618
695
|
if (!item) {
|
619
696
|
// create item
|
620
697
|
if (constructor) {
|
621
|
-
item = new constructor(itemData, me.
|
698
|
+
item = new constructor(itemData, me.conversion, me.options);
|
622
699
|
item.id = id; // TODO: not so nice setting id afterwards
|
623
700
|
me._addItem(item);
|
624
701
|
}
|
@@ -629,8 +706,8 @@ ItemSet.prototype._onUpdate = function _onUpdate(ids) {
|
|
629
706
|
});
|
630
707
|
|
631
708
|
this._order();
|
632
|
-
this.stackDirty = true; // force re-stacking of all items next
|
633
|
-
this.emit('change');
|
709
|
+
this.stackDirty = true; // force re-stacking of all items next redraw
|
710
|
+
this.body.emitter.emit('change');
|
634
711
|
};
|
635
712
|
|
636
713
|
/**
|
@@ -645,7 +722,7 @@ ItemSet.prototype._onAdd = ItemSet.prototype._onUpdate;
|
|
645
722
|
* @param {Number[]} ids
|
646
723
|
* @protected
|
647
724
|
*/
|
648
|
-
ItemSet.prototype._onRemove = function
|
725
|
+
ItemSet.prototype._onRemove = function(ids) {
|
649
726
|
var count = 0;
|
650
727
|
var me = this;
|
651
728
|
ids.forEach(function (id) {
|
@@ -659,8 +736,8 @@ ItemSet.prototype._onRemove = function _onRemove(ids) {
|
|
659
736
|
if (count) {
|
660
737
|
// update order
|
661
738
|
this._order();
|
662
|
-
this.stackDirty = true; // force re-stacking of all items next
|
663
|
-
this.emit('change');
|
739
|
+
this.stackDirty = true; // force re-stacking of all items next redraw
|
740
|
+
this.body.emitter.emit('change');
|
664
741
|
}
|
665
742
|
};
|
666
743
|
|
@@ -668,7 +745,7 @@ ItemSet.prototype._onRemove = function _onRemove(ids) {
|
|
668
745
|
* Update the order of item in all groups
|
669
746
|
* @private
|
670
747
|
*/
|
671
|
-
ItemSet.prototype._order = function
|
748
|
+
ItemSet.prototype._order = function() {
|
672
749
|
// reorder the items in all groups
|
673
750
|
// TODO: optimization: only reorder groups affected by the changed items
|
674
751
|
util.forEach(this.groups, function (group) {
|
@@ -681,7 +758,7 @@ ItemSet.prototype._order = function _order() {
|
|
681
758
|
* @param {Number[]} ids
|
682
759
|
* @private
|
683
760
|
*/
|
684
|
-
ItemSet.prototype._onUpdateGroups = function
|
761
|
+
ItemSet.prototype._onUpdateGroups = function(ids) {
|
685
762
|
this._onAddGroups(ids);
|
686
763
|
};
|
687
764
|
|
@@ -690,7 +767,7 @@ ItemSet.prototype._onUpdateGroups = function _onUpdateGroups(ids) {
|
|
690
767
|
* @param {Number[]} ids
|
691
768
|
* @private
|
692
769
|
*/
|
693
|
-
ItemSet.prototype._onAddGroups = function
|
770
|
+
ItemSet.prototype._onAddGroups = function(ids) {
|
694
771
|
var me = this;
|
695
772
|
|
696
773
|
ids.forEach(function (id) {
|
@@ -730,7 +807,7 @@ ItemSet.prototype._onAddGroups = function _onAddGroups(ids) {
|
|
730
807
|
}
|
731
808
|
});
|
732
809
|
|
733
|
-
this.emit('change');
|
810
|
+
this.body.emitter.emit('change');
|
734
811
|
};
|
735
812
|
|
736
813
|
/**
|
@@ -738,7 +815,7 @@ ItemSet.prototype._onAddGroups = function _onAddGroups(ids) {
|
|
738
815
|
* @param {Number[]} ids
|
739
816
|
* @private
|
740
817
|
*/
|
741
|
-
ItemSet.prototype._onRemoveGroups = function
|
818
|
+
ItemSet.prototype._onRemoveGroups = function(ids) {
|
742
819
|
var groups = this.groups;
|
743
820
|
ids.forEach(function (id) {
|
744
821
|
var group = groups[id];
|
@@ -751,7 +828,7 @@ ItemSet.prototype._onRemoveGroups = function _onRemoveGroups(ids) {
|
|
751
828
|
|
752
829
|
this.markDirty();
|
753
830
|
|
754
|
-
this.emit('change');
|
831
|
+
this.body.emitter.emit('change');
|
755
832
|
};
|
756
833
|
|
757
834
|
/**
|
@@ -794,7 +871,7 @@ ItemSet.prototype._orderGroups = function () {
|
|
794
871
|
* @param {Item} item
|
795
872
|
* @private
|
796
873
|
*/
|
797
|
-
ItemSet.prototype._addItem = function
|
874
|
+
ItemSet.prototype._addItem = function(item) {
|
798
875
|
this.items[item.id] = item;
|
799
876
|
|
800
877
|
// add to group
|
@@ -809,12 +886,12 @@ ItemSet.prototype._addItem = function _addItem(item) {
|
|
809
886
|
* @param {Object} itemData
|
810
887
|
* @private
|
811
888
|
*/
|
812
|
-
ItemSet.prototype._updateItem = function
|
889
|
+
ItemSet.prototype._updateItem = function(item, itemData) {
|
813
890
|
var oldGroupId = item.data.group;
|
814
891
|
|
815
892
|
item.data = itemData;
|
816
893
|
if (item.displayed) {
|
817
|
-
item.
|
894
|
+
item.redraw();
|
818
895
|
}
|
819
896
|
|
820
897
|
// update group
|
@@ -834,7 +911,7 @@ ItemSet.prototype._updateItem = function _updateItem(item, itemData) {
|
|
834
911
|
* @param {Item} item
|
835
912
|
* @private
|
836
913
|
*/
|
837
|
-
ItemSet.prototype._removeItem = function
|
914
|
+
ItemSet.prototype._removeItem = function(item) {
|
838
915
|
// remove from DOM
|
839
916
|
item.hide();
|
840
917
|
|
@@ -857,7 +934,7 @@ ItemSet.prototype._removeItem = function _removeItem(item) {
|
|
857
934
|
* @returns {Array}
|
858
935
|
* @private
|
859
936
|
*/
|
860
|
-
ItemSet.prototype._constructByEndArray = function
|
937
|
+
ItemSet.prototype._constructByEndArray = function(array) {
|
861
938
|
var endArray = [];
|
862
939
|
|
863
940
|
for (var i = 0; i < array.length; i++) {
|
@@ -869,25 +946,17 @@ ItemSet.prototype._constructByEndArray = function _constructByEndArray(array) {
|
|
869
946
|
};
|
870
947
|
|
871
948
|
/**
|
872
|
-
*
|
873
|
-
*
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
width = Math.max(width, group.getLabelWidth());
|
880
|
-
});
|
881
|
-
|
882
|
-
return width;
|
883
|
-
};
|
884
|
-
|
885
|
-
/**
|
886
|
-
* Get the height of the itemsets background
|
887
|
-
* @return {Number} height
|
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
|
888
956
|
*/
|
889
|
-
ItemSet.prototype.
|
890
|
-
|
957
|
+
ItemSet.prototype._onTouch = function (event) {
|
958
|
+
// store the touched item, used in _onDragStart
|
959
|
+
this.touchParams.item = ItemSet.itemFromTarget(event);
|
891
960
|
};
|
892
961
|
|
893
962
|
/**
|
@@ -900,7 +969,7 @@ ItemSet.prototype._onDragStart = function (event) {
|
|
900
969
|
return;
|
901
970
|
}
|
902
971
|
|
903
|
-
var item =
|
972
|
+
var item = this.touchParams.item || null,
|
904
973
|
me = this,
|
905
974
|
props;
|
906
975
|
|
@@ -966,9 +1035,10 @@ ItemSet.prototype._onDragStart = function (event) {
|
|
966
1035
|
*/
|
967
1036
|
ItemSet.prototype._onDrag = function (event) {
|
968
1037
|
if (this.touchParams.itemProps) {
|
969
|
-
var
|
1038
|
+
var range = this.body.range,
|
1039
|
+
snap = this.body.util.snap || null,
|
970
1040
|
deltaX = event.gesture.deltaX,
|
971
|
-
scale = (this.width / (
|
1041
|
+
scale = (this.props.width / (range.end - range.start)),
|
972
1042
|
offset = deltaX / scale;
|
973
1043
|
|
974
1044
|
// move
|
@@ -1000,8 +1070,8 @@ ItemSet.prototype._onDrag = function (event) {
|
|
1000
1070
|
|
1001
1071
|
// TODO: implement onMoving handler
|
1002
1072
|
|
1003
|
-
this.stackDirty = true; // force re-stacking of all items next
|
1004
|
-
this.emit('change');
|
1073
|
+
this.stackDirty = true; // force re-stacking of all items next redraw
|
1074
|
+
this.body.emitter.emit('change');
|
1005
1075
|
|
1006
1076
|
event.stopPropagation();
|
1007
1077
|
}
|
@@ -1021,16 +1091,18 @@ ItemSet.prototype._onDragEnd = function (event) {
|
|
1021
1091
|
|
1022
1092
|
this.touchParams.itemProps.forEach(function (props) {
|
1023
1093
|
var id = props.item.id,
|
1024
|
-
itemData = me.itemsData.get(id);
|
1094
|
+
itemData = me.itemsData.get(id, me.itemOptions);
|
1025
1095
|
|
1026
1096
|
var changed = false;
|
1027
1097
|
if ('start' in props.item.data) {
|
1028
1098
|
changed = (props.start != props.item.data.start.valueOf());
|
1029
|
-
itemData.start = util.convert(props.item.data.start,
|
1099
|
+
itemData.start = util.convert(props.item.data.start,
|
1100
|
+
dataset._options.type && dataset._options.type.start || 'Date');
|
1030
1101
|
}
|
1031
1102
|
if ('end' in props.item.data) {
|
1032
1103
|
changed = changed || (props.end != props.item.data.end.valueOf());
|
1033
|
-
itemData.end = util.convert(props.item.data.end,
|
1104
|
+
itemData.end = util.convert(props.item.data.end,
|
1105
|
+
dataset._options.type && dataset._options.type.end || 'Date');
|
1034
1106
|
}
|
1035
1107
|
if ('group' in props.item.data) {
|
1036
1108
|
changed = changed || (props.group != props.item.data.group);
|
@@ -1042,7 +1114,7 @@ ItemSet.prototype._onDragEnd = function (event) {
|
|
1042
1114
|
me.options.onMove(itemData, function (itemData) {
|
1043
1115
|
if (itemData) {
|
1044
1116
|
// apply changes
|
1045
|
-
itemData[dataset.
|
1117
|
+
itemData[dataset._fieldId] = id; // ensure the item contains its id (can be undefined)
|
1046
1118
|
changes.push(itemData);
|
1047
1119
|
}
|
1048
1120
|
else {
|
@@ -1050,8 +1122,8 @@ ItemSet.prototype._onDragEnd = function (event) {
|
|
1050
1122
|
if ('start' in props) props.item.data.start = props.start;
|
1051
1123
|
if ('end' in props) props.item.data.end = props.end;
|
1052
1124
|
|
1053
|
-
me.stackDirty = true; // force re-stacking of all items next
|
1054
|
-
me.emit('change');
|
1125
|
+
me.stackDirty = true; // force re-stacking of all items next redraw
|
1126
|
+
me.body.emitter.emit('change');
|
1055
1127
|
}
|
1056
1128
|
});
|
1057
1129
|
}
|
@@ -1067,13 +1139,137 @@ ItemSet.prototype._onDragEnd = function (event) {
|
|
1067
1139
|
}
|
1068
1140
|
};
|
1069
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
|
+
|
1070
1266
|
/**
|
1071
1267
|
* Find an item from an event target:
|
1072
1268
|
* searches for the attribute 'timeline-item' in the event target's element tree
|
1073
1269
|
* @param {Event} event
|
1074
1270
|
* @return {Item | null} item
|
1075
1271
|
*/
|
1076
|
-
ItemSet.itemFromTarget = function
|
1272
|
+
ItemSet.itemFromTarget = function(event) {
|
1077
1273
|
var target = event.target;
|
1078
1274
|
while (target) {
|
1079
1275
|
if (target.hasOwnProperty('timeline-item')) {
|
@@ -1091,7 +1287,7 @@ ItemSet.itemFromTarget = function itemFromTarget (event) {
|
|
1091
1287
|
* @param {Event} event
|
1092
1288
|
* @return {Group | null} group
|
1093
1289
|
*/
|
1094
|
-
ItemSet.groupFromTarget = function
|
1290
|
+
ItemSet.groupFromTarget = function(event) {
|
1095
1291
|
var target = event.target;
|
1096
1292
|
while (target) {
|
1097
1293
|
if (target.hasOwnProperty('timeline-group')) {
|
@@ -1109,7 +1305,7 @@ ItemSet.groupFromTarget = function groupFromTarget (event) {
|
|
1109
1305
|
* @param {Event} event
|
1110
1306
|
* @return {ItemSet | null} item
|
1111
1307
|
*/
|
1112
|
-
ItemSet.itemSetFromTarget = function
|
1308
|
+
ItemSet.itemSetFromTarget = function(event) {
|
1113
1309
|
var target = event.target;
|
1114
1310
|
while (target) {
|
1115
1311
|
if (target.hasOwnProperty('timeline-itemset')) {
|
@@ -1126,7 +1322,7 @@ ItemSet.itemSetFromTarget = function itemSetFromTarget (event) {
|
|
1126
1322
|
* @returns {null | DataSet} dataset
|
1127
1323
|
* @private
|
1128
1324
|
*/
|
1129
|
-
ItemSet.prototype._myDataSet = function
|
1325
|
+
ItemSet.prototype._myDataSet = function() {
|
1130
1326
|
// find the root DataSet
|
1131
1327
|
var dataset = this.itemsData;
|
1132
1328
|
while (dataset instanceof DataView) {
|