added all files
[ffqwlibrary] / libffqw-1.0 / sources / ffchartscene.cpp
1 /*
2           GNU GENERAL PUBLIC LICENSE
3                        Version 3, 29 June 2007
4
5  Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
6  Everyone is permitted to copy and distribute verbatim copies
7  of this license document, but changing it is not allowed.
8
9                             Preamble
10
11   The GNU General Public License is a free, copyleft license for
12 software and other kinds of works.
13
14   The licenses for most software and other practical works are designed
15 to take away your freedom to share and change the works.  By contrast,
16 the GNU General Public License is intended to guarantee your freedom to
17 share and change all versions of a program--to make sure it remains free
18 software for all its users.  We, the Free Software Foundation, use the
19 GNU General Public License for most of our software; it applies also to
20 any other work released this way by its authors.  You can apply it to
21 your programs, too.
22
23   When we speak of free software, we are referring to freedom, not
24 price.  Our General Public Licenses are designed to make sure that you
25 have the freedom to distribute copies of free software (and charge for
26 them if you wish), that you receive source code or can get it if you
27 want it, that you can change the software or use pieces of it in new
28 free programs, and that you know you can do these things.
29
30   To protect your rights, we need to prevent others from denying you
31 these rights or asking you to surrender the rights.  Therefore, you have
32 certain responsibilities if you distribute copies of the software, or if
33 you modify it: responsibilities to respect the freedom of others.
34
35   For example, if you distribute copies of such a program, whether
36 gratis or for a fee, you must pass on to the recipients the same
37 freedoms that you received.  You must make sure that they, too, receive
38 or can get the source code.  And you must show them these terms so they
39 know their rights.
40
41   Developers that use the GNU GPL protect your rights with two steps:
42 (1) assert copyright on the software, and (2) offer you this License
43 giving you legal permission to copy, distribute and/or modify it.
44
45   For the developers' and authors' protection, the GPL clearly explains
46 that there is no warranty for this free software.  For both users' and
47 authors' sake, the GPL requires that modified versions be marked as
48 changed, so that their problems will not be attributed erroneously to
49 authors of previous versions.
50
51   Some devices are designed to deny users access to install or run
52 modified versions of the software inside them, although the manufacturer
53 can do so.  This is fundamentally incompatible with the aim of
54 protecting users' freedom to change the software.  The systematic
55 pattern of such abuse occurs in the area of products for individuals to
56 use, which is precisely where it is most unacceptable.  Therefore, we
57 have designed this version of the GPL to prohibit the practice for those
58 products.  If such problems arise substantially in other domains, we
59 stand ready to extend this provision to those domains in future versions
60 of the GPL, as needed to protect the freedom of users.
61
62   Finally, every program is threatened constantly by software patents.
63 States should not allow patents to restrict development and use of
64 software on general-purpose computers, but in those that do, we wish to
65 avoid the special danger that patents applied to a free program could
66 make it effectively proprietary.  To prevent this, the GPL assures that
67 patents cannot be used to render the program non-free.
68
69   The precise terms and conditions for copying, distribution and
70 modification follow.
71
72 http://www.gnu.org/licenses/gpl-3.0.txt
73 */
74 /**
75  * @file ffchartscene.cpp
76  * @brief Implementation of the FFChartScene class.
77  *
78  * @author ComArch S.A.
79  * @date 2009.09.01
80  * @version 1.1
81  */
82
83 #include "ffchartscene.h"
84
85 // ############################################################ CONSTRUCTORS
86
87 /**
88  * Constructs a FFChartScene with a parent.
89  */
90 FFChartScene::FFChartScene(QObject* parent) :
91         QGraphicsScene(parent)
92 {
93         init();
94 }
95
96 /**
97  * A virtual destructor.
98  */
99 FFChartScene::~FFChartScene()
100 {
101
102 }
103
104 /**
105  * Initiates an object of FFChartScene. Sets all needed fields connections.
106  * It is called by all constructors.
107  */
108 void FFChartScene::init()
109 {
110         //sets default configuration
111         moveModeSw = false;
112         zoomModeSw = false;
113         kineticCount = 0;
114
115         accumulatedZoomFactor_ = QSize(1, 1);
116         QBrush zoomRectBrush(QColor(60, 80, 60));
117
118         QPen zoomRectPen;
119         zoomRectPen.setBrush(zoomRectBrush);
120         zoomRectPen.setColor(QColor(80, 180, 80));
121         zoomRectPen.setWidth(3);
122
123         zoomRect = new QGraphicsRectItem;
124         zoomRect->setPen(zoomRectPen);
125         zoomRect->setBrush(zoomRectBrush);
126         setBackgroundBrush(QBrush(QColor(30, 30, 30)));
127
128         timer = new QTimer(this);
129         connect(timer, SIGNAL(timeout()), this, SLOT(kineticScroll()));
130
131         zoomInButton.moveBy(10,10);
132         zoomOutButton.moveBy(10,90);
133         legendButton.moveBy(10, sceneRect().height() - 70);
134
135         subaxesSpacing_ = 40;
136         subaxesPen_.setColor(QColor(80,80,80));
137         subaxesPen_.setStyle(Qt::DashLine);
138         subaxesPen_.setCosmetic(true);
139
140         axesValuesPen_.setColor(QColor(240, 240, 240));
141
142         //adds button to chart
143         addItem(&zoomInButton);
144         addItem(&zoomOutButton);
145         addItem(&legendButton);
146
147
148
149         //connects
150         connect(&zoomInButton, SIGNAL(mouseRelease()), this, SLOT(zoomIn()));
151         connect(&zoomOutButton, SIGNAL(mouseRelease()), this, SLOT(zoomOut()));
152         connect(&legendButton, SIGNAL(mouseRelease()), parent(), SLOT(showLegend()));
153
154         //sets chart's buttons
155         zoomInButton.setImage(":/standard/chart_zoomin");
156         zoomOutButton.setImage(":/standard/chart_zoomout");
157         legendButton.setImage(":/standard/chart_legendON",":/standard/chart_legendOFF");
158
159         zoomInButton.setZoomRatio(1.4);
160         zoomOutButton.setZoomRatio(0.6);
161         legendButton.setZoomRatio(1.4);
162
163         zoomInButton.setSize(QSize(60, 60));
164         zoomOutButton.setSize(QSize(60, 60));
165         legendButton.setSize(QSize(60, 60));
166
167 }
168
169 // ################################################################## PUBLIC
170
171 /**
172  * Moves given point of chart to the scene's top left corner.
173  */
174 void FFChartScene::moveTo(QPoint point)
175 {
176         translateFactor_ = point;
177         update();
178 }
179
180 /**
181  * Moves given point of chart to the scene's top left corner.
182  */
183 void FFChartScene::moveTo(float x, float y)
184 {
185         translateFactor_ = QPointF(x, y);
186         update();
187 }
188
189 /**
190  * Moves the chart by a given vector.
191  */
192 void FFChartScene::moveBy(QPoint destPoint)
193 {
194         translateFactor_ += destPoint;
195         update();
196 }
197
198 /**
199  * Moves the chart by a given vector.
200  */
201 void FFChartScene::moveBy(float x, float y)
202 {
203         translateFactor_ += QPointF(x, y);
204         update();
205 }
206
207 /**
208  * Adds set of points to chart.
209  */
210 void FFChartScene::addSeries(FFChartSeries* series)
211 {
212         this->series.append(series);
213         itemsBoundingRect_ = itemsBoundingRect(&itemsBoundingValues_);
214
215         update();
216
217         emit seriesChanged(this->series);
218 }
219
220 /**
221  * Sets a list of series.
222  */
223 void FFChartScene::setSeries(QList<FFChartSeries*> series)
224 {
225         this->series = series;
226         itemsBoundingRect_ = itemsBoundingRect(&itemsBoundingValues_);
227
228         update();
229
230         emit seriesChanged(&series);
231 }
232
233 /**
234  * Overridden method from QGraphicsScene.
235  */
236 void FFChartScene::setSceneRect(const QRectF& rect)
237 {
238         QGraphicsScene::setSceneRect(rect);
239         legendButton.setPos(10, rect.height() - 70);
240
241         translateFactor_.setX(rect.width() * 0.5);
242         translateFactor_.setY(rect.height() * 0.5);
243
244         sceneRec = rect;
245 }
246
247 /**
248  * Sets a distance in pixels between subaxes.
249  */
250 void FFChartScene::setSubaxesSpacing(const float& subaxesSpacing)
251 {
252         subaxesSpacing_ = subaxesSpacing;
253 }
254
255 /**
256  * Returns a distance in pixels between subaxes.
257  */
258 float FFChartScene::subaxesSpacing() const
259 {
260         return subaxesSpacing_;
261 }
262
263 /**
264  * Sets a pen that will be used to draw subaxes.
265  */
266 void FFChartScene::setSubaxesPen(const QPen& subaxesPen)
267 {
268         subaxesPen_ = subaxesPen;
269 }
270
271 /**
272  * Returns a pen that is used to draw subaxes.
273  */
274 QPen FFChartScene::subaxesPen() const
275 {
276         return subaxesPen_;
277 }
278
279 /**
280  * Sets a pen that will be used to draw values next to subaxes.
281  */
282 void FFChartScene::setAxesValuesPen(const QPen& axesValuesPen)
283 {
284         axesValuesPen_ = axesValuesPen;
285 }
286
287 /**
288  * Returns a pen that is used to draw values next to subaxes.
289  */
290 QPen FFChartScene::axesValuesPen() const
291 {
292         return axesValuesPen_;
293 }
294
295 // ############################################################ PUBLIC SLOTS
296
297 /**
298  * Zooms the chart into the given rectangle.
299  */
300 void FFChartScene::zoom(QRectF zoomRect)
301 {
302         // Normalizing zoom rectangle (width and height must are greater than 0)
303         QRectF zoomRectNormalized(zoomRect);
304         if(zoomRect.width() < 0)
305         {
306                 zoomRectNormalized.setX(zoomRect.x() + zoomRect.width());
307                 zoomRectNormalized.setWidth(qAbs(zoomRect.width()));
308         }
309         if(zoomRect.height() < 0)
310         {
311                 zoomRectNormalized.setY(zoomRect.y() + zoomRect.height());
312                 zoomRectNormalized.setHeight(qAbs(zoomRect.height()));
313         }
314
315         // Calculating zoom factor for scale() function ( >1 zoomin, <1 zoomout )
316         QSizeF zoomFactor(sceneRec.width() / zoomRectNormalized.width(),
317                           sceneRec.height() / zoomRectNormalized.height());
318
319         accumulatedZoomFactor_.setWidth(zoomFactor.width()
320                         * accumulatedZoomFactor_.width());
321         accumulatedZoomFactor_.setHeight(zoomFactor.height()
322                         * accumulatedZoomFactor_.height());
323         //checking if factor of zooming is not to high
324         if(accumulatedZoomFactor_.width() > 20 || accumulatedZoomFactor_.height() > 20)
325         {
326                 accumulatedZoomFactor_.setWidth(20);
327                 accumulatedZoomFactor_.setHeight(20);
328                 return;
329         }
330
331
332
333         translateFactor_ = QPointF((translateFactor_.x()
334                                                    - zoomRectNormalized.x())
335                                                    * zoomFactor.width(),
336                                    (translateFactor_.y()
337                                                    - zoomRectNormalized.y())
338                                                    * zoomFactor.height());
339
340         update();
341 }
342
343 /**
344  * Slot that changes series' set.
345  */
346 void FFChartScene::seriesChanged(QList<FFChartSeries*> series)
347 {
348         setSeries(series);
349 }
350
351 /**
352  * Slot that zooms in the current chart into a rectangle which is smaller by
353  * a given ratio.
354  */
355 void FFChartScene::zoomIn(qreal ratio)
356 {
357         qreal dx, dy;
358
359         if(accumulatedZoomFactor_.width() > 15)
360         {
361                 dx = 0;
362         }
363         else
364         {
365                 dx = ratio * sceneRec.width();
366         }
367
368         if(accumulatedZoomFactor_.height() > 15)
369         {
370                 dy = 0;
371         }
372         else
373         {
374                 dy = ratio * sceneRec.height();
375         }
376
377         zoom(QRectF(dx, dy, sceneRec.width() - 2 * dx, sceneRec.height() - 2
378                         * dy));
379 }
380
381 /**
382  * Slot that zooms out the current chart into a rectangle which is larger by
383  * a given ratio.
384  */
385 void FFChartScene::zoomOut(qreal ratio)
386 {
387         qreal dx, dy;
388
389         if(accumulatedZoomFactor_.width() < 0.1)
390         {
391                 dx = 0;
392         }
393         else
394         {
395                 dx = ratio * sceneRec.width();
396         }
397
398         if(accumulatedZoomFactor_.height() < 0.1)
399         {
400                 dy = 0;
401         }
402         else
403         {
404                 dy = ratio * sceneRec.height();
405         }
406
407         zoom(QRectF(-dx, -dy, sceneRec.width() + 2 * dx, sceneRec.height() + 2
408                         * dy));
409 }
410
411 // ############################################################### PROTECTED
412
413 /**
414  * Overridden method from QGraphicsScene. Draws all items that should be seen
415  * on the chart.
416  */
417 void FFChartScene::drawItems(QPainter* painter,
418                              int numItems,
419                              QGraphicsItem* items[],
420                              const QStyleOptionGraphicsItem options[],
421                              QWidget* widget)
422 {
423         Q_UNUSED(items)
424         Q_UNUSED(numItems)
425         Q_UNUSED(options)
426
427         // Drawing zoom rectangle
428         if(zoomModeSw)
429         {
430                 zoomRect->paint(painter, new QStyleOptionGraphicsItem, widget);
431         }
432
433         painter->scale(1, 1);
434
435
436         // Drawing subaxes
437         drawSubAxes(painter, widget);
438
439         // Drawing axes
440         drawAxes(painter, widget);
441
442         // Drawing series
443         drawSeries(painter, widget);
444
445         // Drawing axes values
446         drawValues(painter, widget);
447
448         // Drawing static items
449         drawStaticItems(painter, widget);
450 }
451
452 /**
453  * Overridden virtual method from QGraphicsScene. It is responsible for
454  * handling a mouse press event.
455  * @param event Contains all informations about event.
456  */
457 void FFChartScene::mousePressEvent(QGraphicsSceneMouseEvent* event)
458 {
459         QGraphicsScene::mousePressEvent(event);
460
461         kinetic = false;
462         timer->stop();
463         kineticCount = 0;
464
465         if(itemAt(event->scenePos()))
466         {
467                 return;
468         }
469
470         pressPos = event->scenePos();
471         moveModeSw = true;
472         zoomModeSw = false;
473
474         if(timer->isActive() == false)
475         {
476                 timer->start(80);
477         }
478
479         update();
480 }
481
482 /**
483  * Overridden virtual method from QGraphicsScene. It is responsible for
484  * handling a mouse double click event.
485  * @param event Contains all informations about event.
486  */
487 void FFChartScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
488 {
489         if(itemAt(event->scenePos()))
490         {
491                 return;
492         }
493
494         zoomModeSw = true;
495         moveModeSw = false;
496         kinetic = false;
497         kineticCount = 0;
498
499         zoomRect->setRect(event->scenePos().x(), event->scenePos().y(), 1, 1);
500         update();
501 }
502
503 /**
504  * Overridden virtual method from QGraphicsScene. It is responsible for
505  * handling a mouse release event.
506  * @param event Contains all informations about event.
507  */
508 void FFChartScene::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
509 {
510         QGraphicsScene::mouseReleaseEvent(event);
511
512         if(zoomModeSw) // zooming
513         {
514                 zoomModeSw = false;
515
516                 if(qAbs(zoomRect->rect().width()) <= 15
517                                 || qAbs(zoomRect->rect().height()) <= 15)
518                 {
519                         update();
520                         return;
521                 }
522
523                 zoom(zoomRect->rect());
524                 update();
525         }
526         else if(moveModeSw) //moving
527         {
528                 moveModeSw = false;
529
530                 if(oldKineticVec != kineticVec && kineticCount > 2 && zoomModeSw == false)
531                 {
532                         kinetic = true;
533                         kineticVec *= kineticRatio;
534                 }
535                 else
536                 {
537                         kinetic = false;
538                         timer->stop();
539                 }
540         }
541 }
542
543 /**
544  * Overridden virtual method from QGraphicsScene. It is responsible for
545  * handling a mouse move event.
546  * @param event Contains all informations about event.
547  */
548 void FFChartScene::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
549 {
550
551         //if button's type is not left button return
552         if(event->buttons() != Qt::LeftButton)
553         {
554                 return;
555         }
556
557         kineticCount++;
558
559         //updates parameters
560         //zooming mode
561         if(zoomModeSw)
562         {
563                 zoomRect->setRect(pressPos.x(),
564                                   pressPos.y(),
565                                   event->scenePos().x() - pressPos.x(),
566                                   event->scenePos().y() - pressPos.y());
567         }
568         //moving mode
569         else if(moveModeSw)
570         {
571                 QPointF scrollRatio(event->scenePos().x() - pressPos.x(),
572                                    event->scenePos().y() - pressPos.y());
573
574                 oldPressPos = pressPos;
575                 pressPos = event->scenePos();
576                 translateFactor_ += scrollRatio;
577         }
578         update();
579 }
580
581 // ################################################################ PPRIVATE
582
583 /**
584  * Returns a rectangle around all points in series
585  * @param boundaryValues vector of boundary values
586  * @return bounding rectangle QRectF
587  */
588 QRectF FFChartScene::itemsBoundingRect(QVector<float>* boundaryValues)
589 {
590         //if any series are available returns zero rectangle
591         if(series.isEmpty())
592         {
593                 return QRectF(0, 0, 0, 0);
594         }
595         //if only one series is available returns rectangle for points from one
596         //series
597         if(series.size() == 1 && series.at(0)->size() == 1)
598         {
599                 return QRectF(series.at(0)->at(0)->x(),
600                               series.at(0)->at(0)->y(),
601                               0,
602                               0);
603         }
604         //looks for maximum points in all series
605         float minX = series.at(0)->at(0)->x();
606         float maxX = series.at(0)->at(0)->x();
607         float minY = series.at(0)->at(0)->y();
608         float maxY = series.at(0)->at(0)->y();
609
610         for(int i = 0; i < series.size(); ++i)
611         {
612                 for(int j = 0; j < series.at(i)->size(); ++j)
613                 {
614                         if(series.at(i)->at(j)->x() < minX)
615                         {
616                                 minX = series.at(i)->at(j)->x();
617                         }
618
619                         if(series.at(i)->at(j)->y() < minY)
620                         {
621                                 minY = series.at(i)->at(j)->y();
622                         }
623
624                         if(series.at(i)->at(j)->x() > maxX)
625                         {
626                                 maxX = series.at(i)->at(j)->x();
627                         }
628
629                         if(series.at(i)->at(j)->y() > maxY)
630                         {
631                                 maxY = series.at(i)->at(j)->y();
632                         }
633                 }
634         }
635
636         if(boundaryValues)
637         {
638                 boundaryValues->clear();
639                 boundaryValues->append(minX);
640                 boundaryValues->append(minY);
641                 boundaryValues->append(maxX);
642                 boundaryValues->append(maxY);
643         }
644
645         return QRectF(minX, maxY, maxX - minX, maxY - minY);
646 }
647
648 /**
649  * Slot that zooms in by default value.
650  */
651 void FFChartScene::zoomIn()
652 {
653         zoomIn(defaultZoomInRatio);
654 }
655
656 /**
657  * Slot that zooms out by default value.
658  */
659 void FFChartScene::zoomOut()
660 {
661         zoomOut(defaultZoomOutRatio);
662 }
663
664 /**
665  * Draws main axes.
666  * @param painter a tool to drawing elements
667  * @param widget points to the widget where elements will be drew
668  */
669 void FFChartScene::drawAxes(QPainter* painter, QWidget* widget)
670 {
671     Q_UNUSED(widget)
672
673     painter->save();
674
675     painter->setPen(QColor(255, 255, 250));
676
677     // horizontal
678     painter->drawLine(QPointF(0,
679                       translateFactor_.y()),
680                       QPointF(sceneRec.width(),
681                       translateFactor_.y()));
682
683     // vertical
684     painter->drawLine(QPointF(translateFactor_.x(),
685                       0),
686                       QPointF(translateFactor_.x(),
687                       sceneRec.height()));
688
689     painter->restore();
690 }
691
692 /**
693  * Draws subaxes.
694  * @param painter a tool to drawing elements
695  * @param widget points to the widget where elements will be drew
696  */
697 void FFChartScene::drawSubAxes(QPainter* painter, QWidget* widget)
698 {
699         Q_UNUSED(widget);
700
701         painter->save();
702
703         //draws horizontal lines
704         int subaxesNumber = (int)(sceneRec.height() / subaxesSpacing_);
705         qreal offset = translateFactor_.y() - (qFloor(translateFactor_.y() / subaxesSpacing_)) * subaxesSpacing_;
706
707         painter->setPen(subaxesPen_);
708
709         int i;
710         for(i = 0; i <= subaxesNumber; i++)
711         {
712                 painter->drawLine(QPointF(0,
713                                   offset + i * subaxesSpacing_),
714                                   QPointF(sceneRec.width(),
715                                   offset + i * subaxesSpacing_));
716         }
717
718         //draws vertical lines
719         subaxesNumber = (int)(sceneRec.width() / subaxesSpacing_);
720         offset = translateFactor_.x() - (qFloor(translateFactor_.x() / subaxesSpacing_)) * subaxesSpacing_;
721
722         for(i = 0; i <= subaxesNumber; i++)
723         {
724                 painter->drawLine(QPointF(offset + i * subaxesSpacing_,
725                                   0),
726                                   QPointF(offset + i * subaxesSpacing_,
727                                   sceneRec.height()));
728         }
729         painter->restore();
730
731 }
732
733 /**
734  * Draws all series on the chart.
735  * @param painter a tool to drawing elements
736  * @param widget points to the widget where elements will be drew
737  */
738 void FFChartScene::drawSeries(QPainter* painter, QWidget* widget)
739 {
740         Q_UNUSED(widget)
741
742         //saves old painter
743         painter->save();
744         //sets painter's configuration
745         painter->translate(translateFactor_);
746         painter->scale(accumulatedZoomFactor_.width(),
747                        accumulatedZoomFactor_.height());
748
749         transform = painter->transform();
750         transform.rotate(180, Qt::XAxis);
751         painter->setTransform(transform, false);
752
753         //draws series
754         for(int i = 0; i < series.size(); ++i)
755         {
756                 if(!series.at(i)->isVisible())
757                 {
758                         continue;
759                 }
760
761                 painter->setPen(*series.at(i)->pen());
762                 painter->drawPolyline(series.at(i)->data(), series.at(i)->size());
763         }
764         //restores paitner
765         painter->restore();
766 }
767
768 /**
769  * Draws static items (they are not moving and being scaled) on the chart,
770  * e.g. zoom buttons.
771  * @param painter a tool to drawing elements
772  * @param widget points to the widget where elements will be drew
773  */
774 void FFChartScene::drawStaticItems(QPainter* painter, QWidget* widget)
775 {
776         //draws zoomInButton
777         painter->save();
778         painter->setMatrix(zoomInButton.sceneMatrix(), true);
779         zoomInButton.paint(painter, new QStyleOptionGraphicsItem, widget);
780         painter->restore();
781
782         //draws zoomOutButton
783         painter->save();
784         painter->setMatrix(zoomOutButton.sceneMatrix(), true);
785         zoomOutButton.paint(painter, new QStyleOptionGraphicsItem, widget);
786         painter->restore();
787
788         //draws legendButton
789         painter->save();
790         painter->setMatrix(legendButton.sceneMatrix(), true);
791         legendButton.paint(painter, new QStyleOptionGraphicsItem, widget);
792         painter->restore();
793 }
794
795 /*
796  * Draws values next to subaxes.
797  * @param painter a tool to drawing elements
798  * @param widget points to the widget where elements will be drew
799  */
800 void FFChartScene::drawValues(QPainter* painter, QWidget* widget)
801 {
802         Q_UNUSED(widget)
803         //saves painter
804         painter->save();
805
806         //sets painter
807         painter->setPen(axesValuesPen_);
808         painter->setFont(QFont(FONT_TITLE_DEF, 10));
809
810         //sets needed values
811         subaxesSpacing_ *= 2;
812
813         //drawing values of axes
814         int subaxesNumber = (int)(sceneRec.height() / subaxesSpacing_);
815         qreal offset = translateFactor_.y() - (qFloor(translateFactor_.y() / subaxesSpacing_)) * subaxesSpacing_;
816
817         int i;
818
819
820         if(translateFactor_.x() < 0)
821         {
822                 for(i = -1; i <= subaxesNumber; i++)
823                 {
824                         painter->drawText(QPointF(1, offset + i * subaxesSpacing_ + 11), QString::number((-translateFactor_.y() + offset + i * subaxesSpacing_) / -accumulatedZoomFactor_.height(), 'f', 1));
825                 }
826         }
827         else if(translateFactor_.x() > sceneRec.width())
828         {
829                 for(i = -1; i <= subaxesNumber; i++)
830                 {
831                         painter->drawText(QRectF(sceneRec.width() - 305, offset + i * subaxesSpacing_ + 11, 300, 11), Qt::AlignRight | Qt::AlignVCenter, QString::number((-translateFactor_.y() + offset + i * subaxesSpacing_) / -accumulatedZoomFactor_.height(), 'f', 1));
832                 }
833         }
834         else
835         {
836                 for(i = -1; i <= subaxesNumber; i++)
837                 {
838                         painter->drawText(QPointF(translateFactor_.x() + 1, offset + i * subaxesSpacing_ + 11), QString::number((-translateFactor_.y() + offset + i * subaxesSpacing_) / -accumulatedZoomFactor_.height(), 'f', 1));
839                 }
840         }
841
842         subaxesNumber = (int)(sceneRec.width() / subaxesSpacing_);
843         offset = translateFactor_.x() - (qFloor(translateFactor_.x() / subaxesSpacing_)) * subaxesSpacing_;
844
845         if(translateFactor_.y() < 0)
846         {
847                 for(i = -1; i <= subaxesNumber; i++)
848                 {
849                         painter->drawText(QPointF(offset + i * subaxesSpacing_ + 1, 11), QString::number((-translateFactor_.x() + offset + i * subaxesSpacing_) / accumulatedZoomFactor_.width(), 'f', 1));
850                 }
851         }
852         else if(translateFactor_.y() > sceneRec.height())
853         {
854                 for(i = -1; i <= subaxesNumber; i++)
855                 {
856                         painter->drawText(QPointF(offset + i * subaxesSpacing_ + 1, sceneRec.height() - 5), QString::number((-translateFactor_.x() + offset + i * subaxesSpacing_) / accumulatedZoomFactor_.width(), 'f', 1));
857                 }
858         }
859         else
860         {
861                 for(i = -1; i <= subaxesNumber; i++)
862                 {
863                         painter->drawText(QPointF(offset + i * subaxesSpacing_ + 1, translateFactor_.y() + 11), QString::number((-translateFactor_.x() + offset + i * subaxesSpacing_) / accumulatedZoomFactor_.width(), 'f', 1));
864                 }
865         }
866
867         subaxesSpacing_ /= 2;
868
869         painter->restore();
870 }
871
872 /**
873  * This method is responsible for kinetic scrolling.
874  */
875 void FFChartScene::kineticScroll()
876 {
877         //check if kinetic mode is active
878         if(kinetic)
879         {
880                 translateFactor_ += kineticVec;
881
882                 if(qAbs((kineticVec *= 0.8).x()) < 0.5 && qAbs((kineticVec
883                                 *= 0.8).y()) < 0.5)
884                 {
885                         timer->stop();
886                         kinetic = false;
887                 }
888
889                 update();
890         }
891         //otherwise updates kinetic's vectors
892         else
893         {
894                 oldKineticVec = kineticVec;
895                 kineticVec =  pressPos - oldPressPos;
896         }
897 }
898
899 /*!
900  * \fn void FFChartScene::seriesChanged(QList<FFChartSeries*>*);
901  *
902  * Signal that is emitted when the set of series has changed.
903  */