PageRenderTime 25ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/Plots/Content/timeglider/js/timeglider/TG_Timeline.js

http://visualizeweb.codeplex.com
JavaScript | 333 lines | 161 code | 112 blank | 60 comment | 27 complexity | 8e70cb5a1de42ace5c29e6668bf5516f MD5 | raw file
Possible License(s): GPL-2.0, MIT, BSD-3-Clause, Apache-2.0
  1. /*
  2. * Timeglider for Javascript / jQuery
  3. * http://timeglider.com/jquery
  4. *
  5. * Copyright 2011, Mnemograph LLC
  6. * Licensed under Timeglider Dual License
  7. * http://timeglider.com/jquery/?p=license
  8. *
  9. */
  10. /*
  11. *
  12. * Timeline
  13. * Backbone Model
  14. *
  15. */
  16. (function(tg){
  17. var TG_Date = tg.TG_Date,
  18. $ = jQuery,
  19. widget_options = {},
  20. app_mediator;
  21. tg.TG_EventCollection = Backbone.Collection.extend({
  22. model: tg.TG_Event
  23. });
  24. // map model onto larger timeglider namespace
  25. /////////////////////////////////////////////
  26. tg.TG_Event = Backbone.Model.extend({
  27. urlRoot : '/event',
  28. defaults: {
  29. "title": "Untitled",
  30. "modalOpen":false
  31. },
  32. initialize: function(ev) {
  33. if (ev.image) {
  34. // register image with image collection for gathering sizes.
  35. var display_class = ev.image_class || "layout";
  36. ev.image = {id: ev.id, src:ev.image, display_class:display_class, width:0, height:0};
  37. // this will follow up with reporting size in separate "thread"
  38. this.getEventImageSize(ev.image);
  39. // app_mediator.imagesToSize++;
  40. } else {
  41. ev.image = '';
  42. }
  43. ev.titleWidth = tg.getStringWidth(ev.title);
  44. this.set(ev);
  45. },
  46. // TODO: validate event attributes
  47. validate: function (attrs) {
  48. // TODO
  49. },
  50. getEventImageSize:function(img) {
  51. var that = this,
  52. imgTesting = new Image(),
  53. img_src = imgTesting.src = img.src;
  54. imgTesting.onerror= delegatr(imgTesting, function () {
  55. debug.log("error loading image:" + img_src);
  56. });
  57. imgTesting.onload = delegatr(imgTesting, function () {
  58. that.get("image").height = this.height;
  59. that.get("image").width = this.width;
  60. });
  61. // hoised function here... TODO: move this to utilities
  62. function delegatr(contextObject, delegateMethod) {
  63. return function() {
  64. return delegateMethod.apply(contextObject, arguments);
  65. }
  66. };
  67. } // end getEventImageSize
  68. });
  69. tg.TG_TimelineCollection = Backbone.Collection.extend({
  70. model: tg.TG_Timeline
  71. });
  72. // map model onto larger timeglider namespace
  73. /////////////////////////////////////////////
  74. tg.TG_Timeline = Backbone.Model.extend({
  75. urlRoot : '/timeline',
  76. defaults: {
  77. // no other defaults?
  78. "initial_zoom":25,
  79. "focus_date":"today",
  80. "timezone":"00:00",
  81. "title": "Untitled",
  82. "events": [],
  83. "legend": []
  84. },
  85. // processes init model data, adds certain calculated values
  86. _chewTimeline : function (tdata) {
  87. // TODO ==> add additional units
  88. app_mediator = tdata.mediator;
  89. widget_options = app_mediator.options;
  90. var dhash = {
  91. "da":[],
  92. "mo":[],
  93. "ye":[],
  94. "de":[],
  95. "ce":[],
  96. "thou":[],
  97. "tenthou":[],
  98. "hundredthou":[],
  99. "mill":[],
  100. "tenmill":[],
  101. "hundredmill":[],
  102. "bill":[]
  103. };
  104. var units = TG_Date.units;
  105. tdata.startSeconds = [];
  106. tdata.endSeconds = [];
  107. tdata.spans = [];
  108. tdata.hasImagesAbove = false;
  109. var tzoff = tdata.timezone || "00:00";
  110. tdata.timeOffset = TG_Date.getTimeOffset(tzoff);
  111. // TODO: VALIDATE COLOR, centralize default color(options?)
  112. if (!tdata.color) { tdata.color = "#333333"; }
  113. if (tdata.events) {
  114. var date, ddisp, ev, id, unit, ser, tWidth;
  115. var l = tdata.events.length;
  116. for(var ei=0; ei< l; ei++) {
  117. /*
  118. We do some pre-processing ** INCLUDING HASHING THE EVENT *
  119. BEFORE putting the event into it's Model&Collection because some
  120. (processed) event attributes are needed at the timeline level
  121. */
  122. ev=tdata.events[ei];
  123. if (ev.map) {
  124. tg.googleMapsLoad();
  125. }
  126. // make sure it has an id!
  127. if (ev.id) {
  128. // TODO :: make sure it's unique... append with timeline id?
  129. id = ev.id
  130. } else {
  131. ev.id = id = "anon" + this.anonEventId++;
  132. }
  133. // date_limit is old JSON prop name, replaced by date_display
  134. ddisp = ev.date_display || ev.date_limit || "da";
  135. ev.date_display = ddisp.toLowerCase().substr(0,2);
  136. // if a timezone offset is set on the timeline, adjust
  137. // any events that do not have the timezone set on them
  138. if (tdata.timeOffset.seconds) {
  139. ev.startdate = TG_Date.tzOffsetStr(ev.startdate, tdata.timeOffset.string);
  140. if (ev.enddate) {
  141. ev.enddate = TG_Date.tzOffsetStr(ev.enddate, tdata.timeOffset.string);
  142. }
  143. }
  144. ev.startdateObj = new TG_Date(ev.startdate, ev.date_display);
  145. // TODO: if they're valid!
  146. if ((ev.enddate) && (ev.enddate !== ev.startdate)){
  147. ev.enddateObj = new TG_Date(ev.enddate, ev.date_display);
  148. ev.span=true;
  149. tdata.spans.push({id:ev.id, start:ev.startdateObj.sec, end:ev.enddateObj.sec});
  150. } else {
  151. ev.enddateObj = ev.startdateObj;
  152. ev.span = false;
  153. }
  154. if (ev.image_class == "above") {
  155. tdata.hasImagesAbove = true;
  156. }
  157. if (!ev.icon || ev.icon === "none") {
  158. ev.icon = "";
  159. } else {
  160. ev.icon = widget_options.icon_folder + ev.icon;
  161. }
  162. // for collapsed view and other metrics
  163. tdata.startSeconds.push(ev.startdateObj.sec);
  164. tdata.endSeconds.push(ev.enddateObj.sec);
  165. //// !! TODO VALIDATE DATE respecting startdate, too
  166. var uxl=units.length;
  167. for (var ux=0; ux < uxl; ux++) {
  168. unit = units[ux];
  169. ///// DATE HASHING in action
  170. ser = TG_Date.getTimeUnitSerial(ev.startdateObj, unit);
  171. if (dhash[unit][ser] !== undefined) {
  172. dhash[unit][ser].push(id);
  173. } else {
  174. // create the array
  175. dhash[unit][ser] = [id];
  176. }
  177. /////////////////////////////
  178. }
  179. /////////////////////////////////
  180. // Since model is defined in the eventCollection
  181. // we just need to add the raw object here and it
  182. // is "vivified"...
  183. var newEvent = new tg.TG_Event(ev);
  184. app_mediator.eventCollection.add(newEvent);
  185. }// end for: cycling through timeline's events
  186. // adding event secs to catalog of entire timeline
  187. var fl = timeglider.getLowHigh($.merge(tdata.startSeconds,tdata.endSeconds));
  188. /// bounds of timeline
  189. tdata.bounds = {"first": fl.low, "last":fl.high };
  190. } /// end if there are events!
  191. /* TODO: necessary to parse this now, or just leave as is? */
  192. if (tdata.legend.length > 0) {
  193. var legend = tdata.legend;
  194. for (var i=0; i<legend.length; i++) {
  195. var legend_item = legend[i];
  196. // debug.log("leg. title:" + legend_item['title'])
  197. }
  198. }
  199. /// i.e. expanded or compressed...
  200. /// ought to be attribute at the timeline level
  201. /// TODO: create a $.merge for defaults for a timeline
  202. tdata.display = "expanded";
  203. tdata.dateHash = dhash;
  204. // keeping events in the eventCollection
  205. // hashing references to evnet IDs inside the date hash
  206. delete tdata.events;
  207. return tdata;
  208. },
  209. initialize: function(attrs) {
  210. var processed = this._chewTimeline(attrs);
  211. this.set(processed);
  212. this.bind("change", function() {
  213. debug.log("changola");
  214. });
  215. },
  216. // TODO: validate event attributes
  217. validate: function (attrs) {
  218. // debug.log("validate data:" + attrs.title);
  219. }
  220. });
  221. })(timeglider);