diff war/scripts/sti/STITimeplot.js @ 3:cf06b77a8bbd

Committed branch of the e4D repos sti-gwt branch 16384. git-svn-id: http://dev.dariah.eu/svn/repos/eu.dariah.de/ap1/sti-gwt-dariah-geobrowser@36 f2b5be40-def6-11e0-8a09-b3c1cc336c6b
author StefanFunk <StefanFunk@f2b5be40-def6-11e0-8a09-b3c1cc336c6b>
date Tue, 17 Jul 2012 13:34:40 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/war/scripts/sti/STITimeplot.js	Tue Jul 17 13:34:40 2012 +0000
@@ -0,0 +1,1089 @@
+/**
+ * defines the timeplot component of the Spatio Temporal Interface
+ * it builds a timeplot context with the Simile Widget Timeplot JavaScript Framework
+ * @param {STICore} core the sti core component, the timeplot component has to deal with
+ * @param {String} window the div id for the window div for the container of the timeplot widget
+ * @param {String} container the div id for the container of the timeplot widget
+ *
+ * @constructor
+ */
+function STITimeplot(core,window,container){
+
+    this.core = core;
+    this.window = window;
+    this.container = container;
+    this.timeplot;
+    this.dataSources;
+    this.eventSources;
+    this.eds;
+    this.timeGeometry;
+    this.valueGeometry;
+    this.canvas;
+    
+    this.leftFlagPole;
+    this.rightFlagPole;
+    this.rangeBox;
+    this.leftFeather;
+    this.rightFeather;
+    this.leftHandle;
+    this.rightHandle;
+    
+    this.leftFlagPos = null;
+    this.leftFlagTime = null;
+    this.rightFlagPos = null;
+    this.rightFlagTime = null;
+    this.leftFeatherTime = null;
+    this.rightFeatherTime = null;
+    
+    this.mouseDownTime;
+    this.mouseUpTime;
+    this.mouseTempTime;    
+    this.mouseDownPos;
+    this.mouseUpPos;
+    this.mouseTempPos;    
+    
+    this.placePoles;    
+    this.hoverSlice;
+    
+    this.status;
+    this.featherWidth;    
+    this.slider;
+    
+    this.initialize();
+    
+}
+
+STITimeplot.prototype = {
+
+    /**
+     * clears the timeplot canvas and the timeGeometry properties
+     */
+	clearTimeplot: function(){
+        this.timeplot._clearCanvas();        
+        this.timeGeometry._earliestDate = null;
+        this.timeGeometry._latestDate = null;
+        this.timeGeometry._clearLabels();
+	},
+
+    /**
+     * initializes the timeplot elements with arrays of objects, that have a specific time granularity
+     * @param {Array} objects an array of object-array, which contain all elements that are in the actual display set
+     * @param {SimileAjax.DateTime} granularity the time granularity of the objects
+     */
+    initTimeplot: function(dataSets, granularity){
+		this.clearTimeplot();
+    	this.resetTimeplot();	
+        for (var i = 0; i < this.timeplot._plots.length; i++) {
+            this.timeplot._plots[i].dispose();
+        }
+        this.timeplot._clearCanvas();        
+        this.timeGeometry._earliestDate = null;
+        this.timeGeometry._latestDate = null;
+        this.valueGeometry._minValue = null;
+        this.valueGeometry._maxValue = null;
+        this.dataSources = new Array();
+        this.plotInfos = new Array();
+        this.eventSources = new Array();
+        for (var i = 0; i < dataSets.length; i++) {
+            	var eventSource = new Timeplot.DefaultEventSource();
+            	var dataSource = new Timeplot.ColumnSource(eventSource, 1);
+            	this.dataSources.push(dataSource);
+            	this.eventSources.push(eventSource);
+            	var c = colors[i];
+            	var plotInfo = Timeplot.createPlotInfo({
+                	id: "plot" + i,
+                	dataSource: dataSource,
+                	timeGeometry: this.timeGeometry,
+                	valueGeometry: this.valueGeometry,
+                	fillGradient: false,
+                	lineColor: 'rgba(' + c.r1 + ',' + c.g1 + ',' + c.b1 + ', 1)',
+                	fillColor: 'rgba(' + c.r0 + ',' + c.g0 + ',' + c.b0 + ', 0.3)',
+                	showValues: true
+            	});
+            	this.plotInfos.push(plotInfo);
+        }
+        this.timeGeometry._granularity = granularity;
+        this.timeGeometry._clearLabels();
+        this.timeplot.resetPlots(this.plotInfos);
+    	if( this.plotInfos.length == 0 ){
+    		this.initLabels( this.timeplot.regularGrid() );
+    		return;
+    	}
+        this.timeGeometry.extendedDataSource = this.eds;
+        this.eds.initialize(this.dataSources, this.eventSources, dataSets, granularity);
+       	this.timeplot.repaint();
+        // set maximum number of slider steps
+        var slices = this.eds.timeSlices.length;
+        var numSlices = Math.floor(slices / this.canvas.width * this.canvas.height + 0.5);
+        this.slider.setMaximum(numSlices);
+        this.initLabels([]);
+        this.initOverview();        
+    },
+    
+    /**
+     * initializes the timeplot for the Spatio Temporal Interface.
+     * all elements (including their events) that are needed for user interaction are instantiated here, the slider element as well
+     */
+    initialize: function(){
+    
+        this.status = 0;
+    	this.paused = true;
+        this.dataSources = new Array();
+        this.plotInfos = new Array();
+        this.eventSources = new Array();
+        this.timeGeometry = new Timeplot.DefaultTimeGeometry({
+            gridColor: "#000000",
+            axisLabelsPlacement: "top"
+        });
+        this.timeGeometry._hideLabels = true;
+        this.timeGeometry._granularity = 0;
+        this.valueGeometry = new Timeplot.DefaultValueGeometry({
+            min: 0
+        });
+        this.placePoles = new Array();
+        this.timeplot = Timeplot.create(document.getElementById(this.container), this.plotInfos);
+        this.eds = new ExtendedDataSource();
+        
+        this.canvas = this.timeplot.getCanvas();
+        
+        this.leftFlagPole = this.timeplot.putDiv("leftflagpole", "timeplot-dayflag-pole");
+        this.rightFlagPole = this.timeplot.putDiv("rightflagpole", "timeplot-dayflag-pole");
+        SimileAjax.Graphics.setOpacity(this.leftFlagPole, 50);
+        SimileAjax.Graphics.setOpacity(this.rightFlagPole, 50);
+
+        this.rangeBox = this.timeplot.putDiv("rangebox", "range-box");
+        this.leftFeather = this.timeplot.putDiv("leftfeather", "left-feather");
+        this.rightFeather = this.timeplot.putDiv("rightfeather", "right-feather");
+        
+        var window = document.getElementById(this.window); 
+        this.leftHandle = document.createElement("div");
+        this.leftHandle.setAttribute('class','plotHandle');
+        this.leftHandle.title = "Click and move mouse to change left border.";
+       	this.rightHandle = document.createElement("div");
+       	this.rightHandle.setAttribute('class','plotHandle');
+        this.rightHandle.title = "Click and move mouse to change right border.";
+        window.appendChild(this.leftHandle);
+        window.appendChild(this.rightHandle);
+        
+		this.poles = this.timeplot.putDiv( "poles", "pole" );
+        this.timeplot.placeDiv(this.poles, {
+            left: 0,
+            bottom: 0,
+            width: this.canvas.width,
+            height: this.canvas.height,
+            display: "block"
+        });
+        this.poles.appendChild(document.createElement("canvas"));
+        
+        this.toolbar = document.createElement("div");
+        this.toolbar.setAttribute('class','plotToolbar');
+        window.appendChild(this.toolbar);
+        
+        this.toolbarAbsoluteDiv = document.createElement("div");
+        this.toolbarAbsoluteDiv.setAttribute('class','absoluteToolbar');
+        this.toolbar.appendChild(this.toolbarAbsoluteDiv);
+        
+        var drag = document.createElement("div");
+        drag.title = "Click to drag the selection on the timeplot. Click again to deselect.";
+        drag.setAttribute('class','dragRange');
+        this.toolbarAbsoluteDiv.appendChild(drag);
+
+        var zoom = document.createElement("div");
+        zoom.title = "Zoom into selection. To undo, use the History button.";
+        zoom.setAttribute('class','zoomRange');
+        this.toolbarAbsoluteDiv.appendChild(zoom);
+        zoom.onclick = function(){
+        	plot.core.refine();
+        }
+
+		// displays the feather divs
+        var displayFeather = function(){        
+            plot.leftFeather.style.visibility = "visible";
+            plot.rightFeather.style.visibility = "visible";            
+            plot.timeplot.placeDiv(plot.leftFeather, {
+                left: plot.leftFlagPos - plot.featherWidth,
+                width: plot.featherWidth,
+                bottom: 0,
+                height: plot.canvas.height,
+                display: "block"
+            });
+            plot.timeplot.placeDiv(plot.rightFeather, {
+                left: plot.rightFlagPos,
+                width: plot.featherWidth,
+                bottom: 0,
+                height: plot.canvas.height,
+                display: "block"
+            });            
+            var leftCv = document.getElementById("leftFeatherCanvas");
+            if (leftCv == null) {
+                leftCv = document.createElement("canvas");
+                leftCv.id = "leftFeatherCanvas";
+                plot.leftFeather.appendChild(leftCv);
+            }
+            leftCv.width = plot.featherWidth;
+            leftCv.height = plot.canvas.height;
+ 
+           if (!leftCv.getContext && G_vmlCanvasManager) 
+                leftCv = G_vmlCanvasManager.initElement(leftCv);
+            var leftCtx = leftCv.getContext('2d');
+            var leftGradient = leftCtx.createLinearGradient(plot.featherWidth, 0, 0, 0);
+            leftGradient.addColorStop(0, 'rgba(95,136,178,0.6)');
+            leftGradient.addColorStop(1, 'rgba(171,171,171,0)');
+            leftCtx.fillStyle = leftGradient;
+            leftCtx.fillRect(0, 0, plot.featherWidth, plot.canvas.height);   
+
+            var rightCv = document.getElementById("rightFeatherCanvas");
+            if (rightCv == null) {
+                rightCv = document.createElement("canvas");
+                rightCv.id = "rightFeatherCanvas";
+                plot.rightFeather.appendChild(rightCv);
+            }
+            rightCv.width = plot.featherWidth;
+            rightCv.height = plot.canvas.height;
+            if (!rightCv.getContext && G_vmlCanvasManager) 
+                rightCv = G_vmlCanvasManager.initElement(rightCv);
+            var rightCtx = rightCv.getContext('2d');
+            var rightGradient = rightCtx.createLinearGradient(0, 0, plot.featherWidth, 0);
+            rightGradient.addColorStop(0, 'rgba(95,136,178,0.6)');
+            rightGradient.addColorStop(1, 'rgba(171,171,171,0)');
+            rightCtx.fillStyle = rightGradient;
+            rightCtx.fillRect(0, 0, plot.featherWidth, plot.canvas.height);
+        }         
+                
+        var featherSliderDiv = document.createElement("div");
+		featherSliderDiv.setAttribute('class', 'featherSlider');
+		featherSliderDiv.title = "Adjust the feather of the selection to smoothen the animations on the map.";
+        var sliderInput = document.createElement("input");
+        featherSliderDiv.appendChild(sliderInput);
+        this.slider = new Slider(featherSliderDiv,sliderInput,"horizontal");
+        this.slider.onchange = function(){
+            if (plot.leftFlagPos != null) {
+                plot.setFeather();
+                var plots = plot.timeplot._plots;
+                for (i = 0; i < plots.length; i++) {
+                    plots[i].fullOpacityPlot(plot.leftFlagTime, plot.rightFlagTime, plot.leftFlagPos, plot.rightFlagPos, plot.leftFeatherTime, plot.rightFeatherTime, plot.featherWidth, colors[i]);
+                    plots[i].opacityPlot.style.visibility = "visible";
+                }
+                displayFeather();
+                plot.updateByTime();
+            }
+        }
+        this.toolbarAbsoluteDiv.appendChild(featherSliderDiv);        
+                
+        var plot = this;
+        
+        var cancel = document.createElement("div");
+        cancel.setAttribute('class','cancelRange');
+        cancel.title = "Clear Selection";
+        this.toolbarAbsoluteDiv.appendChild(cancel);
+        cancel.onclick = function(){
+        	plot.core.reset();
+        }
+        
+        this.overview = document.createElement("div");
+        this.overview.setAttribute('class','timeOverview');
+        window.appendChild(this.overview);
+        
+		var mousedown = false;
+        this.shift = function(shift){
+        	if( !mousedown ){
+        		return;
+        	}
+			if( plot.eds.setShift(shift) ){
+				plot.redrawPlot();
+			}
+			setTimeout( function(){ plot.shift(shift); }, 100 );
+        }
+		
+		var shiftPressed = function(shift){
+        	mousedown = true;
+        	document.onmouseup = function(){
+        		mousedown = false;
+        		document.onmouseup = null;
+        	}
+        	plot.shift(shift);
+		}
+		
+        this.shiftLeft = document.createElement("div");
+        this.shiftLeft.setAttribute('class','shiftLeft');
+        window.appendChild(this.shiftLeft);
+        this.shiftLeft.onmousedown = function(){
+        	shiftPressed(1);
+        }
+
+        this.shiftRight = document.createElement("div");
+        this.shiftRight.setAttribute('class','shiftRight');
+        window.appendChild(this.shiftRight);
+        this.shiftRight.onmousedown = function(){
+        	shiftPressed(-1);
+        }
+
+        this.plotLabels = document.createElement("div");
+        this.plotLabels.setAttribute('class','plotLabels');
+        window.appendChild(this.plotLabels);
+        
+        this.initLabels( this.timeplot.regularGrid() );
+
+        //Finds the time corresponding to the position x on the timeplot
+        var getCorrelatedTime = function(x){
+            if (x > plot.canvas.width) 
+                x = plot.canvas.width;
+            if (isNaN(x) || x < 0) 
+                x = 0;
+            var t = plot.timeGeometry.fromScreen(x);
+            if (t == 0) 
+                return;
+            return plot.dataSources[0].getClosestValidTime(t);
+        }
+        
+        //Finds the position corresponding to the time t on the timeplot
+        var getCorrelatedPosition = function(t){
+			var x = plot.timeGeometry.toScreen(t);
+            if (x > plot.canvas.width) 
+                x = plot.canvas.width;
+            if (isNaN(x) || x < 0) 
+                x = 0;
+            return x;
+        }
+
+        //Maps the 2 positions in the right order to left and right bound of the chosen timeRange
+        var mapPositions = function(pos1, pos2){
+            if (pos1 > pos2) {
+                plot.leftFlagPos = pos2;
+                plot.rightFlagPos = pos1;
+            }
+            else 
+                if (pos1 < pos2) {
+                    plot.leftFlagPos = pos1;
+                    plot.rightFlagPos = pos2;
+                }
+                else {
+                    plot.leftFlagPos = pos1;
+                    plot.rightFlagPos = pos1;
+                }
+            plot.leftFlagTime = plot.dataSources[0].getClosestValidTime(plot.timeGeometry.fromScreen(plot.leftFlagPos));
+            plot.rightFlagTime = plot.dataSources[0].getClosestValidTime(plot.timeGeometry.fromScreen(plot.rightFlagPos));
+        }
+        
+        //Sets the divs corresponding to the actual chosen timeRange
+        var setRangeDivs = function(){
+            plot.leftFlagPole.style.visibility = "visible";
+            plot.rightFlagPole.style.visibility = "visible";
+            plot.rangeBox.style.visibility = "visible";
+            plot.timeplot.placeDiv(plot.leftFlagPole, {
+                left: plot.leftFlagPos,
+                bottom: 0,
+                height: plot.canvas.height,
+                display: "block"
+            });
+            plot.timeplot.placeDiv(plot.rightFlagPole, {
+                left: plot.rightFlagPos,
+                bottom: 0,
+                height: plot.canvas.height,
+                display: "block"
+            });
+            var boxWidth = plot.rightFlagPos - plot.leftFlagPos;
+            plot.timeplot.placeDiv(plot.rangeBox, {
+                left: plot.leftFlagPos,
+                width: boxWidth + 1,
+                height: plot.canvas.height,
+                display: "block"
+            });
+           	plot.setFeather();
+           	displayFeather();
+           	var plots = plot.timeplot._plots;
+           	for (i = 0; i < plots.length; i++) {
+               	plots[i].fullOpacityPlot(plot.leftFlagTime, plot.rightFlagTime, plot.leftFlagPos, plot.rightFlagPos, plot.leftFeatherTime, plot.rightFeatherTime, plot.featherWidth, colors[i]);
+               	plots[i].opacityPlot.style.visibility = "visible";
+           	}
+        	var unit = plot.eds.unit;
+			plot.leftHandle.innerHTML = SimileAjax.DateTime.getTimeLabel(unit,plot.leftFlagTime);
+			plot.rightHandle.innerHTML = SimileAjax.DateTime.getTimeLabel(unit,plot.rightFlagTime);
+        	var leftPos = plot.leftFlagPole.offsetLeft + plot.timeplot.getElement().offsetLeft;
+        	var rightPos = plot.rightFlagPole.offsetLeft + plot.timeplot.getElement().offsetLeft;
+        	var topPos = plot.timeplot.getElement().offsetTop + plot.timeplot.getElement().offsetHeight;
+        	
+        	plot.leftHandle.style.visibility = "visible";        	
+			plot.rightHandle.style.visibility = "visible";
+        	plot.leftHandle.style.left = leftPos+"px";
+        	plot.rightHandle.style.left = (rightPos-plot.rightHandle.offsetWidth+1)+"px";
+        	plot.leftHandle.style.top = (plot.timeplot.getElement().offsetTop)+"px";
+        	
+        	if( rightPos-leftPos < plot.leftHandle.offsetWidth + plot.rightHandle.offsetWidth ){
+				plot.rightHandle.style.top = (plot.timeplot.getElement().offsetTop+plot.rightHandle.offsetHeight)+"px";
+        	}
+        	else {
+				plot.rightHandle.style.top = (plot.timeplot.getElement().offsetTop)+"px";
+        	}
+
+			var rW = rightPos-leftPos;
+			var tW = plot.toolbarAbsoluteDiv.offsetWidth;
+			var pW = plot.canvas.width;
+			var pL = plot.timeplot.getElement().offsetLeft;
+			if( rW >= tW ){
+				plot.toolbar.style.left = leftPos+"px";
+				plot.toolbar.style.width = (rW-1)+"px";
+				plot.toolbarAbsoluteDiv.style.left = ((rW-tW)/2)+"px";
+			} 
+			else {
+				plot.toolbar.style.left = (pL+plot.leftFlagPos*(pW-tW)/(pW-rW))+"px";
+				plot.toolbar.style.width = tW+"px";
+				plot.toolbarAbsoluteDiv.style.left = "0px";
+			}
+			plot.toolbar.style.top = topPos+"px";
+			plot.toolbar.style.visibility = "visible";
+			plot.toolbarAbsoluteDiv.style.visibility = "visible";          
+        }
+
+		var diff, startLeft, startRight;		
+
+		// resets a pole after a mousemove event
+		var resetPole = function( start, shift, pos, leftPole, opposite ){
+			var newPos = start + shift;
+			var newTime = getCorrelatedTime(newPos);
+			var tickPos = plot.timeGeometry.toScreen(newTime);
+			if( tickPos == pos ){
+				return false;
+			}
+			var slice = plot.eds.getSliceIndex(newTime);
+			if( leftPole ){
+				plot.leftFlagPos = tickPos;
+				if( opposite ){
+					plot.rightFlagPos = plot.timeGeometry.toScreen(plot.eds.getSliceTime(slice+diff));
+				}
+			}
+			else {
+				plot.rightFlagPos = tickPos;
+				if( opposite ){
+					plot.leftFlagPos = plot.timeGeometry.toScreen(plot.eds.getSliceTime(slice-diff));
+				}
+			}
+			return true;
+		}
+
+		// mousemove function that causes moving selection of objects and toolbar divs		
+		var moveToolbar = function(start,actual){
+			var pixelShift = actual-start;
+			if( plot.status == 2 ){
+				if( !resetPole( startLeft, pixelShift, plot.leftFlagPos, true, false ) ){
+					return;
+				}
+			}
+			else if( plot.status == 3 ){
+				if( !resetPole( startRight, pixelShift, plot.rightFlagPos, false, false ) ){
+					return;
+				}
+			}
+			else if( plot.status == 4 ){
+				var rangeWidth = plot.rightFlagPos - plot.leftFlagPos;
+				var toolbarWidth = plot.toolbarAbsoluteDiv.offsetWidth;
+				var plotWidth = plot.canvas.width;
+				if( rangeWidth < toolbarWidth ){
+					pixelShift *= (plotWidth-rangeWidth)/(plotWidth-toolbarWidth);
+				}
+				var plotPos = actual - plot.timeplot.getElement().offsetLeft;
+				if( plotPos <= plotWidth/2 ){
+					if( !resetPole( startLeft, pixelShift, plot.leftFlagPos, true, true ) ){
+						return;
+					}
+				}
+				else {
+					if( !resetPole( startRight, pixelShift, plot.rightFlagPos, false, true ) ){
+						return;
+					}
+				}
+			}
+			mapPositions(plot.leftFlagPos,plot.rightFlagPos);
+			setRangeDivs();
+           	plot.updateByTime();
+		}
+
+		// imitates user interaction mouse move
+		var playIt = function(start,actual,reset){
+			if( !plot.paused ){
+				var pixel = plot.canvas.width / ( plot.eds.timeSlices.length - 1 ) / 5;
+				var wait = 20 * pixel;
+				if( reset ){
+					actual = 0;
+				}
+				moveToolbar(start,actual);
+				if( plot.rightFlagPos >= plot.canvas.width ){
+					reset = true;
+					wait = 1000;
+				}
+				else {
+					reset = false;
+				}
+				setTimeout( function(){ playIt(start,actual+pixel,reset) }, wait );
+			}
+		}
+
+		var deactivate;
+		document.onclick = function(){
+			if( plot.status > 1 ){
+				if( deactivate ){
+					plot.stop();
+					document.onmousemove = null;
+				}
+				else {
+					deactivate = true;
+				}
+			}
+		}
+		
+    	/**
+     	 * starts the animation
+     	*/
+		this.play = function(){
+			if( this.leftFlagPos == null ){
+				return;
+			}
+        	deactivate = false;
+			plot.paused = false;
+   			animationImage(true);
+			plot.status = 4;
+			startLeft = plot.leftFlagPos;
+			startRight = plot.rightFlagPos;
+   			diff = plot.eds.getSliceIndex(plot.rightFlagTime) - plot.eds.getSliceIndex(plot.leftFlagTime);
+			var position = Math.round(plot.leftFlagPos);
+			playIt(position,position+1,false);
+		}
+		
+    	/**
+     	 * stops the animation
+     	*/
+		this.stop = function(){
+			plot.paused = true;
+			plot.status = 0;
+       		drag.style.backgroundImage = "url(images/dragger.png)";
+   			animationImage(true);
+		}
+
+		// triggers the mousemove function to move the range and toolbar
+        var toolbarEvent = function(evt){
+        	deactivate = false;
+  			var left = getMousePosition(evt).left;
+   			startLeft = plot.leftFlagPos;
+   			startRight = plot.rightFlagPos;
+   			diff = plot.eds.getSliceIndex(plot.rightFlagTime) - plot.eds.getSliceIndex(plot.leftFlagTime);
+   			document.onmousemove = function(evt){
+    			moveToolbar(left,getMousePosition(evt).left);        	
+      		}
+        }
+        
+		// handles click on left handle
+        this.leftHandle.onclick = function(evt){
+        	if( plot.status != 2 ){
+        		plot.status = 2;
+				toolbarEvent(evt);
+        	}
+        }
+        
+		// handles click on right handle
+        this.rightHandle.onclick = function(evt){
+        	if( plot.status != 3 ){
+        		plot.status = 3;
+				toolbarEvent(evt);
+        	}
+        }
+        
+		// handles click on drag button
+        drag.onclick = function(evt){
+        	if( plot.status != 4 ){
+        		plot.status = 4;
+        		drag.style.backgroundImage = "url(images/dragger-click.png)";
+				toolbarEvent(evt);
+        	}
+        }
+                
+        // handles mousedown-Event on timeplot
+        var mouseDownHandler = function(elmt, evt, target){
+        	if( plot.dataSources.length > 0 ){
+            	var x = Math.round(SimileAjax.DOM.getEventRelativeCoordinates(evt, plot.canvas).x);
+            	if (plot.status == 0 ) {
+                	plot.core.reset();
+                	plot.status = 1;
+                	plot.mouseDownTime = getCorrelatedTime(x);
+                	plot.mouseDownPos = plot.timeGeometry.toScreen(plot.mouseDownTime);
+                	mapPositions(plot.mouseDownPos, plot.mouseDownPos, plot.mouseDownTime, plot.mouseDownTime);
+            	}
+            }
+        }
+        
+        // handles mousemove-Event on timeplot
+        var mouseMoveHandler = function(elmt, evt, target){        	
+        	if( plot.dataSources.length > 0 ){
+            	var x = Math.round(SimileAjax.DOM.getEventRelativeCoordinates(evt, plot.canvas).x);
+            	if (plot.status == 1 && !plot.core.takeTime) {
+                	plot.mouseTempTime = getCorrelatedTime(x);
+                	plot.mouseTempPos = plot.timeGeometry.toScreen(plot.mouseTempTime);
+                	mapPositions(plot.mouseDownPos, plot.mouseTempPos, plot.mouseDownTime, plot.mouseTempTime);
+                	setRangeDivs();
+            	}
+            }
+        }
+                
+	this.selectTimerange = function(min,max){
+		var minTime = new Date(min);
+		var maxTime = new Date(max);
+		var minPos = getCorrelatedPosition(minTime);
+		var maxPos = getCorrelatedPosition(maxTime);
+                mapPositions(minPos, maxPos, minTime, maxTime);
+                setRangeDivs();
+                plot.updateByTime();
+		animationImage(true);
+	}
+
+        // handles mouseup-Event on timeplot
+        var mouseUpHandler = function(elmt, evt, target){
+        	if( plot.dataSources.length > 0 ){
+            var x = Math.round(SimileAjax.DOM.getEventRelativeCoordinates(evt, plot.canvas).x);
+            if (plot.core.takeTime) {
+                plot.core.setElementsTime(getCorrelatedTime(x));
+            }
+            else 
+                if (plot.status == 1) {
+                    plot.status = 0;
+                    plot.mouseUpTime = getCorrelatedTime(x);
+                    plot.mouseUpPos = plot.timeGeometry.toScreen(plot.mouseUpTime);
+                    mapPositions(plot.mouseDownPos, plot.mouseUpPos, plot.mouseDownTime, plot.mouseUpTime);
+                    setRangeDivs();
+                    plot.updateByTime();
+   					animationImage(true);
+                    displayFeather();
+                }
+            }
+        }
+		
+        // handles mouseout-Event on timeplot
+		var mouseOutHandler = function(elmt, evt, target){
+        	if( plot.dataSources.length > 0 ){		
+        		var x = Math.round(SimileAjax.DOM.getEventRelativeCoordinates(evt, plot.canvas).x);
+        		var y = Math.round(SimileAjax.DOM.getEventRelativeCoordinates(evt, plot.canvas).y);
+            	if (x > plot.canvas.width-2 || isNaN(x) || x < 2 )
+					plot.hoverUnselect(true);
+            	if (y > plot.canvas.height-2 || isNaN(y) || y < 2 )
+					plot.hoverUnselect(true);
+			}
+		}
+
+        // handles mouse(h)over-Event on timeplot
+        var mouseHoverHandler = function(elmt, evt, target){
+        	if( plot.dataSources.length > 0 ){        
+				plot.core.undoHover(false);
+				var x = Math.round(SimileAjax.DOM.getEventRelativeCoordinates(evt, plot.canvas).x);
+				var time = getCorrelatedTime(x);
+        		var slices = plot.eds.timeSlices;
+				for (var i = 0; i < slices.length; i++) {
+            		if (slices[i].date.getTime() == time.getTime()){
+						if( plot.hoverSlice != undefined && plot.hoverSlice.date.getTime() == slices[i].date.getTime() ){
+							return;						
+						}
+						plot.hoverSlice = slices[i];
+            			var objects = slices[i].elements;
+            			for (var j = 0; j < objects.length; j++){
+                			for (var k = 0; k < objects[j].length; k++){
+                       			objects[j][k].setHover(true);
+							}
+						}
+						break;
+					}
+				}
+        		plot.core.updateTableAndMap(true);
+        	}
+		}		
+
+		this.redrawPlot = function(){
+			plot.clearTimeplot();				
+			plot.eds.reset(this.timeGeometry);
+	       	plot.timeplot.repaint();
+			if( plot.leftFlagPos != null ){
+				plot.leftFlagPos = getCorrelatedPosition(plot.leftFlagTime);
+				plot.rightFlagPos = getCorrelatedPosition(plot.rightFlagTime);
+				setRangeDivs();
+			}
+			else {
+				plot.polesBySlices();
+			}				
+			plot.initLabels([]);
+			plot.updateOverview();
+		}
+
+    	/**
+     	 * handles zoom of the timeplot
+     	 * @param {int} delta the change of zoom
+     	 * @param {Date} time a time that corresponds to a slice, that was clicked
+     	*/
+		this.zoom = function(delta,time){
+			if( plot.eventSources.length == 0 ){
+				setTimeZoom(0);
+				return false;
+			}
+			if( time == null ){
+				time = getCorrelatedTime(plot.canvas.width/2);
+			}
+			if( plot.eds.setZoom(delta,time,plot.leftFlagTime,plot.rightFlagTime) ){
+				this.redrawPlot();
+			}
+			setTimeZoom(plot.eds.getZoom());
+			return true;
+		}		
+
+		// handles mousewheel event on the timeplot		
+		var mouseWheelHandler = function(elmt, evt, target){
+			if (evt.preventDefault){
+				evt.preventDefault();
+			}
+			if( plot.dataSources.length == 0 ){
+				return;
+			}
+			var delta = 0;
+			if (!evt) evt = window.event;
+			if (evt.wheelDelta) {
+				delta = evt.wheelDelta/120; 
+				if (window.opera) delta = -delta;
+			}
+			else if (evt.detail) {
+				delta = -evt.detail/3;
+			}
+			if (delta){
+				var x = Math.round(SimileAjax.DOM.getEventRelativeCoordinates(evt, plot.canvas).x);
+				var time = getCorrelatedTime(x);
+				plot.zoom(delta,time);
+			}		
+		}
+				
+        var timeplotElement = this.timeplot.getElement();
+        SimileAjax.DOM.registerEvent(timeplotElement, "mousedown", mouseDownHandler);
+        SimileAjax.DOM.registerEvent(timeplotElement, "mousemove", mouseMoveHandler);
+        SimileAjax.DOM.registerEvent(timeplotElement, "mouseup", mouseUpHandler);
+        SimileAjax.DOM.registerEvent(timeplotElement, "mousemove", mouseHoverHandler);
+        SimileAjax.DOM.registerEvent(timeplotElement, "mouseout", mouseOutHandler);
+        //SimileAjax.DOM.registerEvent(timeplotElement, "mousewheel", mouseWheelHandler);
+        
+        this.setCanvas();
+        
+    },
+    
+    /**
+     * updates the data objects percentages after a selection on the timeplot had been performed
+     */
+    updateByTime: function(){
+        this.setFeather();
+        var slices = this.eds.timeSlices;
+        var lfs, ls, rs, rfs;
+        for (var i = 0; i < slices.length; i++) {
+            if (slices[i].date.getTime() == this.leftFeatherTime.getTime()) 
+                lfs = i;
+            if (slices[i].date.getTime() == this.leftFlagTime.getTime()) 
+                ls = i;
+            if (slices[i].date.getTime() == this.rightFlagTime.getTime()) 
+                rs = i;
+            if (slices[i].date.getTime() == this.rightFeatherTime.getTime()) 
+                rfs = i;
+			if( slices[i].date.getTime() >= this.leftFlagTime.getTime() && slices[i].date.getTime() <= this.rightFlagTime.getTime() )
+				slices[i].selected = true;
+        }
+        for (var i = 0; i < slices.length; i++) {
+            var objects = slices[i].elements;
+            for (var j = 0; j < objects.length; j++) 
+                for (var k = 0; k < objects[j].length; k++) 
+                    if (i > lfs && i < ls) 
+                        objects[j][k].setPercentage((i - lfs) / (ls - lfs));
+                    else 
+                        if (i >= ls && i <= rs)
+                            objects[j][k].setPercentage(1);
+                        else 
+                            if (i > rs && i < rfs) 
+                                objects[j][k].setPercentage((rfs - i) / (rfs - rs));
+                            else 
+                                objects[j][k].setPercentage(0);
+        }
+        this.core.updateTableAndMap(false);
+    },
+    
+    /**
+     * sets the background canvas of the timeplot window (or resets it after resizing the browser window)
+     */
+    setCanvas: function(){
+        var cv = document.createElement("canvas");
+        cv.id = "plotCanvas";     
+        var window = document.getElementById(this.window);    
+        window.appendChild(cv);
+        cv.width = window.clientWidth;
+        cv.height = window.clientHeight;
+        if (!cv.getContext && G_vmlCanvasManager) 
+            cv = G_vmlCanvasManager.initElement(cv);
+        var ctx = cv.getContext('2d');
+        var gradient = ctx.createLinearGradient(0, 0, 0, this.canvas.height); 
+        gradient.addColorStop(0, '#c9c9cb');
+        gradient.addColorStop(1, '#ededed ');
+        ctx.fillStyle = gradient;
+        ctx.fillRect(0, 0, window.clientWidth, window.clientHeight);
+    },
+    
+    /**
+     * resets the timeplot to non selection status
+     */
+    resetTimeplot: function(){
+    
+        this.leftFlagPole.style.visibility = "hidden";
+        this.rightFlagPole.style.visibility = "hidden";
+        this.rangeBox.style.visibility = "hidden";
+        this.leftFeather.style.visibility = "hidden";
+        this.rightFeather.style.visibility = "hidden";
+        this.leftHandle.style.visibility = "hidden";
+        this.rightHandle.style.visibility = "hidden";
+        this.toolbar.style.visibility = "hidden";
+        this.toolbarAbsoluteDiv.style.visibility = "hidden";
+        this.poles.style.visibility = "hidden";
+                
+        var plots = this.timeplot._plots;
+        for (var i = 0; i < plots.length; i++) 
+            plots[i].opacityPlot.style.visibility = "hidden";
+        
+        var slices = this.eds.timeSlices;
+        if( slices != undefined ){
+        	for (var i = 0; i < slices.length; i++){ 
+            	slices[i].selected = false;
+            }
+        }
+
+        this.status = 0;
+        this.stop();
+		document.onmousemove = null;
+		animationImage(false);		        	
+        
+        this.leftFlagPos = null;
+        this.leftFlagTime = null;
+        this.rightFlagPos = null;
+        this.rightFlagTime = null;
+        
+        this.mouseDownTime = null;
+        this.mouseUpTime = null;
+        this.mouseTempTime = null;
+        
+        this.mouseDownPos = null;
+        this.mouseUpPos = null;
+        this.mouseTempPos = null;
+    },
+    
+    /**
+     * sets a pole on the timeplot
+     * @param {Date} time the time of the specific timeslice
+     * @param {int[]} the number of selected elements per dataset
+     */
+	setPoles: function( poles ){
+	
+        this.poles.style.visibility = "visible";
+        var cv = this.poles.getElementsByTagName("canvas")[0];
+        cv.width = this.canvas.width;
+        cv.height = this.canvas.height;
+        if (!cv.getContext && G_vmlCanvasManager) 
+            cv = G_vmlCanvasManager.initElement(cv);
+        var ctx = cv.getContext('2d');
+        ctx.clearRect(0,0,this.canvas.width,this.canvas.height);
+
+		var plots = this.timeplot._plots;
+		for( var z=0; z<poles.length; z++ ){ 
+			var elements = poles[z].elements;
+			var time = poles[z].time;
+	        var pos = this.timeGeometry.toScreen(time);
+			var heights = [];
+			var h = 0;
+			for ( var i = 0; i < elements.length; i++) {
+				var data = plots[i]._dataSource.getData();
+				for ( var j = 0; j < data.times.length; j++){ 
+					if (data.times[j].getTime() == time.getTime()) {
+						var height = plots[i]._valueGeometry.toScreen(plots[i]._dataSource.getData().values[j]) * elements[i];
+						heights.push(height);
+						if( height > h )
+							h = height;
+						break;
+					}
+				}
+			}
+			ctx.fillStyle = "rgb(102,102,102)";
+        	ctx.beginPath();
+			ctx.rect(pos-1,100-h,2,h);
+      		ctx.fill();		
+			for( var i=0; i<elements.length; i++ ){
+				if( heights[i] > 0 ){
+					ctx.fillStyle = "rgba("+colors[i].r1+","+colors[i].g1+","+colors[i].b1+",0.6)";
+					ctx.beginPath();
+					ctx.arc(pos, 100-heights[i], 2.5, 0, Math.PI*2, true);
+					ctx.closePath();
+					ctx.fill();
+				}
+			}
+		}
+	},
+	
+    /**
+     * updates the timeplot by setting place poles, after selections had been executed in map or table.
+     * its called by the core component.
+     */
+    polesBySlices: function(){
+        var slices = this.eds.timeSlices;
+        var poles = [];
+        for (var i = 0; i < slices.length; i++) {
+			var elements = [];
+			var neededPole = false;
+			for (var j = 0; j < slices[i].elements.length; j++){
+				var count = 0;
+				for (var k = 0; k < slices[i].elements[j].length; k++)
+					if ( ( !slices[i].selected && slices[i].elements[j][k].percentage == 1 ) || slices[i].elements[j][k].hoverSelect) {
+						neededPole = true;
+						count++;
+					}
+				if( slices[i].elements[j].length == 0 )
+					elements.push( slices[i].elements[j].length );
+				else 
+					elements.push( count / slices[i].elements[j].length );
+			}
+			if( neededPole ){
+				poles.push( { time: slices[i].date, elements: elements } );
+			}
+		}
+		this.setPoles(poles);
+    },
+
+    /**
+     * calculates the new feather bounds
+     */
+    setFeather: function(){
+		this.leftFeatherTime = this.leftFlagTime; 
+		this.rightFeatherTime = this.rightFlagTime; 
+        this.featherWidth = Math.floor(this.canvas.width / this.eds.timeSlices.length * this.slider.getValue());
+        var slices = this.eds.timeSlices;
+        for (var i = 0; i < slices.length; i++) {
+            if (slices[i].date.getTime() == this.leftFlagTime.getTime()) {
+                if (i - this.slider.getValue() >= 0) 
+                    this.leftFeatherTime = slices[i - this.slider.getValue()].date;
+                else 
+                    this.leftFeatherTime = slices[0].date;
+            }
+            if (slices[i].date.getTime() == this.rightFlagTime.getTime()) {
+                if (i + this.slider.getValue() < slices.length) 
+                    this.rightFeatherTime = slices[i + this.slider.getValue()].date;
+                else 
+                    this.rightFeatherTime = slices[slices.length - 1].date;
+            }
+        }
+    },
+	
+    /**
+     * undo hover selection of elements in the hovered slice
+     */
+	hoverUnselect: function(update){
+		if( this.hoverSlice != undefined ){
+   			var objects = this.hoverSlice.elements;
+   			for (var j = 0; j < objects.length; j++){
+       			for (var k = 0; k < objects[j].length; k++){
+           			objects[j][k].setHover(false);
+				}
+			}
+			this.hoverSlice = undefined;
+			if( update ){
+        		this.core.updateTableAndMap(true);
+        	}
+		}
+	},
+	
+    /**
+     * returns the approximate left position of a slice inside the overview representation
+     * @param {Date} time time of the slice
+     */
+	getOverviewLeft: function(time){
+		var w = this.overview.offsetWidth;
+		var s = this.eds.earliest().getTime();
+		var e = this.eds.latest().getTime();
+		var t = time.getTime();		
+		return Math.round(w*(t-s)/(e-s));
+	},
+	
+    /**
+     * visualizes the overview div (shows viewable part of zoomed timeplot)
+     */
+	initOverview: function(){
+        var labels = this.timeGeometry._grid;
+        if( labels.length == 0 ){
+        	var plot = this;
+        	setTimeout( function(){ plot.initOverview(); }, 10 );
+        	return;
+        }
+
+        this.overview.style.width = this.canvas.width+"px";
+
+		this.overview.innerHTML = "";
+
+        this.overviewRange = document.createElement("div");
+        this.overviewRange.setAttribute('class','overviewRange');
+        this.overview.appendChild(this.overviewRange);
+
+        for( var i=0; i<labels.length; i++ ){
+        	var label = document.createElement("div");
+        	label.setAttribute('class','overviewLabel');
+        	label.innerHTML = labels[i].label;
+        	label.style.left = Math.floor(labels[i].x)+"px";
+        	this.overview.appendChild(label);
+        }
+
+		this.updateOverview();
+	},
+
+    /**
+     * visualizes the labels of the timeplot
+     */
+	initLabels: function(labels){
+		if( labels.length == 0 ){
+	        labels = this.timeGeometry._grid;
+    	    if( labels.length == 0 ){
+        		var plot = this;
+        		setTimeout( function(){ plot.initLabels([]); }, 10 );
+        		return;
+        	}
+        }
+        this.plotLabels.style.width = this.canvas.width+"px";
+		this.plotLabels.innerHTML = "";
+        for( var i=0; i<labels.length; i++ ){
+        	var label = document.createElement("div");
+        	label.setAttribute('class','plotLabel');
+        	label.innerHTML = labels[i].label;
+        	label.style.left = Math.floor(labels[i].x)+"px";
+        	this.plotLabels.appendChild(label);
+        }
+	},	
+	
+    /**
+     * updates the overview div
+     */
+	updateOverview: function(){
+		if( this.eds.getZoom() > 0 ){
+			this.plotLabels.style.visibility = "hidden";
+			this.timeGeometry._hideLabels = false;
+			this.overview.style.visibility = "visible";
+			this.shiftLeft.style.visibility = "visible";
+			this.shiftRight.style.visibility = "visible";
+			var left = this.getOverviewLeft( this.eds.timeSlices[this.eds.leftSlice].date );	
+			var right = this.getOverviewLeft( this.eds.timeSlices[this.eds.rightSlice].date );
+			this.overviewRange.style.left = left+"px";	
+			this.overviewRange.style.width = (right-left)+"px";
+		}
+		else {
+			this.timeGeometry._hideLabels = true;
+			this.plotLabels.style.visibility = "visible";
+			this.overview.style.visibility = "hidden";
+			this.shiftLeft.style.visibility = "hidden";
+			this.shiftRight.style.visibility = "hidden";
+		}
+	},
+	
+    /**
+     * returns the time slices which are created by the extended data source
+     */
+	getSlices: function(){
+		return this.eds.timeSlices;
+	}
+	
+}