diff d3s_examples/python-neo4jrestclient/static/platin/js/GeoTemConfig_DW.js @ 8:18ef6948d689

new d3s examples
author Dirk Wintergruen <dwinter@mpiwg-berlin.mpg.de>
date Thu, 01 Oct 2015 17:17:27 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/d3s_examples/python-neo4jrestclient/static/platin/js/GeoTemConfig_DW.js	Thu Oct 01 17:17:27 2015 +0200
@@ -0,0 +1,1272 @@
+/*
+* GeoTemConfig.js
+*
+* Copyright (c) 2012, Stefan Jänicke. All rights reserved.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+* MA 02110-1301  USA
+*/
+
+/**
+ * @class GeoTemConfig
+ * Global GeoTemCo Configuration File
+ * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
+ * @release 1.0
+ * @release date: 2012-07-27
+ * @version date: 2012-07-27
+ */
+
+
+// credits: user76888, The Digital Gabeg (http://stackoverflow.com/questions/1539367)
+$.fn.cleanWhitespace = function() {
+	textNodes = this.contents().filter(	function() { 
+		return (this.nodeType == 3 && !/\S/.test(this.nodeValue)); 
+	}).remove();
+	return this;
+};
+
+GeoTemConfig = {
+	debug : false, //show debug output (esp. regarding corrupt datasets)
+	incompleteData : true, // show/hide data with either temporal or spatial metadata
+	inverseFilter : true, // if inverse filtering is offered
+	mouseWheelZoom : true, // enable/disable zoom with mouse wheel on map & timeplot
+	language : 'en', // default language of GeoTemCo
+	allowFilter : true, // if filtering should be allowed
+	highlightEvents : true, // if updates after highlight events
+	selectionEvents : true, // if updates after selection events
+	tableExportDataset : true, // export dataset to KML 
+	allowCustomColoring : false, // if DataObjects can have an own color (useful for weighted coloring)
+	allowUserShapeAndColorChange: false, // if the user can change the shapes and color of datasets 
+										// this turns MapConfig.useGraphics auto-on, but uses circles as default
+	loadColorFromDataset : false, // if DataObject color should be loaded automatically (from column "color")
+	allowColumnRenaming : true,
+	//proxy : 'php/proxy.php?address=', //set this if a HTTP proxy shall be used (e.g. to bypass X-Domain problems)
+	//colors for several datasets; rgb1 will be used for selected objects, rgb0 for unselected
+	colors : [{
+		r1 : 255,
+		g1 : 101,
+		b1 : 0,
+		r0 : 253,
+		g0 : 229,
+		b0 : 205
+	}, {
+		r1 : 144,
+		g1 : 26,
+		b1 : 255,
+		r0 : 230,
+		g0 : 225,
+		b0 : 255
+	}, {
+		r1 : 0,
+		g1 : 217,
+		b1 : 0,
+		r0 : 213,
+		g0 : 255,
+		b0 : 213
+	}, {
+		r1 : 240,
+		g1 : 220,
+		b1 : 0,
+		r0 : 247,
+		g0 : 244,
+		b0 : 197
+	}]
+
+}
+
+GeoTemConfig.ie = false;
+GeoTemConfig.ie8 = false;
+
+GeoTemConfig.independentMapId = 0;
+GeoTemConfig.independentTimeId = 0;
+
+if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) {
+	GeoTemConfig.ie = true;
+	var ieversion = new Number(RegExp.$1);
+	if (ieversion == 8) {
+		GeoTemConfig.ie8 = true;
+	}
+}
+
+GeoTemConfig.quoteVal = function(val){
+ return val.replace(new RegExp('"', 'g'), '%22');
+
+}
+
+GeoTemConfig.getIndependentId = function(target){
+	if( target == 'map' ){
+		return ++GeoTemConfig.independentMapId;
+	}
+	if( target == 'time' ){
+		return ++GeoTemConfig.independentTimeId;
+	}
+	return 0;
+};
+
+GeoTemConfig.setHexColor = function(hex,index,fill){
+	var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
+	if( fill ){
+		GeoTemConfig.colors[index].r0 = parseInt(result[1], 16);
+		GeoTemConfig.colors[index].g0 = parseInt(result[2], 16);
+		GeoTemConfig.colors[index].b0 = parseInt(result[3], 16);
+	}
+	else {
+		GeoTemConfig.colors[index].r1 = parseInt(result[1], 16);
+		GeoTemConfig.colors[index].g1 = parseInt(result[2], 16);
+		GeoTemConfig.colors[index].b1 = parseInt(result[3], 16);
+	}
+}
+
+GeoTemConfig.setRgbColor = function(r,g,b,index,fill){
+	if( fill ){
+		GeoTemConfig.colors[index].r0 = r;
+		GeoTemConfig.colors[index].g0 = g;
+		GeoTemConfig.colors[index].b0 = b;
+	}
+	else {
+		GeoTemConfig.colors[index].r1 = r;
+		GeoTemConfig.colors[index].g1 = g;
+		GeoTemConfig.colors[index].b1 = b;
+	}
+}
+
+GeoTemConfig.configure = function(urlPrefix) {
+	GeoTemConfig.urlPrefix = urlPrefix;
+	GeoTemConfig.path = GeoTemConfig.urlPrefix + "images/";
+}
+
+GeoTemConfig.applySettings = function(settings) {
+	$.extend(this, settings);
+};
+
+//Keeps track of how many colors where assigned yet.
+GeoTemConfig.assignedColorCount = 0;
+GeoTemConfig.getColor = function(id){
+	if (typeof GeoTemConfig.datasets[id].color === "undefined"){
+		var color;
+		
+		while (true){
+			if( GeoTemConfig.colors.length <= GeoTemConfig.assignedColorCount ){
+				color = {
+					r1 : Math.floor((Math.random()*255)+1),
+					g1 : Math.floor((Math.random()*255)+1),
+					b1 : Math.floor((Math.random()*255)+1),
+					r0 : 230,
+					g0 : 230,
+					b0 : 230
+				};
+			} else
+				color = GeoTemConfig.colors[GeoTemConfig.assignedColorCount];
+			
+			//make sure that no other dataset has this color
+			//TODO: one could also check that they are not too much alike
+			var found = false;
+			for (var i = 0; i < GeoTemConfig.datasets.length; i++){
+				var dataset = GeoTemConfig.datasets[i];
+				
+				if (typeof dataset.color === "undefined")
+					continue;
+
+				if (	(dataset.color.r1 == color.r1) && 
+						(dataset.color.g1 == color.g1) &&
+						(dataset.color.b1 == color.b1) ){
+					found = true;
+					break;
+				}
+			}
+			if (found === true){
+				if( GeoTemConfig.colors.length <= GeoTemConfig.assignedColorCount ){
+					//next time skip over this color
+					GeoTemConfig.assignedColorCount++;
+				}
+				continue;
+			} else {
+				GeoTemConfig.colors.push(color);
+				break;
+			}
+		}
+		GeoTemConfig.datasets[id].color = color;
+
+		GeoTemConfig.assignedColorCount++;
+	}
+	return GeoTemConfig.datasets[id].color;
+};
+
+GeoTemConfig.getAverageDatasetColor = function(id, objects){
+	var c = new Object();
+	var datasetColor = GeoTemConfig.getColor(id);
+	c.r0 = datasetColor.r0;
+	c.g0 = datasetColor.g0;
+	c.b0 = datasetColor.b0;
+	c.r1 = datasetColor.r1;
+	c.g1 = datasetColor.g1;
+	c.b1 = datasetColor.b1;
+	if (!GeoTemConfig.allowCustomColoring)
+		return c;
+	if (objects.length == 0)
+		return c;
+	var avgColor = new Object();
+	avgColor.r0 = 0;
+	avgColor.g0 = 0;
+	avgColor.b0 = 0;
+	avgColor.r1 = 0;
+	avgColor.g1 = 0;
+	avgColor.b1 = 0;
+	
+	$(objects).each(function(){
+		if (this.hasColorInformation){
+			avgColor.r0 += this.color.r0;
+			avgColor.g0 += this.color.g0;
+			avgColor.b0 += this.color.b0;
+			avgColor.r1 += this.color.r1;
+			avgColor.g1 += this.color.g1;
+			avgColor.b1 += this.color.b1;
+		} else {
+			avgColor.r0 += datasetColor.r0;
+			avgColor.g0 += datasetColor.g0;
+			avgColor.b0 += datasetColor.b0;
+			avgColor.r1 += datasetColor.r1;
+			avgColor.g1 += datasetColor.g1;
+			avgColor.b1 += datasetColor.b1;
+		}
+	});
+	
+	c.r0 = Math.floor(avgColor.r0/objects.length);
+	c.g0 = Math.floor(avgColor.g0/objects.length);
+	c.b0 = Math.floor(avgColor.b0/objects.length);
+	c.r1 = Math.floor(avgColor.r1/objects.length);
+	c.g1 = Math.floor(avgColor.g1/objects.length);
+	c.b1 = Math.floor(avgColor.b1/objects.length);
+	
+	return c;
+};
+
+GeoTemConfig.getString = function(field) {
+	if ( typeof Tooltips[GeoTemConfig.language] == 'undefined') {
+		GeoTemConfig.language = 'en';
+	}
+	return Tooltips[GeoTemConfig.language][field];
+}
+/**
+ * returns the actual mouse position
+ * @param {Event} e the mouseevent
+ * @return the top and left position on the screen
+ */
+GeoTemConfig.getMousePosition = function(e) {
+	if (!e) {
+		e = window.event;
+	}
+	var body = (window.document.compatMode && window.document.compatMode == "CSS1Compat") ? window.document.documentElement : window.document.body;
+	return {
+		top : e.pageY ? e.pageY : e.clientY,
+		left : e.pageX ? e.pageX : e.clientX
+	};
+}
+/**
+ * returns the json object of the file from the given url
+ * @param {String} url the url of the file to load
+ * @return json object of given file
+ */
+GeoTemConfig.getJson = function(url,asyncFunc) {
+	var async = false;
+	if( asyncFunc ){
+		async = true;
+	}
+	
+	var data;
+	$.ajax({
+		url : url,
+		async : async,
+		dataType : 'json',
+		success : function(json) {
+			data = json;
+			if (async){
+				asyncFunc(data);
+			}
+		}
+	});
+	
+	if (async){
+		return data;
+	}
+}
+
+GeoTemConfig.mergeObjects = function(set1, set2) {
+	var inside = [];
+	var newSet = [];
+	for (var i = 0; i < GeoTemConfig.datasets.length; i++){
+		inside.push([]);
+		newSet.push([]);
+	}
+	for (var i = 0; i < set1.length; i++) {
+		for (var j = 0; j < set1[i].length; j++) {
+			inside[i][set1[i][j].index] = true;
+			newSet[i].push(set1[i][j]);
+		}
+	}
+	for (var i = 0; i < set2.length; i++) {
+		for (var j = 0; j < set2[i].length; j++) {
+			if (!inside[i][set2[i][j].index]) {
+				newSet[i].push(set2[i][j]);
+			}
+		}
+	}
+	return newSet;
+};
+
+GeoTemConfig.datasets = [];
+
+GeoTemConfig.addDataset = function(newDataset){
+	GeoTemConfig.datasets.push(newDataset);
+	Publisher.Publish('filterData', GeoTemConfig.datasets, null);
+};
+
+GeoTemConfig.addDatasets = function(newDatasets){
+	$(newDatasets).each(function(){
+		GeoTemConfig.datasets.push(this);
+	});	
+	Publisher.Publish('filterData', GeoTemConfig.datasets, null);
+};
+
+GeoTemConfig.removeDataset = function(index){
+	GeoTemConfig.datasets.splice(index,1);
+	Publisher.Publish('filterData', GeoTemConfig.datasets, null);
+};
+
+GeoTemConfig.removeAllDatasets = function() {
+
+	if (GeoTemConfig.datasets.length > 0) {
+		GeoTemConfig.datasets.splice(0, GeoTemConfig.datasets.length);
+		Publisher.Publish('filterData', GeoTemConfig.datasets, null);
+	}
+};
+
+/**
+ * converts the csv-file into json-format
+ * 
+ * @param {String}
+ *            text
+ */
+GeoTemConfig.convertCsv = function(text){
+	/* convert here from CSV to JSON */
+	var json = [];
+	/* define expected csv table headers (first line) */
+	var expectedHeaders = new Array("Name","Address","Description","Longitude","Latitude","TimeStamp","TimeSpan:begin","TimeSpan:end","weight");
+	/* convert csv string to array of arrays using ucsv library */
+	var csvArray = CSV.csvToArray(text);
+	/* get real used table headers from csv file (first line) */
+	var usedHeaders = csvArray[0];
+	/* loop outer array, begin with second line */
+	for (var i = 1; i < csvArray.length; i++) {
+		var innerArray = csvArray[i];
+		var dataObject = new Object();
+		var tableContent = new Object(); 
+		/* exclude lines with no content */
+		var hasContent = false;
+		for (var j = 0; j < innerArray.length; j++) {
+			if (typeof innerArray[j] !== "undefined"){
+				if (typeof innerArray[j] === "string"){
+					if (innerArray[j].length > 0)
+						hasContent = true;
+				} else {
+					hasContent = true;
+				}
+			}
+			
+			if (hasContent === true)
+				break;
+		}
+		if (hasContent === false)
+			continue;
+	   	/* loop inner array */
+		for (var j = 0; j < innerArray.length; j++) {
+			/* Name */
+			if (usedHeaders[j] == expectedHeaders[0]) {
+				dataObject["name"] = ""+innerArray[j];
+				tableContent["name"] = ""+innerArray[j];
+			}
+			/* Address */
+			else if (usedHeaders[j] == expectedHeaders[1]) {
+				dataObject["place"] = ""+innerArray[j];
+				tableContent["place"] = ""+innerArray[j];
+			}
+			/* Description */
+			else if (usedHeaders[j] == expectedHeaders[2]) {
+				dataObject["description"] = ""+innerArray[j];
+				tableContent["description"] = ""+innerArray[j];
+			}
+			/* TimeStamp */
+			else if (usedHeaders[j] == expectedHeaders[5]) {
+				dataObject["time"] = ""+innerArray[j];
+			}
+			/* TimeSpan:begin */
+			else if (usedHeaders[j] == expectedHeaders[6]) {
+				tableContent["TimeSpan:begin"] = ""+innerArray[j];
+			}
+			/* TimeSpan:end */
+			else if (usedHeaders[j] == expectedHeaders[7]) {
+				tableContent["TimeSpan:end"] = ""+innerArray[j];
+			}   						
+			/* weight */
+			else if (usedHeaders[j] == expectedHeaders[8]) {
+				dataObject["weight"] = ""+innerArray[j];
+			}   						
+			/* Longitude */                                                          
+			else if (usedHeaders[j] == expectedHeaders[3]) {                              
+				dataObject["lon"] = parseFloat(innerArray[j]);                                           
+			}                                                                        
+			/* Latitude */                                                           
+			else if (usedHeaders[j] == expectedHeaders[4]) {                              
+				dataObject["lat"] = parseFloat(innerArray[j]);
+			}
+			else {
+				var header = new String(usedHeaders[j]);
+				//remove leading and trailing Whitespace
+				header = $.trim(header);
+				tableContent[header] = ""+innerArray[j];
+			}
+		}
+		
+		dataObject["tableContent"] = tableContent;
+		
+		json.push(dataObject);
+	}
+	
+	return json;
+};
+
+/**
+ * returns the xml dom object of the file from the given url
+ * @param {String} url the url of the file to load
+ * @return xml dom object of given file
+ */
+GeoTemConfig.getKml = function(url,asyncFunc) {
+	var data;
+	var async = false;
+	if( asyncFunc ){
+		async = true;
+	}
+	$.ajax({
+		url : url,
+		async : async,
+		dataType : 'xml',
+		success : function(xml) {
+			if( asyncFunc ){
+				asyncFunc(xml);
+			}
+			else {
+				data = xml;
+			}
+		}
+	});
+	if( !async ){
+		return data;
+	}
+}
+
+/**
+ * returns an array of all xml dom object of the kmls 
+ * found in the zip file from the given url
+ * 
+ * can only be used with asyncFunc (because of browser 
+ * constraints regarding arraybuffer)
+ * 
+ * @param {String} url the url of the file to load
+ * @return xml dom object of given file
+ */
+GeoTemConfig.getKmz = function(url,asyncFunc) {
+	var kmlDom = new Array();
+
+	var async = true;
+	if( !asyncFunc ){
+		//if no asyncFunc is given return an empty array
+		return kmlDom;
+	}
+	
+	//use XMLHttpRequest as "arraybuffer" is not 
+	//supported in jQuery native $.get
+    var req = new XMLHttpRequest();
+    req.open("GET",url,async);
+    req.responseType = "arraybuffer";
+    req.onload = function() {
+    	var zip = new JSZip();
+    	zip.load(req.response, {base64:false});
+    	var kmlFiles = zip.file(new RegExp("kml$"));
+    	
+    	$(kmlFiles).each(function(){
+			var kml = this;
+			if (kml.data != null) {
+				kmlDom.push($.parseXML(kml.data));
+			}
+    	});
+    	
+    	asyncFunc(kmlDom);
+    };
+	req.send();
+};
+
+/**
+ * returns the JSON "object"  
+ * from the csv file from the given url
+ * @param {String} url the url of the file to load
+ * @return xml dom object of given file
+ */
+GeoTemConfig.getCsv = function(url,asyncFunc) {
+	var async = false;
+	if( asyncFunc ){
+		async = true;
+	}
+	
+	//use XMLHttpRequest as synchronous behaviour 
+	//is not supported in jQuery native $.get
+    var req = new XMLHttpRequest();
+    req.open("GET",url,async);
+    //can only be set on asynchronous now
+    //req.responseType = "text";
+    var json;
+    req.onload = function() {
+    	json = GeoTemConfig.convertCsv(req.response);
+    	if( asyncFunc )
+    		asyncFunc(json);
+    };
+	req.send();
+	
+	if( !async ){
+		return json;
+	}
+};
+
+/**
+ * loads a binary file  
+ * @param {String} url of the file to load
+ * @return binary data
+ */
+GeoTemConfig.getBinary = function(url,asyncFunc) {
+	var async = true;
+
+	var req = new XMLHttpRequest();
+    req.open("GET",url,async);
+    req.responseType = "arraybuffer";
+    
+    var binaryData;
+	req.onload = function() {
+		var arrayBuffer = req.response;
+		asyncFunc(arrayBuffer);
+    };
+	req.send();
+};
+
+/**
+ * returns a Date and a SimileAjax.DateTime granularity value for a given XML time
+ * @param {String} xmlTime the XML time as String
+ * @return JSON object with a Date and a SimileAjax.DateTime granularity
+ */
+GeoTemConfig.getTimeData = function(xmlTime) {
+	if (!xmlTime)
+		return;
+	var dateData;
+	try {
+		var bc = false;
+		if (xmlTime.startsWith("-")) {
+			bc = true;
+			xmlTime = xmlTime.substring(1);
+		}
+		var timeSplit = xmlTime.split("T");
+		var timeData = timeSplit[0].split("-");
+		for (var i = 0; i < timeData.length; i++) {
+			parseInt(timeData[i]);
+		}
+		if (bc) {
+			timeData[0] = "-" + timeData[0];
+		}
+		if (timeSplit.length == 1) {
+			dateData = timeData;
+		} else {
+			var dayData;
+			if (timeSplit[1].indexOf("Z") != -1) {
+				dayData = timeSplit[1].substring(0, timeSplit[1].indexOf("Z") - 1).split(":");
+			} else {
+				dayData = timeSplit[1].substring(0, timeSplit[1].indexOf("+") - 1).split(":");
+			}
+			for (var i = 0; i < timeData.length; i++) {
+				parseInt(dayData[i]);
+			}
+			dateData = timeData.concat(dayData);
+		}
+	} catch (exception) {
+		return null;
+	}
+	var date, granularity;
+	if (dateData.length == 6) {
+		granularity = SimileAjax.DateTime.SECOND;
+		date = new Date(Date.UTC(dateData[0], dateData[1] - 1, dateData[2], dateData[3], dateData[4], dateData[5]));
+	} else if (dateData.length == 3) {
+		granularity = SimileAjax.DateTime.DAY;
+		date = new Date(Date.UTC(dateData[0], dateData[1] - 1, dateData[2]));
+	} else if (dateData.length == 2) {
+		granularity = SimileAjax.DateTime.MONTH;
+		date = new Date(Date.UTC(dateData[0], dateData[1] - 1, 1));
+	} else if (dateData.length == 1) {
+		granularity = SimileAjax.DateTime.YEAR;
+		date = new Date(Date.UTC(dateData[0], 0, 1));
+	}
+	if (timeData[0] && timeData[0] < 100) {
+		date.setFullYear(timeData[0]);
+	}
+
+	//check data validity;
+	var isValidDate = true;
+	if ( date instanceof Date ) {
+		if ( isNaN( date.getTime() ) )
+			isValidDate = false;
+	} else
+		isValidDate = false;
+	
+	if (!isValidDate){
+		if ((GeoTemConfig.debug)&&(typeof console !== "undefined"))
+			console.error(xmlTime + " is no valid time format");
+		return null;
+	}
+	
+	return {
+		date : date,
+		granularity : granularity
+	};
+}
+/**
+ * converts a JSON array into an array of data objects
+ * @param {JSON} JSON a JSON array of data items
+ * @return an array of data objects
+ */
+GeoTemConfig.loadJson = function(JSON) {
+	var mapTimeObjects = [];
+	var runningIndex = 0;
+	for (var i in JSON ) {
+		try {
+			var item = JSON[i];
+			var index = item.index || item.id || runningIndex++;
+			var name = item.name || "";
+			var description = item.description || "";
+			var tableContent = item.tableContent || [];
+			var locations = [];
+			if (item.location instanceof Array) {
+				for (var j = 0; j < item.location.length; j++) {
+					var place = item.location[j].place || "unknown";
+					var lon = item.location[j].lon;
+					var lat = item.location[j].lat;
+					if ((typeof lon === "undefined" || typeof lat === "undefined" || isNaN(lon) || isNaN(lat) ) && !GeoTemConfig.incompleteData) {
+						throw "e";
+					}
+					locations.push({
+						longitude : lon,
+						latitude : lat,
+						place : place
+					});
+				}
+			} else {
+				var place = item.place || "unknown";
+				var lon = item.lon;
+				var lat = item.lat;
+				if ((typeof lon === "undefined" || typeof lat === "undefined" || isNaN(lon) || isNaN(lat) ) && !GeoTemConfig.incompleteData) {
+					throw "e";
+				}
+				locations.push({
+					longitude : lon,
+					latitude : lat,
+					place : place
+				});
+			}
+			var dates = [];
+			if (item.time instanceof Array) {
+				for (var j = 0; j < item.time.length; j++) {
+					var time = GeoTemConfig.getTimeData(item.time[j]);
+					if (time == null && !GeoTemConfig.incompleteData) {
+						throw "e";
+					}
+					dates.push(time);
+				}
+			} else {
+				var time = GeoTemConfig.getTimeData(item.time);
+				if (time == null && !GeoTemConfig.incompleteData) {
+					throw "e";
+				}
+				if (time != null) {
+					dates.push(time);
+				}
+			}
+			var weight = parseInt(item.weight) || 1;
+			//add all "other" attributes to table data
+			//this is a hack to allow "invalid" JSONs
+			var specialAttributes = ["id", "name", "description", "lon", "lat", "place", "time", 
+			                        "tableContent", "location", "time"];
+			for (var attribute in item){
+				if ($.inArray(attribute, specialAttributes) == -1){
+					tableContent[attribute] = item[attribute];
+				}
+			}
+			
+			var mapTimeObject = new DataObject(name, description, locations, dates, weight, tableContent);
+			mapTimeObject.setIndex(index);
+			mapTimeObjects.push(mapTimeObject);
+		} catch(e) {
+			continue;
+		}
+	}
+
+	if (GeoTemConfig.loadColorFromDataset)
+		GeoTemConfig.loadDataObjectColoring(mapTimeObjects);
+
+	return mapTimeObjects;
+}
+/**
+ * converts a KML dom into an array of data objects
+ * @param {XML dom} kml the XML dom for the KML file
+ * @return an array of data objects
+ */
+GeoTemConfig.loadKml = function(kml) {
+	var mapObjects = [];
+	var elements = kml.getElementsByTagName("Placemark");
+	if (elements.length == 0) {
+		return [];
+	}
+	var index = 0;
+	var descriptionTableHeaders = [];
+	var xmlSerializer = new XMLSerializer();	
+	
+	for (var i = 0; i < elements.length; i++) {
+		var placemark = elements[i];
+		var name, description, place, granularity, lon, lat, tableContent = [], time = [], location = [];
+		var weight = 1;
+		var timeData = false, mapData = false;
+
+		try {
+			description = placemark.getElementsByTagName("description")[0].childNodes[0].nodeValue;
+			
+			//cleanWhitespace removes non-sense text-nodes (space, tab)
+			//and is an addition to jquery defined above
+			try {
+				var descriptionDocument = $($.parseXML(description)).cleanWhitespace();
+				
+				//check whether the description element contains a table
+				//if yes, this data will be loaded as separate columns
+				$(descriptionDocument).find("table").each(function(){
+					$(this).find("tr").each(
+						function() {
+							var isHeader = true;
+							var lastHeader = "";
+							
+							$(this).find("td").each(
+								function() {
+									if (isHeader) {
+										lastHeader = $.trim($(this).text());
+										isHeader = false;
+									} else {
+										var value = "";
+	
+										//if this td contains HTML, serialize all
+										//it's children (the "content"!)
+										$(this).children().each(
+											function() {
+												value += xmlSerializer.serializeToString(this);
+											}
+										);
+										
+										//no HTML content (or no content at all)
+										if (value.length == 0)
+											value = $(this).text();
+										if (typeof value === "undefined")
+											value = "";
+										
+										if ($.inArray(lastHeader, descriptionTableHeaders) === -1)
+											descriptionTableHeaders.push(lastHeader);
+	
+										if (tableContent[lastHeader] != null)
+											//append if a field occures more than once 
+											tableContent[lastHeader] += "\n" + value;
+										else
+											tableContent[lastHeader] = value;
+	
+										isHeader = true;
+									}
+								}
+							);
+						}
+					);
+				});
+			} catch(e) {
+				//couldn't be parsed, so it contains no html table
+				//or is not in valid XHTML syntax
+			}
+			
+			//check whether the description element contains content in the form of equations
+			//e.g. someDescriptor = someValue, where these eqations are separated by <br/>
+			//if yes, this data will be loaded as separate columns
+			var descriptionRows = description.replace(/<\s*br\s*[\/]*\s*>/g,"<br/>"); 
+			$(descriptionRows.split("<br/>")).each(function(){
+				var row = this;
+				
+				if (typeof row === "undefined")
+					return;
+				
+				var headerAndValue = row.split("=");
+				if (headerAndValue.length != 2)
+					return;
+
+				var header = $.trim(headerAndValue[0]);
+				var value = $.trim(headerAndValue[1]);
+				
+				if ($.inArray(header, descriptionTableHeaders) === -1)
+					descriptionTableHeaders.push(header);
+
+				if (tableContent[header] != null)
+					//append if a field occures more than once 
+					tableContent[header] += "\n" + value;
+				else
+					tableContent[header] = value;
+			});
+
+			tableContent["description"] = description;
+		} catch(e) {
+			description = "";
+		}
+
+		try {
+			name = placemark.getElementsByTagName("name")[0].childNodes[0].nodeValue;
+			tableContent["name"] = name;
+		} catch(e) {
+			if (typeof tableContent["name"] !== "undefined")
+				name = tableContent["name"];
+			else
+				name = "";
+		}		
+
+		try {
+			place = placemark.getElementsByTagName("address")[0].childNodes[0].nodeValue;
+			tableContent["place"] = place;
+		} catch(e) {
+			if (typeof tableContent["place"] !== "undefined")
+				place = tableContent["place"];
+			else
+				place = "";
+		}
+
+		try {
+			var coordinates = placemark.getElementsByTagName("Point")[0].getElementsByTagName("coordinates")[0].childNodes[0].nodeValue;
+			var lonlat = coordinates.split(",");
+			lon = lonlat[0];
+			lat = lonlat[1];
+			if (lon == "" || lat == "" || isNaN(lon) || isNaN(lat)) {
+				throw "e";
+			}
+			location.push({
+				longitude : lon,
+				latitude : lat,
+				place : place
+			});
+		} catch(e) {
+			if (!GeoTemConfig.incompleteData) {
+				continue;
+			}
+		}
+
+		try {
+			var tuple = GeoTemConfig.getTimeData(placemark.getElementsByTagName("TimeStamp")[0].getElementsByTagName("when")[0].childNodes[0].nodeValue);
+			if (tuple != null) {
+				time.push(tuple);
+				timeData = true;
+			} else if (!GeoTemConfig.incompleteData) {
+				continue;
+			}
+		} catch(e) {
+			try {
+				if (	(typeof tableContent["TimeSpan:begin"] === "undefined") &&
+						(typeof tableContent["TimeSpan:end"] === "undefined") ){
+					var timeStart = $(placemark).find("TimeSpan begin").text();
+					var timeEnd = $(placemark).find("TimeSpan end").text();
+					
+					if ( (timeStart != "") && (timeStart != "") ){
+						tableContent["TimeSpan:begin"] = timeStart;
+						tableContent["TimeSpan:end"] = timeEnd;
+
+						timeData = true;
+					}
+				}
+			} catch(e) {
+				if (!GeoTemConfig.incompleteData) {
+					continue;
+				}
+			}
+		}
+		var object = new DataObject(name, description, location, time, 1, tableContent);
+		object.setIndex(index);
+		index++;
+		mapObjects.push(object);
+	}
+	
+	//make sure that all "description table" columns exists in all rows
+	if (descriptionTableHeaders.length > 0){
+		$(mapObjects).each(function(){
+			var object = this;
+			$(descriptionTableHeaders).each(function(){
+				if (typeof object.tableContent[this] === "undefined")
+					object.tableContent[this] = "";
+			});
+		});
+	}
+
+	if (GeoTemConfig.loadColorFromDataset)
+		GeoTemConfig.loadDataObjectColoring(mapObjects);
+
+	return mapObjects;
+};
+
+GeoTemConfig.createKMLfromDataset = function(index){
+	var kmlContent = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><kml xmlns=\"http://www.opengis.net/kml/2.2\"><Document>";
+
+	//credits: Anatoly Mironov, http://stackoverflow.com/questions/2573521/how-do-i-output-an-iso-8601-formatted-string-in-javascript
+	function pad(number) {
+		var r = String(number);
+		if ( r.length === 1 ) {
+			r = '0' + r;
+		}
+		return r;
+	}
+
+	var dateToISOString = function(date, granularity) {
+		var ISOString = date.getFullYear();
+
+		if (granularity <= SimileAjax.DateTime.MONTH)
+			ISOString += '-' + pad( date.getMonth() + 1 );
+		if (granularity <= SimileAjax.DateTime.DAY)
+			ISOString += '-' + pad( date.getDate() );
+		if (granularity <= SimileAjax.DateTime.HOUR){
+			ISOString += 'T' + pad( date.getHours() );
+			if (granularity <= SimileAjax.DateTime.MINUTE)
+				ISOString += ':' + pad( date.getMinutes() );
+			if (granularity <= SimileAjax.DateTime.SECOND)
+				ISOString += ':' + pad( date.getSeconds() );
+			if (granularity <= SimileAjax.DateTime.MILLISECOND)
+				ISOString += '.' + String( (date.getMilliseconds()/1000).toFixed(3) ).slice( 2, 5 );
+			ISOString += 'Z';
+		}
+		
+		return ISOString;
+	};
+      
+	$(GeoTemConfig.datasets[index].objects).each(function(){
+		var name = this.name;
+		var description = this.description;
+		//TODO: allow multiple time/date
+		var place = this.getPlace(0,0);
+		var lat = this.getLatitude(0);
+		var lon = this.getLongitude(0);
+		
+		var kmlEntry = "<Placemark>";
+		
+		kmlEntry += "<name><![CDATA[" + name + "]]></name>";
+		kmlEntry += "<address><![CDATA[" + place + "]]></address>";
+		kmlEntry += "<description><![CDATA[" + description + "]]></description>";
+		kmlEntry += "<Point><coordinates>" + lon + "," + lat + "</coordinates></Point>";
+		  
+		if (this.isTemporal){
+			kmlEntry += "<TimeStamp><when>" + dateToISOString(this.getDate(0), this.getTimeGranularity(0)) + "</when></TimeStamp>";
+		} else if (this.isFuzzyTemporal){
+			kmlEntry +=	"<TimeSpan>"+
+							"<begin>" + dateToISOString(this.TimeSpanBegin.utc().toDate(), this.TimeSpanBeginGranularity) + "</begin>" +
+							"<end>" + dateToISOString(this.TimeSpanEnd.utc().toDate(), this.TimeSpanEndGranularity) + "</end>" +
+						"</TimeSpan>";
+		}
+		
+		kmlEntry += "</Placemark>";
+		      
+		kmlContent += kmlEntry;
+	});
+	  
+	kmlContent += "</Document></kml>";
+	  
+	return(kmlContent);
+};
+
+GeoTemConfig.createCSVfromDataset = function(index){
+	var csvContent = "";
+	var header = ["name", "description", "weight"];
+	var tableContent = [];
+	
+	var firstDataObject = GeoTemConfig.datasets[index].objects[0];
+	
+	for(var key in firstDataObject.tableContent){
+		var found = false;
+		$(header).each(function(index,val){
+			if (val === key){
+				found = true;
+				return false;
+			}				
+		});
+		if (found === true)
+			continue;
+		else
+			tableContent.push(key);
+	}
+	
+	var isFirst = true;
+	$(header).each(function(key,val){
+		if (isFirst){
+			isFirst = false;
+		} else {
+			csvContent += ",";
+		}
+
+		//Rename according to CSV import definition
+		if (val === "name")
+			val = "Name";
+		else if (val === "description")
+			val = "Description";
+		csvContent += "\""+val+"\"";
+	});
+	$(tableContent).each(function(key,val){
+		if (isFirst){
+			isFirst = false;
+		} else {
+			csvContent += ",";
+		}
+		csvContent += "\""+val+"\"";
+	});
+	//Names according to CSV import definition
+	csvContent +=  ",\"Address\",\"Latitude\",\"Longitude\",\"TimeStamp\",\"TimeSpan:begin\",\"TimeSpan:end\"";
+	csvContent += "\n";
+	
+	var isFirstRow = true;
+	$(GeoTemConfig.datasets[index].objects).each(function(){
+		var elem = this;
+		
+		if (isFirstRow){
+			isFirstRow = false;
+		} else {
+			csvContent += "\n";
+		}
+		
+		var isFirst = true;
+		$(header).each(function(key,val){
+			if (isFirst){
+				isFirst = false;
+			} else {
+				csvContent += ",";
+			}
+			csvContent += "\""+elem[val]+"\"";
+		});
+		$(tableContent).each(function(key,val){
+			if (isFirst){
+				isFirst = false;
+			} else {
+				csvContent += ",";
+			}
+		    csvContent += "\""+GeoTemConfig.quoteVal(elem.tableContent[val])+"\"";
+		});
+		
+		csvContent += ",";
+		csvContent += "\"";
+		if (elem.isGeospatial){
+			csvContent += elem.locations[0].place;
+		}
+		csvContent += "\"";
+
+		csvContent += ",";
+		csvContent += "\"";
+		if ( (elem.isGeospatial) && (typeof elem.getLatitude(0) !== "undefined") ){
+			csvContent += elem.getLatitude(0);
+		}
+		csvContent += "\"";
+
+		csvContent += ",";
+		csvContent += "\"";
+		if ( (elem.isGeospatial) && (typeof elem.getLongitude(0) !== "undefined") ){
+			csvContent += elem.getLongitude(0);
+		}
+		csvContent += "\"";
+		
+		csvContent += ",";
+		csvContent += "\"";
+		if ( (elem.isTemporal) && (typeof elem.getDate(0) !== "undefined") ){
+			//TODO: not supported in IE8 switch to moment.js
+			csvContent += elem.getDate(0).toISOString();
+		}
+		csvContent += "\"";
+
+		csvContent += ",";
+		if (elem.isFuzzyTemporal){
+			//TODO: not supported in IE8 switch to moment.js
+			csvContent += "\""+elem.TimeSpanBegin.format()+"\",\""+elem.TimeSpanEnd.format()+"\"";			
+		} else {
+			csvContent += "\"\",\"\"";			
+		}
+	});
+	  
+	return(csvContent);
+};
+/**
+ * iterates over Datasets/DataObjects and loads color values
+ * from the "color0" and "color1" elements, which contains RGB
+ * values in hex (CSS style #RRGGBB)
+ * @param {dataObjects} array of DataObjects
+ */
+GeoTemConfig.loadDataObjectColoring = function(dataObjects) {
+	$(dataObjects).each(function(){
+		var r0,g0,b0,r1,g1,b1;
+		if (	(typeof this.tableContent !== "undefined") &&
+				(typeof this.tableContent["color0"] !== "undefined") ){
+			var color = this.tableContent["color0"];
+			if ( (color.indexOf("#") == 0) && (color.length == 7) ){
+			    r0 = parseInt("0x"+color.substr(1,2));
+			    g0 = parseInt("0x"+color.substr(3,2));
+			    b0 = parseInt("0x"+color.substr(5,2));
+			}
+		}
+		if (	(typeof this.tableContent !== "undefined") &&
+				(typeof this.tableContent["color1"] !== "undefined") ){
+			var color = this.tableContent["color1"];
+			if ( (color.indexOf("#") == 0) && (color.length == 7) ){
+			    r1 = parseInt("0x"+color.substr(1,2));
+			    g1 = parseInt("0x"+color.substr(3,2));
+			    b1 = parseInt("0x"+color.substr(5,2));
+			}
+		}
+		
+		if (	(typeof r0 !== "undefined") && (typeof g0 !== "undefined") && (typeof b0 !== "undefined") &&
+				(typeof r1 !== "undefined") && (typeof g1 !== "undefined") && (typeof b1 !== "undefined") ){
+			this.setColor(r0,g0,b0,r1,g1,b1);
+			delete this.tableContent["color0"];
+			delete this.tableContent["color1"];
+		} else {
+			if ((GeoTemConfig.debug)&&(typeof console !== undefined))
+				console.error("Object '" + this.name + "' has invalid color information");
+		}
+	});
+};
+
+/**
+ * renames (or copies, see below) a column of each DataObject in a Dataset
+ * @param {Dataset} dataset the dataset where the rename should take place
+ * @param {String} oldColumn name of column that will be renamed
+ * @param {String} newColumn new name of column
+ * @param {Boolean} keepOld keep old column (copy mode)
+ * @return an array of data objects
+ */
+GeoTemConfig.renameColumns = function(dataset, renames){
+	if (renames.length===0){
+		return;
+	}
+	for (var renCnt = 0; renCnt < renames.length; renCnt++){
+		var oldColumn = renames[renCnt].oldColumn;
+		var newColumn = renames[renCnt].newColumn;
+
+		var keepOld = renames[renCnt].keepOld;
+		if (typeof keepOld === "undefined"){
+			keepOld = true;
+		}
+		var oldColumObject = {};
+		if (oldColumn.indexOf("[") != -1){
+			oldColumObject.columnName = oldColumn.split("[")[0];
+			var IndexAndAttribute = oldColumn.split("[")[1];
+			if (IndexAndAttribute.indexOf("]") != -1){
+				oldColumObject.type = 2;
+				oldColumObject.arrayIndex = IndexAndAttribute.split("]")[0];
+				var attribute = IndexAndAttribute.split("]")[1];
+				if (attribute.length > 0){
+					oldColumObject.type = 3;
+					oldColumObject.attribute = attribute.split(".")[1];
+				}
+			}
+		} else {
+			oldColumObject.type = 1;
+			oldColumObject.name = oldColumn;
+		}
+
+		var newColumObject = {};
+		if (newColumn.indexOf("[") != -1){
+			newColumObject.name = newColumn.split("[")[0];
+			var IndexAndAttribute = newColumn.split("[")[1];
+			if (IndexAndAttribute.indexOf("]") != -1){
+				newColumObject.type = 2;
+				newColumObject.arrayIndex = IndexAndAttribute.split("]")[0];
+				var attribute = IndexAndAttribute.split("]")[1];
+				if (attribute.length > 0){
+					newColumObject.type = 3;
+					newColumObject.attribute = attribute.split(".")[1];
+				}
+			}
+		} else {
+			newColumObject.type = 1;
+			newColumObject.name = newColumn;
+		}
+
+		for (var i = 0; i < dataset.objects.length; i++){
+			var dataObject = dataset.objects[i];
+			
+			//get value from old column name
+			var value;
+			if (oldColumObject.type == 1){
+				value = dataObject[oldColumObject.name];
+				if (typeof value === "undefined"){
+					value = dataObject.tableContent[oldColumObject.name];
+				}
+				if (!keepOld){
+					delete dataObject.tableContent[oldColumObject.name];
+					delete dataObject[oldColumObject.name];
+				}
+			} else if (oldColumObject.type == 2){
+				value = dataObject[oldColumObject.name][oldColumObject.arrayIndex];
+				if (!keepOld){
+					delete dataObject[oldColumObject.name][oldColumObject.arrayIndex];
+				}
+			} else if (oldColumObject.type == 3){
+				value = dataObject[oldColumObject.name][oldColumObject.arrayIndex][oldColumObject.attribute];
+				if (!keepOld){
+					delete dataObject[oldColumObject.name][oldColumObject.arrayIndex][oldColumObject.attribute];
+				}
+			} 
+
+			//create new column
+			if (newColumObject.type == 1){
+				dataObject[newColumObject.name] = value;
+				dataObject.tableContent[newColumObject.name] = value;
+			} else if (newColumObject.type == 2){
+				if (typeof dataObject[newColumObject.name] == "undefined"){
+					dataObject[newColumObject.name] = [];
+				}
+				dataObject[newColumObject.name][newColumObject.arrayIndex] = value;
+			} else if (newColumObject.type == 3){
+				if (typeof dataObject[newColumObject.name] == "undefined"){
+					dataObject[newColumObject.name] = [];
+				}
+				if (typeof dataObject[newColumObject.name][newColumObject.arrayIndex] == "undefined"){
+					dataObject[newColumObject.name][newColumObject.arrayIndex] = {};
+				}
+				dataObject[newColumObject.name][newColumObject.arrayIndex][newColumObject.attribute] = value; 
+			}
+		}
+	}
+
+	//actually create new dataObjects
+	for (var i = 0; i < dataset.objects.length; i++){
+		var dataObject = dataset.objects[i];
+		//save index
+		var index = dataObject.index;
+
+		dataset.objects[i] = new DataObject(dataObject.name, dataObject.description, dataObject.locations, 
+			dataObject.dates, dataObject.weight, dataObject.tableContent, dataObject.projection);
+		//set index
+		dataset.objects[i].setIndex(index);
+	}
+};
\ No newline at end of file