ZoomAndDragable QML
Unsolved
QML and Qt Quick
-
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, untilanchors.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?