1 /* 2 * Timemap.js Copyright 2010 Nick Rabinowitz. 3 * Licensed under the MIT License (see LICENSE.txt) 4 */ 5 6 /** 7 * @fileOverview 8 * Additional TimeMap manipulation functions. 9 * Functions in this file are used to manipulate a TimeMap, TimeMapDataset, or 10 * TimeMapItem after the initial load process. 11 * 12 * @author Nick Rabinowitz (www.nickrabinowitz.com) 13 */ 14 15 /*globals TimeMap, TimeMapDataset, TimeMapItem, Timeline */ 16 17 (function(){ 18 var window = this, 19 TimeMap = window.TimeMap, 20 TimeMapDataset = window.TimeMapDataset, 21 TimeMapItem = window.TimeMapItem; 22 23 /*---------------------------------------------------------------------------- 24 * TimeMap manipulation: stuff affecting every dataset 25 *---------------------------------------------------------------------------*/ 26 27 /** 28 * Delete all datasets, clearing them from map and timeline. Note 29 * that this is more efficient than calling clear() on each dataset. 30 */ 31 TimeMap.prototype.clear = function() { 32 var tm = this; 33 tm.eachItem(function(item) { 34 item.event = item.placemark = null; 35 }); 36 tm.map.clearOverlays(); 37 tm.eventSource.clear(); 38 tm.datasets = []; 39 }; 40 41 /** 42 * Delete one dataset, clearing it from map and timeline 43 * 44 * @param {String} id Id of dataset to delete 45 */ 46 TimeMap.prototype.deleteDataset = function(id) { 47 this.datasets[id].clear(); 48 delete this.datasets[id]; 49 }; 50 51 /** 52 * Hides placemarks for a given dataset 53 * 54 * @param {String} id The id of the dataset to hide 55 */ 56 TimeMap.prototype.hideDataset = function (id){ 57 if (id in this.datasets) { 58 this.datasets[id].hide(); 59 } 60 }; 61 62 /** 63 * Hides all the datasets on the map 64 */ 65 TimeMap.prototype.hideDatasets = function(){ 66 var tm = this; 67 tm.each(function(ds) { 68 ds.visible = false; 69 }); 70 tm.filter("map"); 71 tm.filter("timeline"); 72 }; 73 74 /** 75 * Shows placemarks for a given dataset 76 * 77 * @param {String} id The id of the dataset to hide 78 */ 79 TimeMap.prototype.showDataset = function(id) { 80 if (id in this.datasets) { 81 this.datasets[id].show(); 82 } 83 }; 84 85 /** 86 * Shows all the datasets on the map 87 */ 88 TimeMap.prototype.showDatasets = function() { 89 var tm = this; 90 tm.each(function(ds) { 91 ds.visible = true; 92 }); 93 tm.filter("map"); 94 tm.filter("timeline"); 95 }; 96 97 /** 98 * Change the default map type 99 * 100 * @param {String|Object} mapType New map type If string, looks up in TimeMap.mapTypes. 101 */ 102 TimeMap.prototype.changeMapType = function (mapType) { 103 var tm = this; 104 // check for no change 105 if (mapType == tm.opts.mapType) { 106 return; 107 } 108 // look for mapType 109 if (typeof(mapType) == 'string') { 110 mapType = TimeMap.mapTypes[mapType]; 111 } 112 // no mapType specified 113 if (!mapType) { 114 return; 115 } 116 // change it 117 tm.opts.mapType = mapType; 118 tm.map.setMapType(mapType); 119 }; 120 121 /*---------------------------------------------------------------------------- 122 * TimeMap manipulation: stuff affecting the timeline 123 *---------------------------------------------------------------------------*/ 124 125 /** 126 * Refresh the timeline, maintaining the current date 127 */ 128 TimeMap.prototype.refreshTimeline = function () { 129 var topband = this.timeline.getBand(0); 130 var centerDate = topband.getCenterVisibleDate(); 131 if (TimeMap.util.TimelineVersion() == "1.2") { 132 topband.getEventPainter().getLayout()._laidout = false; 133 } 134 this.timeline.layout(); 135 topband.setCenterVisibleDate(centerDate); 136 }; 137 138 /** 139 * Change the intervals on the timeline. 140 * 141 * @param {String|Array} intervals New intervals. If string, looks up in TimeMap.intervals. 142 */ 143 TimeMap.prototype.changeTimeIntervals = function (intervals) { 144 var tm = this; 145 // check for no change 146 if (intervals == tm.opts.bandIntervals) { 147 return; 148 } 149 // look for intervals 150 if (typeof(intervals) == 'string') { 151 intervals = TimeMap.intervals[intervals]; 152 } 153 // no intervals specified 154 if (!intervals) { 155 return; 156 } 157 tm.opts.bandIntervals = intervals; 158 // internal function - change band interval 159 function changeInterval(band, interval) { 160 band.getEther()._interval = Timeline.DateTime.gregorianUnitLengths[interval]; 161 band.getEtherPainter()._unit = interval; 162 }; 163 // grab date 164 var topband = tm.timeline.getBand(0), 165 centerDate = topband.getCenterVisibleDate(), 166 x; 167 // change interval for each band 168 for (x=0; x<tm.timeline.getBandCount(); x++) { 169 changeInterval(tm.timeline.getBand(x), intervals[x]); 170 } 171 // re-layout timeline 172 topband.getEventPainter().getLayout()._laidout = false; 173 tm.timeline.layout(); 174 topband.setCenterVisibleDate(centerDate); 175 }; 176 177 178 /*---------------------------------------------------------------------------- 179 * TimeMapDataset manipulation: global settings, stuff affecting every item 180 *---------------------------------------------------------------------------*/ 181 182 /** 183 * Delete all items, clearing them from map and timeline 184 */ 185 TimeMapDataset.prototype.clear = function() { 186 var ds = this; 187 ds.each(function(item) { 188 item.clear(); 189 }); 190 ds.items = []; 191 ds.timemap.timeline.layout(); 192 }; 193 194 /** 195 * Delete one item, clearing it from map and timeline 196 * 197 * @param {TimeMapItem} item Item to delete 198 */ 199 TimeMapDataset.prototype.deleteItem = function(item) { 200 var ds = this, x; 201 for (x=0; x < ds.items.length; x++) { 202 if (ds.items[x] == item) { 203 item.clear(); 204 ds.items.splice(x, 1); 205 break; 206 } 207 } 208 ds.timemap.timeline.layout(); 209 }; 210 211 /** 212 * Show dataset 213 */ 214 TimeMapDataset.prototype.show = function() { 215 var ds = this, 216 tm = ds.timemap; 217 if (!ds.visible) { 218 ds.visible = true; 219 tm.filter("map"); 220 tm.filter("timeline"); 221 tm.timeline.layout(); 222 } 223 }; 224 225 /** 226 * Hide dataset 227 */ 228 TimeMapDataset.prototype.hide = function() { 229 var ds = this, 230 tm = ds.timemap; 231 if (ds.visible) { 232 ds.visible = false; 233 tm.filter("map"); 234 tm.filter("timeline"); 235 } 236 }; 237 238 /** 239 * Change the theme for every item in a dataset 240 * 241 * @param {TimeMapTheme} theme New theme settings 242 */ 243 TimeMapDataset.prototype.changeTheme = function(newTheme) { 244 var ds = this; 245 ds.opts.theme = newTheme; 246 ds.each(function(item) { 247 item.changeTheme(newTheme); 248 }); 249 ds.timemap.timeline.layout(); 250 }; 251 252 253 /*---------------------------------------------------------------------------- 254 * TimeMapItem manipulation: manipulate events and placemarks 255 *---------------------------------------------------------------------------*/ 256 257 /** 258 * Show event and placemark 259 */ 260 TimeMapItem.prototype.show = function() { 261 var item = this; 262 item.showEvent(); 263 item.showPlacemark(); 264 item.visible = true; 265 }; 266 267 /** 268 * Hide event and placemark 269 */ 270 TimeMapItem.prototype.hide = function() { 271 var item = this; 272 item.hideEvent(); 273 item.hidePlacemark(); 274 item.visible = false; 275 }; 276 277 /** 278 * Delete placemark from map and event from timeline 279 */ 280 TimeMapItem.prototype.clear = function() { 281 var item = this, 282 i; 283 if (item.event) { 284 // this is just ridiculous 285 item.dataset.timemap.timeline.getBand(0) 286 .getEventSource()._events._events.remove(item.event); 287 } 288 if (item.placemark) { 289 item.hidePlacemark(); 290 function removeOverlay(p) { 291 try { 292 item.map.removeOverlay(p); 293 } catch(e) {} 294 }; 295 if (item.getType() == "array") { 296 for (i=0; i<item.placemark.length; i++) { 297 removeOverlay(item.placemark[i]); 298 } 299 } else { 300 removeOverlay(item.placemark); 301 } 302 } 303 item.event = item.placemark = null; 304 }; 305 306 /** 307 * Create a new event for the item. 308 * 309 * @param {Date} s Start date for the event 310 * @param {Date} e (Optional) End date for the event 311 */ 312 TimeMapItem.prototype.createEvent = function(s, e) { 313 var item = this, 314 theme = item.opts.theme, 315 instant = (e === undefined), 316 title = item.getTitle(); 317 // create event 318 var event = new Timeline.DefaultEventSource.Event(s, e, null, null, instant, title, 319 null, null, null, theme.eventIcon, theme.eventColor, null); 320 // add references 321 event.item = item; 322 item.event = event; 323 item.dataset.eventSource.add(event); 324 }; 325 326 /** 327 * Change the theme for an item 328 * 329 * @param {TimeMapTheme} theme New theme settings 330 */ 331 TimeMapItem.prototype.changeTheme = function(newTheme) { 332 var item = this, 333 type = item.getType(), 334 event = item.event, 335 placemark = item.placemark, 336 i; 337 item.opts.theme = newTheme; 338 // change placemark 339 if (placemark) { 340 // internal function - takes type, placemark 341 function changePlacemark(pm, type, theme) { 342 type = type || TimeMap.util.getPlacemarkType(pm); 343 switch (type) { 344 case "marker": 345 pm.setImage(theme.icon.image); 346 break; 347 case "polygon": 348 pm.setFillStyle({ 349 'color': newTheme.fillColor, 350 'opacity': newTheme.fillOpacity 351 }); 352 // no break to get stroke style too 353 case "polyline": 354 pm.setStrokeStyle({ 355 'color': newTheme.lineColor, 356 'weight': newTheme.lineWeight, 357 'opacity': newTheme.lineOpacity 358 }); 359 break; 360 } 361 }; 362 if (type == 'array') { 363 for (i=0; i<placemark.length; i++) { 364 changePlacemark(placemark[i], false, newTheme); 365 } 366 } else { 367 changePlacemark(placemark, type, newTheme); 368 } 369 } 370 // change event 371 if (event) { 372 event._color = newTheme.eventColor; 373 event._icon = newTheme.eventIcon; 374 } 375 }; 376 377 /** 378 * Find the next or previous item chronologically 379 * 380 * @param {Boolean} [backwards=false] Whether to look backwards (i.e. find previous) 381 * @param {Boolean} [inDataset=false] Whether to only look in this item's dataset 382 * @return {TimeMapItem} Next/previous item, if any 383 */ 384 TimeMapItem.prototype.getNextPrev = function(backwards, inDataset) { 385 var item = this, 386 eventSource = item.dataset.timemap.timeline.getBand(0).getEventSource(), 387 // iterator dates are non-inclusive, hence the juggle here 388 i = backwards ? 389 eventSource.getEventReverseIterator( 390 new Date(eventSource.getEarliestDate().getTime() - 1), 391 item.event.getStart()) : 392 eventSource.getEventIterator( 393 item.event.getStart(), 394 new Date(eventSource.getLatestDate().getTime() + 1) 395 ), 396 next = null; 397 if (!item.event) { 398 return; 399 } 400 while (next === null) { 401 if (i.hasNext()) { 402 next = i.next().item; 403 if (inDataset && next.dataset != item.dataset) { 404 next = null; 405 } 406 } else { 407 break; 408 } 409 } 410 return next; 411 }; 412 413 /** 414 * Find the next item chronologically 415 * 416 * @param {Boolean} [inDataset=false] Whether to only look in this item's dataset 417 * @return {TimeMapItem} Next item, if any 418 */ 419 TimeMapItem.prototype.getNext = function(inDataset) { 420 return this.getNextPrev(false, inDataset); 421 } 422 423 /** 424 * Find the previous item chronologically 425 * 426 * @requires Timeline v.2.2.0 or greater 427 * 428 * @param {Boolean} [inDataset=false] Whether to only look in this item's dataset 429 * @return {TimeMapItem} Next item, if any 430 */ 431 TimeMapItem.prototype.getPrev = function(inDataset) { 432 return this.getNextPrev(true, inDataset); 433 } 434 435 })();