Mercurial > hg > STI-GWT
view war/scripts/sti/STITimeplot.js @ 41:90b7bbc9962f default
Merged the bugfixes
author | Sebastian Kruse <skruse@mpiwg-berlin.mpg.de> |
---|---|
date | Thu, 06 Dec 2012 18:09:00 +0100 |
parents | cf06b77a8bbd |
children |
line wrap: on
line source
/** * 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; } }