comparison d3s_examples/python-neo4jrestclient/static/platin/js/FuzzyTimeline/FuzzyTimelineRangeBars.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
comparison
equal deleted inserted replaced
7:45dad9e38c82 8:18ef6948d689
1 /*
2 * FuzzyTimelineRangeBars.js
3 *
4 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301 USA
20 */
21
22 /**
23 * @class FuzzyTimelineRangeBars
24 * Implementation for a fuzzy time-ranges barchart
25 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
26 *
27 * @param {HTML object} parent div to append the FuzzyTimeline
28 */
29 function FuzzyTimelineRangeBars(parent) {
30
31 this.rangeBars = this;
32
33 this.parent = parent;
34 this.options = parent.options;
35
36 this.datasets;
37 //contains selected data
38 this.selected = undefined;
39
40 this.datasetsPlot;
41 this.highlightedDatasetsPlot;
42 this.yValMin;
43 this.yValMax;
44 this.displayType;
45
46 this.plotDiv = this.parent.gui.plotDiv;
47
48 this.spanWidth;
49 this.tickSpans;
50 this.plot;
51 }
52
53 FuzzyTimelineRangeBars.prototype = {
54
55 initialize : function(datasets) {
56 var rangeBar = this;
57
58 rangeBar.datasets = datasets;
59 rangeBar.selected = [];
60 },
61
62 createPlot : function(datasets) {
63 var rangeBar = this;
64 var plots = [];
65 var objectHashes = [];
66
67 //-1 because last span is always empty (only there to have the ending date)
68 var tickCount = rangeBar.tickSpans.length-1;
69
70 $(datasets).each(function(){
71 var chartDataCounter = [];
72 var objectHash = new Object();
73
74 for (var i = 0; i < tickCount; i++){
75 chartDataCounter[i]=0;
76 }
77 //check if we got "real" datasets, or just array of objects
78 var datasetObjects = this;
79 if (typeof this.objects !== "undefined")
80 datasetObjects = this.objects;
81 $(datasetObjects).each(function(){
82 var ticks = rangeBar.parent.getTicks(this, rangeBar.spanWidth);
83 if (typeof ticks !== "undefined"){
84 var exactTickCount =
85 ticks.firstTickPercentage+
86 ticks.lastTickPercentage+
87 (ticks.lastTick-ticks.firstTick-1);
88 for (var i = ticks.firstTick; i <= ticks.lastTick; i++){
89 var weight = 0;
90 //calculate the weight for each span, that the object overlaps
91 if (rangeBar.parent.options.timelineMode == 'fuzzy'){
92 //in fuzzy mode, each span gets just a fraction of the complete weight
93 if (i == ticks.firstTick)
94 weight = this.weight * ticks.firstTickPercentage/exactTickCount;
95 else if (i == ticks.lastTick)
96 weight = this.weight * ticks.lastTickPercentage/exactTickCount;
97 else
98 weight = this.weight * 1/exactTickCount;
99 } else if (rangeBar.parent.options.timelineMode == 'stacking'){
100 //in stacking mode each span gets the same amount.
101 //(besides first and last..)
102 if (i == ticks.firstTick)
103 weight = this.weight * ticks.firstTickPercentage;
104 else if (i == ticks.lastTick)
105 weight = this.weight * ticks.lastTickPercentage;
106 else
107 weight = this.weight;
108 }
109
110 chartDataCounter[i] += weight;
111 //add this object to the hash
112 if (typeof objectHash[i] === "undefined")
113 objectHash[i] = [];
114 objectHash[i].push(this);
115 }
116 }
117 });
118
119 //scale according to selected type
120 chartDataCounter = rangeBar.parent.scaleData(chartDataCounter);
121
122 //transform data so it can be passed to the flot barchart
123 var plotData = [];
124 for (var i = 0; i < tickCount; i++){
125 plotData[i] = [];
126 plotData[i][0] = i;
127 plotData[i][1] = chartDataCounter[i];
128 }
129
130 //delete bars with 0 values
131 for (var i = 0; i < tickCount; i++){
132 if (plotData[i][1]==0)
133 delete plotData[i];
134 }
135
136 plots.push(plotData);
137 objectHashes.push(objectHash);
138 });
139
140 return {plots:plots, hashs:objectHashes};
141 },
142
143 showPlot : function(){
144 var rangeBar = this;
145 var plot = rangeBar.datasetsPlot;
146 var highlight_select_plot = $.merge([],plot);
147
148 //see if there are selected/highlighted values
149 if (rangeBar.highlightedDatasetsPlot instanceof Array){
150 //check if plot is some other - external - graph
151 if (plot === rangeBar.datasetsPlot)
152 highlight_select_plot = $.merge(highlight_select_plot,rangeBar.highlightedDatasetsPlot);
153 }
154
155 var tickCount = rangeBar.tickSpans.length-1;
156 var ticks = [];
157
158 var axisFormatString = "YYYY";
159 if (rangeBar.spanWidth<60*1000){
160 axisFormatString = "YYYY/MM/DD HH:mm:ss";
161 } else if (rangeBar.spanWidth<60*60*1000) {
162 axisFormatString = "YYYY/MM/DD HH:mm";
163 } else if (rangeBar.spanWidth<24*60*60*1000){
164 axisFormatString = "YYYY/MM/DD HH";
165 } else if (rangeBar.spanWidth<31*24*60*60*1000){
166 axisFormatString = "YYYY/MM/DD";
167 } else if (rangeBar.spanWidth<12*31*24*60*60*1000){
168 axisFormatString = "YYYY/MM";
169 }
170 //only show ~10 labels on the x-Axis (increase if zoomed)
171 var labelModulo = Math.ceil(tickCount/(10*rangeBar.parent.zoomFactor));
172 for (var i = 0; i < tickCount; i++){
173 var tickLabel = "";
174 if (i%labelModulo==0){
175 tickLabel = rangeBar.tickSpans[i].format(axisFormatString);
176 }
177 while ((tickLabel.length > 1) && (tickLabel.indexOf("0")==0))
178 tickLabel = tickLabel.substring(1);
179 ticks[i] = [i,tickLabel];
180 }
181
182 var options = {
183 series:{
184 bars:{show: true}
185 },
186 grid: {
187 hoverable: true,
188 clickable: true,
189 backgroundColor: rangeBar.parent.options.backgroundColor,
190 borderWidth: 0,
191 minBorderMargin: 0,
192 },
193 xaxis: {
194 ticks: ticks,
195 min : 0,
196 max : tickCount,
197 },
198 yaxis: {
199 min : rangeBar.yValMin,
200 max : rangeBar.yValMax*1.05
201 },
202 tooltip: true,
203 tooltipOpts: {
204 content: function(label, xval, yval, flotItem){
205 var fromLabel = rangeBar.tickSpans[xval].format(axisFormatString);
206 while ((fromLabel.length > 1) && (fromLabel.indexOf("0")==0))
207 fromLabel = fromLabel.substring(1);
208 var toLabel = rangeBar.tickSpans[xval+1].clone().subtract("ms",1).format(axisFormatString);
209 while ((toLabel.length > 1) && (toLabel.indexOf("0")==0))
210 toLabel = toLabel.substring(1);
211 highlightString = fromLabel + " - " + toLabel + " : ";
212 //(max.)2 Nachkomma-Stellen von y-Wert anzeigen
213 highlightString += Math.round(yval*100)/100;
214
215 return highlightString;
216 }
217 },
218 selection: {
219 mode: "x"
220 }
221 };
222 if (!rangeBar.parent.options.showYAxis)
223 options.yaxis.show=false;
224
225 var highlight_select_plot_colors = [];
226 var i = 0;
227 $(highlight_select_plot).each(function(){
228 var color;
229 if (i < GeoTemConfig.datasets.length){
230 var datasetColors = GeoTemConfig.getColor(i);
231 if (highlight_select_plot.length>GeoTemConfig.datasets.length)
232 color = "rgb("+datasetColors.r0+","+datasetColors.g0+","+datasetColors.b0+")";
233 else
234 color = "rgb("+datasetColors.r1+","+datasetColors.g1+","+datasetColors.b1+")";
235 } else {
236 var datasetColors = GeoTemConfig.getColor(i-GeoTemConfig.datasets.length);
237 color = "rgb("+datasetColors.r1+","+datasetColors.g1+","+datasetColors.b1+")";
238 }
239
240 highlight_select_plot_colors.push({
241 color : color,
242 data : this
243 });
244 i++;
245 });
246
247 $(rangeBar.plotDiv).unbind();
248 rangeBar.plot = $.plot($(rangeBar.plotDiv), highlight_select_plot_colors, options);
249 rangeBar.parent.drawHandles();
250
251 var density = rangeBar.parent.density;
252 if (typeof density !== "undefined")
253 $(rangeBar.plotDiv).unbind("plothover", density.hoverFunction);
254 $(rangeBar.plotDiv).unbind("plothover", rangeBar.hoverFunction);
255 $(rangeBar.plotDiv).bind("plothover", $.proxy(rangeBar.hoverFunction,rangeBar));
256
257 //this var prevents the execution of the plotclick event after a select event
258 rangeBar.wasSelection = false;
259 $(rangeBar.plotDiv).unbind("plotclick");
260 $(rangeBar.plotDiv).bind("plotclick", $.proxy(rangeBar.clickFunction,rangeBar));
261
262 $(rangeBar.plotDiv).unbind("plotselected");
263 $(rangeBar.plotDiv).bind("plotselected", $.proxy(rangeBar.selectFunction,rangeBar));
264 },
265
266 hoverFunction : function (event, pos, item) {
267 var rangeBar = this;
268 var hoverBar;
269 var spans;
270 if (item) {
271 hoverBar = item.datapoint[0];
272 }
273 //remember last date, so that we don't redraw the current state
274 //that date may be undefined is on purpose
275 if (rangeBar.highlighted !== hoverBar){
276 rangeBar.highlighted = hoverBar;
277 if (typeof hoverBar === "undefined")
278 rangeBar.triggerHighlight();
279 else
280 rangeBar.triggerHighlight(hoverBar);
281 }
282 },
283
284 clickFunction : function (event, pos, item) {
285 var rangeBar = this;
286 if (rangeBar.wasSelection)
287 rangeBar.wasSelection = false;
288 else {
289 //remove selection handles (if there were any)
290 rangeBar.parent.clearHandles();
291
292 var clickBar;
293 if (item) {
294 //contains the x-value (date)
295 clickBar = item.datapoint[0];
296 }
297 if (typeof clickBar === "undefined")
298 rangeBar.triggerSelection();
299 else
300 rangeBar.triggerSelection(clickBar);
301 wasDataClick = true;
302 }
303 },
304
305 selectFunction : function(event, ranges) {
306 var rangeBar = this;
307 startBar = Math.floor(ranges.xaxis.from);
308 endBar = Math.floor(ranges.xaxis.to);
309 rangeBar.triggerSelection(startBar, endBar);
310 rangeBar.wasSelection = true;
311
312 rangeBar.parent.clearHandles();
313 var xaxis = rangeBar.plot.getAxes().xaxis;
314 var x1 = rangeBar.plot.pointOffset({x:ranges.xaxis.from,y:0}).left;
315 var x2 = rangeBar.plot.pointOffset({x:ranges.xaxis.to,y:0}).left;
316 rangeBar.parent.addHandle(x1,x2);
317 },
318
319 selectByX : function(x1, x2){
320 rangeBar = this;
321 var xaxis = rangeBar.plot.getAxes().xaxis;
322 var offset = rangeBar.plot.getPlotOffset().left;
323 var from = Math.floor(xaxis.c2p(x1-offset));
324 var to = Math.floor(xaxis.c2p(x2-offset));
325
326 rangeBar.triggerSelection(from, to);
327 },
328
329 drawRangeBarChart : function(datasets, spanWidth){
330 var rangeBar = this;
331 rangeBar.spanWidth = spanWidth;
332 rangeBar.tickSpans = rangeBar.parent.getSpanArray(rangeBar.spanWidth);
333 //-1 because last span is always empty (only there to have the ending date)
334 var tickCount = rangeBar.tickSpans.length-1;
335
336 if (tickCount > rangeBar.options.maxBars){
337 var zoomFactor = tickCount / rangeBar.options.maxBars;
338 rangeBar.parent.zoomPlot(zoomFactor);
339 } else
340 rangeBar.parent.zoomPlot(1);
341
342 rangeBar.yValMin = 0;
343 rangeBar.yValMax = 0;
344
345 var plotAndHash = rangeBar.createPlot(datasets);
346 rangeBar.datasetsPlot = plotAndHash.plots;
347 rangeBar.datasetsHash = plotAndHash.hashs;
348 delete rangeBar.highlightedDatasetsPlot;
349 //redraw selected plot to fit (possible) new scale
350 rangeBar.selectionChanged(rangeBar.selected);
351
352 //get min and max values
353 for (var i = 0; i < rangeBar.datasetsPlot.length; i++){
354 for (var j = 0; j < rangeBar.datasetsPlot[i].length; j++){
355 if (typeof rangeBar.datasetsPlot[i][j] !== "undefined"){
356 var val = rangeBar.datasetsPlot[i][j][1];
357
358 if (val < rangeBar.yValMin)
359 rangeBar.yValMin = val;
360 if (val > rangeBar.yValMax)
361 rangeBar.yValMax = val;
362 }
363 }
364 }
365
366 rangeBar.showPlot();
367 },
368
369 highlightChanged : function(objects) {
370 if( !GeoTemConfig.highlightEvents ){
371 return;
372 }
373 var rangeBar = this;
374 var emptyHighlight = true;
375 var selected_highlighted = objects;
376 if (typeof rangeBar.selected !== "undefined")
377 var selected_highlighted = GeoTemConfig.mergeObjects(objects,rangeBar.selected);
378 $(selected_highlighted).each(function(){
379 if ((this instanceof Array) && (this.length > 0)){
380 emptyHighlight = false;
381 return false;
382 }
383 });
384 if (emptyHighlight && (typeof rangeBar.selected === "undefined")){
385 rangeBar.highlightedDatasetsPlot = [];
386 } else {
387 rangeBar.highlightedDatasetsPlot = rangeBar.createPlot(selected_highlighted).plots;
388 }
389 rangeBar.showPlot();
390 },
391
392 selectionChanged : function(objects) {
393 if( !GeoTemConfig.selectionEvents ){
394 return;
395 }
396 var rangeBar = this;
397 rangeBar.selected = objects;
398 rangeBar.highlightChanged([]);
399 },
400
401 triggerHighlight : function(hoverPoint) {
402 var rangeBar = this;
403 var highlightedObjects = [];
404
405 if (typeof hoverPoint !== "undefined"){
406 $(rangeBar.datasetsHash).each(function(){
407 if (typeof this[hoverPoint] !== "undefined")
408 highlightedObjects.push(this[hoverPoint]);
409 else
410 highlightedObjects.push([]);
411 });
412 } else {
413 for (var i = 0; i < GeoTemConfig.datasets.length; i++)
414 highlightedObjects.push([]);
415 }
416
417 this.parent.core.triggerHighlight(highlightedObjects);
418 },
419
420 triggerSelection : function(startBar, endBar) {
421 var rangeBar = this;
422 var selection;
423 if (typeof startBar !== "undefined") {
424 if (typeof endBar === "undefined")
425 endBar = startBar;
426 rangeBar.selected = [];
427 $(rangeBar.datasetsHash).each(function(){
428 var objects = [];
429 for (var i = startBar; i <= endBar; i++){
430 $(this[i]).each(function(){
431 if ($.inArray(this, objects) == -1){
432 objects.push(this);
433 }
434 });
435 }
436 rangeBar.selected.push(objects);
437 });
438 selection = new Selection(rangeBar.selected, rangeBar.parent);
439 } else {
440 rangeBar.selected = [];
441 for (var i = 0; i < GeoTemConfig.datasets.length; i++)
442 rangeBar.selected.push([]);
443 selection = new Selection(rangeBar.selected);
444 }
445
446 rangeBar.parent.selectionChanged(selection);
447 rangeBar.parent.core.triggerSelection(selection);
448 },
449
450 deselection : function() {
451 },
452
453 filtering : function() {
454 },
455
456 inverseFiltering : function() {
457 },
458
459 triggerRefining : function() {
460 },
461
462 reset : function() {
463 },
464
465 show : function() {
466 },
467
468 hide : function() {
469 }
470 };