Mercurial > hg > NetworkVis
diff d3s_examples/python-neo4jrestclient/static/platin/js/Time/TimeDataSource.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/Time/TimeDataSource.js Thu Oct 01 17:17:27 2015 +0200 @@ -0,0 +1,443 @@ +/* +* TimeDataSource.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 TimeDataSource, TimeSlice, TimeStack + * implementation for aggregation of time items + * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de) + * @release 1.0 + * @release date: 2012-07-27 + * @version date: 2012-07-27 + * + * @param {JSON} options time configuration + */ +function TimeDataSource(options) { + + this.options = options; + this.timeSlices = []; + this.unit + this.minDate + this.maxDate + this.eventSources + this.events + this.leftSlice + this.rightSlice + + this.hashMapping + +}; + +TimeDataSource.prototype = { + + findTimeUnits : function(granularity, timeUnit, pixels) { + + var time = SimileAjax.DateTime; + this.availableUnits = []; + var givenUnits = SimileAjax.DateTime.gregorianUnitLengths; + for (var i = 0; i < givenUnits.length; i++) { + if (granularity > i) { + continue; + } + var slices = 0; + var t = new Date(this.minDate.getTime()); + do { + time.roundDownToInterval(t, i, undefined, 1, 0); + slices++; + time.incrementByInterval(t, i, undefined); + } while( t.getTime() <= this.maxDate.getTime() && slices < pixels+2 ); + if (slices > 0 && slices <= pixels) { + this.availableUnits.push({ + unit : i, + slices : slices, + label : SimileAjax.DateTime.Strings[GeoTemConfig.language][i] + }); + } + } + var unitDiff200 = pixels + 1; + for (var i = 0; i < this.availableUnits.length; i++) { + var diff = Math.abs(this.availableUnits[i].slices - 200); + if (diff < unitDiff200) { + unitDiff200 = diff; + this.unit = this.availableUnits[i].unit; + } + } + + }, + + getUnitIndex : function() { + for (var i = 0; i < this.availableUnits.length; i++) { + if (this.unit == this.availableUnits[i].unit) { + return i; + } + } + return 0; + }, + + setTimeUnit : function(unit) { + this.unit = unit; + this.initializeSlices(); + }, + + /** + * initializes the TimeDataSource + * @param {Timeplot.ColumnSource[]} dataSources the column sources corresponding to the data sets + * @param {Timeplot.DefaultEventSource[]} eventSources the event sources corresponding to the column sources + * @param {TimeObject[][]} timeObjects an array of time objects of different sets + * @param {SimileAjax.DateTime} granularity the time granularity of the given data + */ + initialize : function(dataSources, eventSources, timeObjects, granularity, timeUnit, pixels) { + + this.dataSources = dataSources; + this.eventSources = eventSources; + this.timeObjects = timeObjects; + + this.minDate = undefined; + this.maxDate = undefined; + this.hashMapping = []; + this.projHashMapping = []; + + for (var i = 0; i < timeObjects.length; i++) { + this.hashMapping.push([]); + this.projHashMapping.push([]); + for (var j = 0; j < timeObjects[i].length; j++) { + var o = timeObjects[i][j]; + if (o.isTemporal) { + var g = o.dates[this.options.timeIndex].granularity; + //o.getTimeGranularity(this.options.timeIndex); + if (g == null) { + continue; + } + var time = o.dates[this.options.timeIndex].date; + //o.getDate(this.options.timeIndex); + if (this.minDate == undefined || time.getTime() < this.minDate.getTime()) { + this.minDate = time; + } + if (this.maxDate == undefined || time.getTime() > this.maxDate.getTime()) { + this.maxDate = time; + } + } + } + } + + if (this.minDate == undefined) { + this.minDate = this.options.defaultMinDate; + this.maxDate = this.options.defaultMaxDate; + } + + this.findTimeUnits(granularity, timeUnit, pixels); + this.initializeSlices(); + + }, + + initializeSlices : function() { + for (var i = 0; i < this.dataSources.length; i++) { + this.dataSources[i]._range = { + earliestDate : null, + latestDate : null, + min : 0, + max : 0 + }; + } + this.timeSlices = []; + var time = SimileAjax.DateTime; + var t = new Date(this.minDate.getTime() - 0.9 * time.gregorianUnitLengths[this.unit]); + do { + time.roundDownToInterval(t, this.unit, undefined, 1, 0); + var slice = new TimeSlice(SimileAjax.NativeDateUnit.cloneValue(t), this.timeObjects.length, this.dataSources.length); + this.timeSlices.push(slice); + time.incrementByInterval(t, this.unit, undefined); + } while (t.getTime() <= this.maxDate.getTime() + 1.1 * time.gregorianUnitLengths[this.unit]); + + for (var i = 0; i < this.timeObjects.length; i++) { + var projId = i; + if( this.dataSources.length == 1 ){ + projId = 0; + } + for (var j = 0; j < this.timeObjects[i].length; j++) { + var o = this.timeObjects[i][j]; + if (o.isTemporal) { + var date = o.dates[this.options.timeIndex].date; + //o.getDate(this.options.timeIndex); + for (var k = 0; k < this.timeSlices.length - 1; k++) { + var t1 = this.timeSlices[k].date.getTime(); + var t2 = this.timeSlices[k + 1].date.getTime(); + var stack = null, projStack = null; + if (date >= t1 && date < t2) { + stack = this.timeSlices[k].getStack(i); + projStack = this.timeSlices[k].getProjStack(projId); + } + if (k == this.timeSlices.length - 2 && date >= t2) { + stack = this.timeSlices[k + 1].getStack(i); + projStack = this.timeSlices[k + 1].getProjStack(projId); + } + if (stack != null) { + stack.addObject(o); + projStack.addObject(o); + this.hashMapping[i][o.index] = stack; + this.projHashMapping[i][o.index] = projStack; + break; + } + } + } + } + } + + this.events = []; + for (var i = 0; i < this.eventSources.length; i++) { + var eventSet = []; + for (var j = 0; j < this.timeSlices.length; j++) { + var value = new Array("" + this.timeSlices[j].projStacks[i].value); + eventSet.push({ + date : this.timeSlices[j].date, + value : value + }); + } + this.eventSources[i].loadData(eventSet); + this.events.push(eventSet); + } + + this.leftSlice = 0; + this.rightSlice = this.timeSlices.length - 1; + + }, + + getSliceNumber : function() { + return this.timeSlices.length; + }, + + /** + * computes the slice index corresponding to a given time + * @param {Date} time the given time + * @return the corresponding slice index + */ + getSliceIndex : function(time) { + for (var i = 0; i < this.timeSlices.length; i++) { + if (time == this.timeSlices[i].date) { + return i; + } + } + }, + + /** + * returns the time of a specific time slice + * @param {int} time the given slice index + * @return the corresponding slice date + */ + getSliceTime : function(index) { + return this.timeSlices[index].date; + }, + + /** + * shifts the actual zoomed range + * @param {int} delta the value to shift (negative for left shift, positive for right shift) + * @return boolean value, if the range could be shifted + */ + setShift : function(delta) { + if (delta == 1 && this.leftSlice != 0) { + this.leftSlice--; + this.rightSlice--; + return true; + } else if (delta == -1 && this.rightSlice != this.timeSlices.length - 1) { + this.leftSlice++; + this.rightSlice++; + return true; + } else { + return false; + } + }, + + /** + * zooms the actual range + * @param {int} delta the value to zoom (negative for zoom out, positive for zoom in) + * @param {Date} time the corresponding time of the actual mouse position on the plot + * @param {Date} leftTime the time of the left border of a selected timerange or null + * @param {Date} rightTime the time of the right border of a selected timerange or null + * @return boolean value, if the range could be zoomed + */ + setZoom : function(delta, time, leftTime, rightTime) { + var n1 = 0; + var n2 = 0; + var m = -1; + if (delta > 0) { + m = 1; + if (leftTime != null) { + n1 = this.getSliceIndex(leftTime) - this.leftSlice; + n2 = this.rightSlice - this.getSliceIndex(rightTime); + } else { + slice = this.getSliceIndex(time); + if (slice == this.leftSlice || slice == this.rightSlice) { + return; + } + n1 = slice - 1 - this.leftSlice; + n2 = this.rightSlice - slice - 1; + } + } else if (delta < 0) { + + n1 = this.leftSlice; + n2 = this.timeSlices.length - 1 - this.rightSlice; + } + + var zoomSlices = 2 * delta; + if (Math.abs(n1 + n2) < Math.abs(zoomSlices)) { + zoomSlices = n1 + n2; + } + + if (n1 + n2 == 0) { + return false; + } + + var m1 = Math.round(n1 / (n1 + n2) * zoomSlices); + var m2 = zoomSlices - m1; + + this.leftSlice += m1; + this.rightSlice -= m2; + + return true; + }, + + /** + * resets the plots by loading data of actual zoomed range + */ + reset : function(timeGeometry) { + for (var i = 0; i < this.eventSources.length; i++) { + this.eventSources[i].loadData(this.events[i].slice(this.leftSlice, this.rightSlice + 1)); + if (i + 1 < this.eventSources.length) { + timeGeometry._earliestDate = null; + timeGeometry._latestDate = null; + } + + } + }, + + /** + * Getter for actual zoom + * @return actual zoom value + */ + getZoom : function() { + if (this.timeSlices == undefined) { + return 0; + } + return Math.round((this.timeSlices.length - 3) / 2) - Math.round((this.rightSlice - this.leftSlice - 2) / 2); + }, + + /** + * Getter for date of the first timeslice + * @return date of the first timeslice + */ + earliest : function() { + return this.timeSlices[0].date; + }, + + /** + * Getter for date of the last timeslice + * @return date of the last timeslice + */ + latest : function() { + return this.timeSlices[this.timeSlices.length - 1].date; + }, + + setOverlay : function(timeObjects) { + for (var i = 0; i < this.timeSlices.length; i++) { + this.timeSlices[i].reset(); + } + for (var j in timeObjects ) { + for (var k in timeObjects[j] ) { + var o = timeObjects[j][k]; + if (o.isTemporal) { + if (o.getTimeGranularity(this.options.timeIndex) == null) { + continue; + } + this.hashMapping[j][o.index].overlay += o.weight; + this.projHashMapping[j][o.index].overlay += o.weight; + } + } + } + }, + + size : function() { + if (this.timeSlices.length == 0) { + return 0; + } + return this.timeSlices[0].stacks.length; + } +}; + +/** + * small class that represents a time slice of the actual timeplot. + * it has a specific date and contains its corrsponding data objects as well + */ +function TimeSlice(date, rows, projRows) { + + this.date = date; + this.selected = false; + + this.stacks = []; + this.projStacks = []; + for (var i = 0; i < rows; i++) { + this.stacks.push(new TimeStack()); + } + for (var i = 0; i < projRows; i++) { + this.projStacks.push(new TimeStack()); + } + + this.getStack = function(row) { + return this.stacks[row]; + }; + + this.getProjStack = function(row) { + return this.projStacks[row]; + }; + + this.reset = function() { + for (var i in this.projStacks ) { + this.stacks[i].overlay = 0; + this.projStacks[i].overlay = 0; + } + }; + + this.overlay = function() { + var value = 0; + for (var i in this.projStacks ) { + if (this.projStacks[i].overlay > value) { + value = this.projStacks[i].overlay; + } + } + return value; + }; + +}; + +/** + * small class that represents a stack for a time slice which + * holds items for different datasets for the specific time range + */ +function TimeStack() { + + this.overlay = 0; + this.value = 0; + this.elements = []; + + this.addObject = function(object) { + this.elements.push(object); + this.value += object.weight; + }; + +};