0

I used QWT for my project. I used Qwtplotmagnifier for zoom. I want to zoom in relative to the mouse cursor. Can you Help me?

Jan Černý
  • 1,268
  • 2
  • 17
  • 31

2 Answers2

1

I had the same problem and I could not find any answer, so here is mine. Based on this post : Calculating view offset for zooming in at the position of the mouse cursor

In order to implement a GoogleMap-style zoom, you have to inherit from QwtPlotMagnifier and reimplement widgetWheelEvent in order to store the cursor position when a scroll happens, and rescale function, to change the behavior of the zoom.

//widgetWheelEvent method
void CenterMouseMagnifier::widgetWheelEvent(QWheelEvent *wheelEvent)
{
   this->cursorPos = wheelEvent->pos();
   QwtPlotMagnifier::widgetWheelEvent(wheelEvent);
}

For the rescale method, I used the source code and modified it. You need to use the QwtScaleMap object of the canvas to transform the mouse cursor coordinates into axis coordinates of your plot. And finally, you just need to apply the formula given in the other post.

//rescale method
void CenterMouseMagnifier::rescale(double factor)
{
    QwtPlot* plt = plot();
    if ( plt == nullptr )
        return;

    factor = qAbs( factor );
    if ( factor == 1.0 || factor == 0.0 )
        return;

    bool doReplot = false;

    const bool autoReplot = plt->autoReplot();
    plt->setAutoReplot( false );

    for ( int axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
    {
        if ( isAxisEnabled( axisId ) )
        {
            const QwtScaleMap scaleMap = plt->canvasMap( axisId );

            double v1 = scaleMap.s1(); //v1 is the bottom value of the axis scale
            double v2 = scaleMap.s2(); //v2 is the top value of the axis scale

            if ( scaleMap.transformation() )
            {
                // the coordinate system of the paint device is always linear
                v1 = scaleMap.transform( v1 ); // scaleMap.p1()
                v2 = scaleMap.transform( v2 ); // scaleMap.p2()
            }

            double c=0; //represent the position of the cursor in the axis coordinates
            if (axisId == QwtPlot::xBottom) //we only work with these two axis
                c = scaleMap.invTransform(cursorPos.x());
            if (axisId == QwtPlot::yLeft)
                c = scaleMap.invTransform(cursorPos.y());

            const double center = 0.5 * ( v1 + v2 );
            const double width_2 = 0.5 * ( v2 - v1 ) * factor;
            const double newCenter = c - factor * (c - center);

            v1 = newCenter - width_2;
            v2 = newCenter + width_2;

            if ( scaleMap.transformation() )
            {
                v1 = scaleMap.invTransform( v1 );
                v2 = scaleMap.invTransform( v2 );
            }

            plt->setAxisScale( axisId, v1, v2 );
            doReplot = true;
        }
    }

    plt->setAutoReplot( autoReplot );

    if ( doReplot )
        plt->replot();
}

This works fine for me.

Victor
  • 11
  • 1
0

Based on this forum post:

bool ParentWidget::eventFilter(QObject *o, QEvent *e)
{
    QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(e);
    if (mouseEvent->type()==QMouseEvent::MouseButtonPress && ((mouseEvent->buttons() & Qt::LeftButton)==Qt::LeftButton)) //do zoom on a mouse click
    {
        QRectF widgetRect(mouseEvent->pos().x() - 50, mouseEvent->pos().y() - 50, 100, 100); //build a rectangle around mouse cursor position

        const QwtScaleMap xMap = plot->canvasMap(zoom->xAxis());
        const QwtScaleMap yMap = plot->canvasMap(zoom->yAxis());
        QRectF scaleRect = QRectF(
            QPointF(xMap.invTransform(widgetRect.x()), yMap.invTransform(widgetRect.y())),
            QPointF(xMap.invTransform(widgetRect.right()), yMap.invTransform(widgetRect.bottom())) ); //translate mouse rectangle to zoom rectangle

        zoom->zoom(scaleRect);
    }
}
lena
  • 1,181
  • 12
  • 36