update timemap to version 1.6

This commit is contained in:
wlx 2010-06-29 08:58:09 +00:00
parent 8acf29a8c3
commit fc689a66f2
11 changed files with 3015 additions and 1163 deletions

View File

@ -1,5 +1,5 @@
/*
* Timemap.js Copyright 2008 Nick Rabinowitz.
* Timemap.js Copyright 2010 Nick Rabinowitz.
* Licensed under the MIT License (see LICENSE.txt)
*/
@ -10,22 +10,23 @@
* @author Nick Rabinowitz (www.nickrabinowitz.com)
*/
// for JSLint
/*global TimeMap */
/**
* @class
* Flickr loader factory - inherits from jsonp loader
* Flickr loader: Load JSONP data from Flickr.
*
* <p>This is a loader for data from Flickr. You probably want to use it with a
* <p>This is a loader for Flickr data. You probably want to use it with a
* URL for the Flickr Geo Feed API: <a href="http://www.flickr.com/services/feeds/geo/">http://www.flickr.com/services/feeds/geo/</a></p>
*
* <p>The loader takes a full URL, minus the JSONP callback function.</p>
*
* <p>Depends on:</p>
* <ul>
* <li>loaders/jsonp.js</li>
* </ul>
* @augments TimeMap.loaders.jsonp
* @requires loaders/json.js
*
* @example Usage in TimeMap.init():
* @example
TimeMap.init({
datasets: [
{
title: "Flickr Dataset",
@ -36,43 +37,56 @@
url: "http://www.flickr.com/services/feeds/geo/?format=json&jsoncallback="
}
}
]
],
// etc...
});
* @see <a href="../../examples/pathlines.html">Flickr Pathlines Example</a>
*
* @param {Object} options All options for the loader:<pre>
* {String} url Full JSONP url of Flickr feed to load
* {Function} preloadFunction Function to call on data before loading
* {Function} transformFunction Function to call on individual items before loading
* </pre>
* @return {TimeMap.loaders.remote} Remote loader configured for Flickr
* @param {Object} options All options for the loader
* @param {String} options.url Full JSONP url of Flickr feed to load
* @param {mixed} [options[...]] Other options (see {@link TimeMap.loaders.jsonp})
*/
TimeMap.loaders.flickr = function(options) {
var loader = new TimeMap.loaders.jsonp(options);
// preload function for Flickr feeds
/**
* Preload function for Flickr feeds
* @name TimeMap.loaders.flickr#preload
* @function
* @parameter {Object} data Data to preload
* @return {Array} data Array of item data
*/
loader.preload = function(data) {
return data["items"];
};
// transform function for Flickr feeds
/**
* Transform function for Flickr feeds
* @name TimeMap.loaders.flickr#transform
* @function
* @parameter {Object} data Data to transform
* @return {Object} data Transformed data for one item
*/
loader.transform = function(data) {
var item = {
title: data["title"],
start: data["date_taken"],
title: data.title,
start: data.date_taken,
point: {
lat: data["latitude"],
lon: data["longitude"]
lat: data.latitude,
lon: data.longitude
},
options: {
description: data["description"]
description: data.description
.replace(/&gt;/g, ">")
.replace(/&lt;/g, "<")
.replace(/&quot;/g, '"')
}
};
if (options.transformFunction)
if (options.transformFunction) {
item = options.transformFunction(item);
}
return item;
};
return loader;
}
};

View File

@ -1,5 +1,5 @@
/*
* Timemap.js Copyright 2008 Nick Rabinowitz.
* Timemap.js Copyright 2010 Nick Rabinowitz.
* Licensed under the MIT License (see LICENSE.txt)
*/
@ -14,9 +14,9 @@
/**
* @class
* GeoRSS loader factory - inherits from remote loader.
* GeoRSS loader: Load GeoRSS feeds.
*
* <p>This is a loader class for GeoRSS feeds. Parsing is complicated by the
* <p> Parsing is complicated by the
* diversity of GeoRSS formats; this parser handles:</p>
* <ul>
* <li>RSS feeds</li>
@ -28,11 +28,16 @@
* <li>GML </li>
* <li>W3C Geo</li>
* </ul>
* <p>At the moment, this only supports points; polygons, polylines, and boxes
* will be added at some later point.</p>
* <p>At the moment, this only supports points, polygons, polylines; boxes
* may be added at some later point.</p>
*
* @example Usage in TimeMap.init():
* @augments TimeMap.loaders.xml
* @requires loaders/xml.js
* @requires param.js
* @borrows TimeMap.loaders.georss.parse as #parse
*
* @example
TimeMap.init({
datasets: [
{
title: "GeoRSS Dataset",
@ -41,35 +46,35 @@
url: "mydata.rss" // GeoRSS file to load - must be a local URL
}
}
]
],
// etc...
});
* @see <a href="../../examples/earthquake_georss.html">GeoRSS Example</a>
*
* @param {Object} options All options for the loader:<pre>
* {Array} url URL of GeoRSS file to load (NB: must be local address)
* {Function} preloadFunction Function to call on data before loading
* {Function} transformFunction Function to call on individual items before loading
* </pre>
* @return {TimeMap.loaders.remote} Remote loader configured for GeoRSS
* @param {Object} options All options for the loader:
* @param {String} options.url URL of GeoRSS file to load (NB: must be local address)
* @param {mixed} [options[...]] Other options (see {@link TimeMap.loaders.xml})
*/
TimeMap.loaders.georss = function(options) {
var loader = new TimeMap.loaders.remote(options);
var loader = new TimeMap.loaders.xml(options);
loader.parse = TimeMap.loaders.georss.parse;
return loader;
}
};
/**
* Static function to parse GeoRSS
*
* @param {XML text} rss GeoRSS to be parsed
* @return {TimeMapItem Array} Array of TimeMapItems
* @param {String} rss GeoRSS string to be parsed
* @return {TimeMapItem[]} Array of TimeMapItems
*/
TimeMap.loaders.georss.parse = function(rss) {
var items = [], data, node, placemarks, pm;
var items = [], data, node, placemarks, pm, i;
node = GXml.parse(rss);
// get TimeMap utilty functions
// assigning to variables should compress better
var util = TimeMap.util;
var getTagValue = util.getTagValue,
var util = TimeMap.util,
getTagValue = util.getTagValue,
getNodeList = util.getNodeList,
makePoint = util.makePoint,
makePoly = util.makePoly,
@ -88,7 +93,7 @@ TimeMap.loaders.georss.parse = function(rss) {
// look for placemarks
var tName = (feedType == 'rss' ? "item" : "entry");
placemarks = getNodeList(node, tName);
for (var i=0; i<placemarks.length; i++) {
for (i=0; i<placemarks.length; i++) {
pm = placemarks[i];
data = { options: {} };
// get title & description
@ -123,7 +128,8 @@ TimeMap.loaders.georss.parse = function(rss) {
}
}
// find placemark - single geometry only for the moment
PLACEMARK: {
var done = false;
PLACEMARK: while (!done) {
var coords, geom;
// look for point, GeoRSS-Simple
coords = getTagValue(pm, "point", 'georss');
@ -190,14 +196,15 @@ TimeMap.loaders.georss.parse = function(rss) {
}
// XXX: deal with boxes
done = true;
}
// look for any extra tags specified
this.parseExtra(data, pm);
items.push(data);
}
// clean up
node = null;
placemarks = null;
pm = null;
nList = null;
node = placemarks = pm = nList = null;
return items;
};

View File

@ -1,5 +1,5 @@
/*
* Timemap.js Copyright 2008 Nick Rabinowitz.
* Timemap.js Copyright 2010 Nick Rabinowitz.
* Licensed under the MIT License (see LICENSE.txt)
*/
@ -10,11 +10,14 @@
* @author Nick Rabinowitz (www.nickrabinowitz.com)
*/
// for JSLint
/*global TimeMap, TimeMapItem */
/**
* @class
* Google spreadsheet loader factory - inherits from jsonp loader.
* Google Spreadsheet loader.
*
* <p>This is a loader for data from Google Spreadsheets. Takes an optional map
* <p>This is a loader for data from Google Spreadsheets. The constructor takes an optional map
* to indicate which columns contain which data elements; the default column
* names (case-insensitive) are: title, description, start, end, lat, lon</p>
*
@ -26,13 +29,12 @@
* <p>The loader takes either a full URL, minus the JSONP callback function, or
* just the spreadsheet key. Note that the spreadsheet must be published.</p>
*
* <p>Depends on:</p>
* <ul>
* <li>loaders/jsonp.js</li>
* </ul>
* @augments TimeMap.loaders.jsonp
* @requires param.js
* @requires loaders/json.js
*
* @example Usage in TimeMap.init():
* @example
TimeMap.init({
datasets: [
{
title: "Google Spreadsheet by key",
@ -48,18 +50,28 @@
url: "http://spreadsheets.google.com/feeds/list/pjUcDAp-oNIOjmx3LCxT4XA/1/public/values?alt=json-in-script&callback="
}
}
]
],
// etc...
});
* @see <a href="../../examples/google_spreadsheet.html">Google Spreadsheet Example</a>
* @see <a href="../../examples/google_spreadsheet_columns.html">Google Spreadsheet Example, Arbitrary Columns</a>
*
* @param {Object} options All options for the loader:<pre>
* {String} key Key of spreadsheet to load, or
* {String} url Full JSONP url of spreadsheet to load
* {Function} preloadFunction Function to call on data before loading
* {Function} transformFunction Function to call on individual items before loading
* </pre>
* @return {TimeMap.loaders.remote} Remote loader configured for Google Spreadsheets
* @param {Object} options All options for the loader:
* @param {String} options.key Key of spreadsheet to load, or
* @param {String} options.url Full JSONP url of spreadsheet to load
* @param {Object} [options.paramMap] Map of paramName:columnName pairs for core parameters,
* if using non-standard column names; see keys in
* {@link TimeMap.loaders.base#params} for the standard param names
* @param {String[]} [options.extraColumns] Array of additional columns to load; all named columns will be
* loaded into the item.opts object.
* @param {mixed} [options[...]] Other options (see {@link TimeMap.loaders.jsonp})
*/
TimeMap.loaders.gss = function(options) {
var loader = new TimeMap.loaders.jsonp(options);
var loader = new TimeMap.loaders.jsonp(options),
params = loader.params, paramName, x,
setParamField = TimeMap.loaders.gss.setParamField,
paramMap = options.paramMap || {},
extraColumns = options.extraColumns || [];
// use key if no URL was supplied
if (!loader.url) {
@ -67,51 +79,75 @@ TimeMap.loaders.gss = function(options) {
options.key + "/1/public/values?alt=json-in-script&callback=";
}
// column map
loader.map = options.map;
// Set up additional columns
for (x=0; x < extraColumns.length; x++) {
paramName = extraColumns[x];
params[paramName] = new TimeMap.params.OptionParam(paramName);
}
// preload function for spreadsheet data
// Set up parameters to work with Google Spreadsheets
for (paramName in params) {
if (params.hasOwnProperty(paramName)) {
fieldName = paramMap[paramName] || paramName;
setParamField(params[paramName], fieldName);
}
}
/**
* Preload function for spreadsheet data
* @name TimeMap.loaders.gss#preload
* @function
* @parameter {Object} data Data to preload
* @return {Array} data Array of item data
*/
loader.preload = function(data) {
return data["feed"]["entry"];
return data.feed.entry;
};
// transform function for spreadsheet data
/**
* Transform function for spreadsheet data
* @name TimeMap.loaders.gss#transform
* @function
* @parameter {Object} data Data to transform
* @return {Object} data Transformed data for one item
*/
loader.transform = function(data) {
// map spreadsheet column ids to corresponding TimeMap elements
var fieldMap = loader.map || TimeMap.loaders.gss.map;
var getField = function(f) {
if (f in fieldMap && fieldMap[f]) {
return data['gsx$' + fieldMap[f]]['$t'];
} else return false;
};
var item = {
title: getField("title"),
start: getField("start"),
point: {
lat: getField("lat"),
lon: getField("lon")
},
options: {
description: getField("description")
var item = {}, params = loader.params, paramName,
transform = options.transformFunction;
// run through parameters, loading each
for (paramName in params) {
if (params.hasOwnProperty(paramName)) {
params[paramName].setConfigGSS(item, data);
}
};
}
// hook for further transformation
if (options.transformFunction)
item = options.transformFunction(item);
if (transform) {
item = transform(item);
}
return item;
};
return loader;
}
};
/**
* 1:1 map of expected spreadsheet column ids.
* Set a parameter to get its value from a given Google Spreadsheet field.
*
* @param {TimeMap.Param} param Param object
* @param {String} fieldName Name of the field
*/
TimeMap.loaders.gss.map = {
'title':'title',
'description':'description',
'start':'start',
'end':'end',
'lat':'lat',
'lon':'lon'
TimeMap.loaders.gss.setParamField = function(param, fieldName) {
// internal function: Get the value of a Google Spreadsheet field
var getField = function(data, fieldName) {
// get element, converting field name to GSS format
var el = data['gsx$' + fieldName.toLowerCase().replace(" ", "")];
if (el) {
return el.$t;
}
return null;
};
// set the method on the parameter
param.setConfigGSS = function(config, data) {
this.setConfig(config, getField(data, fieldName));
};
};

View File

@ -1,5 +1,5 @@
/*
* Timemap.js Copyright 2008 Nick Rabinowitz.
* Timemap.js Copyright 2010 Nick Rabinowitz.
* Licensed under the MIT License (see LICENSE.txt)
*/
@ -10,9 +10,12 @@
* @author Nick Rabinowitz (www.nickrabinowitz.com)
*/
// for JSLint
/*global TimeMap */
/**
* @class
* JSONP loader class - expects a service that takes a callback function name as
* JSONP loader - expects a service that takes a callback function name as
* the last URL parameter.
*
* <p>The jsonp loader assumes that the JSON can be loaded from a url to which a
@ -20,96 +23,66 @@
* The loader then appends a nonce function name which the JSON should include.
* This works for services like Google Spreadsheets, etc., and accepts remote URLs.</p>
*
* @example Usage in TimeMap.init():
* @augments TimeMap.loaders.remote
*
* @example
TimeMap.init({
datasets: [
{
title: "JSONP Dataset",
type: "jsonp",
options: {
url: "http://www.test.com/getsomejson.php?callback="
url: "http://www.example.com/getsomejson.php?callback="
}
}
]
],
// etc...
});
*
* @constructor
* @param {Object} options All options for the loader:<pre>
* {Array} url URL of JSON service to load, callback name left off
* {Function} preloadFunction Function to call on data before loading
* {Function} transformFunction Function to call on individual items before loading
* </pre>
* @param {Object} options All options for the loader:
* @param {String} options.url URL of JSON service to load, callback name left off
* @param {mixed} [options[...]] Other options (see {@link TimeMap.loaders.remote})
*/
TimeMap.loaders.jsonp = function(options) {
// get standard functions
TimeMap.loaders.mixin(this, options);
// get URL to load
this.url = options.url;
}
var loader = new TimeMap.loaders.remote(options);
/**
* JSONP load function.
*
* @param {TimeMapDataset} dataset Dataset to load data into
* @param {Function} callback Function to call once data is loaded
*/
TimeMap.loaders.jsonp.prototype.load = function(dataset, callback) {
var loader = this;
// get items
TimeMap.loaders.jsonp.read(this.url, function(result) {
// load
items = loader.preload(result);
dataset.loadItems(items, loader.transform);
// callback
callback();
});
}
/**
* Static - for naming anonymous callback functions
* @type int
*/
TimeMap.loaders.jsonp.counter = 0;
/**
* Static - reads JSON from a URL, assuming that the service is set up to apply
* a callback function specified in the URL parameters.
*
* @param {String} jsonUrl URL to load, missing the callback function name
* @param {function} f Callback function to apply to returned data
*/
TimeMap.loaders.jsonp.read = function(url, f) {
// Define a unique function name
var callbackName = "_" + TimeMap.loaders.jsonp.counter++;
TimeMap.loaders.jsonp[callbackName] = function(result) {
// Pass result to user function
f(result);
// Delete the callback function
delete TimeMap.loaders.jsonp[callbackName];
/**
* JSONP load function. Creates a callback function and adds a script tag
* with the appropriate URL to the document, triggering the HTTP request.
* @name TimeMap.loaders.jsonp#load
* @function
*
* @param {TimeMapDataset} dataset Dataset to load data into
* @param {Function} callback Function to call once data is loaded
*/
loader.load = function(dataset, callback) {
// get loader callback name
var callbackName = this.getCallbackName(dataset, callback),
// create a script tag
script = document.createElement("script");
// set the src attribute and add to the document
script.src = this.url + "TimeMap.loaders.cb." + callbackName;
document.body.appendChild(script);
};
// Create a script tag, set its src attribute and add it to the document
// This triggers the HTTP request and submits the query
var script = document.createElement("script");
script.src = url + "TimeMap.loaders.jsonp." + callbackName;
document.body.appendChild(script);
return loader;
};
/**
* @class
* JSON string loader factory - expects a plain JSON array.
* Inherits from remote loader.
*
* <p>The json_string loader assumes an array of items in plain JSON, with no
* callback function - this will require a local URL.</p>
* <p>Note that this loader requires lib/json2.pack.js.</p>
*
* <p>Depends on:</p>
* <ul>
* <li>lib/json2.pack.js</li>
* </ul>
* @augments TimeMap.loaders.remote
*
* @example Usage in TimeMap.init():
* @requires lib/json2.pack.js
*
* @example
TimeMap.init({
datasets: [
{
title: "JSON String Dataset",
@ -118,20 +91,28 @@ TimeMap.loaders.jsonp.read = function(url, f) {
url: "mydata.json" // Must be a local URL
}
}
]
],
// etc...
});
*
* @param {Object} options All options for the loader:<pre>
* {Array} url URL of JSON service to load, callback name left off
* {Function} preloadFunction Function to call on data before loading
* {Function} transformFunction Function to call on individual items before loading
* </pre>
* @return {TimeMap.loaders.remote} Remote loader configured for JSON strings
* @param {Object} options All options for the loader
* @param {String} options.url URL of JSON file to load
* @param {mixed} [options[...]] Other options (see {@link TimeMap.loaders.remote})
*/
TimeMap.loaders.json_string = function(options) {
var loader = new TimeMap.loaders.remote(options);
/**
* Parse a JSON string into a JavaScript object, using the json2.js library.
* @name TimeMap.loaders.json_string#parse
* @function
* @param {String} json JSON string to parse
* @returns {Object} Parsed JavaScript object
*/
loader.parse = JSON.parse;
return loader;
}
};
// Probably the default json loader should be json_string, not
// jsonp. I may change this in the future, so I'd encourage you to use

View File

@ -1,5 +1,5 @@
/*
* Timemap.js Copyright 2008 Nick Rabinowitz.
* Timemap.js Copyright 2010 Nick Rabinowitz.
* Licensed under the MIT License (see LICENSE.txt)
*/
@ -14,13 +14,21 @@
/**
* @class
* KML loader factory - inherits from remote loader
* KML loader: load KML files.
*
* <p>This is a loader class for KML files. Currently supports all geometry
* types (point, polyline, polygon, and overlay) and multiple geometries.</p>
* types (point, polyline, polygon, and overlay) and multiple geometries. Supports loading
* <a href="http://code.google.com/apis/kml/documentation/extendeddata.html">ExtendedData</a>
* through the extendedData parameter.
* </p>
*
* @example Usage in TimeMap.init():
* @augments TimeMap.loaders.xml
* @requires loaders/xml.js
* @requires param.js
* @borrows TimeMap.loaders.kml.parse as #parse
*
* @example
TimeMap.init({
datasets: [
{
title: "KML Dataset",
@ -29,20 +37,36 @@
url: "mydata.kml" // Must be local
}
}
]
],
// etc...
});
* @see <a href="../../examples/kenya.html">KML Example</a>
* @see <a href="../../examples/kml_extendeddata.html">KML ExtendedData Example</a>
*
* @param {Object} options All options for the loader:<pre>
* {Array} url URL of KML file to load (NB: must be local address)
* {Function} preloadFunction Function to call on data before loading
* {Function} transformFunction Function to call on individual items before loading
* </pre>
* @return {TimeMap.loaders.remote} Remote loader configured for KML
* @param {Object} options All options for the loader
* @param {String} options.url URL of KML file to load (NB: must be local address)
* @param {String[]} [options.extendedData] Array of names for ExtendedData data elements
* @param {mixed} [options[...]] Other options (see {@link TimeMap.loaders.xml})
* @return {TimeMap.loaders.xml} Loader configured for KML
*/
TimeMap.loaders.kml = function(options) {
var loader = new TimeMap.loaders.remote(options);
var loader = new TimeMap.loaders.xml(options),
tagMap = options.tagMap || {},
extendedData = options.extendedData || [],
tagName, x;
// Add ExtendedData parameters to extra params
for (x=0; x < extendedData.length; x++) {
tagName = extendedData[x];
loader.extraParams.push(
new TimeMap.params.ExtendedDataParam(tagMap[tagName] || tagName, tagName)
);
}
// set custom parser
loader.parse = TimeMap.loaders.kml.parse;
return loader;
}
};
/**
* Static function to parse KML with time data.
@ -56,8 +80,8 @@ TimeMap.loaders.kml.parse = function(kml) {
// get TimeMap utilty functions
// assigning to variables should compress better
var util = TimeMap.util;
var getTagValue = util.getTagValue,
var util = TimeMap.util,
getTagValue = util.getTagValue,
getNodeList = util.getNodeList,
makePoint = util.makePoint,
makePoly = util.makePoly,
@ -134,6 +158,9 @@ TimeMap.loaders.kml.parse = function(kml) {
// XXX: worth closing unclosed polygons?
data.placemarks.push(pmobj);
}
// look for any extra tags and/or ExtendedData specified
this.parseExtra(data, pm);
items.push(data);
}
@ -156,13 +183,51 @@ TimeMap.loaders.kml.parse = function(kml) {
data.overlay.south = getTagValue(nList[0], "south");
data.overlay.east = getTagValue(nList[0], "east");
data.overlay.west = getTagValue(nList[0], "west");
// look for any extra tags and/or ExtendedData specified
this.parseExtra(data, pm);
items.push(data);
}
// clean up
kmlnode = null;
placemarks = null;
pm = null;
nList = null;
kmlnode = placemarks = pm = nList = null;
return items;
};
/**
* @class
* Class for parameters loaded from KML ExtendedData elements
*
* @augments TimeMap.params.OptionParam
*
* @constructor
* @param {String} paramName String name of the parameter
* @param {String} [tagName] Tag name, if different
*/
TimeMap.params.ExtendedDataParam = function(paramName, tagName) {
return new TimeMap.params.OptionParam(paramName, {
/**
* Set a config object based on an ExtendedData element
* @name TimeMap.params.ExtendedDataParam#setConfigKML
* @function
*
* @param {Object} config Config object to modify
* @param {XML NodeList} node Parent node to look for tags in
*/
setConfigXML: function(config, node) {
var util = TimeMap.util,
nList = util.getNodeList(node, "Data"),
i;
for (i=0; i<nList.length; i++) {
if (nList[i].getAttribute("name") == tagName) {
this.setConfig(config, util.getTagValue(nList[i], "value"))
}
}
node = nList = null;
},
sourceName: tagName
});
};

View File

@ -1,5 +1,5 @@
/*
* Timemap.js Copyright 2008 Nick Rabinowitz.
* Timemap.js Copyright 2010 Nick Rabinowitz.
* Licensed under the MIT License (see LICENSE.txt)
*/
@ -10,28 +10,24 @@
* @author Nick Rabinowitz (www.nickrabinowitz.com)
*/
/*----------------------------------------------------------------------------
* Loader
*
*/
// for JSLint
/*global TimeMap */
/**
* @class
* Metaweb loader factory - inherits from jsonp loader
* Metaweb loader: Load data from freebase.com.
*
* <p>This is a loader for data from the Metaweb service at freebase.com. See
* the API documentation at <a href="http://www.freebase.com/view/en/documentation">http://www.freebase.com/view/en/documentation</a> for
* the API documentation at <a href="http://www.freebase.com/docs/mql/ch01.html">http://www.freebase.com/docs/mql/ch01.html</a> for
* a description of how to write MQL queries. This code is based on code from
* the API site.</p>
*
* <p>Depends on:</p>
* <ul>
* <li>lib/json2.pack.js</li>
* <li>loaders/jsonp.js</li>
* </ul>
* @augments TimeMap.loaders.jsonp
* @requires lib/json2.pack.js
* @requires loaders/jsonp.js
*
* @example Usage in TimeMap.init():
* @example
TimeMap.init({
datasets: [
{
title: "Freebase Dataset",
@ -49,28 +45,56 @@
}
}
}
]
],
// etc...
});
* @see <a href="../../examples/artists.html">Metaweb Example</a>
*
* @param {Object} options All options for the loader:<pre>
* {Object} query MQL query to load
* {Function} preloadFunction Function to call on data before loading
* {Function} transformFunction Function to call on individual items before loading
* </pre>
* @return {TimeMap.loaders.remote} Remote loader configured for MetaWeb
* @param {Object} options All options for the loader
* @param {Object} options.query MQL query to load
* @param {Function} options.transformFunction Function to call on individual items before loading
* @param {String} [options.host=http://www.freebase.com] Host url of web service
* @param {String} [options.service=/api/service/mqlread] Path to web service on host
* @param {mixed} [options[...]] Other options (see {@link TimeMap.loaders.jsonp})
*/
TimeMap.loaders.metaweb = function(options) {
var loader = new TimeMap.loaders.jsonp(options);
var loader = new TimeMap.loaders.jsonp(options),
q = options.query || {},
// format the query URL for Metaweb
querytext = encodeURIComponent(JSON.stringify({qname: {query: q}}));
// Host and service - default to freebase.com
/**
* Host url - default to freebase.com
* @name TimeMap.loaders.metaweb#HOST
* @type {String}
*/
loader.HOST = options.host || "http://www.freebase.com";
/**
* Service path - default to freebase.com default
* @name TimeMap.loaders.metaweb#QUERY_SERVICE
* @type {String}
*/
loader.QUERY_SERVICE = options.service || "/api/service/mqlread";
// Metaweb preload functon
/**
* URL built using encoded query text and the callback name
* @name TimeMap.loaders.metaweb#url
* @type {String}
*/
loader.url = loader.HOST + loader.QUERY_SERVICE + "?queries=" + querytext + "&callback=";
/**
* Preload function for Metaweb
* @name TimeMap.loaders.metaweb#preload
* @function
* @parameter {Object} data Data to preload
* @return {Array} data Array of item data
*/
loader.preload = function(data) {
// Open outer envelope
var innerEnvelope = data.qname;
// Make sure the query was successful
if (innerEnvelope.code.indexOf("/api/status/ok") != 0) {
if (innerEnvelope.code.indexOf("/api/status/ok") !== 0) {
// uncomment for debugging
/*
// If error, get error message and throw
@ -80,16 +104,8 @@ TimeMap.loaders.metaweb = function(options) {
return [];
}
// Get result from inner envelope
var result = innerEnvelope.result;
return result;
return innerEnvelope.result;
};
// format the query URL for Metaweb
var q = options.query || {};
var querytext = encodeURIComponent(JSON.stringify({qname: {query: q}}));
// Build the URL using encoded query text and the callback name
loader.url = loader.HOST + loader.QUERY_SERVICE + "?queries=" + querytext + "&callback=";
return loader;
}
};

View File

@ -0,0 +1,197 @@
/*
* Timemap.js Copyright 2010 Nick Rabinowitz.
* Licensed under the MIT License (see LICENSE.txt)
*/
/**
* @fileOverview
* Progressive loader
*
* @author Nick Rabinowitz (www.nickrabinowitz.com)
*/
// for JSLint
/*global TimeMap */
/**
* @class
* Progressive loader class - basically a wrapper for another remote loader that can
* load data progressively by date range, depending on timeline position.
*
* <p>The progressive loader can take either another loader or parameters for
* another loader. It expects a loader with a "url" attribute including placeholder
* strings [start] and [end] for the start and end dates to retrieve. The assumption
* is that the data service can take start and end parameters and return the data for
* that date range.</p>
*
* @example
TimeMap.init({
datasets: [
{
title: "Progressive JSONP Dataset",
type: "progressive",
options: {
type: "jsonp",
url: "http://www.test.com/getsomejson.php?start=[start]&end=[end]callback="
}
}
],
// etc...
});
*
* @example
TimeMap.init({
datasets: [
{
title: "Progressive KML Dataset",
type: "progressive",
options: {
loader: new TimeMap.loaders.kml({
url: "/mydata.kml?start=[start]&end=[end]"
})
}
}
],
// etc...
});
* @see <a href="../../examples/progressive.html">Progressive Loader Example</a>
*
* @constructor
* @param {Object} options All options for the loader
* @param {TimeMap.loaders.remote} [options.loader] Instantiated loader class (overrides "type")
* @param {String} [options.type] Name of loader class to use
* @param {String|Date} options.start Start of initial date range, as date or string
* @param {Number} options.interval Size in milliseconds of date ranges to load at a time
* @param {String|Date} [options.dataMinDate] Minimum date available in data (optional, will avoid
* unnecessary service requests if supplied)
* @param {String|Date} [options.dataMaxDate] Maximum date available in data (optional, will avoid
* unnecessary service requests if supplied)
* @param {Function} [options.formatUrl] Function taking (urlTemplate, start, end) and returning
* a URL formatted as needed by the service
* @param {Function} [options.formatDate={@link TimeMap.util.formatDate}]
* Function to turn a date into a string formatted
* as needed by the service
* @param {mixed} [options[...]] Other options needed by the "type" loader
*/
TimeMap.loaders.progressive = function(options) {
// get loader
var loader = options.loader,
type = options.type;
if (!loader) {
// get loader class
var loaderClass = (typeof(type) == 'string') ? TimeMap.loaders[type] : type;
loader = new loaderClass(options);
}
// quick string/date check
function cleanDate(d) {
if (typeof(d) == "string") {
d = TimeMapDataset.hybridParser(d);
}
return d;
}
// save loader attributes
var baseUrl = loader.url,
baseLoadFunction = loader.load,
interval = options.interval,
formatDate = options.formatDate || TimeMap.util.formatDate,
formatUrl = options.formatUrl,
zeroDate = cleanDate(options.start),
dataMinDate = cleanDate(options.dataMinDate),
dataMaxDate = cleanDate(options.dataMaxDate),
loaded = {};
if (!formatUrl) {
formatUrl = function(url, start, end) {
return url
.replace('[start]', formatDate(start))
.replace('[end]', formatDate(end));
}
}
// We don't start with a TimeMap reference, so we need
// to stick the listener in on the first load() call
var addListener = function(dataset) {
var band = dataset.timemap.timeline.getBand(0);
// add listener
band.addOnScrollListener(function() {
// determine relevant blocks
var now = band.getCenterVisibleDate(),
currBlock = Math.floor((now.getTime() - zeroDate.getTime()) / interval),
currBlockTime = zeroDate.getTime() + (interval * currBlock)
nextBlockTime = currBlockTime + interval,
prevBlockTime = currBlockTime - interval,
// no callback necessary?
callback = function() {
dataset.timemap.timeline.layout();
};
// is the current block loaded?
if ((!dataMaxDate || currBlockTime < dataMaxDate.getTime()) &&
(!dataMinDate || currBlockTime > dataMinDate.getTime()) &&
!loaded[currBlock]) {
// load it
// console.log("loading current block (" + currBlock + ")");
loader.load(dataset, callback, new Date(currBlockTime), currBlock);
}
// are we close enough to load the next block, and is it loaded?
if (nextBlockTime < band.getMaxDate().getTime() &&
(!dataMaxDate || nextBlockTime < dataMaxDate.getTime()) &&
!loaded[currBlock + 1]) {
// load next block
// console.log("loading next block (" + (currBlock + 1) + ")");
loader.load(dataset, callback, new Date(nextBlockTime), currBlock + 1);
}
// are we close enough to load the previous block, and is it loaded?
if (prevBlockTime > band.getMinDate().getTime() &&
(!dataMinDate || prevBlockTime > dataMinDate.getTime()) &&
!loaded[currBlock - 1]) {
// load previous block
// console.log("loading prev block (" + (currBlock - 1) + ")");
loader.load(dataset, callback, new Date(prevBlockTime), currBlock - 1);
}
});
// kill this function so that listener is only added once
addListener = false;
};
/**
* Load data based on current time
* @name TimeMap.loaders.progressive#load
* @function
* @param {TimeMapDataset} dataset Dataset to load data into
* @param {Function} callback Callback to execute when data is loaded
* @param {Date} start Start date to load data from
* @param {Number} currBlock Index of the current time block
*/
loader.load = function(dataset, callback, start, currBlock) {
// set start date, defaulting to zero date
start = cleanDate(start) || zeroDate;
// set current block, defaulting to 0
currBlock = currBlock || 0;
// set end by interval
var end = new Date(start.getTime() + interval);
// set current block as loaded
// XXX: Failed loads will give a false positive here...
// but I'm not sure how else to avoid multiple loads :(
loaded[currBlock] = true;
// put dates into URL
loader.url = formatUrl(baseUrl, start, end);
// console.log(loader.url);
// load data
baseLoadFunction.call(loader, dataset, function() {
// add onscroll listener if not yet done
if (addListener) {
addListener(dataset);
}
// run callback
callback();
});
};
return loader;
};

View File

@ -0,0 +1,71 @@
/*
* Timemap.js Copyright 2010 Nick Rabinowitz.
* Licensed under the MIT License (see LICENSE.txt)
*/
/**
* @fileOverview
* XML Loader
*
* @author Nick Rabinowitz (www.nickrabinowitz.com)
*/
/*globals TimeMap */
/**
* @class
* This is a base loader class for XML files.
*
* @augments TimeMap.loaders.remote
* @requires param.js
*
* @param {Object} options All options for the loader
* @param {String} options.url URL of XML file to load (NB: must be local address)
* @parem {String[]} [options.extraTags] Array of names for extra tag elements to load
* @param {Object} [options.tagMap] Map of tagName:paramName pairs, if you want to load
* data into a differently-named elements
* @param {mixed} [options[...]] Other options (see {@link TimeMap.loaders.remote})
* @return {TimeMap.loaders.remote} Remote loader configured for XML
*/
TimeMap.loaders.xml = function(options) {
var loader = new TimeMap.loaders.remote(options),
tagMap = options.tagMap || {},
extraTags = options.extraTags || [],
params = loader.params,
paramName, tagName, x;
/**
* Additional parameters to load
* @name TimeMap.loaders.xml#extraParams
* @type TimeMap.params.OptionParam[]
*/
loader.extraParams = [];
// set up extra params
for (x=0; x < extraTags.length; x++) {
tagName = extraTags[x];
loader.extraParams.push(
new TimeMap.params.OptionParam(tagMap[tagName] || tagName, {
sourceName: tagName
})
);
}
/**
* Parse any extra tags that have been specified into the config object
* @name TimeMap.loaders.xml#parseExtra
* @function
*
* @param {Object} config Config object to modify
* @param {XML NodeList} node Parent node to look for tags in
*/
loader.parseExtra = function(config, node) {
var extraParams = loader.extraParams, x;
for (x=0; x<extraParams.length; x++) {
extraParams[x].setConfigXML(config, node);
}
node = null;
};
return loader;
};

274
htdocs/js/timemap/param.js Normal file
View File

@ -0,0 +1,274 @@
/*
* Timemap.js Copyright 2010 Nick Rabinowitz.
* Licensed under the MIT License (see LICENSE.txt)
*/
/**
* @fileOverview
* This file defines the Param class, which is used to get, set, and serialize
* different fields on TimeMap and TimeMapItem objects.
*
* @author Nick Rabinowitz (www.nickrabinowitz.com)
*/
// save a few bytes
(function() {
/**
* @name TimeMap.params
* @namespace Namespace for parameter classes
*/
var params = TimeMap.params = {
/**
* @class
* A parameter, with methods to get, set, and serialize the current value.
*
* @constructor
* @param {String} paramName String name of the parameter
* @param {Object} options Container for named arguments
* @param {String} [sourceName] String name of the source element, if different
* @param {Function} [options.get] Function to get the current param value
* @param {Function} [options.set] Function to set the param to a new value
* @param {Function} [options.setConfig] Function to set a new value in a config object
* @param {Function} [options.fromStr] Function to parse the value from a string
* @param {Function} [options.toStr] Function to serialize the current value to a string
* @param {Function} [options.setConfigXML] Function to parse the value from an XML node and set to config
*/
Param: function(paramName, options) {
var param = this,
options = options || {};
/**
* String name of this param
* @name TimeMap.params.Param#paramName
* @type String
*/
param.paramName = paramName;
/**
* String name of the source element, if different
* @name TimeMap.params.Param#sourceName
*/
param.sourceName = options.sourceName || paramName;
/**
* Get the current state value from a TimeMap or TimeMapItem object
* @name TimeMap.params.Param#get
* @function
*
* @param {TimeMap|TimeMapItem} o Object to inspect
* @return {mixed} Current state value
*/
param.get = options.get;
/**
* Set the current state value on a TimeMap or TimeMapItem object
* @name TimeMap.params.Param#set
* @function
*
* @param {TimeMap|TimeMapItem} o Object to modify
* @param {mixed} value Value to set
*/
param.set = options.set;
/**
* Set a new value on a config object for TimeMap.init()
* @name TimeMap.params.Param#setConfig
* @function
* @see TimeMap.init
*
* @param {Object} config Config object to modify
* @param {mixed} value Value to set
*/
param.setConfig = options.setConfig || function(config, value) {
// default: set at top level
config[paramName] = value;
};
/**
* Parse a state value from a string
* @name TimeMap.params.Param#fromString
* @function
*
* @param {String} s String to parse
* @return {mixed} Current state value
*/
param.fromString = options.fromStr || function(s) {
// default: param is a string
return s;
};
/**
* Serialize a state value as a string
* @name TimeMap.params.Param#toString
* @function
*
* @param {mixed} value Value to serialize
* @return {String} Serialized string
*/
param.toString = options.toStr || function(value) {
// default: use the built-in string method
return value.toString();
};
/**
* Get the current value as a string
* @name TimeMap.params.Param#getString
* @function
*
* @param {TimeMap|TimeMapItem} o Object to inspect
*/
param.getString = function(o) {
param.toString(param.get(o));
};
/**
* Set the current state value from a string
* @name TimeMap.params.Param#setString
* @function
*
* @param {TimeMap|TimeMapItem} o Object to modify
* @param {String} s String version of value to set
*/
param.setString = function(o, s) {
param.set(o, param.fromString(s));
};
/**
* Set a config object based on an XML tag
* @name TimeMap.params.Param#setConfigXML
* @function
*
* @param {Object} config Config object to modify
* @param {XML NodeList} node Parent node of the desired tag
*/
param.setConfigXML = options.setConfigXML || function(config, node) {
var tagName = param.sourceName,
nameParts = tagName.split(':'),
ns;
// deal with namespaced tags
if (nameParts.length > 1) {
tagName = nameParts[1];
ns = nameParts[0];
}
// set to config
param.setConfig(config, TimeMap.util.getTagValue(node, tagName, ns));
};
},
/**
* @class
* A convenience class for those parameters which deal with a value
* in the options of a TimeMap or TimeMapItem object, setting some
* additional default functions.
*
* @augments TimeMap.params.Param
*
* @constructor
* @param {String} paramName String name of the option parameter
* @param {Object} [options] Container for named arguments (see {@link TimeMap.params.Param})
*/
OptionParam: function(paramName, options) {
options = options || {};
var defaults = {
/**
* Get the current state value from the opts object of a TimeMap or TimeMapItem
* @name TimeMap.params.OptionParam#get
* @function
*
* @param {TimeMap|TimeMapItem} o Object to inspect
* @return {mixed} Current state value
*/
get: function(o) {
return o.opts[paramName];
},
/**
* Set the state value in the opts object of a TimeMap or TimeMapItem
* @name TimeMap.params.OptionParam#set
*
* @param {TimeMap|TimeMapItem} o Object to modify
* @param {mixed} value Value to set
*/
set: function(o, value) {
o.opts[paramName] = value;
},
/**
* Set a new value on a config object for TimeMap.init() or a particular item
* @name TimeMap.params.OptionParam#setConfig
* @function
*
* @param {Object} config Config object to modify
* @param {mixed} value Value to set
*/
setConfig: function(config, value) {
config.options = config.options || {};
config.options[paramName] = value;
}
};
options = TimeMap.util.merge(options, defaults);
return new params.Param(paramName, options);
}
};
/*----------------------------------------------------------------------------
* TimeMapItem params
*---------------------------------------------------------------------------*/
/**
* @namespace Namespace for parameters used for loading data into a TimeMapItem
* object. Because these are intended for loading, only setConfig is defined.
*/
TimeMap.loaders.base.prototype.params = {
/**
* Item title
* @type TimeMap.params.Param
*/
title: new params.Param("title"),
/**
* Item start date
* @type TimeMap.params.Param
*/
start: new params.Param("start"),
/**
* Item end date
* @type TimeMap.params.Param
*/
end: new params.Param("end"),
/**
* Item description
* @type TimeMap.params.OptionParam
*/
description: new params.OptionParam("description"),
/**
* Item latitude
* @type TimeMap.params.Param
*/
lat: new params.Param("lat", {
setConfig: function(config, value) {
config.point = config.point || {};
config.point.lat = value;
}
}),
/**
* Item longitude
* @type TimeMap.params.Param
*/
lon: new params.Param("lon", {
setConfig: function(config, value) {
config.point = config.point || {};
config.point.lon = value;
}
})
};
})();

314
htdocs/js/timemap/state.js Normal file
View File

@ -0,0 +1,314 @@
/*
* Timemap.js Copyright 2010 Nick Rabinowitz.
* Licensed under the MIT License (see LICENSE.txt)
*/
/**
* @fileOverview
* Functions in this file are used to set the timemap state programmatically,
* either in a script or from the url hash.
*
* @requires param.js
*
* @author Nick Rabinowitz (www.nickrabinowitz.com)
*/
// save a few bytes
(function() {
/*----------------------------------------------------------------------------
* State namespace, with setters, serializers, and url functions
*---------------------------------------------------------------------------*/
var paramNS = TimeMap.params,
/**
* @name TimeMap.state
* @namespace Namespace for static state functions used to
* set the timemap state programmatically, either in a script or
* from the url hash.
* @see <a href="../../examples/state.html#zoom=8&center=44.04811573082351,13.29345703125&date=1500-01-21T12:17:37Z&selected=0">State Example</a>
*/
stateNS = TimeMap.state = {
/**
* Get the state parameters from the URL, returning as a config object
*
* @return {Object} Object with state config settings
*/
fromUrl: function() {
var pairs = location.hash.substring(1).split('&'),
params = stateNS.params,
state = {}, x, pair, key;
for (x=0; x < pairs.length; x++) {
if (pairs[x] != "") {
pair = pairs[x].split('=');
key = pair[0];
if (key && key in params) {
state[key] = params[key].fromString(decodeURI(pair[1]));
}
}
}
return state;
},
/**
* Make a parameter string from a state object
*
* @param {Object} state Object with state config settings
* @return {String} Parameter string in URL param format
*/
toParamString: function(state) {
var params = stateNS.params,
paramArray = [],
key;
// go through each key in state
for (key in state) {
if (state.hasOwnProperty(key)) {
if (key in params) {
paramArray.push(key + "=" + encodeURI(params[key].toString(state[key])));
}
}
}
return paramArray.join("&");
},
/**
* Make a full URL from a state object
*
* @param {Object} state Object with state config settings
* @return {String} Full URL with parameters
*/
toUrl: function(state) {
var paramString = stateNS.toParamString(state),
url = location.href.split("#")[0];
return url + "#" + paramString;
},
/**
* Set state settings on a config object for TimeMap.init()
* @see TimeMap.init
*
* @param {Object} config Config object for TimeMap.init(), modified in place
* @param {Object} state Object with state config settings
*/
setConfig: function(config, state) {
var params = stateNS.params,
key;
for (key in state) {
if (state.hasOwnProperty(key)) {
if (key in params) {
params[key].setConfig(config, state[key]);
}
}
}
},
/**
* Set state settings on a config object for TimeMap.init() using
* parameters in the URL. Note that as of Timemap.js v.1.6, this
* will run automatically if state functions are present.
* @see TimeMap.init
* @example
// set up the config object
var config = {
// various settings, as usual for TimeMap.init()
};
// get state settings from the URL, e.g.:
// http://www.example.com/mytimemap.html#zoom=4&selected=1
TimeMap.state.setConfigFromUrl(config);
// initialize TimeMap object
var tm = TimeMap.init(config);
*
* @param {Object} config Config object for TimeMap.init()
*/
setConfigFromUrl: function(config) {
stateNS.setConfig(config, stateNS.fromUrl());
}
};
/*----------------------------------------------------------------------------
* TimeMap object methods
*---------------------------------------------------------------------------*/
/**
* Set the timemap state with a set of configuration options.
*
* @param {Object} state Object with state config settings
*/
TimeMap.prototype.setState = function(state) {
var params = stateNS.params,
key;
// go through each key in state
for (key in state) {
if (state.hasOwnProperty(key)) {
if (key in params) {
// run setter function with config value
params[key].set(this, state[key]);
}
}
}
};
/**
* Get a configuration object of state variables
*
* @return {Object} Object with state config settings
*/
TimeMap.prototype.getState = function() {
var state = {},
params = stateNS.params,
key;
// run through params, adding values to state
for (key in params) {
if (params.hasOwnProperty(key)) {
// get state value
state[key] = params[key].get(this);
}
}
return state;
};
/**
* Initialize state tracking based on URL.
* Note: continuous tracking will only work
* on browsers that support the "onhashchange" event.
*/
TimeMap.prototype.initState = function() {
var tm = this;
tm.setStateFromUrl();
window.onhashchange = function() {
tm.setStateFromUrl();
};
};
/**
* Set the timemap state with parameters in the URL
*/
TimeMap.prototype.setStateFromUrl = function() {
this.setState(stateNS.fromUrl());
};
/**
* Get current state parameters serialized as a hash string
*
* @return {String} State parameters serialized as a hash string
*/
TimeMap.prototype.getStateParamString = function() {
return stateNS.toParamString(this.getState());
};
/**
* Get URL with current state parameters in hash
*
* @return {String} URL with state parameters
*/
TimeMap.prototype.getStateUrl = function() {
return stateNS.toUrl(this.getState());
};
/*----------------------------------------------------------------------------
* State parameters
*---------------------------------------------------------------------------*/
/**
* @namespace
* Namespace for state parameters, each with a set of functions to set and serialize values.
* Add your own Param objects to this namespace to get and set additional state variables.
*/
TimeMap.state.params = {
/**
* Map zoom level
* @type TimeMap.params.Param
*/
zoom: new paramNS.OptionParam("mapZoom", {
get: function(tm) {
return tm.map.getZoom();
},
set: function(tm, value) {
tm.map.setZoom(value);
},
fromStr: function(s) {
return parseInt(s);
}
}),
/**
* Map center
* @type TimeMap.params.Param
*/
center: new paramNS.OptionParam("mapCenter", {
get: function(tm) {
return tm.map.getCenter();
},
set: function(tm, value) {
tm.map.setCenter(value);
},
fromStr: function(s) {
var params = s.split(",");
if (params.length < 2) {
// give up
return null;
}
return new GLatLng(
parseFloat(params[0]),
parseFloat(params[1])
);
},
toStr: function(value) {
return value.lat() + "," + value.lng();
}
}),
/**
* Timeline center date
* @type TimeMap.params.Param
*/
date: new paramNS.Param("scrollTo", {
get: function(tm) {
return tm.timeline.getBand(0).getCenterVisibleDate();
},
set: function(tm, value) {
tm.scrollToDate(value);
},
fromStr: function(s) {
return TimeMapDataset.hybridParser(s);
},
toStr: function(value) {
return TimeMap.util.formatDate(value);
}
}),
/**
* Index of selected/open item, if any
* @type TimeMap.params.Param
*/
selected: new paramNS.Param("selected", {
get: function(tm) {
var items = tm.getItems(),
i = items.length-1;
while (i >= 0 && i--) {
if (items[i].selected) break;
}
return i;
},
set: function(tm, value) {
if (value >= 0) {
var item = tm.getItems()[value];
if (item) {
item.openInfoWindow();
}
}
},
fromStr: function(s) {
return parseInt(s);
}
})
};
})();

File diff suppressed because it is too large Load Diff