timeline/js/timeline.js
changeset 65 03bbfd9cd3c6
child 66 37492d1ce841
equal deleted inserted replaced
64:d1e2781852dc 65:03bbfd9cd3c6
       
     1 /*
       
     2  * Main Timeline code
       
     3  */
       
     4 
       
     5 window.Tlns = {
       
     6     Utils : {},
       
     7     Defaults : {},
       
     8     Templates : {},
       
     9     Classes : {}
       
    10 };
       
    11 
       
    12 /* Utility Functions */
       
    13 
       
    14 Tlns.Utils.SetDefaults = function(_object, _defaults, _options) {
       
    15     var _options = _options || {};
       
    16     _(_defaults).each(function(_v, _k) {
       
    17         if(/^m(in|ax)_/.test(_k)) {
       
    18             var _tab = _k.split('_')
       
    19             if( typeof _object[_tab[1]] !== "undefined") {
       
    20                 var _fn = (_tab[0] === "min" ? Math.max : Math.min);
       
    21                 _object[_tab[1]] = _fn(_object[_tab[1]], _v);
       
    22             }
       
    23         } else {
       
    24             if( typeof _options[_k] !== "undefined") {
       
    25                 _object[_k] = _options[_k];
       
    26             } else {
       
    27                 _object[_k] = _v;
       
    28             }
       
    29         }
       
    30     });
       
    31 }
       
    32 
       
    33 Tlns.Utils.dateFormat = function(_date, _template) {
       
    34     if (typeof _data !== "object") {
       
    35         _date = new Date(_date);
       
    36     }
       
    37     function zeroPad(_n) {
       
    38         return (_n < 10 ? "0" : "") + _n
       
    39     }
       
    40     var _params = {
       
    41         hours: _date.getHours(),
       
    42         "0hours": zeroPad(_date.getHours()),
       
    43         minutes: _date.getMinutes(),
       
    44         "0minutes": zeroPad(_date.getMinutes()),
       
    45         seconds: _date.getSeconds(),
       
    46         "0seconds": zeroPad(_date.getSeconds()),
       
    47         dayOfWeek: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"][_date.getDay()],
       
    48         shortDayOfWeek: ["Dim","Lun","Mar","Mer","Jeu","Ven","Sam"][_date.getDay()],
       
    49         dayOfMonth: _date.getDate(),
       
    50         "0dayOfMonth": zeroPad(_date.getDate()),
       
    51         monthNumber: 1+_date.getMonth(),
       
    52         "0monthNumber": zeroPad(1+_date.getMonth()),
       
    53         monthName: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"][_date.getMonth()],
       
    54         shortMonthName: ["jan","fev","mar","avr","mai","jun","jul","aou","sep","oct","nov","dec"][_date.getMonth()],
       
    55         year: _date.getFullYear()
       
    56     }
       
    57     return Mustache.to_html(_template, _params);
       
    58 }
       
    59 
       
    60 /* Defaults */
       
    61 
       
    62 Tlns.Defaults.Timeline = {
       
    63     container : "timeline",
       
    64     width : 950,
       
    65     height : 200,
       
    66     url_univers : '',
       
    67     min_width : 400,
       
    68     min_height : 100,
       
    69     main_width : 800,
       
    70     timescales : [{
       
    71         label : "Mois",
       
    72         span : 32 * 86400 * 1000,
       
    73         grid_interval : 5 * 86400 * 1000,
       
    74         grid_date_format : '{{dayOfMonth}} {{shortMonthName}}',
       
    75         start_date_format : '{{dayOfMonth}} {{shortMonthName}}',
       
    76         end_date_format : '{{dayOfMonth}} {{shortMonthName}} {{year}}'
       
    77     }, {
       
    78         label : "Semaine",
       
    79         span : 8 * 86400 * 1000,
       
    80         grid_interval : 86400 * 1000,
       
    81         grid_date_format : '{{shortDayOfWeek}} {{0dayOfMonth}}/{{0monthNumber}}',
       
    82         start_date_format : '{{dayOfMonth}} {{shortMonthName}}',
       
    83         end_date_format : '{{dayOfMonth}} {{shortMonthName}}'
       
    84     }, {
       
    85         label : "2 jours",
       
    86         span : 2 * 86400 * 1000,
       
    87         grid_interval : 8 * 3600 * 1000,
       
    88         grid_date_format : '{{shortDayOfWeek}} {{0dayOfMonth}}/{{0monthNumber}} {{hours}}h',
       
    89         start_date_format : '{{dayOfMonth}} {{shortMonthName}}',
       
    90         end_date_format : '{{dayOfMonth}} {{shortMonthName}}'
       
    91     }, {
       
    92         label : "Demi-Journée",
       
    93         span : 12 * 3600 * 1000,
       
    94         grid_interval : 2 * 3600 * 1000,
       
    95         grid_date_format : '{{hours}}h',
       
    96         start_date_format : '{{dayOfMonth}} {{shortMonthName}} {{hours}}h',
       
    97         end_date_format : '{{dayOfMonth}} {{shortMonthName}} {{hours}}h'
       
    98     }, {
       
    99         label : "3 Heures",
       
   100         span : 3 * 3600 * 1000,
       
   101         grid_interval : 30 * 60 * 1000,
       
   102         grid_date_format : '{{0hours}}:{{0minutes}}',
       
   103         start_date_format : '{{dayOfMonth}} {{shortMonthName}} {{0hours}}:{{0minutes}}',
       
   104         end_date_format : '{{0hours}}:{{0minutes}}'
       
   105     }, {
       
   106         label : "1 Heure",
       
   107         span : 80 * 60 * 1000,
       
   108         grid_interval : 15 * 60 * 1000,
       
   109         grid_date_format : '{{0hours}}:{{0minutes}}',
       
   110         start_date_format : '{{dayOfMonth}} {{shortMonthName}} {{0hours}}:{{0minutes}}',
       
   111         end_date_format : '{{0hours}}:{{0minutes}}'
       
   112     }],
       
   113     level: 0,
       
   114     central_time: 0,
       
   115     sync_now: true,
       
   116     url_occurrences: '',
       
   117     occurrences: {}
       
   118 }
       
   119 
       
   120 for (var _i = 0; _i < Tlns.Defaults.Timeline.timescales.length; _i++) {
       
   121     Tlns.Defaults.Timeline.timescales[_i].level = _i;
       
   122 }
       
   123 
       
   124 /* Templates */
       
   125 
       
   126 Tlns.Templates.Timeline = '<div class="Tl-TopBar"><div class="Tl-TopBar-Button Tl-Border-Right"><div class="Tl-TopBar-AddButton"></div></div><div class="Tl-TopBar-Spacer Tl-Border-Right"></div>'
       
   127     + '<div class="Tl-TopBar-Button Tl-Border-Right"><div class="Tl-TopBar-PreviousButton"></div></div><div class="Tl-TopBar-TimeSpan Tl-TopBar-TextBtn Tl-Border-Right">--/--</div>'
       
   128     + '<div class="Tl-TopBar-Button Tl-Border-Right"><div class="Tl-TopBar-SyncButton"></div></div><div class="Tl-TopBar-Button Tl-Border-Right"><div class="Tl-TopBar-NextButton"></div></div><div class="Tl-TopBar-Spacer Tl-Border-Right"></div>'
       
   129     + '<div class="Tl-TopBar-Timescales">{{#timescales}}<div class="Tl-TopBar-Button Tl-TopBar-TextBtn Tl-Border-Right" data-level="{{level}}">{{label}}</div>{{/timescales}}</div></div>'
       
   130     + '<div class="Tl-BottomPart"><ul class="Tl-UniversLabels"></ul><div class="Tl-MainPart"><div class="Tl-Grid"></div></div></div>';
       
   131 
       
   132 Tlns.Templates.Univers = '<span class="Tl-UniversText">{{title}}</span>'
       
   133 
       
   134 /* Classes */
       
   135 
       
   136 Tlns.Classes.Timeline = function(_options) {
       
   137 
       
   138     /* Setting Defaults */
       
   139     Tlns.Utils.SetDefaults(this, Tlns.Defaults.Timeline, _options);
       
   140 
       
   141     /* Setting container CSS */
       
   142     this.$ = $('#' + this.container);
       
   143     this.$.addClass('Tl-Main');
       
   144     this.$.css({
       
   145         width : this.width + "px",
       
   146         height : this.height + "px"
       
   147     });
       
   148     this.$.html(Mustache.to_html(Tlns.Templates.Timeline, this));
       
   149     
       
   150     this.main_height = this.height - this.$.find('.Tl-TopBar').outerHeight();
       
   151     this.$.find('.Tl-BottomPart').css("height", this.main_height + "px");
       
   152     this.$.find('.Tl-MainPart').css("width", this.main_width + "px");
       
   153     var _o = this.$.find('.Tl-MainPart').offset();
       
   154     this.dragging_bounds = {
       
   155         left: _o.left,
       
   156         top: _o.top,
       
   157         right: _o.left + this.$.find('.Tl-MainPart').outerWidth(),
       
   158         bottom: _o.top + this.$.find('.Tl-MainPart').outerHeight(),
       
   159     };
       
   160     
       
   161     this.setLevel(this.level);
       
   162     
       
   163     var _this = this;
       
   164     this.$.find('.Tl-TopBar-Timescales>div').click(function() {
       
   165         _this.setLevel($(this).attr("data-level"));
       
   166     });
       
   167     
       
   168     this.$.find('.Tl-TopBar-SyncButton').click(function() {
       
   169         _this.sync_now = !_this.sync_now;
       
   170         _this.drawGrid();
       
   171     })
       
   172     
       
   173     this.$.find('.Tl-TopBar-PreviousButton').click(function() {
       
   174         _this.offsetTime(-_this.timescales[_this.level].span / 4);
       
   175     });
       
   176     
       
   177     this.$.find('.Tl-TopBar-NextButton').click(function() {
       
   178         _this.offsetTime(_this.timescales[_this.level].span / 4);
       
   179     });
       
   180     
       
   181     this.$.find('.Tl-MainPart').mousedown(function(_event) {
       
   182         _this.onMouseDown(_event);
       
   183         return false;
       
   184     });
       
   185     
       
   186     this.$.find('.Tl-MainPart').mousemove(function(_event) {
       
   187         _this.onMouseMove(_event);
       
   188         return false;
       
   189     });
       
   190     
       
   191     this.$.find('.Tl-MainPart').mouseup(function(_event) {
       
   192         _this.onMouseUp(_event);
       
   193         return false;
       
   194     });
       
   195     
       
   196     this.throttledSetTime = _.throttle(function(_time) {
       
   197         _this.setTime(_time)
       
   198     }, 150);
       
   199     
       
   200     /* Loading Univers */
       
   201     $.getJSON(this.url_univers, function(_data) {
       
   202         _this.onUniversLoaded(_data);
       
   203     });
       
   204 }
       
   205 
       
   206 Tlns.Classes.Timeline.prototype.onMouseDown = function(_event) {
       
   207     this.mouse_down = true;
       
   208     this.is_dragging = false;
       
   209     this.start_pos = {
       
   210         x: _event.pageX,
       
   211         y: _event.pageY
       
   212     };
       
   213     var _target = $(_event.target);
       
   214     while (!_target.hasClass("Tl-Main") && _target.length) {
       
   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     }
       
   222 }
       
   223 
       
   224 Tlns.Classes.Timeline.prototype.onMouseUp = function(_event) {
       
   225     this.mouse_down = false;
       
   226     this.is_dragging = false;
       
   227 }
       
   228 
       
   229 Tlns.Classes.Timeline.prototype.onMouseMove = function(_event) {
       
   230     if (this.mouse_down) {
       
   231         this.is_dragging = true;
       
   232         if (_event.pageX > this.dragging_bounds.left
       
   233             && _event.pageX < this.dragging_bounds.right
       
   234             && _event.pageY > this.dragging_bounds.top
       
   235             && _event.pageY < this.dragging_bounds.bottom) {
       
   236             switch (this.dragging_type) {
       
   237                 case "timeline":
       
   238                     var _newTime = Math.floor(this.time_at_start + ( this.start_pos.x - _event.pageX ) / this.current_scale);
       
   239                     this.throttledSetTime(_newTime);
       
   240                 break;
       
   241             }
       
   242         } else {
       
   243             this.onMouseUp(_event);
       
   244         }
       
   245     }
       
   246 }
       
   247 
       
   248 Tlns.Classes.Timeline.prototype.onUniversLoaded = function(_data) {
       
   249     this.univers = [];
       
   250     if(_data.length) {
       
   251         this.univers_height = Math.floor(this.main_height / _data.length);
       
   252     }
       
   253     for(var _i = 0; _i < _data.length; _i++) {
       
   254         this.univers.push(new Tlns.Classes.Univers(_data[_i], this, _i));
       
   255     }
       
   256 }
       
   257 
       
   258 Tlns.Classes.Timeline.prototype.offsetTime = function(_timeOffset) {
       
   259     this.setTime(this.central_time + _timeOffset);
       
   260 }
       
   261 
       
   262 Tlns.Classes.Timeline.prototype.setTime = function(_centralTime) {
       
   263     this.sync_now = false;
       
   264     this.central_time = _centralTime;
       
   265     this.drawGrid();
       
   266 }
       
   267 
       
   268 Tlns.Classes.Timeline.prototype.setLevel = function(_level) {
       
   269     if (_level >= 0 && _level < this.timescales.length) {
       
   270         this.$.find('.Tl-TopBar-Timescales>div').each(function() {
       
   271             var _el = $(this);
       
   272             if (_el.attr("data-level") == _level) {
       
   273                 _el.addClass("active");
       
   274             } else {
       
   275                 _el.removeClass("active");
       
   276             }
       
   277         });
       
   278         this.level = _level;
       
   279         this.drawGrid();
       
   280     }
       
   281 }
       
   282 
       
   283 Tlns.Classes.Timeline.prototype.drawGrid = function() {
       
   284     var _now = new Date().valueOf();
       
   285     if (this.sync_now) {
       
   286         this.central_time = _now;
       
   287         this.$.find('.Tl-TopBar-SyncButton').addClass("active");
       
   288     } else {
       
   289         this.$.find('.Tl-TopBar-SyncButton').removeClass("active");
       
   290     }
       
   291     var _timescale = this.timescales[this.level],
       
   292         _offset = new Date().getTimezoneOffset() * 60000;
       
   293     this.current_scale = this.main_width / (_timescale.span);
       
   294     var _tmin = this.central_time - (_timescale.span / 2),
       
   295         _tmax = this.central_time + (_timescale.span / 2),
       
   296         _grid_width = Math.floor(_timescale.grid_interval * this.current_scale),
       
   297         _roundstart = Math.floor((_tmin - _offset) / _timescale.grid_interval) * _timescale.grid_interval + _offset,
       
   298         _html = '';
       
   299     this.$.find('.Tl-TopBar-TimeSpan').html(Tlns.Utils.dateFormat(_tmin, _timescale.start_date_format) + ' - ' + Tlns.Utils.dateFormat(_tmax, _timescale.end_date_format));
       
   300     for (var _t = _roundstart; _t < _tmax; _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">'
       
   302         + '<div class="Tl-Grid-Label">' + Tlns.Utils.dateFormat(_t, _timescale.grid_date_format) + '</div></div>';
       
   303     }
       
   304 /*
       
   305  
       
   306     for (var _t = _roundstart; _t < _tmax; _t += _timescale.grid_interval) {
       
   307         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">'
       
   309         + ( _isMajor ? '<div class="Tl-Grid-Label">' + Tlns.Utils.dateFormat(_t, _timescale.date_format) + '</div>' : '' ) + '</div>';
       
   310     }
       
   311 */
       
   312     if (_tmin <= _now && _tmax >= _now) {
       
   313         _html += '<div class="Tl-Grid-Now" style="left: ' + this.current_scale * (_now - this.central_time) + 'px"></div>'
       
   314     }
       
   315     this.$.find('.Tl-Grid').html(_html);
       
   316 }
       
   317 
       
   318 Tlns.Classes.Timeline.prototype.drawOccurrences = function() {
       
   319     
       
   320 }
       
   321 
       
   322 Tlns.Classes.Univers = function(_data, _timeline, _index) {
       
   323     this.id = _data.id;
       
   324     this.index = _index;
       
   325     this.title = _data.nom;
       
   326     this.mainCharacter = _data.personnage;
       
   327 
       
   328     this.$label = $('<li>').css({
       
   329         height : _timeline.univers_height + "px"
       
   330     }).html(Mustache.to_html(Tlns.Templates.Univers, this))
       
   331     .addClass((_index % 2) ? 'Tl-Line-Odd' : 'Tl-Line-Even');
       
   332     
       
   333     _timeline.$.find('.Tl-UniversLabels').append(this.$label);
       
   334     var _txt = _data.nom,
       
   335         _span = this.$label.find('span');
       
   336 
       
   337     while (_span.outerWidth() > (_timeline.width - _timeline.main_width) && _txt) {
       
   338         _txt = _txt.substr(0, _txt.length - 1);
       
   339         _span.html(_txt + '&hellip;');
       
   340     }
       
   341 }