Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Zooming/Scaling an Image at a specific point within a Flickable
QtWS25 Last Chance

Zooming/Scaling an Image at a specific point within a Flickable

Scheduled Pinned Locked Moved Solved QML and Qt Quick
7 Posts 3 Posters 4.1k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Edwin F.E Offline
    Edwin F.E Offline
    Edwin F.
    wrote on last edited by
    #1

    By moving a Slider, I want to be able to scale (zoom in) on an Image and once scaled (zoomed in), be able to move around, ( flick ) I have this example working here below, but my problem is the following.

    If I zoom in, scale in, and then flick around to a spot on the image, then I want to zoom (scale) in further on that specific point in the center of the window, when I scale in using the Slider, the zoom (scale) occurs at the center of the image because by default the 'transformOrigin' is Item.Center

    Try running the code to understand what I am talking about: ( you will need to change the image source)

    import QtQuick 2.12
    import QtQuick.Controls 2.3
    
    
    Item {
        id: mainId
        width: 1280
        height: 720
        property int scaleMultiplier: 3
    
    
        Flickable {
            id: flickArea
            anchors.fill: parent
            focus: true
            contentWidth: Math.max(inner.width * slider.value * scaleMultiplier, width)
            contentHeight: Math.max(inner.height  * slider.value * scaleMultiplier, height)
            anchors.centerIn: parent
            boundsBehavior: Flickable.StopAtBounds
            contentX: contentWidth === width ? 0 : inner.width * slider.value * scaleMultiplier / 2 - flickArea.width / 2
            contentY: contentHeight === height ? 0 : inner.height * slider.value * scaleMultiplier / 2 - flickArea.height / 2
    
    
            Image {
                id: inner
                scale: slider.value * scaleMultiplier
                anchors.centerIn: parent
                source: "test_images/1.png"
            }
        }
    
        Slider {
            id: slider
            value: .01
            orientation: Qt.Vertical
            anchors {
                bottom: parent.bottom
                right: parent.right
                top: parent.top
                margins: 50
            }
    
            from: 0.01
        }
    
    }
    

    I tried setting an arbitrary transform origin point like so:

    Image {
                id: inner
                scale: slider.value * scaleMultiplier
                anchors.centerIn: parent
    
                source: "test_images/1.png"
    
                transform: Scale {
                                    id: scaleID ;
                                    origin.x: flickArea.contentX + flickArea.width * flickArea.visibleArea.widthRatio / 2
                                    origin.y: flickArea.contentY + flickArea.height * flickArea.visibleArea.heightRatio / 2
                }
            }
    
    

    But it seems to have no effect. Any help is appreciated. What am I missing?

    Again what I want is when I flick to a specific point on the Image, and scale in, I want the point of origin to scale into be the area in the center of the viewable flickarea. For example let's say I am zoomed in the upper right corner of the image, then I wish to zoom in further, when I zoom in further, the Image is brought back to the center of the image.

    Thanks.

    1 Reply Last reply
    0
    • sierdzioS Offline
      sierdzioS Offline
      sierdzio
      Moderators
      wrote on last edited by
      #2

      You need to use resizeContents() method from Flickable. And example: https://github.com/sierdzio/closecombatfree/blob/master/qml/scenarios/Scenario.qml#L43

      So in your case it'll look like this:

      property real zoom: 1;
      onZoomChanged: {
              var zoomPoint = Qt.point(flickArea.width/2 + flickArea.contentX,
                                   flickArea.height/2 + flickArea.contentY);
      
              flickArea.resizeContent((inner.width * zoom), (inner.height * zoom), zoomPoint);
              flickArea.returnToBounds();
          }
      

      (Z(:^

      C 1 Reply Last reply
      4
      • Edwin F.E Offline
        Edwin F.E Offline
        Edwin F.
        wrote on last edited by
        #3

        I sincerely appreciate your reply @sierdzio , I am trying to understand your response.

        What drives the 'zoom' property, do I bind it to the slider.value? I tried many variations but the image is still zooming at the center instead of where I am currently viewing the the Flickable

        import QtQuick 2.12
        import QtQuick.Controls 2.3
        
        
        Item {
            id: mainId
            width: 1280
            height: 720
            property int scaleMultiplier: 3
            property real zoom
        
        
            onZoomChanged: {
                    var zoomPoint = Qt.point(flickArea.width/2 + flickArea.contentX,
                                         flickArea.height/2 + flickArea.contentY);
        
                    flickArea.resizeContent((inner.width * zoom), (inner.height * zoom), zoomPoint);
                    flickArea.returnToBounds();
                }
        
        
            Flickable {
                id: flickArea
                anchors.fill: parent
                focus: true
                contentWidth: Math.max(inner.width * slider.value * scaleMultiplier, width)
                contentHeight: Math.max(inner.height  * slider.value * scaleMultiplier, height)
                anchors.centerIn: parent
                boundsBehavior: Flickable.StopAtBounds
                contentX: contentWidth === width ? 0 : inner.width * slider.value * scaleMultiplier / 2 - flickArea.width / 2
                contentY: contentHeight === height ? 0 : inner.height * slider.value * scaleMultiplier / 2 - flickArea.height / 2
        
                Image {
                    id: inner
                    //scale: slider.value * scaleMultiplier
                    scale: zoom
                    anchors.centerIn: parent
        
                    source: "test_images/1.png"
        
                    transform: Scale {
                                        id: scaleID ;
                                        origin.x: flickArea.contentX + flickArea.width * flickArea.visibleArea.widthRatio / 2
                                        origin.y: flickArea.contentY + flickArea.height * flickArea.visibleArea.heightRatio / 2
                    }
                }
            }
        
            Slider {
                id: slider
                value: .01
                orientation: Qt.Vertical
                anchors {
                    bottom: parent.bottom
                    right: parent.right
                    top: parent.top
                    margins: 50
                }
        
                from: 0.01
        
                onValueChanged: {
                    zoom = value * scaleMultiplier
                }
            }
        }
        
        sierdzioS 1 Reply Last reply
        0
        • Edwin F.E Edwin F.

          I sincerely appreciate your reply @sierdzio , I am trying to understand your response.

          What drives the 'zoom' property, do I bind it to the slider.value? I tried many variations but the image is still zooming at the center instead of where I am currently viewing the the Flickable

          import QtQuick 2.12
          import QtQuick.Controls 2.3
          
          
          Item {
              id: mainId
              width: 1280
              height: 720
              property int scaleMultiplier: 3
              property real zoom
          
          
              onZoomChanged: {
                      var zoomPoint = Qt.point(flickArea.width/2 + flickArea.contentX,
                                           flickArea.height/2 + flickArea.contentY);
          
                      flickArea.resizeContent((inner.width * zoom), (inner.height * zoom), zoomPoint);
                      flickArea.returnToBounds();
                  }
          
          
              Flickable {
                  id: flickArea
                  anchors.fill: parent
                  focus: true
                  contentWidth: Math.max(inner.width * slider.value * scaleMultiplier, width)
                  contentHeight: Math.max(inner.height  * slider.value * scaleMultiplier, height)
                  anchors.centerIn: parent
                  boundsBehavior: Flickable.StopAtBounds
                  contentX: contentWidth === width ? 0 : inner.width * slider.value * scaleMultiplier / 2 - flickArea.width / 2
                  contentY: contentHeight === height ? 0 : inner.height * slider.value * scaleMultiplier / 2 - flickArea.height / 2
          
                  Image {
                      id: inner
                      //scale: slider.value * scaleMultiplier
                      scale: zoom
                      anchors.centerIn: parent
          
                      source: "test_images/1.png"
          
                      transform: Scale {
                                          id: scaleID ;
                                          origin.x: flickArea.contentX + flickArea.width * flickArea.visibleArea.widthRatio / 2
                                          origin.y: flickArea.contentY + flickArea.height * flickArea.visibleArea.heightRatio / 2
                      }
                  }
              }
          
              Slider {
                  id: slider
                  value: .01
                  orientation: Qt.Vertical
                  anchors {
                      bottom: parent.bottom
                      right: parent.right
                      top: parent.top
                      margins: 50
                  }
          
                  from: 0.01
          
                  onValueChanged: {
                      zoom = value * scaleMultiplier
                  }
              }
          }
          
          sierdzioS Offline
          sierdzioS Offline
          sierdzio
          Moderators
          wrote on last edited by
          #4

          @Edwin-F. said in Zooming/Scaling an Image at a specific point within a Flickable:

          What drives the 'zoom' property, do I bind it to the slider.value?

          Yes, in your case you can use slider's value, either by binding or remove zoom property and use only the slider's property.

          Try this:

          // REMOVE THESE LINES:
          contentWidth: Math.max(inner.width * slider.value * scaleMultiplier, width)
          contentHeight: Math.max(inner.height  * slider.value * scaleMultiplier, height)
          contentX: contentWidth === width ? 0 : inner.width * slider.value * scaleMultiplier / 2 - flickArea.width / 2
          contentY: contentHeight === height ? 0 : inner.height * slider.value * scaleMultiplier / 2 - flickArea.height / 2
          
          // Instead, do:
          contentWidth: inner.width
          contentHeight: inner.height
          

          I suspect these lines are inhibiting my zoom slot.

          (Z(:^

          1 Reply Last reply
          3
          • Edwin F.E Offline
            Edwin F.E Offline
            Edwin F.
            wrote on last edited by
            #5

            This works beautifully, THANK YOU! You're the man. If you were here I'd hug you and buy you a beer.

            1 Reply Last reply
            1
            • sierdzioS Offline
              sierdzioS Offline
              sierdzio
              Moderators
              wrote on last edited by
              #6

              Haha, thanks. Happy coding :-)

              (Z(:^

              1 Reply Last reply
              0
              • sierdzioS sierdzio

                You need to use resizeContents() method from Flickable. And example: https://github.com/sierdzio/closecombatfree/blob/master/qml/scenarios/Scenario.qml#L43

                So in your case it'll look like this:

                property real zoom: 1;
                onZoomChanged: {
                        var zoomPoint = Qt.point(flickArea.width/2 + flickArea.contentX,
                                             flickArea.height/2 + flickArea.contentY);
                
                        flickArea.resizeContent((inner.width * zoom), (inner.height * zoom), zoomPoint);
                        flickArea.returnToBounds();
                    }
                
                C Offline
                C Offline
                Creaperdown
                wrote on last edited by Creaperdown
                #7

                @sierdzio Hi, I am running into a similar problem, but I can't figure out how to get the correct zoom point.
                I have a ListView and I want to zoom in and out on it. The zooming itself works fine, but it is not zooming into the middle of the listview, but scrolls up while zooming (https://streamable.com/o1frzj).

                I am using code which is very similar to yours:

                function zoom(factor)
                {
                    let newWidth = listView.contentWidth * factor;
                    
                    // Copied from your response
                    var zoomPoint = Qt.point(listView.width/2 + listView.contentX,
                                             listView.height/2 + listView.contentY);
                    
                
                    listView.resizeContent(Math.round(newWidth),
                                           Math.round(newWidth / listView.currentItem.pageRatio),
                                           zoomPoint);
                    
                    listView.returnToBounds();
                }
                

                Do you have an idea why it doesn't scroll into the middle of the screen?
                Thanks in advance

                1 Reply Last reply
                0

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved