comparison geotemco/js/FuzzyTimeline/FuzzyTimelineWidget.js @ 0:b12c99b7c3f0

commit for previous development
author Zoe Hong <zhong@mpiwg-berlin.mpg.de>
date Mon, 19 Jan 2015 17:13:49 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:b12c99b7c3f0
1 /*
2 * FuzzyTimelineWidget.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 FuzzyTimelineWidget
24 * FuzzyTimelineWidget Implementation
25 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
26 *
27 * @param {WidgetWrapper} core wrapper for interaction to other widgets
28 * @param {HTML object} div parent div to append the FuzzyTimeline widget div
29 * @param {JSON} options user specified configuration that overwrites options in FuzzyTimelineConfig.js
30 */
31 FuzzyTimelineWidget = function(core, div, options) {
32
33 this.datasets;
34 this.selected = undefined;
35 this.overallMin;
36 this.overallMax;
37
38 this.core = core;
39 this.core.setWidget(this);
40
41 this.options = (new FuzzyTimelineConfig(options)).options;
42 this.gui = new FuzzyTimelineGui(this, div, this.options);
43
44 this.viewMode;
45 this.density;
46 this.rangeSlider;
47 this.rangeBars;
48 this.rangePiechart;
49 this.spanHash = [];
50
51 this.handles = [];
52 this.zoomFactor = 1;
53
54 this.scaleMode = "normal";
55 }
56
57 FuzzyTimelineWidget.prototype = {
58
59 initWidget : function(data) {
60 var fuzzyTimeline = this;
61
62 delete fuzzyTimeline.overallMin;
63 delete fuzzyTimeline.overallMax;
64
65 $(fuzzyTimeline.gui.plotDiv).empty();
66 $(fuzzyTimeline.gui.sliderTable).empty();
67 delete fuzzyTimeline.rangeSlider;
68 $(fuzzyTimeline.gui.rangePiechartDiv).empty();
69 delete fuzzyTimeline.rangePiechart;
70
71 fuzzyTimeline.switchViewMode("density");
72
73 if ( (data instanceof Array) && (data.length > 0) )
74 {
75 fuzzyTimeline.datasets = data;
76
77 $(fuzzyTimeline.datasets).each(function(){
78 $(this.objects).each(function(){
79 var datemin,datemax;
80 if (this.isTemporal){
81 //TODO: allow more than one date
82 datemin = moment(this.dates[0].date);
83 datemax = datemin;
84 } else if (this.isFuzzyTemporal){
85 //TODO: allow more than one date
86 datemin = this.TimeSpanBegin;
87 datemax = this.TimeSpanEnd;
88 }
89
90 if (typeof fuzzyTimeline.overallMin === "undefined")
91 fuzzyTimeline.overallMin = datemin;
92 if (typeof fuzzyTimeline.overallMax === "undefined")
93 fuzzyTimeline.overallMax = datemax;
94
95 if (fuzzyTimeline.overallMin > datemin)
96 fuzzyTimeline.overallMin = datemin;
97 if (fuzzyTimeline.overallMax < datemax)
98 fuzzyTimeline.overallMax = datemax;
99 });
100 });
101
102 fuzzyTimeline.rangeSlider = new FuzzyTimelineRangeSlider(fuzzyTimeline);
103 fuzzyTimeline.rangeSlider.initialize(fuzzyTimeline.datasets);
104
105 fuzzyTimeline.rangePiechart = new FuzzyTimelineRangePiechart(fuzzyTimeline, fuzzyTimeline.gui.rangePiechartDiv);
106 fuzzyTimeline.rangePiechart.initialize(fuzzyTimeline.datasets);
107 }
108 },
109
110 switchViewMode : function(viewMode){
111 var fuzzyTimeline = this;
112 if (viewMode !== fuzzyTimeline.viewMode){
113 $(fuzzyTimeline.gui.plotDiv).empty();
114 if (viewMode === "density"){
115 fuzzyTimeline.density = new FuzzyTimelineDensity(fuzzyTimeline,fuzzyTimeline.gui.plotDiv);
116 } else if (viewMode === "barchart"){
117 fuzzyTimeline.rangeBars = new FuzzyTimelineRangeBars(fuzzyTimeline);
118 }
119 fuzzyTimeline.viewMode = viewMode;
120 }
121 },
122
123 scaleData : function(data){
124 var fuzzyTimeline = this;
125 if (fuzzyTimeline.scaleMode == "normal"){
126 return data;
127 } else if (fuzzyTimeline.scaleMode == "logarithm"){
128 for(var index in data){
129 var val = data[index];
130 if (val!=0){
131 var sign = 1;
132 if (val<0){
133 sign = -1;
134 }
135 data[index] = sign*Math.log(Math.abs(data[index])+1);
136 }
137 }
138 return data;
139 } else if (fuzzyTimeline.scaleMode == "percentage"){
140 var overallCnt = 0;
141 for(var index in data){
142 var val = data[index];
143 if (val > 0){
144 overallCnt += val;
145 }
146 }
147 //make 1 = 100%
148 overallCnt = overallCnt/100;
149 if (overallCnt != 0){
150 for(var index in data){
151 data[index] = (data[index])/overallCnt;
152 }
153 }
154 return data;
155 }
156 },
157
158 changeScaleMode : function(scaleMode) {
159 var fuzzyTimeline = this;
160 fuzzyTimeline.scaleMode = scaleMode;
161 fuzzyTimeline.drawFuzzyTimeline();
162 },
163
164 slidePositionChanged : function(spanWidth) {
165 var fuzzyTimeline = this;
166 fuzzyTimeline.spanWidth = spanWidth;
167 fuzzyTimeline.drawFuzzyTimeline();
168 },
169
170 drawFuzzyTimeline : function(){
171 var fuzzyTimeline = this;
172 var datasets = fuzzyTimeline.datasets;
173 if (fuzzyTimeline.viewMode === "density"){
174 //redraw density plot
175 fuzzyTimeline.density.drawDensityPlot(datasets);
176 //select currently selected data (if there is any)
177 fuzzyTimeline.density.selectionChanged(fuzzyTimeline.selected);
178 } else if (fuzzyTimeline.viewMode === "barchart"){
179 //redraw range plot
180 fuzzyTimeline.rangeBars.drawRangeBarChart(datasets,fuzzyTimeline.spanWidth);
181 //select currently selected data (if there is any)
182 fuzzyTimeline.rangeBars.selectionChanged(fuzzyTimeline.selected);
183 }
184 },
185
186 highlightChanged : function(objects) {
187 var fuzzyTimeline = this;
188 if( !GeoTemConfig.highlightEvents ){
189 return;
190 }
191 if ( (typeof objects === "undefined") || (objects.length == 0) ){
192 return;
193 }
194 if (fuzzyTimeline.viewMode === "density")
195 this.density.highlightChanged(objects);
196 else if (fuzzyTimeline.viewMode === "barchart")
197 this.rangeBars.highlightChanged(objects);
198
199 fuzzyTimeline.rangePiechart.highlightChanged(objects);
200 },
201
202 selectionChanged : function(selection) {
203 var fuzzyTimeline = this;
204 if( !GeoTemConfig.selectionEvents ){
205 return;
206 }
207 if ((typeof selection.objects !== "undefined")&&
208 (selection.objects.length == GeoTemConfig.datasets.length))
209 fuzzyTimeline.selected = selection.objects;
210 else
211 delete fuzzyTimeline.selected;
212 if (fuzzyTimeline.viewMode === "density")
213 this.density.selectionChanged(fuzzyTimeline.selected);
214 else if (fuzzyTimeline.viewMode === "barchart")
215 this.rangeBars.selectionChanged(fuzzyTimeline.selected);
216
217 if (selection.valid())
218 fuzzyTimeline.rangePiechart.selectionChanged(fuzzyTimeline.selected);
219 else
220 fuzzyTimeline.rangePiechart.selectionChanged([]);
221
222 //selections "overwrite" each other
223 if (selection.widget != fuzzyTimeline)
224 fuzzyTimeline.clearHandles();
225 },
226
227 buildSpanArray : function(spanWidth) {
228 var spanArray = [];
229 var tickStart = moment(this.overallMin);
230 do{
231 spanArray.push(moment(tickStart));
232 tickStart.add(spanWidth);
233 } while (tickStart <= this.overallMax);
234 spanArray.push(moment(tickStart));
235
236 this.spanHash.push({spanWidth:spanWidth,overallMin:moment(this.overallMin),spanArray:spanArray});
237 return(spanArray);
238 },
239
240 getSpanArray : function(spanWidth){
241 for (var i = 0; i < this.spanHash.length; i++){
242 var element = this.spanHash[i];
243 if ( ((this.overallMin-element.overallMin)===0) &&
244 ((spanWidth-element.spanWidth)===0))
245 return element.spanArray;
246 }
247 return this.buildSpanArray(spanWidth);
248 },
249
250 clearSpanArray : function(){
251 this.spanHash = [];
252 },
253
254 getTicks : function(dataObject, spanWidth) {
255 var datemin,datemax;
256 if (dataObject.isTemporal){
257 datemin = moment(dataObject.dates[0].date);
258 datemax = datemin;
259 } else if (dataObject.isFuzzyTemporal){
260 datemin = dataObject.TimeSpanBegin;
261 datemax = dataObject.TimeSpanEnd;
262 } else{
263 return;
264 }
265
266 if (typeof spanWidth._data === "undefined"){
267 //This does only work with millisecond spans, as the length of years is (very) inaccurate.
268 //(e.g. 100-0 = 99, 2000-1000 = 1001, 5000-0 = 5003, and so on and even more: duration(5000a) = 4932a)
269 //So the time consuming loop below is needed for accurate dates, when years/months/days etc. are supplied
270 var firstTick = Math.floor((datemin-this.overallMin)/spanWidth);
271 var lastTick = Math.floor((datemax-this.overallMin)/spanWidth);
272 //calculate how much the first (and last) tick and the time-span overlap
273 var firstTickPercentage = 1;
274 var lastTickPercentage = 1;
275 if (firstTick != lastTick){
276 var secondTickStart = this.overallMin+(firstTick+1)*spanWidth;
277 var lastTickStart = this.overallMin+lastTick*spanWidth;
278 firstTickPercentage = (secondTickStart-datemin)/spanWidth;
279 lastTickPercentage = (datemax-lastTickStart)/spanWidth;
280 }
281 if (firstTickPercentage === 0){
282 firstTick++;
283 firstTickPercentage = 1;
284 }
285 if (lastTickPercentage === 0){
286 lastTick--;
287 lastTickPercentage = 1;
288 }
289 } else {
290 var spanArray = this.getSpanArray(spanWidth);
291 var firstTick, lastTick;
292 var tickCount = 0;
293 var tickStart = spanArray[0];
294 var lastTickStart;
295 do{
296 lastTickStart = spanArray[tickCount];
297 tickCount++;
298 tickStart = spanArray[tickCount];
299 if ( (typeof firstTick === "undefined") && (datemin < tickStart) ){
300 firstTick = tickCount-1;
301 firstTickPercentage = (tickStart - datemin)/spanWidth;
302 }
303 if ( (typeof lastTick === "undefined") && (datemax <= tickStart) ){
304 lastTick = tickCount-1;
305 lastTickPercentage = (datemax - lastTickStart)/spanWidth;
306 }
307 } while (tickStart < datemax);
308 if (firstTick == lastTick){
309 firstTickPercentage = 1;
310 lastTickPercentage = 1;
311 }
312 }
313
314 return({ firstTick:firstTick,
315 lastTick:lastTick,
316 firstTickPercentage:firstTickPercentage,
317 lastTickPercentage:lastTickPercentage});
318 },
319
320 getObjects : function(dateStart, dateEnd) {
321 var fuzzyTimeline = this;
322 var searchDateStart, searchDateEnd;
323 if (typeof dateStart !== "undefined")
324 searchDateStart = moment(dateStart);
325 if (typeof dateEnd !== "undefined")
326 searchDateEnd = moment(dateEnd);
327
328 var datasets = [];
329 $(fuzzyTimeline.datasets).each(function(){
330 var objects = [];
331 //check if we got "real" datasets, or just array of objects
332 var datasetObjects = this;
333 if (typeof this.objects !== "undefined")
334 datasetObjects = this.objects;
335 $(datasetObjects).each(function(){
336 var datemin,datemax;
337 var dataObject = this;
338 if (dataObject.isTemporal){
339 datemin = moment(dataObject.dates[0].date);
340 datemax = datemin;
341 } else if (dataObject.isFuzzyTemporal){
342 datemin = dataObject.TimeSpanBegin;
343 datemax = dataObject.TimeSpanEnd;
344 } else{
345 return;
346 }
347
348 if (typeof searchDateEnd === 'undefined'){
349 if ( (datemin <= searchDateStart) && (datemax >= searchDateStart) )
350 objects.push(this);
351 } else {
352 if ((datemin < searchDateEnd) && (datemax >= searchDateStart))
353 objects.push(this);
354 }
355 });
356 datasets.push(objects);
357 });
358
359 return(datasets);
360 },
361
362 triggerHighlight : function(highlightedObjects){
363 var fuzzyTimeline = this;
364 if (fuzzyTimeline.viewMode === "density")
365 fuzzyTimeline.density.highlightChanged(highlightedObjects);
366 else if (fuzzyTimeline.viewMode === "barchart")
367 fuzzyTimeline.rangeBars.highlightChanged(highlightedObjects);
368
369 fuzzyTimeline.core.triggerHighlight(highlightedObjects);
370 },
371
372 triggerSelection : function(selectedObjects){
373 var fuzzyTimeline = this;
374 fuzzyTimeline.selected = selectedObjects;
375 if (fuzzyTimeline.viewMode === "density")
376 fuzzyTimeline.density.selectionChanged(selectedObjects);
377 else if (fuzzyTimeline.viewMode === "barchart")
378 fuzzyTimeline.rangeBars.selectionChanged(selectedObjects);
379
380 selection = new Selection(selectedObjects);
381
382 fuzzyTimeline.core.triggerSelection(selection);
383 },
384
385 addHandle : function(x1,x2){
386 var fuzzyTimeline = this;
387 //make sure the interval is ordered correctly
388 if (x2<x1){
389 var temp = x1;
390 x1 = x2;
391 x2 = temp;
392 }
393 fuzzyTimeline.handles.push({x1:x1,x2:x2});
394 fuzzyTimeline.drawHandles();
395 //enabled "play" button
396 $(fuzzyTimeline.rangeSlider.startAnimation).removeClass("playDisabled").addClass("playEnabled");
397 },
398
399 selectByX : function(x1,x2){
400 var fuzzyTimeline = this;
401 if (fuzzyTimeline.viewMode === "density"){
402 fuzzyTimeline.density.selectByX(x1,x2);
403 } else if (fuzzyTimeline.viewMode === "barchart"){
404 fuzzyTimeline.rangeBars.selectByX(x1,x2);
405 }
406 },
407
408 drawHandles : function(){
409 var fuzzyTimeline = this;
410
411 $(fuzzyTimeline.gui.plotDiv).find(".plotHandle").remove();
412 $(fuzzyTimeline.gui.plotDiv).find(".dragTimeRangeAlt").remove();
413 $(fuzzyTimeline.gui.plotDiv).find(".plotHandleBox").remove();
414
415 var plotHeight = (fuzzyTimeline.density.plot?fuzzyTimeline.density.plot:fuzzyTimeline.rangeBars.plot).height();
416 var plotWidth = (fuzzyTimeline.density.plot?fuzzyTimeline.density.plot:fuzzyTimeline.rangeBars.plot).width();
417 //flot sends the wrong width if we extend the parent div, so scale it accordingly
418 plotWidth = plotWidth*fuzzyTimeline.zoomFactor;
419 var plotOffset = (fuzzyTimeline.density.plot?fuzzyTimeline.density.plot:fuzzyTimeline.rangeBars.plot).getPlotOffset().left;
420
421 $(fuzzyTimeline.handles).each(function(){
422 var handle = this;
423
424 var moveLeftHandle = function(){
425 leftHandle.style.left = handle.x1-$(leftHandle).width() + "px";
426 };
427
428 var moveRightHandle = function(){
429 rightHandle.style.left = handle.x2+ "px";
430 };
431
432 var resizeHandleBox = function(){
433 handleBox.style.left = handle.x1+"px";
434 $(handleBox).width(handle.x2-handle.x1);
435 };
436
437 var moveDragButton = function(){
438 dragButton.style.left = (handle.x1+handle.x2)/2 - $(dragButton).width()/2 + "px";
439 };
440
441 var leftHandle = document.createElement("div");
442 leftHandle.title = GeoTemConfig.getString('leftHandle');
443 leftHandle.style.backgroundImage = "url(" + GeoTemConfig.path + "leftHandle.png" + ")";
444 leftHandle.setAttribute('class', 'plotHandle plotHandleIcon');
445 leftHandle.style.visibility = "visible";
446 $(fuzzyTimeline.gui.plotDiv).append(leftHandle);
447 moveLeftHandle();
448 leftHandle.style.top = plotHeight/2-$(leftHandle).height()/2 + "px";
449
450 var rightHandle = document.createElement("div");
451 rightHandle.title = GeoTemConfig.getString('leftHandle');
452 rightHandle.style.backgroundImage = "url(" + GeoTemConfig.path + "rightHandle.png" + ")";
453 rightHandle.setAttribute('class', 'plotHandle plotHandleIcon');
454 rightHandle.style.visibility = "visible";
455 moveRightHandle();
456 $(fuzzyTimeline.gui.plotDiv).append(rightHandle);
457
458 rightHandle.style.top = plotHeight/2-$(rightHandle).height()/2 + "px";
459
460 var handleBox = document.createElement("div");
461 $(fuzzyTimeline.gui.plotDiv).append(handleBox);
462 $(handleBox).addClass("plotHandleBox");
463 resizeHandleBox();
464 $(handleBox).height(plotHeight);
465
466 var dragButton = document.createElement("div");
467 dragButton.title = GeoTemConfig.getString('dragTimeRange');
468 dragButton.style.backgroundImage = "url(" + GeoTemConfig.path + "drag.png" + ")";
469 dragButton.setAttribute('class', 'dragTimeRangeAlt plotHandleIcon');
470 $(fuzzyTimeline.gui.plotDiv).append(dragButton);
471 moveDragButton();
472 dragButton.style.top = plotHeight + "px";
473
474 $(leftHandle).mousedown(function(){
475 $(fuzzyTimeline.gui.plotDiv).mousemove(function(eventObj){
476 var x = eventObj.clientX;
477 x += $(fuzzyTimeline.gui.plotDiv).parent().scrollLeft();
478 if ((x < handle.x2) &&
479 (x >= plotOffset)){
480 x = x - leftHandle.offsetWidth;
481 handle.x1 = x + $(leftHandle).width();
482
483 moveLeftHandle();
484 resizeHandleBox();
485 moveDragButton();
486 }
487 });
488 $(fuzzyTimeline.gui.plotDiv).mouseup(function(eventObj){
489 fuzzyTimeline.selectByX(handle.x1,handle.x2);
490 $(fuzzyTimeline.gui.plotDiv).unbind("mouseup");
491 $(fuzzyTimeline.gui.plotDiv).unbind("mousemove");
492 });
493 });
494
495 $(rightHandle).mousedown(function(){
496 $(fuzzyTimeline.gui.plotDiv).mousemove(function(eventObj){
497 var x = eventObj.clientX;
498 x += $(fuzzyTimeline.gui.plotDiv).parent().scrollLeft();
499 x = x - rightHandle.offsetWidth;
500 if ((x > handle.x1) &&
501 (x <= plotOffset+plotWidth)){
502 handle.x2 = x;
503
504 moveRightHandle();
505 resizeHandleBox();
506 moveDragButton();
507 }
508 });
509 $(fuzzyTimeline.gui.plotDiv).mouseup(function(eventObj){
510 fuzzyTimeline.selectByX(handle.x1,handle.x2);
511 $(fuzzyTimeline.gui.plotDiv).unbind("mouseup");
512 $(fuzzyTimeline.gui.plotDiv).unbind("mousemove");
513 });
514 });
515
516 $(dragButton).mousedown(function(){
517 $(fuzzyTimeline.gui.plotDiv).mousemove(function(eventObj){
518 var x = eventObj.clientX;
519 //TODO: for some reason we don't need the scoll offset here
520 //this should be investigated?
521 //x += $(fuzzyTimeline.gui.plotDiv).parent().scrollLeft();
522 var xdiff = x - $(dragButton).offset().left - $(dragButton).width()/2;
523 handle.x1 = handle.x1+xdiff;
524 handle.x2 = handle.x2+xdiff;
525
526 moveLeftHandle();
527 moveRightHandle();
528 resizeHandleBox();
529 moveDragButton();
530 });
531 $(fuzzyTimeline.gui.plotDiv).mouseup(function(eventObj){
532 if (handle.x1 < plotOffset)
533 handle.x1 = plotOffset;
534 if (handle.x2 > plotOffset+plotWidth)
535 handle.x2 = plotOffset+plotWidth;
536
537 moveLeftHandle();
538 moveRightHandle();
539 resizeHandleBox();
540 moveDragButton();
541
542 fuzzyTimeline.selectByX(handle.x1,handle.x2);
543 $(fuzzyTimeline.gui.plotDiv).unbind("mouseup");
544 $(fuzzyTimeline.gui.plotDiv).unbind("mousemove");
545 });
546 });
547 });
548 },
549
550 clearHandles : function(){
551 var fuzzyTimeline = this;
552 $(fuzzyTimeline.gui.plotDiv).find(".plotHandle").remove();
553 $(fuzzyTimeline.gui.plotDiv).find(".dragTimeRangeAlt").remove();
554 $(fuzzyTimeline.gui.plotDiv).find(".plotHandleBox").remove();
555 fuzzyTimeline.handles = [];
556 //disable buttons
557 $(fuzzyTimeline.rangeSlider.startAnimation).removeClass("playEnabled").addClass("playDisabled");
558 $(fuzzyTimeline.rangeSlider.pauseAnimation).removeClass("pauseEnabled").addClass("pauseDisabled");
559 //stop the animation (if one was running)
560 fuzzyTimeline.pauseAnimation();
561 },
562
563 startAnimation : function(){
564 var fuzzyTimeline = this;
565 fuzzyTimeline.loopFunction = function(steps){
566 $(fuzzyTimeline.handles).each(function(){
567 if (typeof steps === "undefined")
568 steps = 1;
569
570 var handle = this;
571 var x1 = handle.x1;
572 var x2 = handle.x2;
573
574 if (typeof handle.width === "undefined")
575 handle.width = x2-x1;
576
577 var plotWidth = (fuzzyTimeline.density.plot?fuzzyTimeline.density.plot:fuzzyTimeline.rangeBars.plot).width();
578 var plotOffset = (fuzzyTimeline.density.plot?fuzzyTimeline.density.plot:fuzzyTimeline.rangeBars.plot).getPlotOffset().left;
579
580 var plotMax = plotWidth+plotOffset;
581
582 //TODO: has to be plotMin
583 if (!((x1 === plotOffset)&&(x2-x1 <= handle.width))){
584 x1 += steps;
585 }
586 if (x2 <= plotMax){
587 x2 += steps;
588 if (x2 > plotMax)
589 x2 = plotMax;
590 if (x2-x1 > handle.width){
591 x1 = x2-handle.width;
592 }
593 }
594 if (x1 >= plotMax){
595 //TODO: has to be plotMin
596 x1 = plotOffset;
597 x2 = plotOffset;
598 }
599
600 handle.x1 = x1;
601 handle.x2 = x2;
602
603 fuzzyTimeline.drawHandles();
604 fuzzyTimeline.selectByX(handle.x1, handle.x2);
605 });
606 };
607
608 fuzzyTimeline.loopId = setInterval(function(){
609 fuzzyTimeline.loopFunction(10);
610 }, 100);
611 },
612
613 pauseAnimation : function(){
614 var fuzzyTimeline = this;
615 clearInterval(fuzzyTimeline.loopId);
616 $(fuzzyTimeline.handles).each(function(){
617 var handle = this;
618 delete handle.width;
619 });
620 },
621
622 //This function enlargens the plot area
623 zoomPlot : function(zoomFactor){
624 var fuzzyTimeline = this;
625 var oldZoomFactor = fuzzyTimeline.zoomFactor;
626 fuzzyTimeline.zoomFactor = zoomFactor;
627 if (zoomFactor > 1){
628 $(fuzzyTimeline.gui.plotDiv).width(zoomFactor*100+"%");
629 //leave place for the scrollbar
630 $(fuzzyTimeline.gui.plotDiv).height(fuzzyTimeline.gui.plotDIVHeight-20);
631 } else{
632 $(fuzzyTimeline.gui.plotDiv).width("100%");
633 $(fuzzyTimeline.gui.plotDiv).height(fuzzyTimeline.gui.plotDIVHeight);
634 }
635
636 //fit handles
637 //this does not make much sense, as the selections are _completely_ different
638 //for each scale rate, as the objects may reside in different "ticks" of the graph
639 $(fuzzyTimeline.handles).each(function(){
640 var handle = this;
641 handle.x1 = handle.x1 * (zoomFactor/oldZoomFactor);
642 handle.x2 = handle.x2 * (zoomFactor/oldZoomFactor);
643 });
644 }
645 };