1 /* 2 * Timemap.js Copyright 2010 Nick Rabinowitz. 3 * Licensed under the MIT License (see LICENSE.txt) 4 */ 5 6 /** 7 * @fileOverview 8 * Functions in this file are used to set the timemap state programmatically, 9 * either in a script or from the url hash. 10 * 11 * @requires param.js 12 * 13 * @author Nick Rabinowitz (www.nickrabinowitz.com) 14 */ 15 16 // save a few bytes 17 (function() { 18 19 /*---------------------------------------------------------------------------- 20 * State namespace, with setters, serializers, and url functions 21 *---------------------------------------------------------------------------*/ 22 23 var paramNS = TimeMap.params, 24 25 /** 26 * @name TimeMap.state 27 * @namespace Namespace for static state functions used to 28 * set the timemap state programmatically, either in a script or 29 * from the url hash. 30 * @see <a href="../../examples/state.html#zoom=8¢er=44.04811573082351,13.29345703125&date=1500-01-21T12:17:37Z&selected=0">State Example</a> 31 */ 32 stateNS = TimeMap.state = { 33 34 /** 35 * Get the state parameters from the URL, returning as a config object 36 * 37 * @return {Object} Object with state config settings 38 */ 39 fromUrl: function() { 40 var pairs = location.hash.substring(1).split('&'), 41 params = stateNS.params, 42 state = {}, x, pair, key; 43 for (x=0; x < pairs.length; x++) { 44 if (pairs[x] != "") { 45 pair = pairs[x].split('='); 46 key = pair[0]; 47 if (key && key in params) { 48 state[key] = params[key].fromString(decodeURI(pair[1])); 49 } 50 } 51 } 52 return state; 53 }, 54 55 /** 56 * Make a parameter string from a state object 57 * 58 * @param {Object} state Object with state config settings 59 * @return {String} Parameter string in URL param format 60 */ 61 toParamString: function(state) { 62 var params = stateNS.params, 63 paramArray = [], 64 key; 65 // go through each key in state 66 for (key in state) { 67 if (state.hasOwnProperty(key)) { 68 if (key in params) { 69 paramArray.push(key + "=" + encodeURI(params[key].toString(state[key]))); 70 } 71 } 72 } 73 return paramArray.join("&"); 74 }, 75 76 /** 77 * Make a full URL from a state object 78 * 79 * @param {Object} state Object with state config settings 80 * @return {String} Full URL with parameters 81 */ 82 toUrl: function(state) { 83 var paramString = stateNS.toParamString(state), 84 url = location.href.split("#")[0]; 85 return url + "#" + paramString; 86 }, 87 88 /** 89 * Set state settings on a config object for TimeMap.init() 90 * @see TimeMap.init 91 * 92 * @param {Object} config Config object for TimeMap.init(), modified in place 93 * @param {Object} state Object with state config settings 94 */ 95 setConfig: function(config, state) { 96 var params = stateNS.params, 97 key; 98 for (key in state) { 99 if (state.hasOwnProperty(key)) { 100 if (key in params) { 101 params[key].setConfig(config, state[key]); 102 } 103 } 104 } 105 }, 106 107 /** 108 * Set state settings on a config object for TimeMap.init() using 109 * parameters in the URL. Note that as of Timemap.js v.1.6, this 110 * will run automatically if state functions are present. 111 * @see TimeMap.init 112 * @example 113 // set up the config object 114 var config = { 115 // various settings, as usual for TimeMap.init() 116 }; 117 118 // get state settings from the URL, e.g.: 119 // http://www.example.com/mytimemap.html#zoom=4&selected=1 120 TimeMap.state.setConfigFromUrl(config); 121 122 // initialize TimeMap object 123 var tm = TimeMap.init(config); 124 * 125 * @param {Object} config Config object for TimeMap.init() 126 */ 127 setConfigFromUrl: function(config) { 128 stateNS.setConfig(config, stateNS.fromUrl()); 129 } 130 131 }; 132 133 /*---------------------------------------------------------------------------- 134 * TimeMap object methods 135 *---------------------------------------------------------------------------*/ 136 137 /** 138 * Set the timemap state with a set of configuration options. 139 * 140 * @param {Object} state Object with state config settings 141 */ 142 TimeMap.prototype.setState = function(state) { 143 var params = stateNS.params, 144 key; 145 // go through each key in state 146 for (key in state) { 147 if (state.hasOwnProperty(key)) { 148 if (key in params) { 149 // run setter function with config value 150 params[key].set(this, state[key]); 151 } 152 } 153 } 154 }; 155 156 /** 157 * Get a configuration object of state variables 158 * 159 * @return {Object} Object with state config settings 160 */ 161 TimeMap.prototype.getState = function() { 162 var state = {}, 163 params = stateNS.params, 164 key; 165 // run through params, adding values to state 166 for (key in params) { 167 if (params.hasOwnProperty(key)) { 168 // get state value 169 state[key] = params[key].get(this); 170 } 171 } 172 return state; 173 }; 174 175 /** 176 * Initialize state tracking based on URL. 177 * Note: continuous tracking will only work 178 * on browsers that support the "onhashchange" event. 179 */ 180 TimeMap.prototype.initState = function() { 181 var tm = this; 182 tm.setStateFromUrl(); 183 window.onhashchange = function() { 184 tm.setStateFromUrl(); 185 }; 186 }; 187 188 /** 189 * Set the timemap state with parameters in the URL 190 */ 191 TimeMap.prototype.setStateFromUrl = function() { 192 this.setState(stateNS.fromUrl()); 193 }; 194 195 /** 196 * Get current state parameters serialized as a hash string 197 * 198 * @return {String} State parameters serialized as a hash string 199 */ 200 TimeMap.prototype.getStateParamString = function() { 201 return stateNS.toParamString(this.getState()); 202 }; 203 204 /** 205 * Get URL with current state parameters in hash 206 * 207 * @return {String} URL with state parameters 208 */ 209 TimeMap.prototype.getStateUrl = function() { 210 return stateNS.toUrl(this.getState()); 211 }; 212 213 214 /*---------------------------------------------------------------------------- 215 * State parameters 216 *---------------------------------------------------------------------------*/ 217 218 /** 219 * @namespace 220 * Namespace for state parameters, each with a set of functions to set and serialize values. 221 * Add your own Param objects to this namespace to get and set additional state variables. 222 */ 223 TimeMap.state.params = { 224 225 /** 226 * Map zoom level 227 * @type TimeMap.params.Param 228 */ 229 zoom: new paramNS.OptionParam("mapZoom", { 230 get: function(tm) { 231 return tm.map.getZoom(); 232 }, 233 set: function(tm, value) { 234 tm.map.setZoom(value); 235 }, 236 fromStr: function(s) { 237 return parseInt(s); 238 } 239 }), 240 241 /** 242 * Map center 243 * @type TimeMap.params.Param 244 */ 245 center: new paramNS.OptionParam("mapCenter", { 246 get: function(tm) { 247 return tm.map.getCenter(); 248 }, 249 set: function(tm, value) { 250 tm.map.setCenter(value); 251 }, 252 fromStr: function(s) { 253 var params = s.split(","); 254 if (params.length < 2) { 255 // give up 256 return null; 257 } 258 return new GLatLng( 259 parseFloat(params[0]), 260 parseFloat(params[1]) 261 ); 262 }, 263 toStr: function(value) { 264 return value.lat() + "," + value.lng(); 265 } 266 }), 267 268 /** 269 * Timeline center date 270 * @type TimeMap.params.Param 271 */ 272 date: new paramNS.Param("scrollTo", { 273 get: function(tm) { 274 return tm.timeline.getBand(0).getCenterVisibleDate(); 275 }, 276 set: function(tm, value) { 277 tm.scrollToDate(value); 278 }, 279 fromStr: function(s) { 280 return TimeMapDataset.hybridParser(s); 281 }, 282 toStr: function(value) { 283 return TimeMap.util.formatDate(value); 284 } 285 }), 286 287 /** 288 * Index of selected/open item, if any 289 * @type TimeMap.params.Param 290 */ 291 selected: new paramNS.Param("selected", { 292 get: function(tm) { 293 var items = tm.getItems(), 294 i = items.length-1; 295 while (i >= 0 && i--) { 296 if (items[i].selected) break; 297 } 298 return i; 299 }, 300 set: function(tm, value) { 301 if (value >= 0) { 302 var item = tm.getItems()[value]; 303 if (item) { 304 item.openInfoWindow(); 305 } 306 } 307 }, 308 fromStr: function(s) { 309 return parseInt(s); 310 } 311 }) 312 }; 313 314 })(); 315