diff -r d1e2781852dc -r 03bbfd9cd3c6 timeline/js/timeline.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/timeline/js/timeline.js Tue May 22 14:55:44 2012 +0200 @@ -0,0 +1,341 @@ +/* + * Main Timeline code + */ + +window.Tlns = { + Utils : {}, + Defaults : {}, + Templates : {}, + Classes : {} +}; + +/* Utility Functions */ + +Tlns.Utils.SetDefaults = function(_object, _defaults, _options) { + var _options = _options || {}; + _(_defaults).each(function(_v, _k) { + if(/^m(in|ax)_/.test(_k)) { + var _tab = _k.split('_') + if( typeof _object[_tab[1]] !== "undefined") { + var _fn = (_tab[0] === "min" ? Math.max : Math.min); + _object[_tab[1]] = _fn(_object[_tab[1]], _v); + } + } else { + if( typeof _options[_k] !== "undefined") { + _object[_k] = _options[_k]; + } else { + _object[_k] = _v; + } + } + }); +} + +Tlns.Utils.dateFormat = function(_date, _template) { + if (typeof _data !== "object") { + _date = new Date(_date); + } + function zeroPad(_n) { + return (_n < 10 ? "0" : "") + _n + } + var _params = { + hours: _date.getHours(), + "0hours": zeroPad(_date.getHours()), + minutes: _date.getMinutes(), + "0minutes": zeroPad(_date.getMinutes()), + seconds: _date.getSeconds(), + "0seconds": zeroPad(_date.getSeconds()), + dayOfWeek: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"][_date.getDay()], + shortDayOfWeek: ["Dim","Lun","Mar","Mer","Jeu","Ven","Sam"][_date.getDay()], + dayOfMonth: _date.getDate(), + "0dayOfMonth": zeroPad(_date.getDate()), + monthNumber: 1+_date.getMonth(), + "0monthNumber": zeroPad(1+_date.getMonth()), + monthName: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"][_date.getMonth()], + shortMonthName: ["jan","fev","mar","avr","mai","jun","jul","aou","sep","oct","nov","dec"][_date.getMonth()], + year: _date.getFullYear() + } + return Mustache.to_html(_template, _params); +} + +/* Defaults */ + +Tlns.Defaults.Timeline = { + container : "timeline", + width : 950, + height : 200, + url_univers : '', + min_width : 400, + min_height : 100, + main_width : 800, + timescales : [{ + label : "Mois", + span : 32 * 86400 * 1000, + grid_interval : 5 * 86400 * 1000, + grid_date_format : '{{dayOfMonth}} {{shortMonthName}}', + start_date_format : '{{dayOfMonth}} {{shortMonthName}}', + end_date_format : '{{dayOfMonth}} {{shortMonthName}} {{year}}' + }, { + label : "Semaine", + span : 8 * 86400 * 1000, + grid_interval : 86400 * 1000, + grid_date_format : '{{shortDayOfWeek}} {{0dayOfMonth}}/{{0monthNumber}}', + start_date_format : '{{dayOfMonth}} {{shortMonthName}}', + end_date_format : '{{dayOfMonth}} {{shortMonthName}}' + }, { + label : "2 jours", + span : 2 * 86400 * 1000, + grid_interval : 8 * 3600 * 1000, + grid_date_format : '{{shortDayOfWeek}} {{0dayOfMonth}}/{{0monthNumber}} {{hours}}h', + start_date_format : '{{dayOfMonth}} {{shortMonthName}}', + end_date_format : '{{dayOfMonth}} {{shortMonthName}}' + }, { + label : "Demi-Journée", + span : 12 * 3600 * 1000, + grid_interval : 2 * 3600 * 1000, + grid_date_format : '{{hours}}h', + start_date_format : '{{dayOfMonth}} {{shortMonthName}} {{hours}}h', + end_date_format : '{{dayOfMonth}} {{shortMonthName}} {{hours}}h' + }, { + label : "3 Heures", + span : 3 * 3600 * 1000, + grid_interval : 30 * 60 * 1000, + grid_date_format : '{{0hours}}:{{0minutes}}', + start_date_format : '{{dayOfMonth}} {{shortMonthName}} {{0hours}}:{{0minutes}}', + end_date_format : '{{0hours}}:{{0minutes}}' + }, { + label : "1 Heure", + span : 80 * 60 * 1000, + grid_interval : 15 * 60 * 1000, + grid_date_format : '{{0hours}}:{{0minutes}}', + start_date_format : '{{dayOfMonth}} {{shortMonthName}} {{0hours}}:{{0minutes}}', + end_date_format : '{{0hours}}:{{0minutes}}' + }], + level: 0, + central_time: 0, + sync_now: true, + url_occurrences: '', + occurrences: {} +} + +for (var _i = 0; _i < Tlns.Defaults.Timeline.timescales.length; _i++) { + Tlns.Defaults.Timeline.timescales[_i].level = _i; +} + +/* Templates */ + +Tlns.Templates.Timeline = '
' + + '
--/--
' + + '
' + + '
{{#timescales}}
{{label}}
{{/timescales}}
' + + '
'; + +Tlns.Templates.Univers = '{{title}}' + +/* Classes */ + +Tlns.Classes.Timeline = function(_options) { + + /* Setting Defaults */ + Tlns.Utils.SetDefaults(this, Tlns.Defaults.Timeline, _options); + + /* Setting container CSS */ + this.$ = $('#' + this.container); + this.$.addClass('Tl-Main'); + this.$.css({ + width : this.width + "px", + height : this.height + "px" + }); + this.$.html(Mustache.to_html(Tlns.Templates.Timeline, this)); + + this.main_height = this.height - this.$.find('.Tl-TopBar').outerHeight(); + this.$.find('.Tl-BottomPart').css("height", this.main_height + "px"); + this.$.find('.Tl-MainPart').css("width", this.main_width + "px"); + var _o = this.$.find('.Tl-MainPart').offset(); + this.dragging_bounds = { + left: _o.left, + top: _o.top, + right: _o.left + this.$.find('.Tl-MainPart').outerWidth(), + bottom: _o.top + this.$.find('.Tl-MainPart').outerHeight(), + }; + + this.setLevel(this.level); + + var _this = this; + this.$.find('.Tl-TopBar-Timescales>div').click(function() { + _this.setLevel($(this).attr("data-level")); + }); + + this.$.find('.Tl-TopBar-SyncButton').click(function() { + _this.sync_now = !_this.sync_now; + _this.drawGrid(); + }) + + this.$.find('.Tl-TopBar-PreviousButton').click(function() { + _this.offsetTime(-_this.timescales[_this.level].span / 4); + }); + + this.$.find('.Tl-TopBar-NextButton').click(function() { + _this.offsetTime(_this.timescales[_this.level].span / 4); + }); + + this.$.find('.Tl-MainPart').mousedown(function(_event) { + _this.onMouseDown(_event); + return false; + }); + + this.$.find('.Tl-MainPart').mousemove(function(_event) { + _this.onMouseMove(_event); + return false; + }); + + this.$.find('.Tl-MainPart').mouseup(function(_event) { + _this.onMouseUp(_event); + return false; + }); + + this.throttledSetTime = _.throttle(function(_time) { + _this.setTime(_time) + }, 150); + + /* Loading Univers */ + $.getJSON(this.url_univers, function(_data) { + _this.onUniversLoaded(_data); + }); +} + +Tlns.Classes.Timeline.prototype.onMouseDown = function(_event) { + this.mouse_down = true; + this.is_dragging = false; + this.start_pos = { + x: _event.pageX, + y: _event.pageY + }; + var _target = $(_event.target); + while (!_target.hasClass("Tl-Main") && _target.length) { + if (_target.hasClass("Tl-MainPart")) { + this.dragging_type = "timeline"; + this.time_at_start = this.central_time; + break; + } + _target = _target.parent(); + } +} + +Tlns.Classes.Timeline.prototype.onMouseUp = function(_event) { + this.mouse_down = false; + this.is_dragging = false; +} + +Tlns.Classes.Timeline.prototype.onMouseMove = function(_event) { + if (this.mouse_down) { + this.is_dragging = true; + if (_event.pageX > this.dragging_bounds.left + && _event.pageX < this.dragging_bounds.right + && _event.pageY > this.dragging_bounds.top + && _event.pageY < this.dragging_bounds.bottom) { + switch (this.dragging_type) { + case "timeline": + var _newTime = Math.floor(this.time_at_start + ( this.start_pos.x - _event.pageX ) / this.current_scale); + this.throttledSetTime(_newTime); + break; + } + } else { + this.onMouseUp(_event); + } + } +} + +Tlns.Classes.Timeline.prototype.onUniversLoaded = function(_data) { + this.univers = []; + if(_data.length) { + this.univers_height = Math.floor(this.main_height / _data.length); + } + for(var _i = 0; _i < _data.length; _i++) { + this.univers.push(new Tlns.Classes.Univers(_data[_i], this, _i)); + } +} + +Tlns.Classes.Timeline.prototype.offsetTime = function(_timeOffset) { + this.setTime(this.central_time + _timeOffset); +} + +Tlns.Classes.Timeline.prototype.setTime = function(_centralTime) { + this.sync_now = false; + this.central_time = _centralTime; + this.drawGrid(); +} + +Tlns.Classes.Timeline.prototype.setLevel = function(_level) { + if (_level >= 0 && _level < this.timescales.length) { + this.$.find('.Tl-TopBar-Timescales>div').each(function() { + var _el = $(this); + if (_el.attr("data-level") == _level) { + _el.addClass("active"); + } else { + _el.removeClass("active"); + } + }); + this.level = _level; + this.drawGrid(); + } +} + +Tlns.Classes.Timeline.prototype.drawGrid = function() { + var _now = new Date().valueOf(); + if (this.sync_now) { + this.central_time = _now; + this.$.find('.Tl-TopBar-SyncButton').addClass("active"); + } else { + this.$.find('.Tl-TopBar-SyncButton').removeClass("active"); + } + var _timescale = this.timescales[this.level], + _offset = new Date().getTimezoneOffset() * 60000; + this.current_scale = this.main_width / (_timescale.span); + var _tmin = this.central_time - (_timescale.span / 2), + _tmax = this.central_time + (_timescale.span / 2), + _grid_width = Math.floor(_timescale.grid_interval * this.current_scale), + _roundstart = Math.floor((_tmin - _offset) / _timescale.grid_interval) * _timescale.grid_interval + _offset, + _html = ''; + this.$.find('.Tl-TopBar-TimeSpan').html(Tlns.Utils.dateFormat(_tmin, _timescale.start_date_format) + ' - ' + Tlns.Utils.dateFormat(_tmax, _timescale.end_date_format)); + for (var _t = _roundstart; _t < _tmax; _t += _timescale.grid_interval) { + _html += '
' + + '
' + Tlns.Utils.dateFormat(_t, _timescale.grid_date_format) + '
'; + } +/* + + for (var _t = _roundstart; _t < _tmax; _t += _timescale.grid_interval) { + var _isMajor = !(Math.floor((_t - _offset) / _timescale.grid_interval) % _timescale.major_interval); + _html += '
' + + ( _isMajor ? '
' + Tlns.Utils.dateFormat(_t, _timescale.date_format) + '
' : '' ) + '
'; + } +*/ + if (_tmin <= _now && _tmax >= _now) { + _html += '
' + } + this.$.find('.Tl-Grid').html(_html); +} + +Tlns.Classes.Timeline.prototype.drawOccurrences = function() { + +} + +Tlns.Classes.Univers = function(_data, _timeline, _index) { + this.id = _data.id; + this.index = _index; + this.title = _data.nom; + this.mainCharacter = _data.personnage; + + this.$label = $('
  • ').css({ + height : _timeline.univers_height + "px" + }).html(Mustache.to_html(Tlns.Templates.Univers, this)) + .addClass((_index % 2) ? 'Tl-Line-Odd' : 'Tl-Line-Even'); + + _timeline.$.find('.Tl-UniversLabels').append(this.$label); + var _txt = _data.nom, + _span = this.$label.find('span'); + + while (_span.outerWidth() > (_timeline.width - _timeline.main_width) && _txt) { + _txt = _txt.substr(0, _txt.length - 1); + _span.html(_txt + '…'); + } +}