Reputation: 11905
Similar to google.com/maps, I would like it so that if my mouse is over a QGraphicsItem, then when I move the wheelmouse forward and back, the area of the image under the mouse is what is centered in my QGraphicsView.
Can I accomplish this in the wheelEvent method of the custom QGraphicsIte I have created?
I have some code like this
update();
qreal factor = 1.2;
if (event->delta() < 0)
factor = 1.0 / factor;
scale(factor, factor);
scaleFactor *=factor;
this->scene()->setSceneRect(0,0,this->boundingRect().width(), this->boundingRect().height());
What can I add to this to give the desired effect?
As an example, in google maps, if you hold your mouse over utah, and keep zooming in with the wheel mouse, eventually Utah is the only thing left in the viewport.
Upvotes: 0
Views: 2296
Reputation: 6369
Also see setTransformationAnchor( QGraphicsView::AnchorUnderMouse );
Upvotes: 1
Reputation: 5848
Th equation is like ,,,
margin = -half_overflow + (((center_offset - click_offset) * resize_ratio) - (center_offset - click_offset));
... and you have to do it for x and y.
Below Ill paste in some code which does it but keep in mind that this code deals with square images, so I use width for both width and height. For you to use this on rectangle images you will need to also grab the height and use that on all Y calculations where I have width, as well as setting all of vars which I am using like content_width etc. But the algorithm are all there and you can work it out from the code ...
zoomChart: function(e)
{
var chart_max = 2048;
var zoom_max = egapp.user.options.zoom_multiplier || 2; // >= 2
var chart_bounds = $('#egapp_chart_bounds');
var chart_imgs = chart_bounds.find('img');
var width = chart_imgs.width();
if (width == chart_bounds.width()) { // zoom in
// margin = -half_overflow + (((center_offset - click_offset) * resize_ratio) - (center_offset - click_offset));
chart_bounds.removeClass('egapp_zoom_in');
if (width == chart_max)
return;
chart_bounds.addClass('egapp_zoom_out');
var new_width = parseInt(width * zoom_max);
if (new_width > chart_max)
new_width = chart_max;
var ratio = new_width / width;
var moveX = moveY = -((new_width - width) / 2);
var chart_offset = chart_bounds.offset();
var offsetX = (chart_offset.left + (width / 2)) - e.pageX;
var offsetY = (chart_offset.top + (width / 2)) - e.pageY;
moveX += parseInt((offsetX * ratio) - offsetX);
moveY += parseInt((offsetY * ratio) - offsetY);
chart_imgs.animate({width: new_width+'px', height: new_width+'px', marginLeft: moveX+'px', marginTop: moveY+'px'}, 'fast');
chart_bounds.addClass('egapp_zoom_out');
}
else { // zoom out
var new_width = egapp.content_width - 10;
chart_imgs.animate({width: new_width+'px', height: new_width+'px', marginLeft: 0, marginTop: 0}, 'fast');
chart_bounds.removeClass('egapp_zoom_out').addClass('egapp_zoom_in');
}
},
The HTML is something like ...
<div id="egapp_chart_bounds" style="width: 608px; height: 608px;" class="egapp_zoom_in">
<img id="egapp_timeline_chart" src="some.image" class="egapp_chart" style="width: 608px; height: 608px; margin-left: 0px; margin-top: 0px;">
<img id="egapp_expression_chart_9" src="overlay.image" class="egapp_chart_overlay" style="width: 608px; height: 608px;">
</div>
And the CSS is like ...
#egapp_chart_bounds{
overflow: hidden;
}
.egapp_chart, .egapp_chart_overlay{
position: absolute;
}
.egapp_zoom_in{
cursor: -moz-zoom-in;
cursor: -webkit-zoom-in;
cursor: zoom-in;
}
.egapp_zoom_out{
cursor: -moz-zoom-out;
cursor: -webkit-zoom-out;
cursor: zoom-out;
}
Upvotes: 0
Reputation: 11732
Let's rephrase your aim in a more direct way. On the wheel event:
You've implemented (1) with the scale call. What remains is (2). To scroll the view to a certain location, you need to do:
horizontalScrollbar().setValue(x);
verticalScrollbar().setValue(y);
This scrolls the scene so (x, y) is at the top-left corner of the view. But you want (x, y) to be at the mouse position (in relation to the QGraphicsView). So you need to scroll to (x-mx, y-my) where (mx, my) is the mouse position in relation to the QGraphicsView and (x, y) is the scene position that was under the mouse before the wheel event.
This is untested and may be wrong in the details (for example in the exact behavior of QScrollBar::setValue) but the math concept is correct so it should be enough for you to get it working.
Upvotes: 0