Mercurial > hg > NetworkVis
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 }; |