5

In my application I use QChart to show line graph. Unfortunately Qt Charts doesn't support such basic functions as zooming using mouse wheel and scrolling by mouse. Yes, there is RubberBand functionality but that still doesn't support scrolling etc end that isn't so intuitive to users. Also I need to scale only x-axis, some kind of setRubberBand(QChartView::HorizontalRubberBand) but using mouse wheel. So far, after diving into QChartView I've use the following workaround:

class ChartView : public QChartView {
protected:
    void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE
    {
        QRectF rect = chart()->plotArea();            
        if(event->angleDelta().y() > 0)
        {
            rect.setX(rect.x() + rect.width() / 4);
            rect.setWidth(rect.width() / 2);                                   
        }
        else
        {
            qreal adjustment = rect.width() / 2;
            rect.adjust(-adjustment, 0, adjustment, 0);                    
        }            
        chart()->zoomIn(rect);
        event->accept();            
        QChartView::wheelEvent(event);
    }
}

That works but zooming in and then zooming out doesn't lead to the same result. There is a small deviation. After debuging I've found that chart()->plotArea() always returns the same rect, so this workaround was useless.

It there some way to get rect of a visible area only? Or may be someone could point me to the right solution how to do zooming/scrolling by mouse for QChartView?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
folibis
  • 12,048
  • 6
  • 54
  • 97

2 Answers2

5

Instead of using zoomIn() and zoomOut() you could use zoom() as shown below:

class ChartView : public QChartView {
protected:
    void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE
    {
        qreal factor = event->angleDelta().y() > 0? 0.5: 2.0;
        chart()->zoom(factor);
        event->accept();
        QChartView::wheelEvent(event);
    }
};

Regarding zoomIn() and zoomOut(), it is not clear to what kind of coordinates it refers, I am still investing, when I have more information I will update my answer.

update:

As I observe one of the problems is the multiplication of floating point, and the other is to locate the center of the figure, to not have those problems my solution resets the zoom and then sets the change:

class ChartView : public QChartView {
    qreal mFactor=1.0;
protected:
    void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE
    {
        chart()->zoomReset();

        mFactor *= event->angleDelta().y() > 0 ? 0.5 : 2;

        QRectF rect = chart()->plotArea();
        QPointF c = chart()->plotArea().center();
        rect.setWidth(mFactor*rect.width());
        rect.moveCenter(c);
        chart()->zoomIn(rect);

        QChartView::wheelEvent(event);
    }
};
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thanks for the answer. I've forgot to notice, I need only x-axis scaling. So zoom is not so usable here. Some kind like `setRubberBand(QChartView::HorizontalRubberBand)` but using mouse wheel. – folibis Feb 05 '18 at 20:38
  • @folibis I have added a new solution. :D – eyllanesc Feb 05 '18 at 22:19
  • Nice solution, @eyllanesc! Thanks! That helped me very much. Another solution I've found so far is just a small correction of `QChartPrivate::zoomIn()` i.e. remove height scaling but that will require to create custom class inherits from QChart. Your solution is more elegant. – folibis Feb 06 '18 at 07:09
2

I got this working for both x and y zooming with the following code:

void wheelEvent(QWheelEvent *event){
qreal factor;
if ( event->delta() > 0 )
    factor = 2.0;
else
    factor = 0.5;

QRectF r = QRectF(chart()->plotArea().left(),chart()->plotArea().top(),
                                    chart()->plotArea().width()/factor,chart()->plotArea().height()/factor);
QPointF mousePos = mapFromGlobal(QCursor::pos());
r.moveCenter(mousePos);
chart()->zoomIn(r);
QPointF delta = chart()->plotArea().center() -mousePos;
chart()->scroll(delta.x(),-delta.y());}
yonnak
  • 21
  • 1