--- /dev/null
+/*
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+http://www.gnu.org/licenses/gpl-3.0.txt
+*/
+/**
+ * @file ffchartscene.cpp
+ * @brief Implementation of the FFChartScene class.
+ *
+ * @author ComArch S.A.
+ * @date 2009.09.01
+ * @version 1.1
+ */
+
+#include "ffchartscene.h"
+
+// ############################################################ CONSTRUCTORS
+
+/**
+ * Constructs a FFChartScene with a parent.
+ */
+FFChartScene::FFChartScene(QObject* parent) :
+ QGraphicsScene(parent)
+{
+ init();
+}
+
+/**
+ * A virtual destructor.
+ */
+FFChartScene::~FFChartScene()
+{
+
+}
+
+/**
+ * Initiates an object of FFChartScene. Sets all needed fields connections.
+ * It is called by all constructors.
+ */
+void FFChartScene::init()
+{
+ //sets default configuration
+ moveModeSw = false;
+ zoomModeSw = false;
+ kineticCount = 0;
+
+ accumulatedZoomFactor_ = QSize(1, 1);
+ QBrush zoomRectBrush(QColor(60, 80, 60));
+
+ QPen zoomRectPen;
+ zoomRectPen.setBrush(zoomRectBrush);
+ zoomRectPen.setColor(QColor(80, 180, 80));
+ zoomRectPen.setWidth(3);
+
+ zoomRect = new QGraphicsRectItem;
+ zoomRect->setPen(zoomRectPen);
+ zoomRect->setBrush(zoomRectBrush);
+ setBackgroundBrush(QBrush(QColor(30, 30, 30)));
+
+ timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), this, SLOT(kineticScroll()));
+
+ zoomInButton.moveBy(10,10);
+ zoomOutButton.moveBy(10,90);
+ legendButton.moveBy(10, sceneRect().height() - 70);
+
+ subaxesSpacing_ = 40;
+ subaxesPen_.setColor(QColor(80,80,80));
+ subaxesPen_.setStyle(Qt::DashLine);
+ subaxesPen_.setCosmetic(true);
+
+ axesValuesPen_.setColor(QColor(240, 240, 240));
+
+ //adds button to chart
+ addItem(&zoomInButton);
+ addItem(&zoomOutButton);
+ addItem(&legendButton);
+
+
+
+ //connects
+ connect(&zoomInButton, SIGNAL(mouseRelease()), this, SLOT(zoomIn()));
+ connect(&zoomOutButton, SIGNAL(mouseRelease()), this, SLOT(zoomOut()));
+ connect(&legendButton, SIGNAL(mouseRelease()), parent(), SLOT(showLegend()));
+
+ //sets chart's buttons
+ zoomInButton.setImage(":/standard/chart_zoomin");
+ zoomOutButton.setImage(":/standard/chart_zoomout");
+ legendButton.setImage(":/standard/chart_legendON",":/standard/chart_legendOFF");
+
+ zoomInButton.setZoomRatio(1.4);
+ zoomOutButton.setZoomRatio(0.6);
+ legendButton.setZoomRatio(1.4);
+
+ zoomInButton.setSize(QSize(60, 60));
+ zoomOutButton.setSize(QSize(60, 60));
+ legendButton.setSize(QSize(60, 60));
+
+}
+
+// ################################################################## PUBLIC
+
+/**
+ * Moves given point of chart to the scene's top left corner.
+ */
+void FFChartScene::moveTo(QPoint point)
+{
+ translateFactor_ = point;
+ update();
+}
+
+/**
+ * Moves given point of chart to the scene's top left corner.
+ */
+void FFChartScene::moveTo(float x, float y)
+{
+ translateFactor_ = QPointF(x, y);
+ update();
+}
+
+/**
+ * Moves the chart by a given vector.
+ */
+void FFChartScene::moveBy(QPoint destPoint)
+{
+ translateFactor_ += destPoint;
+ update();
+}
+
+/**
+ * Moves the chart by a given vector.
+ */
+void FFChartScene::moveBy(float x, float y)
+{
+ translateFactor_ += QPointF(x, y);
+ update();
+}
+
+/**
+ * Adds set of points to chart.
+ */
+void FFChartScene::addSeries(FFChartSeries* series)
+{
+ this->series.append(series);
+ itemsBoundingRect_ = itemsBoundingRect(&itemsBoundingValues_);
+
+ update();
+
+ emit seriesChanged(this->series);
+}
+
+/**
+ * Sets a list of series.
+ */
+void FFChartScene::setSeries(QList<FFChartSeries*> series)
+{
+ this->series = series;
+ itemsBoundingRect_ = itemsBoundingRect(&itemsBoundingValues_);
+
+ update();
+
+ emit seriesChanged(&series);
+}
+
+/**
+ * Overridden method from QGraphicsScene.
+ */
+void FFChartScene::setSceneRect(const QRectF& rect)
+{
+ QGraphicsScene::setSceneRect(rect);
+ legendButton.setPos(10, rect.height() - 70);
+
+ translateFactor_.setX(rect.width() * 0.5);
+ translateFactor_.setY(rect.height() * 0.5);
+
+ sceneRec = rect;
+}
+
+/**
+ * Sets a distance in pixels between subaxes.
+ */
+void FFChartScene::setSubaxesSpacing(const float& subaxesSpacing)
+{
+ subaxesSpacing_ = subaxesSpacing;
+}
+
+/**
+ * Returns a distance in pixels between subaxes.
+ */
+float FFChartScene::subaxesSpacing() const
+{
+ return subaxesSpacing_;
+}
+
+/**
+ * Sets a pen that will be used to draw subaxes.
+ */
+void FFChartScene::setSubaxesPen(const QPen& subaxesPen)
+{
+ subaxesPen_ = subaxesPen;
+}
+
+/**
+ * Returns a pen that is used to draw subaxes.
+ */
+QPen FFChartScene::subaxesPen() const
+{
+ return subaxesPen_;
+}
+
+/**
+ * Sets a pen that will be used to draw values next to subaxes.
+ */
+void FFChartScene::setAxesValuesPen(const QPen& axesValuesPen)
+{
+ axesValuesPen_ = axesValuesPen;
+}
+
+/**
+ * Returns a pen that is used to draw values next to subaxes.
+ */
+QPen FFChartScene::axesValuesPen() const
+{
+ return axesValuesPen_;
+}
+
+// ############################################################ PUBLIC SLOTS
+
+/**
+ * Zooms the chart into the given rectangle.
+ */
+void FFChartScene::zoom(QRectF zoomRect)
+{
+ // Normalizing zoom rectangle (width and height must are greater than 0)
+ QRectF zoomRectNormalized(zoomRect);
+ if(zoomRect.width() < 0)
+ {
+ zoomRectNormalized.setX(zoomRect.x() + zoomRect.width());
+ zoomRectNormalized.setWidth(qAbs(zoomRect.width()));
+ }
+ if(zoomRect.height() < 0)
+ {
+ zoomRectNormalized.setY(zoomRect.y() + zoomRect.height());
+ zoomRectNormalized.setHeight(qAbs(zoomRect.height()));
+ }
+
+ // Calculating zoom factor for scale() function ( >1 zoomin, <1 zoomout )
+ QSizeF zoomFactor(sceneRec.width() / zoomRectNormalized.width(),
+ sceneRec.height() / zoomRectNormalized.height());
+
+ accumulatedZoomFactor_.setWidth(zoomFactor.width()
+ * accumulatedZoomFactor_.width());
+ accumulatedZoomFactor_.setHeight(zoomFactor.height()
+ * accumulatedZoomFactor_.height());
+ //checking if factor of zooming is not to high
+ if(accumulatedZoomFactor_.width() > 20 || accumulatedZoomFactor_.height() > 20)
+ {
+ accumulatedZoomFactor_.setWidth(20);
+ accumulatedZoomFactor_.setHeight(20);
+ return;
+ }
+
+
+
+ translateFactor_ = QPointF((translateFactor_.x()
+ - zoomRectNormalized.x())
+ * zoomFactor.width(),
+ (translateFactor_.y()
+ - zoomRectNormalized.y())
+ * zoomFactor.height());
+
+ update();
+}
+
+/**
+ * Slot that changes series' set.
+ */
+void FFChartScene::seriesChanged(QList<FFChartSeries*> series)
+{
+ setSeries(series);
+}
+
+/**
+ * Slot that zooms in the current chart into a rectangle which is smaller by
+ * a given ratio.
+ */
+void FFChartScene::zoomIn(qreal ratio)
+{
+ qreal dx, dy;
+
+ if(accumulatedZoomFactor_.width() > 15)
+ {
+ dx = 0;
+ }
+ else
+ {
+ dx = ratio * sceneRec.width();
+ }
+
+ if(accumulatedZoomFactor_.height() > 15)
+ {
+ dy = 0;
+ }
+ else
+ {
+ dy = ratio * sceneRec.height();
+ }
+
+ zoom(QRectF(dx, dy, sceneRec.width() - 2 * dx, sceneRec.height() - 2
+ * dy));
+}
+
+/**
+ * Slot that zooms out the current chart into a rectangle which is larger by
+ * a given ratio.
+ */
+void FFChartScene::zoomOut(qreal ratio)
+{
+ qreal dx, dy;
+
+ if(accumulatedZoomFactor_.width() < 0.1)
+ {
+ dx = 0;
+ }
+ else
+ {
+ dx = ratio * sceneRec.width();
+ }
+
+ if(accumulatedZoomFactor_.height() < 0.1)
+ {
+ dy = 0;
+ }
+ else
+ {
+ dy = ratio * sceneRec.height();
+ }
+
+ zoom(QRectF(-dx, -dy, sceneRec.width() + 2 * dx, sceneRec.height() + 2
+ * dy));
+}
+
+// ############################################################### PROTECTED
+
+/**
+ * Overridden method from QGraphicsScene. Draws all items that should be seen
+ * on the chart.
+ */
+void FFChartScene::drawItems(QPainter* painter,
+ int numItems,
+ QGraphicsItem* items[],
+ const QStyleOptionGraphicsItem options[],
+ QWidget* widget)
+{
+ Q_UNUSED(items)
+ Q_UNUSED(numItems)
+ Q_UNUSED(options)
+
+ // Drawing zoom rectangle
+ if(zoomModeSw)
+ {
+ zoomRect->paint(painter, new QStyleOptionGraphicsItem, widget);
+ }
+
+ painter->scale(1, 1);
+
+
+ // Drawing subaxes
+ drawSubAxes(painter, widget);
+
+ // Drawing axes
+ drawAxes(painter, widget);
+
+ // Drawing series
+ drawSeries(painter, widget);
+
+ // Drawing axes values
+ drawValues(painter, widget);
+
+ // Drawing static items
+ drawStaticItems(painter, widget);
+}
+
+/**
+ * Overridden virtual method from QGraphicsScene. It is responsible for
+ * handling a mouse press event.
+ * @param event Contains all informations about event.
+ */
+void FFChartScene::mousePressEvent(QGraphicsSceneMouseEvent* event)
+{
+ QGraphicsScene::mousePressEvent(event);
+
+ kinetic = false;
+ timer->stop();
+ kineticCount = 0;
+
+ if(itemAt(event->scenePos()))
+ {
+ return;
+ }
+
+ pressPos = event->scenePos();
+ moveModeSw = true;
+ zoomModeSw = false;
+
+ if(timer->isActive() == false)
+ {
+ timer->start(80);
+ }
+
+ update();
+}
+
+/**
+ * Overridden virtual method from QGraphicsScene. It is responsible for
+ * handling a mouse double click event.
+ * @param event Contains all informations about event.
+ */
+void FFChartScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
+{
+ if(itemAt(event->scenePos()))
+ {
+ return;
+ }
+
+ zoomModeSw = true;
+ moveModeSw = false;
+ kinetic = false;
+ kineticCount = 0;
+
+ zoomRect->setRect(event->scenePos().x(), event->scenePos().y(), 1, 1);
+ update();
+}
+
+/**
+ * Overridden virtual method from QGraphicsScene. It is responsible for
+ * handling a mouse release event.
+ * @param event Contains all informations about event.
+ */
+void FFChartScene::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
+{
+ QGraphicsScene::mouseReleaseEvent(event);
+
+ if(zoomModeSw) // zooming
+ {
+ zoomModeSw = false;
+
+ if(qAbs(zoomRect->rect().width()) <= 15
+ || qAbs(zoomRect->rect().height()) <= 15)
+ {
+ update();
+ return;
+ }
+
+ zoom(zoomRect->rect());
+ update();
+ }
+ else if(moveModeSw) //moving
+ {
+ moveModeSw = false;
+
+ if(oldKineticVec != kineticVec && kineticCount > 2 && zoomModeSw == false)
+ {
+ kinetic = true;
+ kineticVec *= kineticRatio;
+ }
+ else
+ {
+ kinetic = false;
+ timer->stop();
+ }
+ }
+}
+
+/**
+ * Overridden virtual method from QGraphicsScene. It is responsible for
+ * handling a mouse move event.
+ * @param event Contains all informations about event.
+ */
+void FFChartScene::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
+{
+
+ //if button's type is not left button return
+ if(event->buttons() != Qt::LeftButton)
+ {
+ return;
+ }
+
+ kineticCount++;
+
+ //updates parameters
+ //zooming mode
+ if(zoomModeSw)
+ {
+ zoomRect->setRect(pressPos.x(),
+ pressPos.y(),
+ event->scenePos().x() - pressPos.x(),
+ event->scenePos().y() - pressPos.y());
+ }
+ //moving mode
+ else if(moveModeSw)
+ {
+ QPointF scrollRatio(event->scenePos().x() - pressPos.x(),
+ event->scenePos().y() - pressPos.y());
+
+ oldPressPos = pressPos;
+ pressPos = event->scenePos();
+ translateFactor_ += scrollRatio;
+ }
+ update();
+}
+
+// ################################################################ PPRIVATE
+
+/**
+ * Returns a rectangle around all points in series
+ * @param boundaryValues vector of boundary values
+ * @return bounding rectangle QRectF
+ */
+QRectF FFChartScene::itemsBoundingRect(QVector<float>* boundaryValues)
+{
+ //if any series are available returns zero rectangle
+ if(series.isEmpty())
+ {
+ return QRectF(0, 0, 0, 0);
+ }
+ //if only one series is available returns rectangle for points from one
+ //series
+ if(series.size() == 1 && series.at(0)->size() == 1)
+ {
+ return QRectF(series.at(0)->at(0)->x(),
+ series.at(0)->at(0)->y(),
+ 0,
+ 0);
+ }
+ //looks for maximum points in all series
+ float minX = series.at(0)->at(0)->x();
+ float maxX = series.at(0)->at(0)->x();
+ float minY = series.at(0)->at(0)->y();
+ float maxY = series.at(0)->at(0)->y();
+
+ for(int i = 0; i < series.size(); ++i)
+ {
+ for(int j = 0; j < series.at(i)->size(); ++j)
+ {
+ if(series.at(i)->at(j)->x() < minX)
+ {
+ minX = series.at(i)->at(j)->x();
+ }
+
+ if(series.at(i)->at(j)->y() < minY)
+ {
+ minY = series.at(i)->at(j)->y();
+ }
+
+ if(series.at(i)->at(j)->x() > maxX)
+ {
+ maxX = series.at(i)->at(j)->x();
+ }
+
+ if(series.at(i)->at(j)->y() > maxY)
+ {
+ maxY = series.at(i)->at(j)->y();
+ }
+ }
+ }
+
+ if(boundaryValues)
+ {
+ boundaryValues->clear();
+ boundaryValues->append(minX);
+ boundaryValues->append(minY);
+ boundaryValues->append(maxX);
+ boundaryValues->append(maxY);
+ }
+
+ return QRectF(minX, maxY, maxX - minX, maxY - minY);
+}
+
+/**
+ * Slot that zooms in by default value.
+ */
+void FFChartScene::zoomIn()
+{
+ zoomIn(defaultZoomInRatio);
+}
+
+/**
+ * Slot that zooms out by default value.
+ */
+void FFChartScene::zoomOut()
+{
+ zoomOut(defaultZoomOutRatio);
+}
+
+/**
+ * Draws main axes.
+ * @param painter a tool to drawing elements
+ * @param widget points to the widget where elements will be drew
+ */
+void FFChartScene::drawAxes(QPainter* painter, QWidget* widget)
+{
+ Q_UNUSED(widget)
+
+ painter->save();
+
+ painter->setPen(QColor(255, 255, 250));
+
+ // horizontal
+ painter->drawLine(QPointF(0,
+ translateFactor_.y()),
+ QPointF(sceneRec.width(),
+ translateFactor_.y()));
+
+ // vertical
+ painter->drawLine(QPointF(translateFactor_.x(),
+ 0),
+ QPointF(translateFactor_.x(),
+ sceneRec.height()));
+
+ painter->restore();
+}
+
+/**
+ * Draws subaxes.
+ * @param painter a tool to drawing elements
+ * @param widget points to the widget where elements will be drew
+ */
+void FFChartScene::drawSubAxes(QPainter* painter, QWidget* widget)
+{
+ Q_UNUSED(widget);
+
+ painter->save();
+
+ //draws horizontal lines
+ int subaxesNumber = (int)(sceneRec.height() / subaxesSpacing_);
+ qreal offset = translateFactor_.y() - (qFloor(translateFactor_.y() / subaxesSpacing_)) * subaxesSpacing_;
+
+ painter->setPen(subaxesPen_);
+
+ int i;
+ for(i = 0; i <= subaxesNumber; i++)
+ {
+ painter->drawLine(QPointF(0,
+ offset + i * subaxesSpacing_),
+ QPointF(sceneRec.width(),
+ offset + i * subaxesSpacing_));
+ }
+
+ //draws vertical lines
+ subaxesNumber = (int)(sceneRec.width() / subaxesSpacing_);
+ offset = translateFactor_.x() - (qFloor(translateFactor_.x() / subaxesSpacing_)) * subaxesSpacing_;
+
+ for(i = 0; i <= subaxesNumber; i++)
+ {
+ painter->drawLine(QPointF(offset + i * subaxesSpacing_,
+ 0),
+ QPointF(offset + i * subaxesSpacing_,
+ sceneRec.height()));
+ }
+ painter->restore();
+
+}
+
+/**
+ * Draws all series on the chart.
+ * @param painter a tool to drawing elements
+ * @param widget points to the widget where elements will be drew
+ */
+void FFChartScene::drawSeries(QPainter* painter, QWidget* widget)
+{
+ Q_UNUSED(widget)
+
+ //saves old painter
+ painter->save();
+ //sets painter's configuration
+ painter->translate(translateFactor_);
+ painter->scale(accumulatedZoomFactor_.width(),
+ accumulatedZoomFactor_.height());
+
+ transform = painter->transform();
+ transform.rotate(180, Qt::XAxis);
+ painter->setTransform(transform, false);
+
+ //draws series
+ for(int i = 0; i < series.size(); ++i)
+ {
+ if(!series.at(i)->isVisible())
+ {
+ continue;
+ }
+
+ painter->setPen(*series.at(i)->pen());
+ painter->drawPolyline(series.at(i)->data(), series.at(i)->size());
+ }
+ //restores paitner
+ painter->restore();
+}
+
+/**
+ * Draws static items (they are not moving and being scaled) on the chart,
+ * e.g. zoom buttons.
+ * @param painter a tool to drawing elements
+ * @param widget points to the widget where elements will be drew
+ */
+void FFChartScene::drawStaticItems(QPainter* painter, QWidget* widget)
+{
+ //draws zoomInButton
+ painter->save();
+ painter->setMatrix(zoomInButton.sceneMatrix(), true);
+ zoomInButton.paint(painter, new QStyleOptionGraphicsItem, widget);
+ painter->restore();
+
+ //draws zoomOutButton
+ painter->save();
+ painter->setMatrix(zoomOutButton.sceneMatrix(), true);
+ zoomOutButton.paint(painter, new QStyleOptionGraphicsItem, widget);
+ painter->restore();
+
+ //draws legendButton
+ painter->save();
+ painter->setMatrix(legendButton.sceneMatrix(), true);
+ legendButton.paint(painter, new QStyleOptionGraphicsItem, widget);
+ painter->restore();
+}
+
+/*
+ * Draws values next to subaxes.
+ * @param painter a tool to drawing elements
+ * @param widget points to the widget where elements will be drew
+ */
+void FFChartScene::drawValues(QPainter* painter, QWidget* widget)
+{
+ Q_UNUSED(widget)
+ //saves painter
+ painter->save();
+
+ //sets painter
+ painter->setPen(axesValuesPen_);
+ painter->setFont(QFont(FONT_TITLE_DEF, 10));
+
+ //sets needed values
+ subaxesSpacing_ *= 2;
+
+ //drawing values of axes
+ int subaxesNumber = (int)(sceneRec.height() / subaxesSpacing_);
+ qreal offset = translateFactor_.y() - (qFloor(translateFactor_.y() / subaxesSpacing_)) * subaxesSpacing_;
+
+ int i;
+
+
+ if(translateFactor_.x() < 0)
+ {
+ for(i = -1; i <= subaxesNumber; i++)
+ {
+ painter->drawText(QPointF(1, offset + i * subaxesSpacing_ + 11), QString::number((-translateFactor_.y() + offset + i * subaxesSpacing_) / -accumulatedZoomFactor_.height(), 'f', 1));
+ }
+ }
+ else if(translateFactor_.x() > sceneRec.width())
+ {
+ for(i = -1; i <= subaxesNumber; i++)
+ {
+ 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));
+ }
+ }
+ else
+ {
+ for(i = -1; i <= subaxesNumber; i++)
+ {
+ painter->drawText(QPointF(translateFactor_.x() + 1, offset + i * subaxesSpacing_ + 11), QString::number((-translateFactor_.y() + offset + i * subaxesSpacing_) / -accumulatedZoomFactor_.height(), 'f', 1));
+ }
+ }
+
+ subaxesNumber = (int)(sceneRec.width() / subaxesSpacing_);
+ offset = translateFactor_.x() - (qFloor(translateFactor_.x() / subaxesSpacing_)) * subaxesSpacing_;
+
+ if(translateFactor_.y() < 0)
+ {
+ for(i = -1; i <= subaxesNumber; i++)
+ {
+ painter->drawText(QPointF(offset + i * subaxesSpacing_ + 1, 11), QString::number((-translateFactor_.x() + offset + i * subaxesSpacing_) / accumulatedZoomFactor_.width(), 'f', 1));
+ }
+ }
+ else if(translateFactor_.y() > sceneRec.height())
+ {
+ for(i = -1; i <= subaxesNumber; i++)
+ {
+ painter->drawText(QPointF(offset + i * subaxesSpacing_ + 1, sceneRec.height() - 5), QString::number((-translateFactor_.x() + offset + i * subaxesSpacing_) / accumulatedZoomFactor_.width(), 'f', 1));
+ }
+ }
+ else
+ {
+ for(i = -1; i <= subaxesNumber; i++)
+ {
+ painter->drawText(QPointF(offset + i * subaxesSpacing_ + 1, translateFactor_.y() + 11), QString::number((-translateFactor_.x() + offset + i * subaxesSpacing_) / accumulatedZoomFactor_.width(), 'f', 1));
+ }
+ }
+
+ subaxesSpacing_ /= 2;
+
+ painter->restore();
+}
+
+/**
+ * This method is responsible for kinetic scrolling.
+ */
+void FFChartScene::kineticScroll()
+{
+ //check if kinetic mode is active
+ if(kinetic)
+ {
+ translateFactor_ += kineticVec;
+
+ if(qAbs((kineticVec *= 0.8).x()) < 0.5 && qAbs((kineticVec
+ *= 0.8).y()) < 0.5)
+ {
+ timer->stop();
+ kinetic = false;
+ }
+
+ update();
+ }
+ //otherwise updates kinetic's vectors
+ else
+ {
+ oldKineticVec = kineticVec;
+ kineticVec = pressPos - oldPressPos;
+ }
+}
+
+/*!
+ * \fn void FFChartScene::seriesChanged(QList<FFChartSeries*>*);
+ *
+ * Signal that is emitted when the set of series has changed.
+ */