Qt World Summit: Submit your Presentation

Flickable calculate position depending on scale

  • Hello,
    I am relatively new to QML so probably I am missing something obvious.

    I am trying to "reproject" a flickable item (an image) to get its X, Y in original values in order to regenerate an image after a zoom or pan occurred. To make it short I need to know where is the topleft corner in the image source coordinates. It is very easy to do for a drag movement but I cannot find a solution when a pinch occurs.

    At the beginning the flickable item is centered on the center of the image, and I save the initial X and Y values:

        flick.contentWidth = img.sourceSize.width
        flick.contentHeight = img.sourceSize.height
        flick.contentX = (flick.contentWidth - rect.width) / 2
        flick.contentY = (flick.contentHeight - rect.height) / 2
        initialX = flick.contentX
        initialY = flick.contentY
        initialW = flick.contentWidth'

    Then when a drag occurs I get what I need with something like:

       backend.sendImageChange(flick.contentX - initialX, flick.contentY - initialY, 1.0)

    But I cannot figure a way to do it when a pinch occurs. I have no problem calculating the current scale which is initialW/contentWidth, but I cannot find a way to convert the new contentX and contentY back in original image coordinates. The pinchArea is:

        PinchArea {
            id: pi
            width: Math.max(flick.contentWidth, flick.width)
            height: Math.max(flick.contentHeight, flick.height)
            property real initialWidth
            property real initialHeight
            onPinchStarted: {
                initialWidth = flick.contentWidth
                initialHeight = flick.contentHeight
                console.log("pinch start", flick.contentX, flick.contentY, flick.contentWidth, flick.contentHeight, flick.scale)
            onPinchUpdated: {
                // adjust content pos due to drag
                flick.contentX += pinch.previousCenter.x - pinch.center.x
                flick.contentY += pinch.previousCenter.y - pinch.center.y
                // resize content
                flick.resizeContent(initialWidth * pinch.scale, initialHeight * pinch.scale, pinch.center)
            onPinchFinished: {
                // Move its content within bounds.
                console.log("pinch end", flick.contentX, flick.contentY, flick.contentWidth, flick.contentHeight, flick.scale)
                var scale = initialW / flick.contentWidth
                backend.sendImageChange(flick.contentX - initialX, flick.contentY - initialY, scale)

    The flickable and the image behave as expected, but the calculated offset is wrong. I have tried to apply scale in various manners on contentX and contentY but couldn't find a working solution.

    Thanks in advance for any help or explanations

  • Finally got it: the offsets in original coordinates system can be calculated like that:

            var scale = flick.contentWidth / initialW
            var expectedX = ((flick.contentWidth - initialW) / 2.0) + initialX
            var expectedY = ((flick.contentHeight - initialH) / 2.0) + initialY
            var offsetX = (flick.contentX - expectedX) * scale
            var offsetY = (flick.contentY - expectedY) * scale

Log in to reply