chaplinks-library-timeline 2.5.5 → 2.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/lib/chaplinks/library/timeline/version.rb +1 -1
- data/vendor/assets/javascripts/chaplinks-library/timeline/timeline-locales.js +65 -33
- data/vendor/assets/javascripts/chaplinks-library/timeline/timeline.js +758 -193
- data/vendor/assets/stylesheets/chaplinks-library/timeline/index.css +3 -0
- metadata +16 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38fefa2f824f0f0240cf305b0957211958d4feb7
|
4
|
+
data.tar.gz: faf9c59c8ab1c628c66ae2c85b7a7b49babe23eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0da5dfa904b50daadace34c2b98933bdf8e1a219d75934df78f654ae9a5d8ef7b67a7e21665f1372a8cef6e2e45615eb74e10fb014bc750422ab3e42d3cf4c6a
|
7
|
+
data.tar.gz: 81002371685bc5994f9a29e59f9d0c22c30eddbbdb7f6fd09e35f1510a71986b26330f6c701544452a0528d89fcdb911072e0d560526a0a88943f145d2237ce7
|
data/Gemfile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
if (typeof links === 'undefined') {
|
1
|
+
if (typeof links === 'undefined') {
|
2
2
|
links = {};
|
3
3
|
links.locales = {};
|
4
4
|
} else if (typeof links.locales === 'undefined') {
|
@@ -7,10 +7,10 @@ if (typeof links === 'undefined') {
|
|
7
7
|
|
8
8
|
// English ===================================================
|
9
9
|
links.locales['en'] = {
|
10
|
-
'MONTHS':
|
11
|
-
'MONTHS_SHORT':
|
12
|
-
'DAYS':
|
13
|
-
'DAYS_SHORT':
|
10
|
+
'MONTHS': ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
|
11
|
+
'MONTHS_SHORT': ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
|
12
|
+
'DAYS': ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
|
13
|
+
'DAYS_SHORT': ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
14
14
|
'ZOOM_IN': "Zoom in",
|
15
15
|
'ZOOM_OUT': "Zoom out",
|
16
16
|
'MOVE_LEFT': "Move left",
|
@@ -24,10 +24,10 @@ links.locales['en_UK'] = links.locales['en'];
|
|
24
24
|
|
25
25
|
// French ===================================================
|
26
26
|
links.locales['fr'] = {
|
27
|
-
'MONTHS':
|
28
|
-
'MONTHS_SHORT':
|
29
|
-
'DAYS':
|
30
|
-
'DAYS_SHORT':
|
27
|
+
'MONTHS': ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"],
|
28
|
+
'MONTHS_SHORT': ["Jan", "Fev", "Mar", "Avr", "Mai", "Jun", "Jul", "Aou", "Sep", "Oct", "Nov", "Dec"],
|
29
|
+
'DAYS': ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"],
|
30
|
+
'DAYS_SHORT': ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"],
|
31
31
|
'ZOOM_IN': "Zoomer",
|
32
32
|
'ZOOM_OUT': "Dézoomer",
|
33
33
|
'MOVE_LEFT': "Déplacer à gauche",
|
@@ -42,10 +42,10 @@ links.locales['fr_CA'] = links.locales['fr'];
|
|
42
42
|
|
43
43
|
// Catalan ===================================================
|
44
44
|
links.locales['ca'] = {
|
45
|
-
'MONTHS':
|
46
|
-
'MONTHS_SHORT':
|
47
|
-
'DAYS':
|
48
|
-
'DAYS_SHORT':
|
45
|
+
'MONTHS': ["Gener", "Febrer", "Març", "Abril", "Maig", "Juny", "Juliol", "Setembre", "Octubre", "Novembre", "Desembre"],
|
46
|
+
'MONTHS_SHORT': ["Gen", "Feb", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Oct", "Nov", "Des"],
|
47
|
+
'DAYS': ["Diumenge", "Dilluns", "Dimarts", "Dimecres", "Dijous", "Divendres", "Dissabte"],
|
48
|
+
'DAYS_SHORT': ["Dm.", "Dl.", "Dm.", "Dc.", "Dj.", "Dv.", "Ds."],
|
49
49
|
'ZOOM_IN': "Augmentar zoom",
|
50
50
|
'ZOOM_OUT': "Disminuir zoom",
|
51
51
|
'MOVE_LEFT': "Moure esquerra",
|
@@ -57,10 +57,10 @@ links.locales['ca_ES'] = links.locales['ca'];
|
|
57
57
|
|
58
58
|
// German ===================================================
|
59
59
|
links.locales['de'] = {
|
60
|
-
'MONTHS':
|
61
|
-
'MONTHS_SHORT':
|
62
|
-
'DAYS':
|
63
|
-
'DAYS_SHORT':
|
60
|
+
'MONTHS': ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
|
61
|
+
'MONTHS_SHORT': ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"],
|
62
|
+
'DAYS': ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
|
63
|
+
'DAYS_SHORT': ["Son", "Mon", "Die", "Mit", "Don", "Fre", "Sam"],
|
64
64
|
'ZOOM_IN': "Vergrößern",
|
65
65
|
'ZOOM_OUT': "Verkleinern",
|
66
66
|
'MOVE_LEFT': "Nach links verschieben",
|
@@ -74,10 +74,10 @@ links.locales['de_CH'] = links.locales['de'];
|
|
74
74
|
|
75
75
|
// Danish ===================================================
|
76
76
|
links.locales['da'] = {
|
77
|
-
'MONTHS':
|
78
|
-
'MONTHS_SHORT':
|
79
|
-
'DAYS':
|
80
|
-
'DAYS_SHORT':
|
77
|
+
'MONTHS': ["januar", "februar", "marts", "april", "maj", "juni", "juli", "august", "september", "oktober", "november", "december"],
|
78
|
+
'MONTHS_SHORT': ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "aug", "sep", "okt", "nov", "dec"],
|
79
|
+
'DAYS': ["søndag", "mandag", "tirsdag", "onsdag", "torsdag", "fredag", "lørdag"],
|
80
|
+
'DAYS_SHORT': ["søn", "man", "tir", "ons", "tor", "fre", "lør"],
|
81
81
|
'ZOOM_IN': "Zoom in",
|
82
82
|
'ZOOM_OUT': "Zoom out",
|
83
83
|
'MOVE_LEFT': "Move left",
|
@@ -89,10 +89,10 @@ links.locales['da_DK'] = links.locales['da'];
|
|
89
89
|
|
90
90
|
// Russian ===================================================
|
91
91
|
links.locales['ru'] = {
|
92
|
-
'MONTHS':
|
93
|
-
'MONTHS_SHORT':
|
94
|
-
'DAYS':
|
95
|
-
'DAYS_SHORT':
|
92
|
+
'MONTHS': ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"],
|
93
|
+
'MONTHS_SHORT': ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"],
|
94
|
+
'DAYS': ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"],
|
95
|
+
'DAYS_SHORT': ["Вос", "Пон", "Втo", "Срe", "Чет", "Пят", "Суб"],
|
96
96
|
'ZOOM_IN': "Увeличить",
|
97
97
|
'ZOOM_OUT': "Умeньшить",
|
98
98
|
'MOVE_LEFT': "Сдвинуть налeво",
|
@@ -104,10 +104,10 @@ links.locales['ru_RU'] = links.locales['ru'];
|
|
104
104
|
|
105
105
|
// Spanish ===================================================
|
106
106
|
links.locales['es'] = {
|
107
|
-
'MONTHS':
|
108
|
-
'MONTHS_SHORT':
|
109
|
-
'DAYS':
|
110
|
-
'DAYS_SHORT':
|
107
|
+
'MONTHS': ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"],
|
108
|
+
'MONTHS_SHORT': ["Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"],
|
109
|
+
'DAYS': ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"],
|
110
|
+
'DAYS_SHORT': ["Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb"],
|
111
111
|
'ZOOM_IN': "Aumentar zoom",
|
112
112
|
'ZOOM_OUT': "Disminuir zoom",
|
113
113
|
'MOVE_LEFT': "Mover izquierda",
|
@@ -120,10 +120,10 @@ links.locales['es_ES'] = links.locales['es'];
|
|
120
120
|
|
121
121
|
// Dutch =====================================================
|
122
122
|
links.locales['nl'] = {
|
123
|
-
'MONTHS':
|
124
|
-
'MONTHS_SHORT':
|
125
|
-
'DAYS':
|
126
|
-
'DAYS_SHORT':
|
123
|
+
'MONTHS': ["januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"],
|
124
|
+
'MONTHS_SHORT': ["jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"],
|
125
|
+
'DAYS': ["zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"],
|
126
|
+
'DAYS_SHORT': ["zo", "ma", "di", "wo", "do", "vr", "za"],
|
127
127
|
'ZOOM_IN': "Inzoomen",
|
128
128
|
'ZOOM_OUT': "Uitzoomen",
|
129
129
|
'MOVE_LEFT': "Naar links",
|
@@ -134,3 +134,35 @@ links.locales['nl'] = {
|
|
134
134
|
|
135
135
|
links.locales['nl_NL'] = links.locales['nl'];
|
136
136
|
links.locales['nl_BE'] = links.locales['nl'];
|
137
|
+
|
138
|
+
// Turkish ===================================================
|
139
|
+
links.locales['tr'] = {
|
140
|
+
'MONTHS': ["Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"],
|
141
|
+
'MONTHS_SHORT': ["Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara"],
|
142
|
+
'DAYS': ["Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi"],
|
143
|
+
'DAYS_SHORT': ["Paz", "Pzt", "Sal", "Çar", "Per", "Cum", "Cmt"],
|
144
|
+
'ZOOM_IN': "Büyült",
|
145
|
+
'ZOOM_OUT': "Küçült",
|
146
|
+
'MOVE_LEFT': "Sola Taşı",
|
147
|
+
'MOVE_RIGHT': "Sağa Taşı",
|
148
|
+
'NEW': "Yeni",
|
149
|
+
'CREATE_NEW_EVENT': "Yeni etkinlik oluştur"
|
150
|
+
};
|
151
|
+
|
152
|
+
links.locales['tr_TR'] = links.locales['tr'];
|
153
|
+
|
154
|
+
// Hungarian ===================================================
|
155
|
+
links.locales['hu'] = {
|
156
|
+
'MONTHS': ["január", "február", "március", "április", "május", "június", "július", "augusztus", "szeptember", "október", "november", "december"],
|
157
|
+
'MONTHS_SHORT': ["jan", "feb", "márc", "ápr", "máj", "jún", "júl", "aug", "szep", "okt", "nov", "dec"],
|
158
|
+
'DAYS': ["vasárnap", "hétfő", "kedd", "szerda", "csütörtök", "péntek", "szombat"],
|
159
|
+
'DAYS_SHORT': ["vas", "hét", "kedd", "sze", "csü", "pé", "szo"],
|
160
|
+
'ZOOM_IN': "Nagyítás",
|
161
|
+
'ZOOM_OUT': "Kicsinyítés",
|
162
|
+
'MOVE_LEFT': "Balra",
|
163
|
+
'MOVE_RIGHT': "Jobbra",
|
164
|
+
'NEW': "Új",
|
165
|
+
'CREATE_NEW_EVENT': "Új esemény készítése"
|
166
|
+
};
|
167
|
+
|
168
|
+
links.locales['hu_HU'] = links.locales['hu'];
|
@@ -27,11 +27,11 @@
|
|
27
27
|
* License for the specific language governing permissions and limitations under
|
28
28
|
* the License.
|
29
29
|
*
|
30
|
-
* Copyright (c) 2011-
|
30
|
+
* Copyright (c) 2011-2014 Almende B.V.
|
31
31
|
*
|
32
|
-
* @author
|
33
|
-
* @date
|
34
|
-
* @version 2.
|
32
|
+
* @author Jos de Jong, <jos@almende.org>
|
33
|
+
* @date 2014-07-28
|
34
|
+
* @version 2.9.0
|
35
35
|
*/
|
36
36
|
|
37
37
|
/*
|
@@ -43,7 +43,7 @@
|
|
43
43
|
* TODO
|
44
44
|
*
|
45
45
|
* Add zooming with pinching on Android
|
46
|
-
*
|
46
|
+
*
|
47
47
|
* Bug: when an item contains a javascript onclick or a link, this does not work
|
48
48
|
* when the item is not selected (when the item is being selected,
|
49
49
|
* it is redrawn, which cancels any onclick or link action)
|
@@ -60,8 +60,8 @@
|
|
60
60
|
*/
|
61
61
|
if (typeof links === 'undefined') {
|
62
62
|
links = {};
|
63
|
-
// important: do not use var, as "var links = {};" will overwrite
|
64
|
-
// the existing links variable value with undefined in IE8, IE7.
|
63
|
+
// important: do not use var, as "var links = {};" will overwrite
|
64
|
+
// the existing links variable value with undefined in IE8, IE7.
|
65
65
|
}
|
66
66
|
|
67
67
|
|
@@ -70,7 +70,7 @@ if (typeof links === 'undefined') {
|
|
70
70
|
*/
|
71
71
|
if (typeof google === 'undefined') {
|
72
72
|
google = undefined;
|
73
|
-
// important: do not use var, as "var google = undefined;" will overwrite
|
73
|
+
// important: do not use var, as "var google = undefined;" will overwrite
|
74
74
|
// the existing google variable value with undefined in IE8, IE7.
|
75
75
|
}
|
76
76
|
|
@@ -109,9 +109,11 @@ if (!Array.prototype.forEach) {
|
|
109
109
|
* The timeline is developed in javascript as a Google Visualization Chart.
|
110
110
|
*
|
111
111
|
* @param {Element} container The DOM element in which the Timeline will
|
112
|
-
*
|
112
|
+
* be created. Normally a div element.
|
113
|
+
* @param {Object} options A name/value map containing settings for the
|
114
|
+
* timeline. Optional.
|
113
115
|
*/
|
114
|
-
links.Timeline = function(container) {
|
116
|
+
links.Timeline = function(container, options) {
|
115
117
|
if (!container) {
|
116
118
|
// this call was probably only for inheritance, no constructor-code is required
|
117
119
|
return;
|
@@ -136,7 +138,7 @@ links.Timeline = function(container) {
|
|
136
138
|
|
137
139
|
this.listeners = {}; // event listener callbacks
|
138
140
|
|
139
|
-
// Initialize sizes.
|
141
|
+
// Initialize sizes.
|
140
142
|
// Needed for IE (which gives an error when you try to set an undefined
|
141
143
|
// value in a style)
|
142
144
|
this.size = {
|
@@ -170,10 +172,14 @@ links.Timeline = function(container) {
|
|
170
172
|
|
171
173
|
this.dom.container = container;
|
172
174
|
|
175
|
+
//
|
176
|
+
// Let's set the default options first
|
177
|
+
//
|
173
178
|
this.options = {
|
174
179
|
'width': "100%",
|
175
180
|
'height': "auto",
|
176
181
|
'minHeight': 0, // minimal height in pixels
|
182
|
+
'groupMinHeight': 0,
|
177
183
|
'autoHeight': true,
|
178
184
|
|
179
185
|
'eventMargin': 10, // minimal margin between events
|
@@ -192,28 +198,31 @@ links.Timeline = function(container) {
|
|
192
198
|
'editable': false,
|
193
199
|
'snapEvents': true,
|
194
200
|
'groupChangeable': true,
|
201
|
+
'timeChangeable': true,
|
195
202
|
|
196
203
|
'showCurrentTime': true, // show a red bar displaying the current time
|
197
|
-
'showCustomTime': false, // show a blue, draggable bar displaying a custom time
|
204
|
+
'showCustomTime': false, // show a blue, draggable bar displaying a custom time
|
198
205
|
'showMajorLabels': true,
|
199
206
|
'showMinorLabels': true,
|
200
207
|
'showNavigation': false,
|
201
208
|
'showButtonNew': false,
|
202
209
|
'groupsOnRight': false,
|
210
|
+
'groupsOrder' : true,
|
203
211
|
'axisOnTop': false,
|
204
212
|
'stackEvents': true,
|
205
213
|
'animate': true,
|
206
214
|
'animateZoom': true,
|
207
215
|
'cluster': false,
|
216
|
+
'clusterMaxItems': 5,
|
208
217
|
'style': 'box',
|
209
218
|
'customStackOrder': false, //a function(a,b) for determining stackorder amongst a group of items. Essentially a comparator, -ve value for "a before b" and vice versa
|
210
219
|
|
211
220
|
// i18n: Timeline only has built-in English text per default. Include timeline-locales.js to support more localized text.
|
212
221
|
'locale': 'en',
|
213
|
-
'MONTHS':
|
214
|
-
'MONTHS_SHORT':
|
215
|
-
'DAYS':
|
216
|
-
'DAYS_SHORT':
|
222
|
+
'MONTHS': ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
|
223
|
+
'MONTHS_SHORT': ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
|
224
|
+
'DAYS': ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
|
225
|
+
'DAYS_SHORT': ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
217
226
|
'ZOOM_IN': "Zoom in",
|
218
227
|
'ZOOM_OUT': "Zoom out",
|
219
228
|
'MOVE_LEFT': "Move left",
|
@@ -221,6 +230,11 @@ links.Timeline = function(container) {
|
|
221
230
|
'NEW': "New",
|
222
231
|
'CREATE_NEW_EVENT': "Create new event"
|
223
232
|
};
|
233
|
+
|
234
|
+
//
|
235
|
+
// Now we can set the givenproperties
|
236
|
+
//
|
237
|
+
this.setOptions(options);
|
224
238
|
|
225
239
|
this.clientTimeOffset = 0; // difference between client time and the time
|
226
240
|
// set via Timeline.setCurrentTime()
|
@@ -236,16 +250,17 @@ links.Timeline = function(container) {
|
|
236
250
|
|
237
251
|
// add standard item types
|
238
252
|
this.itemTypes = {
|
239
|
-
box:
|
240
|
-
range:
|
241
|
-
|
253
|
+
box: links.Timeline.ItemBox,
|
254
|
+
range: links.Timeline.ItemRange,
|
255
|
+
floatingRange: links.Timeline.ItemFloatingRange,
|
256
|
+
dot: links.Timeline.ItemDot
|
242
257
|
};
|
243
258
|
|
244
259
|
// initialize data
|
245
260
|
this.data = [];
|
246
261
|
this.firstDraw = true;
|
247
262
|
|
248
|
-
// date interval must be initialized
|
263
|
+
// date interval must be initialized
|
249
264
|
this.setVisibleChartRange(undefined, undefined, false);
|
250
265
|
|
251
266
|
// render for the first time
|
@@ -270,11 +285,16 @@ links.Timeline = function(container) {
|
|
270
285
|
* Object DataTable is defined in
|
271
286
|
* google.visualization.DataTable
|
272
287
|
* @param {Object} options A name/value map containing settings for the
|
273
|
-
* timeline. Optional.
|
288
|
+
* timeline. Optional. The use of options here
|
289
|
+
* is deprecated. Pass timeline options in the
|
290
|
+
* constructor or use setOptions()
|
274
291
|
*/
|
275
292
|
links.Timeline.prototype.draw = function(data, options) {
|
293
|
+
if (options) {
|
294
|
+
console.log("WARNING: Passing options in draw() is deprecated. Pass options to the constructur or use setOptions() instead!");
|
295
|
+
}
|
276
296
|
this.setOptions(options);
|
277
|
-
|
297
|
+
|
278
298
|
if (this.options.selectable) {
|
279
299
|
links.Timeline.addClassName(this.dom.frame, "timeline-selectable");
|
280
300
|
}
|
@@ -308,7 +328,7 @@ links.Timeline.prototype.setOptions = function(options) {
|
|
308
328
|
this.options[i] = options[i];
|
309
329
|
}
|
310
330
|
}
|
311
|
-
|
331
|
+
|
312
332
|
// prepare i18n dependent on set locale
|
313
333
|
if (typeof links.locales !== 'undefined' && this.options.locale !== 'en') {
|
314
334
|
var localeOpts = links.locales[this.options.locale];
|
@@ -344,6 +364,15 @@ links.Timeline.prototype.setOptions = function(options) {
|
|
344
364
|
this.options.autoHeight = (this.options.height === "auto");
|
345
365
|
};
|
346
366
|
|
367
|
+
/**
|
368
|
+
* Get options for the timeline.
|
369
|
+
*
|
370
|
+
* @return the options object
|
371
|
+
*/
|
372
|
+
links.Timeline.prototype.getOptions = function() {
|
373
|
+
return this.options;
|
374
|
+
};
|
375
|
+
|
347
376
|
/**
|
348
377
|
* Add new type of items
|
349
378
|
* @param {String} typeName Name of new type
|
@@ -389,10 +418,10 @@ links.Timeline.mapColumnIds = function (dataTable) {
|
|
389
418
|
cols.start = 0;
|
390
419
|
cols.end = 1;
|
391
420
|
cols.content = 2;
|
392
|
-
if (colCount
|
393
|
-
if (colCount
|
394
|
-
if (colCount
|
395
|
-
if (colCount
|
421
|
+
if (colCount > 3) {cols.group = 3}
|
422
|
+
if (colCount > 4) {cols.className = 4}
|
423
|
+
if (colCount > 5) {cols.editable = 5}
|
424
|
+
if (colCount > 6) {cols.type = 6}
|
396
425
|
}
|
397
426
|
|
398
427
|
return cols;
|
@@ -431,7 +460,7 @@ links.Timeline.prototype.setData = function(data) {
|
|
431
460
|
'group': ((cols.group != undefined) ? data.getValue(row, cols.group) : undefined),
|
432
461
|
'className': ((cols.className != undefined) ? data.getValue(row, cols.className) : undefined),
|
433
462
|
'editable': ((cols.editable != undefined) ? data.getValue(row, cols.editable) : undefined),
|
434
|
-
'type': ((cols.
|
463
|
+
'type': ((cols.type != undefined) ? data.getValue(row, cols.type) : undefined)
|
435
464
|
}));
|
436
465
|
}
|
437
466
|
}
|
@@ -564,6 +593,79 @@ links.Timeline.prototype.getItemIndex = function(element) {
|
|
564
593
|
return index;
|
565
594
|
};
|
566
595
|
|
596
|
+
|
597
|
+
/**
|
598
|
+
* Find the cluster index from a given HTML element
|
599
|
+
* If no cluster index is found, undefined is returned
|
600
|
+
* @param {Element} element
|
601
|
+
* @return {Number | undefined} index
|
602
|
+
*/
|
603
|
+
links.Timeline.prototype.getClusterIndex = function(element) {
|
604
|
+
var e = element,
|
605
|
+
dom = this.dom,
|
606
|
+
frame = dom.items.frame,
|
607
|
+
clusters = this.clusters,
|
608
|
+
index = undefined;
|
609
|
+
|
610
|
+
if (this.clusters) {
|
611
|
+
// try to find the frame where the clusters are located in
|
612
|
+
while (e.parentNode && e.parentNode !== frame) {
|
613
|
+
e = e.parentNode;
|
614
|
+
}
|
615
|
+
|
616
|
+
if (e.parentNode === frame) {
|
617
|
+
// yes! we have found the parent element of all clusters
|
618
|
+
// retrieve its id from the array with clusters
|
619
|
+
for (var i = 0, iMax = clusters.length; i < iMax; i++) {
|
620
|
+
if (clusters[i].dom === e) {
|
621
|
+
index = i;
|
622
|
+
break;
|
623
|
+
}
|
624
|
+
}
|
625
|
+
}
|
626
|
+
}
|
627
|
+
|
628
|
+
return index;
|
629
|
+
};
|
630
|
+
|
631
|
+
/**
|
632
|
+
* Find all elements within the start and end range
|
633
|
+
* If no element is found, returns an empty array
|
634
|
+
* @param start time
|
635
|
+
* @param end time
|
636
|
+
* @return Array itemsInRange
|
637
|
+
*/
|
638
|
+
links.Timeline.prototype.getVisibleItems = function (start, end) {
|
639
|
+
var items = this.items;
|
640
|
+
var itemsInRange = [];
|
641
|
+
|
642
|
+
if (items) {
|
643
|
+
for (var i = 0, iMax = items.length; i < iMax; i++) {
|
644
|
+
var item = items[i];
|
645
|
+
if (item.end) {
|
646
|
+
// Time range object // NH use getLeft and getRight here
|
647
|
+
if (start <= item.start && item.end <= end) {
|
648
|
+
itemsInRange.push({"row": i});
|
649
|
+
}
|
650
|
+
} else {
|
651
|
+
// Point object
|
652
|
+
if (start <= item.start && item.start <= end) {
|
653
|
+
itemsInRange.push({"row": i});
|
654
|
+
}
|
655
|
+
}
|
656
|
+
}
|
657
|
+
}
|
658
|
+
|
659
|
+
// var sel = [];
|
660
|
+
// if (this.selection) {
|
661
|
+
// sel.push({"row": this.selection.index});
|
662
|
+
// }
|
663
|
+
// return sel;
|
664
|
+
|
665
|
+
return itemsInRange;
|
666
|
+
};
|
667
|
+
|
668
|
+
|
567
669
|
/**
|
568
670
|
* Set a new size for the timeline
|
569
671
|
* @param {string} width Width in pixels or percentage (for example "800px"
|
@@ -776,7 +878,6 @@ links.Timeline.prototype.render = function(options) {
|
|
776
878
|
this.clusterItems();
|
777
879
|
this.filterItems();
|
778
880
|
this.stackItems(animate);
|
779
|
-
|
780
881
|
this.recalcItems();
|
781
882
|
|
782
883
|
// TODO: only repaint when resized or when filterItems or stackItems gave a change?
|
@@ -851,8 +952,6 @@ links.Timeline.prototype.repaintFrame = function() {
|
|
851
952
|
if (!dom.frame) {
|
852
953
|
dom.frame = document.createElement("DIV");
|
853
954
|
dom.frame.className = "timeline-frame ui-widget ui-widget-content ui-corner-all";
|
854
|
-
dom.frame.style.position = "relative";
|
855
|
-
dom.frame.style.overflow = "hidden";
|
856
955
|
dom.container.appendChild(dom.frame);
|
857
956
|
needsReflow = true;
|
858
957
|
}
|
@@ -870,8 +969,7 @@ links.Timeline.prototype.repaintFrame = function() {
|
|
870
969
|
if (!dom.content) {
|
871
970
|
// create content box where the axis and items will be created
|
872
971
|
dom.content = document.createElement("DIV");
|
873
|
-
dom.content.
|
874
|
-
dom.content.style.overflow = "hidden";
|
972
|
+
dom.content.className = "timeline-content";
|
875
973
|
dom.frame.appendChild(dom.content);
|
876
974
|
|
877
975
|
var timelines = document.createElement("DIV");
|
@@ -1451,9 +1549,9 @@ links.Timeline.prototype.reflowItems = function() {
|
|
1451
1549
|
}
|
1452
1550
|
|
1453
1551
|
if (group) {
|
1454
|
-
group.itemsHeight = group.itemsHeight ?
|
1552
|
+
group.itemsHeight = Math.max(this.options.groupMinHeight,group.itemsHeight ?
|
1455
1553
|
Math.max(group.itemsHeight, item.height) :
|
1456
|
-
item.height;
|
1554
|
+
item.height);
|
1457
1555
|
}
|
1458
1556
|
}
|
1459
1557
|
|
@@ -1547,9 +1645,12 @@ links.Timeline.prototype.recalcItems = function () {
|
|
1547
1645
|
for (i = 0, iMax = groups.length; i < iMax; i++) {
|
1548
1646
|
group = groups[i];
|
1549
1647
|
|
1550
|
-
|
1648
|
+
//
|
1649
|
+
// TODO: Do we want to apply a max height? how ?
|
1650
|
+
//
|
1651
|
+
var groupHeight = group.itemsHeight;
|
1551
1652
|
resized = resized || (groupHeight != group.height);
|
1552
|
-
group.height = groupHeight;
|
1653
|
+
group.height = Math.max(groupHeight, options.groupMinHeight);
|
1553
1654
|
|
1554
1655
|
actualHeight += groups[i].height + options.eventMargin;
|
1555
1656
|
}
|
@@ -1577,16 +1678,6 @@ links.Timeline.prototype.recalcItems = function () {
|
|
1577
1678
|
}
|
1578
1679
|
}
|
1579
1680
|
|
1580
|
-
// calculate top position of the visible items
|
1581
|
-
for (i = 0, iMax = renderedItems.length; i < iMax; i++) {
|
1582
|
-
item = renderedItems[i];
|
1583
|
-
group = item.group;
|
1584
|
-
|
1585
|
-
if (group) {
|
1586
|
-
item.top = group.top;
|
1587
|
-
}
|
1588
|
-
}
|
1589
|
-
|
1590
1681
|
resized = true;
|
1591
1682
|
}
|
1592
1683
|
|
@@ -1873,7 +1964,7 @@ links.Timeline.prototype.repaintGroups = function() {
|
|
1873
1964
|
labels.splice(needed, current - needed);
|
1874
1965
|
labelLines.splice(needed, current - needed);
|
1875
1966
|
itemLines.splice(needed, current - needed);
|
1876
|
-
|
1967
|
+
|
1877
1968
|
links.Timeline.addClassName(frame, options.groupsOnRight ? 'timeline-groups-axis-onright' : 'timeline-groups-axis-onleft');
|
1878
1969
|
|
1879
1970
|
// position the groups
|
@@ -2056,8 +2147,8 @@ links.Timeline.prototype.repaintDeleteButton = function () {
|
|
2056
2147
|
dom.items.deleteButton = deleteButton;
|
2057
2148
|
}
|
2058
2149
|
|
2059
|
-
var index = this.selection ? this.selection.index : -1,
|
2060
|
-
item = this.selection ? this.items[index] : undefined;
|
2150
|
+
var index = (this.selection && this.selection.index !== undefined) ? this.selection.index : -1,
|
2151
|
+
item = (this.selection && this.selection.index !== undefined) ? this.items[index] : undefined;
|
2061
2152
|
if (item && item.rendered && this.isEditable(item)) {
|
2062
2153
|
var right = item.getRight(this),
|
2063
2154
|
top = item.top;
|
@@ -2107,12 +2198,12 @@ links.Timeline.prototype.repaintDragAreas = function () {
|
|
2107
2198
|
}
|
2108
2199
|
|
2109
2200
|
// reposition left and right drag area
|
2110
|
-
var index = this.selection ? this.selection.index : -1,
|
2111
|
-
item = this.selection ? this.items[index] : undefined;
|
2201
|
+
var index = (this.selection && this.selection.index !== undefined) ? this.selection.index : -1,
|
2202
|
+
item = (this.selection && this.selection.index !== undefined) ? this.items[index] : undefined;
|
2112
2203
|
if (item && item.rendered && this.isEditable(item) &&
|
2113
|
-
(item instanceof links.Timeline.ItemRange)) {
|
2114
|
-
var left =
|
2115
|
-
right =
|
2204
|
+
(item instanceof links.Timeline.ItemRange || item instanceof links.Timeline.ItemFloatingRange)) {
|
2205
|
+
var left = item.getLeft(this), // NH change to getLeft
|
2206
|
+
right = item.getRight(this), // NH change to getRight
|
2116
2207
|
top = item.top,
|
2117
2208
|
height = item.height;
|
2118
2209
|
|
@@ -2178,9 +2269,9 @@ links.Timeline.prototype.repaintNavigation = function () {
|
|
2178
2269
|
navBar.addButton.className = "timeline-navigation-new";
|
2179
2270
|
navBar.addButton.title = options.CREATE_NEW_EVENT;
|
2180
2271
|
var addIconSpan = document.createElement("SPAN");
|
2181
|
-
addIconSpan.className = "ui-icon ui-icon-circle-plus";
|
2272
|
+
addIconSpan.className = "ui-icon ui-icon-circle-plus";
|
2182
2273
|
navBar.addButton.appendChild(addIconSpan);
|
2183
|
-
|
2274
|
+
|
2184
2275
|
var onAdd = function(event) {
|
2185
2276
|
links.Timeline.preventDefault(event);
|
2186
2277
|
links.Timeline.stopPropagation(event);
|
@@ -2188,11 +2279,9 @@ links.Timeline.prototype.repaintNavigation = function () {
|
|
2188
2279
|
// create a new event at the center of the frame
|
2189
2280
|
var w = timeline.size.contentWidth;
|
2190
2281
|
var x = w / 2;
|
2191
|
-
var xstart = timeline.screenToTime(x
|
2192
|
-
var xend = timeline.screenToTime(x + w / 10); // add 10% of timeline width
|
2282
|
+
var xstart = timeline.screenToTime(x);
|
2193
2283
|
if (options.snapEvents) {
|
2194
2284
|
timeline.step.snap(xstart);
|
2195
|
-
timeline.step.snap(xend);
|
2196
2285
|
}
|
2197
2286
|
|
2198
2287
|
var content = options.NEW;
|
@@ -2200,7 +2289,6 @@ links.Timeline.prototype.repaintNavigation = function () {
|
|
2200
2289
|
var preventRender = true;
|
2201
2290
|
timeline.addItem({
|
2202
2291
|
'start': xstart,
|
2203
|
-
'end': xend,
|
2204
2292
|
'content': content,
|
2205
2293
|
'group': group
|
2206
2294
|
}, preventRender);
|
@@ -2242,7 +2330,7 @@ links.Timeline.prototype.repaintNavigation = function () {
|
|
2242
2330
|
var ziIconSpan = document.createElement("SPAN");
|
2243
2331
|
ziIconSpan.className = "ui-icon ui-icon-circle-zoomin";
|
2244
2332
|
navBar.zoomInButton.appendChild(ziIconSpan);
|
2245
|
-
|
2333
|
+
|
2246
2334
|
var onZoomIn = function(event) {
|
2247
2335
|
links.Timeline.preventDefault(event);
|
2248
2336
|
links.Timeline.stopPropagation(event);
|
@@ -2260,7 +2348,7 @@ links.Timeline.prototype.repaintNavigation = function () {
|
|
2260
2348
|
var zoIconSpan = document.createElement("SPAN");
|
2261
2349
|
zoIconSpan.className = "ui-icon ui-icon-circle-zoomout";
|
2262
2350
|
navBar.zoomOutButton.appendChild(zoIconSpan);
|
2263
|
-
|
2351
|
+
|
2264
2352
|
var onZoomOut = function(event) {
|
2265
2353
|
links.Timeline.preventDefault(event);
|
2266
2354
|
links.Timeline.stopPropagation(event);
|
@@ -2280,7 +2368,7 @@ links.Timeline.prototype.repaintNavigation = function () {
|
|
2280
2368
|
var mlIconSpan = document.createElement("SPAN");
|
2281
2369
|
mlIconSpan.className = "ui-icon ui-icon-circle-arrow-w";
|
2282
2370
|
navBar.moveLeftButton.appendChild(mlIconSpan);
|
2283
|
-
|
2371
|
+
|
2284
2372
|
var onMoveLeft = function(event) {
|
2285
2373
|
links.Timeline.preventDefault(event);
|
2286
2374
|
links.Timeline.stopPropagation(event);
|
@@ -2298,7 +2386,7 @@ links.Timeline.prototype.repaintNavigation = function () {
|
|
2298
2386
|
var mrIconSpan = document.createElement("SPAN");
|
2299
2387
|
mrIconSpan.className = "ui-icon ui-icon-circle-arrow-e";
|
2300
2388
|
navBar.moveRightButton.appendChild(mrIconSpan);
|
2301
|
-
|
2389
|
+
|
2302
2390
|
var onMoveRight = function(event) {
|
2303
2391
|
links.Timeline.preventDefault(event);
|
2304
2392
|
links.Timeline.stopPropagation(event);
|
@@ -2524,7 +2612,7 @@ links.Timeline.prototype.onTouchMove = function(event) {
|
|
2524
2612
|
}
|
2525
2613
|
|
2526
2614
|
if (!params.zoomed) {
|
2527
|
-
// move
|
2615
|
+
// move
|
2528
2616
|
this.onMouseMove(event);
|
2529
2617
|
}
|
2530
2618
|
else {
|
@@ -2628,10 +2716,12 @@ links.Timeline.prototype.onMouseDown = function(event) {
|
|
2628
2716
|
params.itemDragRight = (params.target === dragRight);
|
2629
2717
|
|
2630
2718
|
if (params.itemDragLeft || params.itemDragRight) {
|
2631
|
-
params.itemIndex = this.selection ? this.selection.index : undefined;
|
2719
|
+
params.itemIndex = (this.selection && this.selection.index !== undefined) ? this.selection.index : undefined;
|
2720
|
+
delete params.clusterIndex;
|
2632
2721
|
}
|
2633
2722
|
else {
|
2634
2723
|
params.itemIndex = this.getItemIndex(params.target);
|
2724
|
+
params.clusterIndex = this.getClusterIndex(params.target);
|
2635
2725
|
}
|
2636
2726
|
|
2637
2727
|
params.customTime = (params.target === dom.customTime ||
|
@@ -2659,6 +2749,7 @@ links.Timeline.prototype.onMouseDown = function(event) {
|
|
2659
2749
|
'group': this.getGroupName(group)
|
2660
2750
|
});
|
2661
2751
|
params.itemIndex = (this.items.length - 1);
|
2752
|
+
delete params.clusterIndex;
|
2662
2753
|
this.selectItem(params.itemIndex);
|
2663
2754
|
params.itemDragRight = true;
|
2664
2755
|
}
|
@@ -2670,8 +2761,8 @@ links.Timeline.prototype.onMouseDown = function(event) {
|
|
2670
2761
|
params.itemStart = item.start;
|
2671
2762
|
params.itemEnd = item.end;
|
2672
2763
|
params.itemGroup = item.group;
|
2673
|
-
params.itemLeft = item.
|
2674
|
-
params.itemRight = item.
|
2764
|
+
params.itemLeft = item.getLeft(this); // NH Use item.getLeft here
|
2765
|
+
params.itemRight = item.getRight(this); // NH Use item.getRight here
|
2675
2766
|
}
|
2676
2767
|
else {
|
2677
2768
|
this.dom.frame.style.cursor = 'move';
|
@@ -2741,7 +2832,7 @@ links.Timeline.prototype.onMouseMove = function (event) {
|
|
2741
2832
|
left,
|
2742
2833
|
right;
|
2743
2834
|
|
2744
|
-
if (params.itemDragLeft) {
|
2835
|
+
if (params.itemDragLeft && options.timeChangeable) {
|
2745
2836
|
// move the start of the item
|
2746
2837
|
left = params.itemLeft + diffX;
|
2747
2838
|
right = params.itemRight;
|
@@ -2756,8 +2847,9 @@ links.Timeline.prototype.onMouseMove = function (event) {
|
|
2756
2847
|
left = right;
|
2757
2848
|
item.start = this.screenToTime(left);
|
2758
2849
|
}
|
2850
|
+
this.trigger('change');
|
2759
2851
|
}
|
2760
|
-
else if (params.itemDragRight) {
|
2852
|
+
else if (params.itemDragRight && options.timeChangeable) {
|
2761
2853
|
// move the end of the item
|
2762
2854
|
left = params.itemLeft;
|
2763
2855
|
right = params.itemRight + diffX;
|
@@ -2772,8 +2864,9 @@ links.Timeline.prototype.onMouseMove = function (event) {
|
|
2772
2864
|
right = left;
|
2773
2865
|
item.end = this.screenToTime(right);
|
2774
2866
|
}
|
2867
|
+
this.trigger('change');
|
2775
2868
|
}
|
2776
|
-
else {
|
2869
|
+
else if (options.timeChangeable) {
|
2777
2870
|
// move the item
|
2778
2871
|
left = params.itemLeft + diffX;
|
2779
2872
|
item.start = this.screenToTime(left);
|
@@ -2786,6 +2879,7 @@ links.Timeline.prototype.onMouseMove = function (event) {
|
|
2786
2879
|
right = left + (params.itemRight - params.itemLeft);
|
2787
2880
|
item.end = this.screenToTime(right);
|
2788
2881
|
}
|
2882
|
+
this.trigger('change');
|
2789
2883
|
}
|
2790
2884
|
|
2791
2885
|
item.setPosition(left, right);
|
@@ -2827,7 +2921,7 @@ links.Timeline.prototype.onMouseMove = function (event) {
|
|
2827
2921
|
this.recalcConversion();
|
2828
2922
|
|
2829
2923
|
// move the items by changing the left position of their frame.
|
2830
|
-
// this is much faster than repositioning all elements individually via the
|
2924
|
+
// this is much faster than repositioning all elements individually via the
|
2831
2925
|
// repaintFrame() function (which is done once at mouseup)
|
2832
2926
|
// note that we round diffX to prevent wrong positioning on millisecond scale
|
2833
2927
|
var previousLeft = params.previousLeft || 0;
|
@@ -2894,10 +2988,13 @@ links.Timeline.prototype.onMouseUp = function (event) {
|
|
2894
2988
|
'end': item.end
|
2895
2989
|
});
|
2896
2990
|
|
2897
|
-
// fire an add or
|
2898
|
-
// Note that the change can be canceled from within an event listener if
|
2991
|
+
// fire an add or changed event.
|
2992
|
+
// Note that the change can be canceled from within an event listener if
|
2899
2993
|
// this listener calls the method cancelChange().
|
2900
|
-
this.trigger(params.addItem ? 'add' : '
|
2994
|
+
this.trigger(params.addItem ? 'add' : 'changed');
|
2995
|
+
|
2996
|
+
//retrieve item data again to include changes made to it in the triggered event handlers
|
2997
|
+
item = this.items[params.itemIndex];
|
2901
2998
|
|
2902
2999
|
if (params.addItem) {
|
2903
3000
|
if (this.applyAdd) {
|
@@ -2933,6 +3030,11 @@ links.Timeline.prototype.onMouseUp = function (event) {
|
|
2933
3030
|
item.group = params.itemGroup;
|
2934
3031
|
// TODO: original group should be restored too
|
2935
3032
|
item.setPosition(params.itemLeft, params.itemRight);
|
3033
|
+
|
3034
|
+
this.updateData(params.itemIndex, {
|
3035
|
+
'start': params.itemStart,
|
3036
|
+
'end': params.itemEnd
|
3037
|
+
});
|
2936
3038
|
}
|
2937
3039
|
}
|
2938
3040
|
|
@@ -2950,7 +3052,7 @@ links.Timeline.prototype.onMouseUp = function (event) {
|
|
2950
3052
|
|
2951
3053
|
if (params.target === this.dom.items.deleteButton) {
|
2952
3054
|
// delete item
|
2953
|
-
if (this.selection) {
|
3055
|
+
if (this.selection && this.selection.index !== undefined) {
|
2954
3056
|
this.confirmDeleteItem(this.selection.index);
|
2955
3057
|
}
|
2956
3058
|
}
|
@@ -2962,6 +3064,10 @@ links.Timeline.prototype.onMouseUp = function (event) {
|
|
2962
3064
|
this.trigger('select');
|
2963
3065
|
}
|
2964
3066
|
}
|
3067
|
+
else if(params.clusterIndex != undefined) {
|
3068
|
+
this.selectCluster(params.clusterIndex);
|
3069
|
+
this.trigger('select');
|
3070
|
+
}
|
2965
3071
|
else {
|
2966
3072
|
if (options.unselectable) {
|
2967
3073
|
this.unselectItem();
|
@@ -3013,10 +3119,8 @@ links.Timeline.prototype.onDblClick = function (event) {
|
|
3013
3119
|
|
3014
3120
|
// create a new event at the current mouse position
|
3015
3121
|
var xstart = this.screenToTime(x);
|
3016
|
-
var xend = this.screenToTime(x + size.frameWidth / 10); // add 10% of timeline width
|
3017
3122
|
if (options.snapEvents) {
|
3018
3123
|
this.step.snap(xstart);
|
3019
|
-
this.step.snap(xend);
|
3020
3124
|
}
|
3021
3125
|
|
3022
3126
|
var content = options.NEW;
|
@@ -3024,7 +3128,6 @@ links.Timeline.prototype.onDblClick = function (event) {
|
|
3024
3128
|
var preventRender = true;
|
3025
3129
|
this.addItem({
|
3026
3130
|
'start': xstart,
|
3027
|
-
'end': xend,
|
3028
3131
|
'content': content,
|
3029
3132
|
'group': this.getGroupName(group)
|
3030
3133
|
}, preventRender);
|
@@ -3067,7 +3170,7 @@ links.Timeline.prototype.onMouseWheel = function(event) {
|
|
3067
3170
|
event = window.event;
|
3068
3171
|
}
|
3069
3172
|
|
3070
|
-
// retrieve delta
|
3173
|
+
// retrieve delta
|
3071
3174
|
var delta = 0;
|
3072
3175
|
if (event.wheelDelta) { /* IE/Opera. */
|
3073
3176
|
delta = event.wheelDelta/120;
|
@@ -3081,7 +3184,7 @@ links.Timeline.prototype.onMouseWheel = function(event) {
|
|
3081
3184
|
// Basically, delta is now positive if wheel was scrolled up,
|
3082
3185
|
// and negative, if wheel was scrolled down.
|
3083
3186
|
if (delta) {
|
3084
|
-
// TODO: on FireFox, the window is not redrawn within repeated scroll-events
|
3187
|
+
// TODO: on FireFox, the window is not redrawn within repeated scroll-events
|
3085
3188
|
// -> use a delayed redraw? Make a zoom queue?
|
3086
3189
|
|
3087
3190
|
var timeline = this;
|
@@ -3300,8 +3403,8 @@ links.Timeline.prototype.confirmDeleteItem = function(index) {
|
|
3300
3403
|
this.selectItem(index);
|
3301
3404
|
}
|
3302
3405
|
|
3303
|
-
// fire a delete event trigger.
|
3304
|
-
// Note that the delete event can be canceled from within an event listener if
|
3406
|
+
// fire a delete event trigger.
|
3407
|
+
// Note that the delete event can be canceled from within an event listener if
|
3305
3408
|
// this listener calls the method cancelChange().
|
3306
3409
|
this.trigger('delete');
|
3307
3410
|
|
@@ -3323,7 +3426,7 @@ links.Timeline.prototype.deleteItem = function(index, preventRender) {
|
|
3323
3426
|
throw "Cannot delete row, index out of range";
|
3324
3427
|
}
|
3325
3428
|
|
3326
|
-
if (this.selection) {
|
3429
|
+
if (this.selection && this.selection.index !== undefined) {
|
3327
3430
|
// adjust the selection
|
3328
3431
|
if (this.selection.index == index) {
|
3329
3432
|
// item to be deleted is selected
|
@@ -3586,6 +3689,16 @@ links.Timeline.Item.prototype.setPosition = function (left, right) {
|
|
3586
3689
|
// Should be implemented by sub-prototype
|
3587
3690
|
};
|
3588
3691
|
|
3692
|
+
/**
|
3693
|
+
* Calculate the left position of the item
|
3694
|
+
* @param {links.Timeline} timeline
|
3695
|
+
* @return {Number} left
|
3696
|
+
*/
|
3697
|
+
links.Timeline.Item.prototype.getLeft = function (timeline) {
|
3698
|
+
// Should be implemented by sub-prototype
|
3699
|
+
return 0;
|
3700
|
+
};
|
3701
|
+
|
3589
3702
|
/**
|
3590
3703
|
* Calculate the right position of the item
|
3591
3704
|
* @param {links.Timeline} timeline
|
@@ -3871,6 +3984,27 @@ links.Timeline.ItemBox.prototype.setPosition = function (left, right) {
|
|
3871
3984
|
}
|
3872
3985
|
};
|
3873
3986
|
|
3987
|
+
/**
|
3988
|
+
* Calculate the left position of the item
|
3989
|
+
* @param {links.Timeline} timeline
|
3990
|
+
* @return {Number} left
|
3991
|
+
* @override
|
3992
|
+
*/
|
3993
|
+
links.Timeline.ItemBox.prototype.getLeft = function (timeline) {
|
3994
|
+
var boxAlign = (timeline.options.box && timeline.options.box.align) ?
|
3995
|
+
timeline.options.box.align : undefined;
|
3996
|
+
|
3997
|
+
var left = timeline.timeToScreen(this.start);
|
3998
|
+
if (boxAlign == 'right') {
|
3999
|
+
left = left - width;
|
4000
|
+
}
|
4001
|
+
else { // default or 'center'
|
4002
|
+
left = (left - this.width / 2);
|
4003
|
+
}
|
4004
|
+
|
4005
|
+
return left;
|
4006
|
+
};
|
4007
|
+
|
3874
4008
|
/**
|
3875
4009
|
* Calculate the right position of the item
|
3876
4010
|
* @param {links.Timeline} timeline
|
@@ -4080,6 +4214,16 @@ links.Timeline.ItemRange.prototype.setPosition = function (left, right) {
|
|
4080
4214
|
}
|
4081
4215
|
};
|
4082
4216
|
|
4217
|
+
/**
|
4218
|
+
* Calculate the left position of the item
|
4219
|
+
* @param {links.Timeline} timeline
|
4220
|
+
* @return {Number} left
|
4221
|
+
* @override
|
4222
|
+
*/
|
4223
|
+
links.Timeline.ItemRange.prototype.getLeft = function (timeline) {
|
4224
|
+
return timeline.timeToScreen(this.start);
|
4225
|
+
};
|
4226
|
+
|
4083
4227
|
/**
|
4084
4228
|
* Calculate the right position of the item
|
4085
4229
|
* @param {links.Timeline} timeline
|
@@ -4100,6 +4244,237 @@ links.Timeline.ItemRange.prototype.getWidth = function (timeline) {
|
|
4100
4244
|
return timeline.timeToScreen(this.end) - timeline.timeToScreen(this.start);
|
4101
4245
|
};
|
4102
4246
|
|
4247
|
+
/**
|
4248
|
+
* @constructor links.Timeline.ItemFloatingRange
|
4249
|
+
* @extends links.Timeline.Item
|
4250
|
+
* @param {Object} data Object containing parameters start, end
|
4251
|
+
* content, group, type, className, editable.
|
4252
|
+
* @param {Object} [options] Options to set initial property values
|
4253
|
+
* {Number} top
|
4254
|
+
* {Number} left
|
4255
|
+
* {Number} width
|
4256
|
+
* {Number} height
|
4257
|
+
*/
|
4258
|
+
links.Timeline.ItemFloatingRange = function (data, options) {
|
4259
|
+
links.Timeline.Item.call(this, data, options);
|
4260
|
+
};
|
4261
|
+
|
4262
|
+
links.Timeline.ItemFloatingRange.prototype = new links.Timeline.Item();
|
4263
|
+
|
4264
|
+
/**
|
4265
|
+
* Select the item
|
4266
|
+
* @override
|
4267
|
+
*/
|
4268
|
+
links.Timeline.ItemFloatingRange.prototype.select = function () {
|
4269
|
+
var dom = this.dom;
|
4270
|
+
links.Timeline.addClassName(dom, 'timeline-event-selected ui-state-active');
|
4271
|
+
};
|
4272
|
+
|
4273
|
+
/**
|
4274
|
+
* Unselect the item
|
4275
|
+
* @override
|
4276
|
+
*/
|
4277
|
+
links.Timeline.ItemFloatingRange.prototype.unselect = function () {
|
4278
|
+
var dom = this.dom;
|
4279
|
+
links.Timeline.removeClassName(dom, 'timeline-event-selected ui-state-active');
|
4280
|
+
};
|
4281
|
+
|
4282
|
+
/**
|
4283
|
+
* Creates the DOM for the item, depending on its type
|
4284
|
+
* @return {Element | undefined}
|
4285
|
+
* @override
|
4286
|
+
*/
|
4287
|
+
links.Timeline.ItemFloatingRange.prototype.createDOM = function () {
|
4288
|
+
// background box
|
4289
|
+
var divBox = document.createElement("DIV");
|
4290
|
+
divBox.style.position = "absolute";
|
4291
|
+
|
4292
|
+
// contents box
|
4293
|
+
var divContent = document.createElement("DIV");
|
4294
|
+
divContent.className = "timeline-event-content";
|
4295
|
+
divBox.appendChild(divContent);
|
4296
|
+
|
4297
|
+
this.dom = divBox;
|
4298
|
+
this.updateDOM();
|
4299
|
+
|
4300
|
+
return divBox;
|
4301
|
+
};
|
4302
|
+
|
4303
|
+
/**
|
4304
|
+
* Append the items DOM to the given HTML container. If items DOM does not yet
|
4305
|
+
* exist, it will be created first.
|
4306
|
+
* @param {Element} container
|
4307
|
+
* @override
|
4308
|
+
*/
|
4309
|
+
links.Timeline.ItemFloatingRange.prototype.showDOM = function (container) {
|
4310
|
+
var dom = this.dom;
|
4311
|
+
if (!dom) {
|
4312
|
+
dom = this.createDOM();
|
4313
|
+
}
|
4314
|
+
|
4315
|
+
if (dom.parentNode != container) {
|
4316
|
+
if (dom.parentNode) {
|
4317
|
+
// container changed. remove the item from the old container
|
4318
|
+
this.hideDOM();
|
4319
|
+
}
|
4320
|
+
|
4321
|
+
// append to the new container
|
4322
|
+
container.appendChild(dom);
|
4323
|
+
this.rendered = true;
|
4324
|
+
}
|
4325
|
+
};
|
4326
|
+
|
4327
|
+
/**
|
4328
|
+
* Remove the items DOM from the current HTML container
|
4329
|
+
* The DOM will be kept in memory
|
4330
|
+
* @override
|
4331
|
+
*/
|
4332
|
+
links.Timeline.ItemFloatingRange.prototype.hideDOM = function () {
|
4333
|
+
var dom = this.dom;
|
4334
|
+
if (dom) {
|
4335
|
+
if (dom.parentNode) {
|
4336
|
+
dom.parentNode.removeChild(dom);
|
4337
|
+
}
|
4338
|
+
this.rendered = false;
|
4339
|
+
}
|
4340
|
+
};
|
4341
|
+
|
4342
|
+
/**
|
4343
|
+
* Update the DOM of the item. This will update the content and the classes
|
4344
|
+
* of the item
|
4345
|
+
* @override
|
4346
|
+
*/
|
4347
|
+
links.Timeline.ItemFloatingRange.prototype.updateDOM = function () {
|
4348
|
+
var divBox = this.dom;
|
4349
|
+
if (divBox) {
|
4350
|
+
// update contents
|
4351
|
+
divBox.firstChild.innerHTML = this.content;
|
4352
|
+
|
4353
|
+
// update class
|
4354
|
+
divBox.className = "timeline-event timeline-event-range ui-widget ui-state-default";
|
4355
|
+
|
4356
|
+
if (this.isCluster) {
|
4357
|
+
links.Timeline.addClassName(divBox, 'timeline-event-cluster ui-widget-header');
|
4358
|
+
}
|
4359
|
+
|
4360
|
+
// add item specific class name when provided
|
4361
|
+
if (this.className) {
|
4362
|
+
links.Timeline.addClassName(divBox, this.className);
|
4363
|
+
}
|
4364
|
+
|
4365
|
+
// TODO: apply selected className?
|
4366
|
+
}
|
4367
|
+
};
|
4368
|
+
|
4369
|
+
/**
|
4370
|
+
* Reposition the item, recalculate its left, top, and width, using the current
|
4371
|
+
* range of the timeline and the timeline options. *
|
4372
|
+
* @param {links.Timeline} timeline
|
4373
|
+
* @override
|
4374
|
+
*/
|
4375
|
+
links.Timeline.ItemFloatingRange.prototype.updatePosition = function (timeline) {
|
4376
|
+
var dom = this.dom;
|
4377
|
+
if (dom) {
|
4378
|
+
var contentWidth = timeline.size.contentWidth,
|
4379
|
+
left = this.getLeft(timeline), // NH use getLeft
|
4380
|
+
right = this.getRight(timeline); // NH use getRight;
|
4381
|
+
|
4382
|
+
// limit the width of the this, as browsers cannot draw very wide divs
|
4383
|
+
if (left < -contentWidth) {
|
4384
|
+
left = -contentWidth;
|
4385
|
+
}
|
4386
|
+
if (right > 2 * contentWidth) {
|
4387
|
+
right = 2 * contentWidth;
|
4388
|
+
}
|
4389
|
+
|
4390
|
+
dom.style.top = this.top + "px";
|
4391
|
+
dom.style.left = left + "px";
|
4392
|
+
//dom.style.width = Math.max(right - left - 2 * this.borderWidth, 1) + "px"; // TODO: borderWidth
|
4393
|
+
dom.style.width = Math.max(right - left, 1) + "px";
|
4394
|
+
}
|
4395
|
+
};
|
4396
|
+
|
4397
|
+
/**
|
4398
|
+
* Check if the item is visible in the timeline, and not part of a cluster
|
4399
|
+
* @param {Number} start
|
4400
|
+
* @param {Number} end
|
4401
|
+
* @return {boolean} visible
|
4402
|
+
* @override
|
4403
|
+
*/
|
4404
|
+
links.Timeline.ItemFloatingRange.prototype.isVisible = function (start, end) {
|
4405
|
+
if (this.cluster) {
|
4406
|
+
return false;
|
4407
|
+
}
|
4408
|
+
|
4409
|
+
// NH check for no end value
|
4410
|
+
if (this.end && this.start) {
|
4411
|
+
return (this.end > start)
|
4412
|
+
&& (this.start < end);
|
4413
|
+
} else if (this.start) {
|
4414
|
+
return (this.start < end);
|
4415
|
+
} else if (this.end) {
|
4416
|
+
return (this.end > start);
|
4417
|
+
} else {return true;}
|
4418
|
+
};
|
4419
|
+
|
4420
|
+
/**
|
4421
|
+
* Reposition the item
|
4422
|
+
* @param {Number} left
|
4423
|
+
* @param {Number} right
|
4424
|
+
* @override
|
4425
|
+
*/
|
4426
|
+
links.Timeline.ItemFloatingRange.prototype.setPosition = function (left, right) {
|
4427
|
+
var dom = this.dom;
|
4428
|
+
|
4429
|
+
dom.style.left = left + 'px';
|
4430
|
+
dom.style.width = (right - left) + 'px';
|
4431
|
+
|
4432
|
+
if (this.group) {
|
4433
|
+
this.top = this.group.top;
|
4434
|
+
dom.style.top = this.top + 'px';
|
4435
|
+
}
|
4436
|
+
};
|
4437
|
+
|
4438
|
+
/**
|
4439
|
+
* Calculate the left position of the item
|
4440
|
+
* @param {links.Timeline} timeline
|
4441
|
+
* @return {Number} left
|
4442
|
+
* @override
|
4443
|
+
*/
|
4444
|
+
links.Timeline.ItemFloatingRange.prototype.getLeft = function (timeline) {
|
4445
|
+
// NH check for no start value
|
4446
|
+
if (this.start) {
|
4447
|
+
return timeline.timeToScreen(this.start);
|
4448
|
+
} else {
|
4449
|
+
return 0;
|
4450
|
+
}
|
4451
|
+
};
|
4452
|
+
|
4453
|
+
/**
|
4454
|
+
* Calculate the right position of the item
|
4455
|
+
* @param {links.Timeline} timeline
|
4456
|
+
* @return {Number} right
|
4457
|
+
* @override
|
4458
|
+
*/
|
4459
|
+
links.Timeline.ItemFloatingRange.prototype.getRight = function (timeline) {
|
4460
|
+
// NH check for no end value
|
4461
|
+
if (this.end) {
|
4462
|
+
return timeline.timeToScreen(this.end);
|
4463
|
+
} else {
|
4464
|
+
return timeline.size.contentWidth;
|
4465
|
+
}
|
4466
|
+
};
|
4467
|
+
|
4468
|
+
/**
|
4469
|
+
* Calculate the width of the item
|
4470
|
+
* @param {links.Timeline} timeline
|
4471
|
+
* @return {Number} width
|
4472
|
+
* @override
|
4473
|
+
*/
|
4474
|
+
links.Timeline.ItemFloatingRange.prototype.getWidth = function (timeline) {
|
4475
|
+
return this.getRight(timeline) - this.getLeft(timeline);
|
4476
|
+
};
|
4477
|
+
|
4103
4478
|
/**
|
4104
4479
|
* @constructor links.Timeline.ItemDot
|
4105
4480
|
* @extends links.Timeline.Item
|
@@ -4312,6 +4687,16 @@ links.Timeline.ItemDot.prototype.setPosition = function (left, right) {
|
|
4312
4687
|
}
|
4313
4688
|
};
|
4314
4689
|
|
4690
|
+
/**
|
4691
|
+
* Calculate the left position of the item
|
4692
|
+
* @param {links.Timeline} timeline
|
4693
|
+
* @return {Number} left
|
4694
|
+
* @override
|
4695
|
+
*/
|
4696
|
+
links.Timeline.ItemDot.prototype.getLeft = function (timeline) {
|
4697
|
+
return timeline.timeToScreen(this.start);
|
4698
|
+
};
|
4699
|
+
|
4315
4700
|
/**
|
4316
4701
|
* Calculate the right position of the item
|
4317
4702
|
* @param {links.Timeline} timeline
|
@@ -4325,7 +4710,7 @@ links.Timeline.ItemDot.prototype.getRight = function (timeline) {
|
|
4325
4710
|
/**
|
4326
4711
|
* Retrieve the properties of an item.
|
4327
4712
|
* @param {Number} index
|
4328
|
-
* @return {Object}
|
4713
|
+
* @return {Object} itemData Object containing item properties:<br>
|
4329
4714
|
* {Date} start (required),
|
4330
4715
|
* {Date} end (optional),
|
4331
4716
|
* {String} content (required),
|
@@ -4339,28 +4724,91 @@ links.Timeline.prototype.getItem = function (index) {
|
|
4339
4724
|
throw "Cannot get item, index out of range";
|
4340
4725
|
}
|
4341
4726
|
|
4727
|
+
// take the original data as start, includes foreign fields
|
4728
|
+
var data = this.data,
|
4729
|
+
itemData;
|
4730
|
+
if (google && google.visualization &&
|
4731
|
+
data instanceof google.visualization.DataTable) {
|
4732
|
+
// map the datatable columns
|
4733
|
+
var cols = links.Timeline.mapColumnIds(data);
|
4734
|
+
|
4735
|
+
itemData = {};
|
4736
|
+
for (var col in cols) {
|
4737
|
+
if (cols.hasOwnProperty(col)) {
|
4738
|
+
itemData[col] = this.data.getValue(index, cols[col]);
|
4739
|
+
}
|
4740
|
+
}
|
4741
|
+
}
|
4742
|
+
else if (links.Timeline.isArray(this.data)) {
|
4743
|
+
// read JSON array
|
4744
|
+
itemData = links.Timeline.clone(this.data[index]);
|
4745
|
+
}
|
4746
|
+
else {
|
4747
|
+
throw "Unknown data type. DataTable or Array expected.";
|
4748
|
+
}
|
4749
|
+
|
4750
|
+
// override the data with current settings of the item (should be the same)
|
4342
4751
|
var item = this.items[index];
|
4343
4752
|
|
4344
|
-
|
4345
|
-
properties.start = new Date(item.start.valueOf());
|
4753
|
+
itemData.start = new Date(item.start.valueOf());
|
4346
4754
|
if (item.end) {
|
4347
|
-
|
4755
|
+
itemData.end = new Date(item.end.valueOf());
|
4348
4756
|
}
|
4349
|
-
|
4757
|
+
itemData.content = item.content;
|
4350
4758
|
if (item.group) {
|
4351
|
-
|
4759
|
+
itemData.group = this.getGroupName(item.group);
|
4352
4760
|
}
|
4353
|
-
if (
|
4354
|
-
|
4761
|
+
if (item.className) {
|
4762
|
+
itemData.className = item.className;
|
4355
4763
|
}
|
4356
|
-
if (
|
4357
|
-
|
4764
|
+
if (typeof item.editable !== 'undefined') {
|
4765
|
+
itemData.editable = item.editable;
|
4358
4766
|
}
|
4359
4767
|
if (item.type) {
|
4360
|
-
|
4768
|
+
itemData.type = item.type;
|
4769
|
+
}
|
4770
|
+
|
4771
|
+
return itemData;
|
4772
|
+
};
|
4773
|
+
|
4774
|
+
|
4775
|
+
/**
|
4776
|
+
* Retrieve the properties of a cluster.
|
4777
|
+
* @param {Number} index
|
4778
|
+
* @return {Object} clusterdata Object containing cluster properties:<br>
|
4779
|
+
* {Date} start (required),
|
4780
|
+
* {String} type (optional)
|
4781
|
+
* {Array} array with item data as is in getItem()
|
4782
|
+
*/
|
4783
|
+
links.Timeline.prototype.getCluster = function (index) {
|
4784
|
+
if (index >= this.clusters.length) {
|
4785
|
+
throw "Cannot get cluster, index out of range";
|
4361
4786
|
}
|
4362
4787
|
|
4363
|
-
|
4788
|
+
var clusterData = {},
|
4789
|
+
cluster = this.clusters[index],
|
4790
|
+
clusterItems = cluster.items;
|
4791
|
+
|
4792
|
+
clusterData.start = new Date(cluster.start.valueOf());
|
4793
|
+
if (cluster.type) {
|
4794
|
+
clusterData.type = cluster.type;
|
4795
|
+
}
|
4796
|
+
|
4797
|
+
// push cluster item data
|
4798
|
+
clusterData.items = [];
|
4799
|
+
for(var i = 0; i < clusterItems.length; i++){
|
4800
|
+
for(var j = 0; j < this.items.length; j++){
|
4801
|
+
// TODO could be nicer to be able to have the item index into the cluster
|
4802
|
+
if(this.items[j] == clusterItems[i])
|
4803
|
+
{
|
4804
|
+
clusterData.items.push(this.getItem(j));
|
4805
|
+
break;
|
4806
|
+
}
|
4807
|
+
|
4808
|
+
}
|
4809
|
+
}
|
4810
|
+
|
4811
|
+
return clusterData;
|
4364
4812
|
};
|
4365
4813
|
|
4366
4814
|
/**
|
@@ -4431,15 +4879,9 @@ links.Timeline.prototype.addItems = function (itemsData, preventRender) {
|
|
4431
4879
|
*/
|
4432
4880
|
links.Timeline.prototype.createItem = function(itemData) {
|
4433
4881
|
var type = itemData.type || (itemData.end ? 'range' : this.options.style);
|
4434
|
-
var data =
|
4435
|
-
|
4436
|
-
|
4437
|
-
content: itemData.content,
|
4438
|
-
className: itemData.className,
|
4439
|
-
editable: itemData.editable,
|
4440
|
-
group: this.getGroup(itemData.group),
|
4441
|
-
type: type
|
4442
|
-
};
|
4882
|
+
var data = links.Timeline.clone(itemData);
|
4883
|
+
data.type = type;
|
4884
|
+
data.group = this.getGroup(itemData.group);
|
4443
4885
|
// TODO: optimize this, when creating an item, all data is copied twice...
|
4444
4886
|
|
4445
4887
|
// TODO: is initialTop needed?
|
@@ -4456,7 +4898,7 @@ links.Timeline.prototype.createItem = function(itemData) {
|
|
4456
4898
|
return new this.itemTypes[type](data, {'top': initialTop})
|
4457
4899
|
}
|
4458
4900
|
|
4459
|
-
console.log('ERROR: Unknown event
|
4901
|
+
console.log('ERROR: Unknown event type "' + type + '"');
|
4460
4902
|
return new links.Timeline.Item(data, {
|
4461
4903
|
'top': initialTop
|
4462
4904
|
});
|
@@ -4480,10 +4922,10 @@ links.Timeline.prototype.changeItem = function (index, itemData, preventRender)
|
|
4480
4922
|
|
4481
4923
|
// replace item, merge the changes
|
4482
4924
|
var newItem = this.createItem({
|
4483
|
-
'start':
|
4484
|
-
'end':
|
4485
|
-
'content':
|
4486
|
-
'group':
|
4925
|
+
'start': itemData.hasOwnProperty('start') ? itemData.start : oldItem.start,
|
4926
|
+
'end': itemData.hasOwnProperty('end') ? itemData.end : oldItem.end,
|
4927
|
+
'content': itemData.hasOwnProperty('content') ? itemData.content : oldItem.content,
|
4928
|
+
'group': itemData.hasOwnProperty('group') ? itemData.group : this.getGroupName(oldItem.group),
|
4487
4929
|
'className': itemData.hasOwnProperty('className') ? itemData.className : oldItem.className,
|
4488
4930
|
'editable': itemData.hasOwnProperty('editable') ? itemData.editable : oldItem.editable,
|
4489
4931
|
'type': itemData.hasOwnProperty('type') ? itemData.type : oldItem.type
|
@@ -4540,20 +4982,24 @@ links.Timeline.prototype.getGroup = function (groupName) {
|
|
4540
4982
|
'content': groupName,
|
4541
4983
|
'labelTop': 0,
|
4542
4984
|
'lineTop': 0
|
4543
|
-
// note: this object will lateron get addition information,
|
4544
|
-
// such as height and width of the group
|
4985
|
+
// note: this object will lateron get addition information,
|
4986
|
+
// such as height and width of the group
|
4545
4987
|
};
|
4546
4988
|
groups.push(groupObj);
|
4547
4989
|
// sort the groups
|
4548
|
-
|
4549
|
-
|
4550
|
-
|
4551
|
-
|
4552
|
-
|
4553
|
-
|
4554
|
-
|
4555
|
-
|
4556
|
-
|
4990
|
+
if (this.options.groupsOrder == true) {
|
4991
|
+
groups = groups.sort(function (a, b) {
|
4992
|
+
if (a.content > b.content) {
|
4993
|
+
return 1;
|
4994
|
+
}
|
4995
|
+
if (a.content < b.content) {
|
4996
|
+
return -1;
|
4997
|
+
}
|
4998
|
+
return 0;
|
4999
|
+
});
|
5000
|
+
} else if (typeof(this.options.groupsOrder) == "function") {
|
5001
|
+
groups = groups.sort(this.options.groupsOrder)
|
5002
|
+
}
|
4557
5003
|
|
4558
5004
|
// rebuilt the groupIndexes
|
4559
5005
|
for (var i = 0, iMax = groups.length; i < iMax; i++) {
|
@@ -4657,7 +5103,12 @@ links.Timeline.prototype.setSelection = function(selection) {
|
|
4657
5103
|
links.Timeline.prototype.getSelection = function() {
|
4658
5104
|
var sel = [];
|
4659
5105
|
if (this.selection) {
|
4660
|
-
|
5106
|
+
if(this.selection.index !== undefined)
|
5107
|
+
{
|
5108
|
+
sel.push({"row": this.selection.index});
|
5109
|
+
} else {
|
5110
|
+
sel.push({"cluster": this.selection.cluster});
|
5111
|
+
}
|
4661
5112
|
}
|
4662
5113
|
return sel;
|
4663
5114
|
};
|
@@ -4692,6 +5143,24 @@ links.Timeline.prototype.selectItem = function(index) {
|
|
4692
5143
|
}
|
4693
5144
|
};
|
4694
5145
|
|
5146
|
+
/**
|
5147
|
+
* Select an cluster by its index
|
5148
|
+
* @param {Number} index
|
5149
|
+
*/
|
5150
|
+
links.Timeline.prototype.selectCluster = function(index) {
|
5151
|
+
this.unselectItem();
|
5152
|
+
|
5153
|
+
this.selection = undefined;
|
5154
|
+
|
5155
|
+
if (this.clusters[index] != undefined) {
|
5156
|
+
this.selection = {
|
5157
|
+
'cluster': index
|
5158
|
+
};
|
5159
|
+
this.repaintDeleteButton();
|
5160
|
+
this.repaintDragAreas();
|
5161
|
+
}
|
5162
|
+
};
|
5163
|
+
|
4695
5164
|
/**
|
4696
5165
|
* Check if an item is currently selected
|
4697
5166
|
* @param {Number} index
|
@@ -4705,7 +5174,7 @@ links.Timeline.prototype.isSelected = function (index) {
|
|
4705
5174
|
* Unselect the currently selected event (if any)
|
4706
5175
|
*/
|
4707
5176
|
links.Timeline.prototype.unselectItem = function() {
|
4708
|
-
if (this.selection) {
|
5177
|
+
if (this.selection && this.selection.index !== undefined) {
|
4709
5178
|
var item = this.items[this.selection.index];
|
4710
5179
|
|
4711
5180
|
if (item && item.dom) {
|
@@ -4729,12 +5198,6 @@ links.Timeline.prototype.unselectItem = function() {
|
|
4729
5198
|
* defaults to false.
|
4730
5199
|
*/
|
4731
5200
|
links.Timeline.prototype.stackItems = function(animate) {
|
4732
|
-
if (this.groups.length > 0) {
|
4733
|
-
// under this conditions we refuse to stack the events
|
4734
|
-
// TODO: implement support for stacking items per group
|
4735
|
-
return;
|
4736
|
-
}
|
4737
|
-
|
4738
5201
|
if (animate == undefined) {
|
4739
5202
|
animate = false;
|
4740
5203
|
}
|
@@ -4785,6 +5248,29 @@ links.Timeline.prototype.stackCancelAnimation = function() {
|
|
4785
5248
|
}
|
4786
5249
|
};
|
4787
5250
|
|
5251
|
+
links.Timeline.prototype.getItemsByGroup = function(items) {
|
5252
|
+
var itemsByGroup = {};
|
5253
|
+
for (var i = 0; i < items.length; ++i) {
|
5254
|
+
var item = items[i];
|
5255
|
+
var group = "undefined";
|
5256
|
+
|
5257
|
+
if (item.group) {
|
5258
|
+
if (item.group.content) {
|
5259
|
+
group = item.group.content;
|
5260
|
+
} else {
|
5261
|
+
group = item.group;
|
5262
|
+
}
|
5263
|
+
}
|
5264
|
+
|
5265
|
+
if (!itemsByGroup[group]) {
|
5266
|
+
itemsByGroup[group] = [];
|
5267
|
+
}
|
5268
|
+
|
5269
|
+
itemsByGroup[group].push(item);
|
5270
|
+
}
|
5271
|
+
|
5272
|
+
return itemsByGroup;
|
5273
|
+
};
|
4788
5274
|
|
4789
5275
|
/**
|
4790
5276
|
* Order the items in the array this.items. The default order is determined via:
|
@@ -4798,16 +5284,16 @@ links.Timeline.prototype.stackOrder = function(items) {
|
|
4798
5284
|
// TODO: store the sorted items, to have less work later on
|
4799
5285
|
var sortedItems = items.concat([]);
|
4800
5286
|
|
4801
|
-
//if a customer stack order function exists, use it.
|
5287
|
+
//if a customer stack order function exists, use it.
|
4802
5288
|
var f = this.options.customStackOrder && (typeof this.options.customStackOrder === 'function') ? this.options.customStackOrder : function (a, b)
|
4803
5289
|
{
|
4804
|
-
if ((a instanceof links.Timeline.ItemRange) &&
|
4805
|
-
!(b instanceof links.Timeline.ItemRange)) {
|
5290
|
+
if ((a instanceof links.Timeline.ItemRange || a instanceof links.Timeline.ItemFloatingRange) &&
|
5291
|
+
!(b instanceof links.Timeline.ItemRange || b instanceof links.Timeline.ItemFloatingRange)) {
|
4806
5292
|
return -1;
|
4807
5293
|
}
|
4808
5294
|
|
4809
|
-
if (!(a instanceof links.Timeline.ItemRange) &&
|
4810
|
-
(b instanceof links.Timeline.ItemRange)) {
|
5295
|
+
if (!(a instanceof links.Timeline.ItemRange || a instanceof links.Timeline.ItemFloatingRange) &&
|
5296
|
+
(b instanceof links.Timeline.ItemRange || b instanceof links.Timeline.ItemFloatingRange)) {
|
4811
5297
|
return 1;
|
4812
5298
|
}
|
4813
5299
|
|
@@ -4826,56 +5312,83 @@ links.Timeline.prototype.stackOrder = function(items) {
|
|
4826
5312
|
* @return {Object[]} finalItems
|
4827
5313
|
*/
|
4828
5314
|
links.Timeline.prototype.stackCalculateFinal = function(items) {
|
4829
|
-
var
|
4830
|
-
iMax,
|
4831
|
-
size = this.size,
|
4832
|
-
axisTop = size.axis.top,
|
4833
|
-
axisHeight = size.axis.height,
|
5315
|
+
var size = this.size,
|
4834
5316
|
options = this.options,
|
4835
5317
|
axisOnTop = options.axisOnTop,
|
4836
5318
|
eventMargin = options.eventMargin,
|
4837
5319
|
eventMarginAxis = options.eventMarginAxis,
|
4838
|
-
|
5320
|
+
groupBase = (axisOnTop)
|
5321
|
+
? size.axis.height + eventMarginAxis + eventMargin/2
|
5322
|
+
: size.contentHeight - eventMarginAxis - eventMargin/2,
|
5323
|
+
groupedItems, groupFinalItems, finalItems = [];
|
5324
|
+
|
5325
|
+
groupedItems = this.getItemsByGroup(items);
|
5326
|
+
|
5327
|
+
//
|
5328
|
+
// groupedItems contains all items by group, plus it may contain an
|
5329
|
+
// additional "undefined" group which contains all items with no group. We
|
5330
|
+
// first process the grouped items, and then the ungrouped
|
5331
|
+
//
|
5332
|
+
for (j = 0; j<this.groups.length; ++j) {
|
5333
|
+
var group = this.groups[j];
|
5334
|
+
|
5335
|
+
if (!groupedItems[group.content]) {
|
5336
|
+
if (axisOnTop) {
|
5337
|
+
groupBase += options.groupMinHeight + eventMargin;
|
5338
|
+
} else {
|
5339
|
+
groupBase -= (options.groupMinHeight + eventMargin);
|
5340
|
+
}
|
5341
|
+
continue;
|
5342
|
+
}
|
4839
5343
|
|
4840
|
-
|
4841
|
-
|
4842
|
-
|
4843
|
-
|
4844
|
-
|
4845
|
-
height = item.height,
|
4846
|
-
width = item.getWidth(this),
|
4847
|
-
right = item.getRight(this),
|
4848
|
-
left = right - width;
|
5344
|
+
// initialize final positions and fill finalItems
|
5345
|
+
groupFinalItems = this.finalItemsPosition(groupedItems[group.content], groupBase, group);
|
5346
|
+
groupFinalItems.forEach(function(item) {
|
5347
|
+
finalItems.push(item);
|
5348
|
+
});
|
4849
5349
|
|
4850
5350
|
if (axisOnTop) {
|
4851
|
-
|
4852
|
-
}
|
4853
|
-
|
4854
|
-
top = axisTop - height - eventMarginAxis - eventMargin / 2;
|
5351
|
+
groupBase += group.itemsHeight + eventMargin;
|
5352
|
+
} else {
|
5353
|
+
groupBase -= (group.itemsHeight + eventMargin);
|
4855
5354
|
}
|
4856
|
-
|
5355
|
+
}
|
4857
5356
|
|
4858
|
-
|
4859
|
-
|
4860
|
-
|
4861
|
-
|
4862
|
-
|
4863
|
-
|
4864
|
-
|
4865
|
-
|
5357
|
+
//
|
5358
|
+
// Ungrouped items' turn now!
|
5359
|
+
//
|
5360
|
+
if (groupedItems["undefined"]) {
|
5361
|
+
// initialize final positions and fill finalItems
|
5362
|
+
groupFinalItems = this.finalItemsPosition(groupedItems["undefined"], groupBase);
|
5363
|
+
groupFinalItems.forEach(function(item) {
|
5364
|
+
finalItems.push(item);
|
5365
|
+
});
|
4866
5366
|
}
|
4867
5367
|
|
4868
|
-
|
4869
|
-
|
4870
|
-
|
4871
|
-
|
4872
|
-
|
4873
|
-
|
4874
|
-
|
5368
|
+
return finalItems;
|
5369
|
+
};
|
5370
|
+
|
5371
|
+
links.Timeline.prototype.finalItemsPosition = function(items, groupBase, group) {
|
5372
|
+
var i,
|
5373
|
+
iMax,
|
5374
|
+
options = this.options,
|
5375
|
+
axisOnTop = options.axisOnTop,
|
5376
|
+
eventMargin = options.eventMargin,
|
5377
|
+
groupFinalItems;
|
5378
|
+
|
5379
|
+
// initialize final positions and fill finalItems
|
5380
|
+
groupFinalItems = this.initialItemsPosition(items, groupBase);
|
5381
|
+
|
5382
|
+
// calculate new, non-overlapping positions
|
5383
|
+
for (i = 0, iMax = groupFinalItems.length; i < iMax; i++) {
|
5384
|
+
var finalItem = groupFinalItems[i];
|
5385
|
+
var collidingItem = null;
|
5386
|
+
|
5387
|
+
if (this.options.stackEvents) {
|
4875
5388
|
do {
|
4876
5389
|
// TODO: optimize checking for overlap. when there is a gap without items,
|
4877
5390
|
// you only need to check for items from the next item on, not from zero
|
4878
|
-
collidingItem = this.stackItemsCheckOverlap(
|
5391
|
+
collidingItem = this.stackItemsCheckOverlap(groupFinalItems, i, 0, i-1);
|
4879
5392
|
if (collidingItem != null) {
|
4880
5393
|
// There is a collision. Reposition the event above the colliding element
|
4881
5394
|
if (axisOnTop) {
|
@@ -4888,11 +5401,54 @@ links.Timeline.prototype.stackCalculateFinal = function(items) {
|
|
4888
5401
|
}
|
4889
5402
|
} while (collidingItem);
|
4890
5403
|
}
|
5404
|
+
|
5405
|
+
if (group) {
|
5406
|
+
if (axisOnTop) {
|
5407
|
+
group.itemsHeight = (group.itemsHeight)
|
5408
|
+
? Math.max(group.itemsHeight, finalItem.bottom - groupBase)
|
5409
|
+
: finalItem.height + eventMargin;
|
5410
|
+
} else {
|
5411
|
+
group.itemsHeight = (group.itemsHeight)
|
5412
|
+
? Math.max(group.itemsHeight, groupBase - finalItem.top)
|
5413
|
+
: finalItem.height + eventMargin;
|
5414
|
+
}
|
5415
|
+
}
|
4891
5416
|
}
|
4892
5417
|
|
4893
|
-
return
|
5418
|
+
return groupFinalItems;
|
4894
5419
|
};
|
4895
5420
|
|
5421
|
+
links.Timeline.prototype.initialItemsPosition = function(items, groupBase) {
|
5422
|
+
var options = this.options,
|
5423
|
+
axisOnTop = options.axisOnTop,
|
5424
|
+
finalItems = [];
|
5425
|
+
|
5426
|
+
for (var i = 0, iMax = items.length; i < iMax; ++i) {
|
5427
|
+
var item = items[i],
|
5428
|
+
top,
|
5429
|
+
bottom,
|
5430
|
+
height = item.height,
|
5431
|
+
width = item.getWidth(this),
|
5432
|
+
right = item.getRight(this),
|
5433
|
+
left = right - width;
|
5434
|
+
|
5435
|
+
top = (axisOnTop) ? groupBase
|
5436
|
+
: groupBase - height;
|
5437
|
+
|
5438
|
+
bottom = top + height;
|
5439
|
+
|
5440
|
+
finalItems.push({
|
5441
|
+
'left': left,
|
5442
|
+
'top': top,
|
5443
|
+
'right': right,
|
5444
|
+
'bottom': bottom,
|
5445
|
+
'height': height,
|
5446
|
+
'item': item
|
5447
|
+
});
|
5448
|
+
}
|
5449
|
+
|
5450
|
+
return finalItems;
|
5451
|
+
};
|
4896
5452
|
|
4897
5453
|
/**
|
4898
5454
|
* Move the events one step in the direction of their final positions
|
@@ -4907,7 +5463,7 @@ links.Timeline.prototype.stackMoveOneStep = function(currentItems, finalItems) {
|
|
4907
5463
|
var arrived = true;
|
4908
5464
|
|
4909
5465
|
// apply new positions animated
|
4910
|
-
for (i = 0, iMax = finalItems.length; i < iMax; i++) {
|
5466
|
+
for (var i = 0, iMax = finalItems.length; i < iMax; i++) {
|
4911
5467
|
var finalItem = finalItems[i],
|
4912
5468
|
item = finalItem.item;
|
4913
5469
|
|
@@ -4949,7 +5505,7 @@ links.Timeline.prototype.stackMoveOneStep = function(currentItems, finalItems) {
|
|
4949
5505
|
*/
|
4950
5506
|
links.Timeline.prototype.stackMoveToFinal = function(currentItems, finalItems) {
|
4951
5507
|
// Put the events directly at there final position
|
4952
|
-
for (i = 0, iMax = finalItems.length; i < iMax; i++) {
|
5508
|
+
for (var i = 0, iMax = finalItems.length; i < iMax; i++) {
|
4953
5509
|
var finalItem = finalItems[i],
|
4954
5510
|
current = finalItem.item;
|
4955
5511
|
|
@@ -4976,7 +5532,7 @@ links.Timeline.prototype.stackItemsCheckOverlap = function(items, itemIndex,
|
|
4976
5532
|
var eventMargin = this.options.eventMargin,
|
4977
5533
|
collision = this.collision;
|
4978
5534
|
|
4979
|
-
// we loop from end to start, as we suppose that the chance of a
|
5535
|
+
// we loop from end to start, as we suppose that the chance of a
|
4980
5536
|
// collision is larger for items at the end, so check these first.
|
4981
5537
|
var item1 = items[itemIndex];
|
4982
5538
|
for (var i = itemEnd; i >= itemStart; i--) {
|
@@ -5004,7 +5560,7 @@ links.Timeline.prototype.stackItemsCheckOverlap = function(items, itemIndex,
|
|
5004
5560
|
* @return {boolean} true if item1 and item2 collide, else false
|
5005
5561
|
*/
|
5006
5562
|
links.Timeline.prototype.collision = function(item1, item2, margin) {
|
5007
|
-
// set margin if not specified
|
5563
|
+
// set margin if not specified
|
5008
5564
|
if (margin == undefined) {
|
5009
5565
|
margin = 0;
|
5010
5566
|
}
|
@@ -5059,7 +5615,7 @@ links.Timeline.prototype.clusterItems = function () {
|
|
5059
5615
|
return;
|
5060
5616
|
}
|
5061
5617
|
|
5062
|
-
var clusters = this.clusterGenerator.getClusters(this.conversion.factor);
|
5618
|
+
var clusters = this.clusterGenerator.getClusters(this.conversion.factor, this.options.clusterMaxItems);
|
5063
5619
|
if (this.clusters != clusters) {
|
5064
5620
|
// cluster level changed
|
5065
5621
|
var queue = this.renderQueue;
|
@@ -5235,20 +5791,14 @@ links.Timeline.ClusterGenerator.prototype.filterData = function () {
|
|
5235
5791
|
* defined as (windowWidth / (endDate - startDate))
|
5236
5792
|
* @return {Item[]} clusters
|
5237
5793
|
*/
|
5238
|
-
links.Timeline.ClusterGenerator.prototype.getClusters = function (scale) {
|
5794
|
+
links.Timeline.ClusterGenerator.prototype.getClusters = function (scale, maxItems) {
|
5239
5795
|
var level = -1,
|
5240
5796
|
granularity = 2, // TODO: what granularity is needed for the cluster levels?
|
5241
|
-
timeWindow = 0
|
5242
|
-
maxItems = 5; // TODO: do not hard code maxItems
|
5797
|
+
timeWindow = 0; // milliseconds
|
5243
5798
|
|
5244
5799
|
if (scale > 0) {
|
5245
5800
|
level = Math.round(Math.log(100 / scale) / Math.log(granularity));
|
5246
5801
|
timeWindow = Math.pow(granularity, level);
|
5247
|
-
|
5248
|
-
// groups must have a larger time window, as the items will not be stacked
|
5249
|
-
if (this.timeline.groups && this.timeline.groups.length) {
|
5250
|
-
timeWindow *= 4;
|
5251
|
-
}
|
5252
5802
|
}
|
5253
5803
|
|
5254
5804
|
// clear the cache when and re-filter the data when needed.
|
@@ -5333,7 +5883,7 @@ links.Timeline.ClusterGenerator.prototype.getClusters = function (scale) {
|
|
5333
5883
|
}
|
5334
5884
|
min = (min != undefined) ? Math.min(min, start) : start;
|
5335
5885
|
max = (max != undefined) ? Math.max(max, end) : end;
|
5336
|
-
containsRanges = containsRanges || (p instanceof links.Timeline.ItemRange);
|
5886
|
+
containsRanges = containsRanges || (p instanceof links.Timeline.ItemRange || p instanceof links.Timeline.ItemFloatingRange);
|
5337
5887
|
count++;
|
5338
5888
|
m++;
|
5339
5889
|
}
|
@@ -5643,7 +6193,7 @@ links.Timeline.StepDate.prototype.end = function () {
|
|
5643
6193
|
links.Timeline.StepDate.prototype.next = function() {
|
5644
6194
|
var prev = this.current.valueOf();
|
5645
6195
|
|
5646
|
-
// Two cases, needed to prevent issues with switching daylight savings
|
6196
|
+
// Two cases, needed to prevent issues with switching daylight savings
|
5647
6197
|
// (end of March and end of October)
|
5648
6198
|
if (this.current.getMonth() < 6) {
|
5649
6199
|
switch (this.scale) {
|
@@ -5810,7 +6360,7 @@ links.Timeline.StepDate.prototype.snap = function(date) {
|
|
5810
6360
|
if (date.getDate() > 15) {
|
5811
6361
|
date.setDate(1);
|
5812
6362
|
date.setMonth(date.getMonth() + 1);
|
5813
|
-
// important: first set Date to 1, after that change the month.
|
6363
|
+
// important: first set Date to 1, after that change the month.
|
5814
6364
|
}
|
5815
6365
|
else {
|
5816
6366
|
date.setDate(1);
|
@@ -6002,7 +6552,7 @@ links.Timeline.StepDate.prototype.addZeros = function(value, len) {
|
|
6002
6552
|
*/
|
6003
6553
|
links.imageloader = (function () {
|
6004
6554
|
var urls = {}; // the loaded urls
|
6005
|
-
var callbacks = {}; // the urls currently being loaded. Each key contains
|
6555
|
+
var callbacks = {}; // the urls currently being loaded. Each key contains
|
6006
6556
|
// an array with callbacks
|
6007
6557
|
|
6008
6558
|
/**
|
@@ -6354,7 +6904,7 @@ links.Timeline.getPageX = function (event) {
|
|
6354
6904
|
links.Timeline.addClassName = function(elem, className) {
|
6355
6905
|
var classes = elem.className.split(' ');
|
6356
6906
|
var classesToAdd = className.split(' ');
|
6357
|
-
|
6907
|
+
|
6358
6908
|
var added = false;
|
6359
6909
|
for (var i=0; i<classesToAdd.length; i++) {
|
6360
6910
|
if (classes.indexOf(classesToAdd[i]) == -1) {
|
@@ -6362,7 +6912,7 @@ links.Timeline.addClassName = function(elem, className) {
|
|
6362
6912
|
added = true;
|
6363
6913
|
}
|
6364
6914
|
}
|
6365
|
-
|
6915
|
+
|
6366
6916
|
if (added) {
|
6367
6917
|
elem.className = classes.join(' ');
|
6368
6918
|
}
|
@@ -6376,7 +6926,7 @@ links.Timeline.addClassName = function(elem, className) {
|
|
6376
6926
|
links.Timeline.removeClassName = function(elem, className) {
|
6377
6927
|
var classes = elem.className.split(' ');
|
6378
6928
|
var classesToRemove = className.split(' ');
|
6379
|
-
|
6929
|
+
|
6380
6930
|
var removed = false;
|
6381
6931
|
for (var i=0; i<classesToRemove.length; i++) {
|
6382
6932
|
var index = classes.indexOf(classesToRemove[i]);
|
@@ -6385,7 +6935,7 @@ links.Timeline.removeClassName = function(elem, className) {
|
|
6385
6935
|
removed = true;
|
6386
6936
|
}
|
6387
6937
|
}
|
6388
|
-
|
6938
|
+
|
6389
6939
|
if (removed) {
|
6390
6940
|
elem.className = classes.join(' ');
|
6391
6941
|
}
|
@@ -6404,6 +6954,21 @@ links.Timeline.isArray = function (obj) {
|
|
6404
6954
|
return (Object.prototype.toString.call(obj) === '[object Array]');
|
6405
6955
|
};
|
6406
6956
|
|
6957
|
+
/**
|
6958
|
+
* Shallow clone an object
|
6959
|
+
* @param {Object} object
|
6960
|
+
* @return {Object} clone
|
6961
|
+
*/
|
6962
|
+
links.Timeline.clone = function (object) {
|
6963
|
+
var clone = {};
|
6964
|
+
for (var prop in object) {
|
6965
|
+
if (object.hasOwnProperty(prop)) {
|
6966
|
+
clone[prop] = object[prop];
|
6967
|
+
}
|
6968
|
+
}
|
6969
|
+
return clone;
|
6970
|
+
};
|
6971
|
+
|
6407
6972
|
/**
|
6408
6973
|
* parse a JSON date
|
6409
6974
|
* @param {Date | String | Number} date Date object to be parsed. Can be:
|