PinchArea default behavior does not respect the pinch center + solution
-
[With Qt 5.15.2:]
When using the default PinchArea behavior by setting pinch.target, the center of the pinch movement is ignored for zooming in or out. Zooming happens with respect to the center of the target.
This can be observed by running below example code and zooming in/out near the border of the area. In certain scenarios, this can even cause the target to go out of reach: zoom in strongly to e.g. the upperleft corner, and the zoom out significantly. The target shrinks to the bottom right and disappears.import QtQuick 2.0 Item { Rectangle { id:thetarget width: parent.width height:parent.height color: "red" border.color:"blue" border.width: 5 Text { width: parent.width height: parent.height text: "FOO\nBAR"; horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.pixelSize: 200 } } PinchArea { id: pinchArea anchors.fill: parent pinch.target: thetarget pinch.minimumRotation: 0 pinch.maximumRotation: 0 pinch.maximumScale: 10 pinch.minimumScale:1 pinch.minimumX: -width * thetarget.scale pinch.maximumX: width * thetarget.scale pinch.minimumY: -height * thetarget.scale pinch.maximumY: height * thetarget.scale pinch.dragAxis: Pinch.XAndYAxis }I worked out a solution:
-
remove the line setting the pinch.target
-
configure a handler for pinch updates by adding below fragment to the PinchArea:
onPinchUpdated: function(pinchEvent) { // scale change: var oldScale = thetarget.scale; var newScale = oldScale * (pinchEvent.scale / pinchEvent.previousScale); newScale = Math.min( Math.max(pinchArea.pinch.minimumScale, newScale), pinchArea.pinch.maximumScale); var scaleRatio = newScale / oldScale; thetarget.scale = newScale; // keep the map center point on its place: thetarget.x *= scaleRatio; thetarget.y *= scaleRatio; // compensate to keep old pinch center in place: var deltaX = pinchEvent.previousCenter.x - thetarget.width/2; // positive if pinching right of center var deltaY = pinchEvent.previousCenter.y - thetarget.height/2; // positive if pinching below center deltaX *= (newScale - oldScale)/newScale; //positive a.o. if pinch center is to the right and zooming in deltaY *= (newScale - oldScale)/newScale; thetarget.x -= deltaX; thetarget.y -= deltaY; // apply the move of the pinch center: deltaX = pinchEvent.center.x - pinchEvent.previousCenter.x; // positive if panning to the right deltaY = pinchEvent.center.y - pinchEvent.previousCenter.y thetarget.x += deltaX; thetarget.y += deltaY; // enforce limits: thetarget.x = Math.min(Math.max(thetarget.x, pinchArea.pinch.minimumX), pinchArea.pinch.maximumX); thetarget.y = Math.min(Math.max(thetarget.y, pinchArea.pinch.minimumY), pinchArea.pinch.maximumY); }Notice that it is important not to put the PinchArea element inside the target element: this would impact the coordinates used in the pinchEvent and invalidates the above calculation.
IMO the current implementation is a bug, but I did not find a ticket in the Qt bug tracker. Not sure if I should/can report an issue...
-