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. ZoomAndDragable QML
Forum Updated to NodeBB v4.3 + New Features

ZoomAndDragable QML

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
1 Posts 1 Posters 103 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.
  • R Offline
    R Offline
    Redman
    wrote on last edited by Redman
    #1

    Hi,

    a friend of mine provided me with this code which works really good
    ZoomAndDragable.qml

    import QtQuick 2.15
    
    Flickable {
        id: flickable
        property int itemWidth
        property int itemHeight
        default property Component sourceComponent
        contentWidth: itemWidth
        contentHeight: itemHeight
    
        boundsBehavior: Flickable.StopAtBounds
        boundsMovement: Flickable.StopAtBounds
        clip: true
    
        states: [
            State {
                name: "state_StickToCenter" // state is used when content size is less than flickable size then content
                // center should stick to flickable center
                when: (flickable.contentWidth < flickable.width
                       || flickable.contentHeight < flickable.height)
                AnchorChanges {
                    target: flickable.contentItem
                    anchors.horizontalCenter: width
                                              < flickable.width ? flickable.horizontalCenter : undefined
                    anchors.verticalCenter: height
                                            < flickable.height ? flickable.verticalCenter : undefined
                }
            }
        ]
        onStateChanged: {
            cancelFlick()
            returnToBounds()
        }
    
        Rectangle {
            id: mItem
            color: "yellow"
            width: flickable.contentWidth
            height: flickable.contentHeight
            Component.onCompleted: {
                itemWidth = contentLoader.implicitWidth
                itemHeight = contentLoader.implicitHeight
            }
    
            Loader {
                id: contentLoader
                sourceComponent: flickable.sourceComponent
                transform: [
                    Scale {
                        xScale: pinchArea.pinchActive ? pinchArea.scaleFactorBeforePinchReleased : privateProperties.currentZoomFactor
                        yScale: pinchArea.pinchActive ? pinchArea.scaleFactorBeforePinchReleased : privateProperties.currentZoomFactor
                    }
                ]
            }
    
            PinchArea {
                id: pinchArea
                anchors.fill: parent
                property bool zoomTriggeredFromPinchArea: false
                property point pinchCenter
                property bool pinchActive: false
                property real scaleFactorBeforePinchReleased: privateProperties.currentZoomFactor
    
                onPinchStarted: zoomTriggeredFromPinchArea = true
                onPinchUpdated: function (pinch) {
                    pinchActive = true
                    var newZoomFactor = privateProperties.currentZoomFactor
                            + privateProperties.currentZoomFactor * (pinch.scale - 1)
                    pinchCenter = pinch.center
                    let boundedScaleFactor = privateProperties.getBoundedScaleFactor(
                            newZoomFactor)
                    scaleFactorBeforePinchReleased = boundedScaleFactor
                    privateProperties.zoom(boundedScaleFactor)
                }
    
                onPinchFinished: function (pinch) {
                    privateProperties.currentZoomFactor
                            += privateProperties.currentZoomFactor * (pinch.scale - 1)
                    privateProperties.currentZoomFactor = privateProperties.getBoundedScaleFactor(
                                privateProperties.currentZoomFactor)
                    zoomTriggeredFromPinchArea = false
                    scaleFactorBeforePinchReleased = privateProperties.currentZoomFactor
                    pinchActive = false
                }
    
                MouseArea {
                    id: mouseArea
                    anchors.fill: parent
                    propagateComposedEvents: true
                    scrollGestureEnabled: false
                    hoverEnabled: true
    
                    onDoubleClicked: {
                        if (privateProperties.currentZoomFactor > 1)
                            resetScale()
                        else {
                            var widthScale = (flickable.width + 20) / mItem.width
                            var heightScale = (flickable.height + 20) / mItem.height
                            var maxScale = Math.max(widthScale, heightScale)
                            if (maxScale > 1) {
                                privateProperties.pointOfDoubleClick = Qt.point(
                                            mouseX, mouseY)
                                privateProperties.useDoubleClickPoint = true
                                privateProperties.currentZoomFactor = maxScale
                            }
                        }
                    }
    
                    onWheel: {
                        if (wheel.modifiers === Qt.ControlModifier) {
                            wheel.accepted = true
                            var newZoomFactor
                            if (wheel.angleDelta.y > 0)
                                newZoomFactor = privateProperties.currentZoomFactor
                                        + (privateProperties.currentZoomFactor
                                           * privateProperties.zoomStepFactor)
                            else
                                newZoomFactor = privateProperties.currentZoomFactor
                                        - (privateProperties.currentZoomFactor
                                           * privateProperties.zoomStepFactor)
                            privateProperties.currentZoomFactor
                                    = privateProperties.getBoundedScaleFactor(
                                        newZoomFactor)
                            return
                        }
                        wheel.accepted = false
                    }
                }
            }
        }
    
        QtObject {
            id: privateProperties
            // adjust according to your need
            property real maxZoomFactor: 2.5
            property real zoomStepFactor: 0.3
            property real minZoomFactor: 0.7
            // do not modify
            property bool useDoubleClickPoint: false
            property point pointOfDoubleClick
            property real currentZoomFactor: 1
            property point scaleCenter: pinchArea.zoomTriggeredFromPinchArea ? pinchArea.pinchCenter : Qt.point(mouseArea.mouseX, mouseArea.mouseY)
    
            Behavior on currentZoomFactor {
                NumberAnimation {
                    id: scaleNumberAnimation
                    duration: pinchArea.zoomTriggeredFromPinchArea ? 0 : privateProperties.useDoubleClickPoint ? Math.min(200 * privateProperties.currentZoomFactor, 500) : 200
                    onRunningChanged: if (!running)
                                          privateProperties.useDoubleClickPoint = false
                }
            }
    
            onCurrentZoomFactorChanged: {
                if (!pinchArea.zoomTriggeredFromPinchArea)
                    zoom(currentZoomFactor)
            }
    
            function zoom(scaleFactor) {
                var targetWidth = itemWidth * scaleFactor
                var targetHeight = itemHeight * scaleFactor
                if (useDoubleClickPoint)
                    resizeContent(targetWidth, targetHeight,
                                  mapToItem(mItem, pointOfDoubleClick))
                else
                    resizeContent(targetWidth, targetHeight, scaleCenter)
                returnToBounds()
            }
    
            function getBoundedScaleFactor(ScaleFactor) {
                if (ScaleFactor > maxZoomFactor)
                    ScaleFactor = maxZoomFactor
                else if (ScaleFactor < minZoomFactor)
                    ScaleFactor = minZoomFactor
                return ScaleFactor
            }
        }
    
        function resetScale() {
            privateProperties.pointOfDoubleClick = Qt.point(0, 0)
            privateProperties.useDoubleClickPoint = true
            privateProperties.currentZoomFactor = 1
        }
    }
    
    

    You can pass a sourceComponent to ZoomAndDragable and it will get loaded.
    My sourceComponent is a x-stretched rectangle.
    When I zoom in the state at the top of the file works good, until anchors.horizontalCenter will be set to undefined. Then it kinda snaps to a fixed position and disturbs the zoom feeling.

    I tried to fix it but I couldnt manage it.

    Can anyone suggest to me how to resolve this?

    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