204 } |
215 } |
205 |
216 |
206 Tlns.Classes.Timeline.prototype.onMouseDown = function(_event) { |
217 Tlns.Classes.Timeline.prototype.onMouseDown = function(_event) { |
207 this.mouse_down = true; |
218 this.mouse_down = true; |
208 this.is_dragging = false; |
219 this.is_dragging = false; |
|
220 this.time_at_start = this.central_time; |
209 this.start_pos = { |
221 this.start_pos = { |
210 x: _event.pageX, |
222 x: _event.pageX, |
211 y: _event.pageY |
223 y: _event.pageY |
212 }; |
224 }; |
213 var _target = $(_event.target); |
225 if (typeof this.dragging_type === "undefined") { |
214 while (!_target.hasClass("Tl-Main") && _target.length) { |
226 this.dragging_type = "timeline"; |
215 if (_target.hasClass("Tl-MainPart")) { |
|
216 this.dragging_type = "timeline"; |
|
217 this.time_at_start = this.central_time; |
|
218 break; |
|
219 } |
|
220 _target = _target.parent(); |
|
221 } |
227 } |
222 } |
228 } |
223 |
229 |
224 Tlns.Classes.Timeline.prototype.onMouseUp = function(_event) { |
230 Tlns.Classes.Timeline.prototype.onMouseUp = function(_event) { |
225 this.mouse_down = false; |
231 this.mouse_down = false; |
226 this.is_dragging = false; |
232 this.is_dragging = false; |
|
233 this.dragging_type = undefined; |
227 } |
234 } |
228 |
235 |
229 Tlns.Classes.Timeline.prototype.onMouseMove = function(_event) { |
236 Tlns.Classes.Timeline.prototype.onMouseMove = function(_event) { |
230 if (this.mouse_down) { |
237 if (this.mouse_down) { |
231 this.is_dragging = true; |
238 this.is_dragging = true; |
|
239 this.$.find('.Tl-Overlay-Box').hide(); |
232 if (_event.pageX > this.dragging_bounds.left |
240 if (_event.pageX > this.dragging_bounds.left |
233 && _event.pageX < this.dragging_bounds.right |
241 && _event.pageX < this.dragging_bounds.right |
234 && _event.pageY > this.dragging_bounds.top |
242 && _event.pageY > this.dragging_bounds.top |
235 && _event.pageY < this.dragging_bounds.bottom) { |
243 && _event.pageY < this.dragging_bounds.bottom |
|
244 ) { |
|
245 var _newTime = Math.floor(this.time_at_start + ( this.start_pos.x - _event.pageX ) / this.current_scale); |
236 switch (this.dragging_type) { |
246 switch (this.dragging_type) { |
237 case "timeline": |
247 case "timeline": |
238 var _newTime = Math.floor(this.time_at_start + ( this.start_pos.x - _event.pageX ) / this.current_scale); |
|
239 this.throttledSetTime(_newTime); |
248 this.throttledSetTime(_newTime); |
240 break; |
249 break; |
241 } |
250 } |
242 } else { |
251 } else { |
243 this.onMouseUp(_event); |
252 this.onMouseUp(_event); |
288 } else { |
298 } else { |
289 this.$.find('.Tl-TopBar-SyncButton').removeClass("active"); |
299 this.$.find('.Tl-TopBar-SyncButton').removeClass("active"); |
290 } |
300 } |
291 var _timescale = this.timescales[this.level], |
301 var _timescale = this.timescales[this.level], |
292 _offset = new Date().getTimezoneOffset() * 60000; |
302 _offset = new Date().getTimezoneOffset() * 60000; |
293 this.current_scale = this.main_width / (_timescale.span); |
303 this.current_scale = this.main_width / (_timescale.span) |
294 var _tmin = this.central_time - (_timescale.span / 2), |
304 this.start_time = this.central_time - (_timescale.span / 2); |
295 _tmax = this.central_time + (_timescale.span / 2), |
305 this.end_time = this.central_time + (_timescale.span / 2); |
296 _grid_width = Math.floor(_timescale.grid_interval * this.current_scale), |
306 var _grid_width = Math.floor(_timescale.grid_interval * this.current_scale), |
297 _roundstart = Math.floor((_tmin - _offset) / _timescale.grid_interval) * _timescale.grid_interval + _offset, |
307 _roundstart = Math.floor((this.start_time - _offset) / _timescale.grid_interval) * _timescale.grid_interval + _offset, |
298 _html = ''; |
308 _html = ''; |
299 this.$.find('.Tl-TopBar-TimeSpan').html(Tlns.Utils.dateFormat(_tmin, _timescale.start_date_format) + ' - ' + Tlns.Utils.dateFormat(_tmax, _timescale.end_date_format)); |
309 this.$.find('.Tl-TopBar-TimeSpan').html(Tlns.Utils.dateFormat(this.start_time, _timescale.start_date_format) + ' - ' + Tlns.Utils.dateFormat(this.end_time, _timescale.end_date_format)); |
300 for (var _t = _roundstart; _t < _tmax; _t += _timescale.grid_interval) { |
310 for (var _t = _roundstart; _t < this.end_time; _t += _timescale.grid_interval) { |
301 _html += '<div class="Tl-Grid-Column" style="width:' + _grid_width + 'px; left: ' + this.current_scale * (_t - this.central_time) + 'px">' |
311 _html += '<div class="Tl-Grid-Column" style="width:' + _grid_width + 'px; left: ' + this.current_scale * (_t - this.central_time) + 'px">' |
302 + '<div class="Tl-Grid-Label">' + Tlns.Utils.dateFormat(_t, _timescale.grid_date_format) + '</div></div>'; |
312 + '<div class="Tl-Grid-Label">' + Tlns.Utils.dateFormat(_t, _timescale.grid_date_format) + '</div></div>'; |
303 } |
313 } |
304 /* |
314 /* |
305 |
315 |
307 var _isMajor = !(Math.floor((_t - _offset) / _timescale.grid_interval) % _timescale.major_interval); |
317 var _isMajor = !(Math.floor((_t - _offset) / _timescale.grid_interval) % _timescale.major_interval); |
308 _html += '<div class="Tl-Grid-Column' + ( _isMajor ? ' Tl-Grid-Major' : '' ) + '" style="width:' + _grid_width + 'px; left: ' + _scale * (_t - this.central_time) + 'px">' |
318 _html += '<div class="Tl-Grid-Column' + ( _isMajor ? ' Tl-Grid-Major' : '' ) + '" style="width:' + _grid_width + 'px; left: ' + _scale * (_t - this.central_time) + 'px">' |
309 + ( _isMajor ? '<div class="Tl-Grid-Label">' + Tlns.Utils.dateFormat(_t, _timescale.date_format) + '</div>' : '' ) + '</div>'; |
319 + ( _isMajor ? '<div class="Tl-Grid-Label">' + Tlns.Utils.dateFormat(_t, _timescale.date_format) + '</div>' : '' ) + '</div>'; |
310 } |
320 } |
311 */ |
321 */ |
312 if (_tmin <= _now && _tmax >= _now) { |
322 if (this.start_time <= _now && this.end_time >= _now) { |
313 _html += '<div class="Tl-Grid-Now" style="left: ' + this.current_scale * (_now - this.central_time) + 'px"></div>' |
323 _html += '<div class="Tl-Grid-Now" style="left: ' + this.current_scale * (_now - this.central_time) + 'px"></div>' |
314 } |
324 } |
315 this.$.find('.Tl-Grid').html(_html); |
325 this.$.find('.Tl-Grid').html(_html); |
|
326 this.drawOccurrences(); |
|
327 } |
|
328 |
|
329 Tlns.Classes.Timeline.prototype.loadOccurrences = function() { |
|
330 var _url = Mustache.to_html(this.url_occurrences, { |
|
331 from_time: this.start_time, |
|
332 to_time: this.end_time |
|
333 }), |
|
334 _this = this; |
|
335 $.getJSON(_url, function(_data) { |
|
336 _this.onOccurrencesLoaded(_data); |
|
337 }); |
|
338 } |
|
339 |
|
340 Tlns.Classes.Timeline.prototype.onOccurrencesLoaded = function(_data) { |
|
341 if (typeof _data.occurrencesNarratives === "object" && _data.occurrencesNarratives !== null) { |
|
342 for (var _i = 0; _i < _data.occurrencesNarratives.length; _i++) { |
|
343 this.createOrUpdateOccurrence("narrative", _data.occurrencesNarratives[_i]); |
|
344 } |
|
345 for (var _i = 0; _i < _data.occurrencesProduction.length; _i++) { |
|
346 this.createOrUpdateOccurrence("production", _data.occurrencesProduction[_i]); |
|
347 } |
|
348 } |
|
349 if (!this.mouse_down) { |
|
350 this.drawOccurrences(); |
|
351 } |
|
352 } |
|
353 |
|
354 Tlns.Classes.Timeline.prototype.getOccurrence = function(_type, _id) { |
|
355 return _(this.occurrences).find(function(_occ) { |
|
356 return (_occ.type == _type && _occ.id == _id); |
|
357 }); |
|
358 } |
|
359 |
|
360 Tlns.Classes.Timeline.prototype.createOrUpdateOccurrence = function(_type, _data) { |
|
361 var _occurrence = this.getOccurrence(_type, _data.id); |
|
362 if (typeof _occurrence === "undefined") { |
|
363 _occurrence = new Tlns.Classes.Occurrence(this); |
|
364 this.occurrences.push(_occurrence); |
|
365 } |
|
366 _occurrence.update(_type, _data); |
|
367 } |
|
368 |
|
369 Tlns.Classes.Timeline.prototype.showTooltip = function(_x, _y, _html) { |
|
370 this.$.find('.Tl-Overlay-Box').show() |
|
371 .css({ |
|
372 left: _x + "px", |
|
373 top: _y + "px" |
|
374 }); |
|
375 this.$.find('.Tl-Overlay-Main').html(_html); |
|
376 } |
|
377 |
|
378 Tlns.Classes.Timeline.prototype.hideTooltip = function() { |
|
379 this.$.find('.Tl-Overlay-Box').hide(); |
316 } |
380 } |
317 |
381 |
318 Tlns.Classes.Timeline.prototype.drawOccurrences = function() { |
382 Tlns.Classes.Timeline.prototype.drawOccurrences = function() { |
319 |
383 var _this = this, |
320 } |
384 _visible = _(this.occurrences).filter(function(_occ) { |
|
385 return (_occ.date >= _this.start_time && _occ.date <= _this.end_time && _occ.published); |
|
386 }); |
|
387 _(_visible).each(function(_occ) { |
|
388 _occ.x = _this.current_scale * (_occ.date - _this.central_time); |
|
389 _occ.in_cluster = false; |
|
390 }); |
|
391 |
|
392 var _moved = true; |
|
393 while (_moved) { |
|
394 _moved = false; |
|
395 for (var _i = 0; _i < _visible.length; _i++) { |
|
396 for (var _j = 0; _j < _i; _j++) { |
|
397 if (_visible[_j].univers_id == _visible[_i].univers_id |
|
398 && _visible[_j].x != _visible[_i].x |
|
399 && Math.abs(_visible[_j].x-_visible[_i].x) < this.cluster_spacing |
|
400 ) { |
|
401 _moved = true; |
|
402 _visible[_i].x = this.cluster_spacing * Math.round(_visible[_i].x / this.cluster_spacing); |
|
403 _visible[_j].x = this.cluster_spacing * Math.round(_visible[_j].x / this.cluster_spacing); |
|
404 } |
|
405 } |
|
406 } |
|
407 } |
|
408 var _clusters = []; |
|
409 for (var _i = 0; _i < _visible.length; _i++) { |
|
410 for (var _j = 0; _j < _i; _j++) { |
|
411 if (_visible[_j].univers_id == _visible[_i].univers_id && _visible[_j].x == _visible[_i].x) { |
|
412 _visible[_j].in_cluster = true; |
|
413 _visible[_i].in_cluster = true; |
|
414 var _x = _visible[_j].x, |
|
415 _y = _visible[_j].univers.y; |
|
416 _cluster = _(_clusters).find(function(_c) { return _c.x == _x && _c.y == _y }); |
|
417 if (typeof _cluster === "undefined") { |
|
418 _cluster = { x: _x, y: _y, occurrences: [] }; |
|
419 _clusters.push(_cluster); |
|
420 } |
|
421 if ("undefined" === typeof _(_cluster.occurrences).find(function(_o) { |
|
422 return _o.type == _visible[_j].type && _o.id == _visible[_j].id; |
|
423 })) { |
|
424 _cluster.occurrences.push({type: _visible[_j].type, id: _visible[_j].id}); |
|
425 } |
|
426 if ("undefined" === typeof _(_cluster.occurrences).find(function(_o) { |
|
427 return _o.type == _visible[_i].type && _o.id == _visible[_i].id; |
|
428 })) { |
|
429 _cluster.occurrences.push({type: _visible[_i].type, id: _visible[_i].id}); |
|
430 } |
|
431 } |
|
432 } |
|
433 } |
|
434 _(_clusters).each(function(_cluster) { |
|
435 _cluster.type = _cluster.occurrences[0].type; |
|
436 for (var _i = 1; _i < _cluster.occurrences.length; _i++) { |
|
437 if (_cluster.occurrences[_i].type !== _cluster.type) { |
|
438 _cluster.type = "both"; |
|
439 break; |
|
440 } |
|
441 } |
|
442 }); |
|
443 |
|
444 var _html = Mustache.to_html(Tlns.Templates.Occurrence, { |
|
445 occurrences:_(_visible).reject(function(_o) {return _o.in_cluster}), |
|
446 clusters: _clusters |
|
447 }); |
|
448 this.$.find('.Tl-Occurrences').html(_html); |
|
449 this.$.find('.Tl-Occurrence').mousedown(function() { |
|
450 _this.dragging_type = "occurrence" |
|
451 }).mouseover(function() { |
|
452 var _el = $(this), |
|
453 _occurrence = _this.getOccurrence(_el.attr("occurrence-type"),_el.attr("occurrence-id")); |
|
454 _this.showTooltip(_occurrence.x, _occurrence.univers.y, _occurrence.title); |
|
455 }).mouseout(function() { |
|
456 _this.hideTooltip(); |
|
457 }); |
|
458 } |
|
459 |
|
460 Tlns.Classes.Timeline.prototype.getUnivers = function(_id) { |
|
461 return _(this.univers).find(function(_univ) { |
|
462 return (_univ.id == _id); |
|
463 }); |
|
464 } |
|
465 |
|
466 /* |
|
467 * Univers |
|
468 */ |
321 |
469 |
322 Tlns.Classes.Univers = function(_data, _timeline, _index) { |
470 Tlns.Classes.Univers = function(_data, _timeline, _index) { |
323 this.id = _data.id; |
471 this.id = _data.id; |
324 this.index = _index; |
472 this.index = _index; |
325 this.title = _data.nom; |
473 this.title = _data.nom; |
326 this.mainCharacter = _data.personnage; |
474 this.mainCharacter = _data.personnage; |
|
475 this.y = (_timeline.univers_height * _index); |
327 |
476 |
328 this.$label = $('<li>').css({ |
477 this.$label = $('<li>').css({ |
329 height : _timeline.univers_height + "px" |
478 height : _timeline.univers_height + "px" |
330 }).html(Mustache.to_html(Tlns.Templates.Univers, this)) |
479 }).html(Mustache.to_html(Tlns.Templates.Univers, this)) |
331 .addClass((_index % 2) ? 'Tl-Line-Odd' : 'Tl-Line-Even'); |
480 .addClass((_index % 2) ? 'Tl-Line-Odd' : 'Tl-Line-Even'); |
332 |
481 |
333 _timeline.$.find('.Tl-UniversLabels').append(this.$label); |
482 _timeline.$.find('.Tl-UniversLabels').append(this.$label); |
334 var _txt = _data.nom, |
483 var _txt = _data.nom, |
335 _span = this.$label.find('span'); |
484 _span = this.$label.find('span'); |
336 |
485 |
337 while (_span.outerWidth() > (_timeline.width - _timeline.main_width) && _txt) { |
486 while (_span.outerWidth() > (_timeline.width - _timeline.main_width) && _txt) { |
338 _txt = _txt.substr(0, _txt.length - 1); |
487 _txt = _txt.substr(0, _txt.length - 1); |
339 _span.html(_txt + '…'); |
488 _span.html(_txt + '…'); |
340 } |
489 } |
341 } |
490 } |
|
491 |
|
492 /* |
|
493 * Occurrence |
|
494 */ |
|
495 |
|
496 Tlns.Classes.Occurrence = function(_timeline) { |
|
497 this.timeline = _timeline; |
|
498 } |
|
499 |
|
500 Tlns.Classes.Occurrence.prototype.update = function(_type, _data) { |
|
501 this.type = _type; |
|
502 this.id = _data.id || _.uniqueId(); |
|
503 this.date = _data.date || _data.datePublication; |
|
504 this.title = _data.titre || "<untitled>"; |
|
505 this.univers_id = _data.univers; |
|
506 this.univers = this.timeline.getUnivers(this.univers_id); |
|
507 this.status = _data.statut; |
|
508 this.published = _data.publie || false; |
|
509 this.locked = _data.verrouille || false; |
|
510 this.characters = _data.personnagesSecondaires || []; |
|
511 this.dependsOn = _data.dependDe || []; |
|
512 } |
|
513 |
|
514 Tlns.Classes.Occurrence.prototype.toString = function() { |
|
515 return "Occurrence " + this.type + ': "' + this.title + '"'; |
|
516 } |