Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Native Development

Reply
Regular Contributor
CrozyBB
Posts: 83
Registered: ‎07-19-2012
My Device: Bold 9790, Dev Alpha A
My Carrier: Koodo

Pinch and Translate QML Controls through Gestures

[ Edited ]

Hey all, I just wanted to post a solution that i got via help from the dev community today. This code is to scale and rotate a control using the pinch gesture while simultaneously translating the X and Y position. The code is good for now and it works but it definitely needs some refining. Feel free to check out the code yourself (I believe you'll need a Dev Alpha for multi-touch handling) and give any feedback you have for improving the overall user experience :smileyhappy:

 

[Edit: updated code so that the final position of the object is remembered and loaded once touch interaction occurs again + added comments to describe code a bit better]

 

ImageView {
            id: myImage

            // This custom property stores the initial scale of the image when a
            // pinch gesture begins
            property double initialScale: 1.0
			
            // This custom property determines how quickly the image grows or
            // shrinks in response to the pinch gesture
            property double scaleFactor: 1.0
            
//This is the initialization of two variables which will be used as the
//initial position measurement of the object property int iniX: 0; property int iniY: 0;

//Final X and Y position of object property int finalX: 0;
            property int finalY: 0;
layoutProperties: DockLayoutProperties { horizontalAlignment: HorizontalAlignment.Center verticalAlignment: VerticalAlignment.Center }

//Set source of image imageSource: "asset:///images/beer1.png" gestureHandlers: [ // Add a handler for pinch gestures PinchHandler { // When the pinch gesture starts, save the initial scale of // the image onPinchStart: { myImage.initialScale = myImage.scaleX; } // As the pinch expands or contracts, change the scale of the // image onPinchUpdate: { myImage.scaleX = myImage.initialScale + ((event.pinchRatio - 1) * myImage.scaleFactor); myImage.scaleY = myImage.initialScale + ((event.pinchRatio - 1) * myImage.scaleFactor); myImage.rotationZ = event.rotation; } } ] onTouch: { if (event.isDown()) { // event.isDown() occurs once immediately when the user touches the object
//set initial X and Y position variables iniX = event.windowX; iniY = event.windowY; } else if (event.isMove()) { //event.isMove() occurs as object is being dragged (presumably at 60Hz)
//calculate the translation by taking difference between initial position, final position and current position myImage.translationX = event.windowX - iniX + finalX; myImage.translationY = event.windowY - iniY + finalY; } else if (event.isUp()) { //event.isUp() occurs once object is no longer touched by user
//set final position in variable to be loaded once the control (imageView) is touched by user again finalX = myImage.translationX;
finalY = myImage.translationY; } } }

 Cheers!

Please use plain text.
BlackBerry Development Advisor (Retired)
gperry
Posts: 138
Registered: ‎05-11-2012
My Device: Developer
My Carrier: Developer

Re: Pinch and Translate QML Controls through Gestures

Thank you for sharing this code.

 

Regards

Graham

Please use plain text.
Contributor
casantos
Posts: 33
Registered: ‎01-13-2013
My Device: BlackBerry Z10, Q10
My Carrier: Claro (Brazil)

Re: Pinch and Translate QML Controls through Gestures

[ Edited ]

I tried with your solution but found it unstable. I fixed the problem by means of flags that prevent interferences between the drag and pinch gestures. I also chose higher acceleration factors. [Edited to fix comments]

 

import bb.cascades 1.0

Page {
    content: Container {
        // The top-level container uses a dock layout so that the image can
        // always remain centered on the screen as it changes size
        layout: DockLayout {
        }

        ImageView {
            id: myImage
            
            // Flag to prevent a drag gesture from starting during pinch
            property bool pinchHappening: false

            // The scale of the image when a pinch gesture begins
            property double initialScale: 1.0

            // How fast the image grows/shrinks in response to the pinch gesture
            property double scaleFactor: 1.25

            // The rotation of the image when a pinch gesture begins
            property double initialRotationZ: 0.0

            // How fast the image rotates in response to the pinch gesture
            property double rotationFactor: 1.5

            // Flag to prevent dragging when a pinch ends but the two fingers are
            // not taken off the screen simultaneously
            property bool dragHappening: false

            // The position of the image when a drag gesture begins
            property double initialWindowX
            property double initialWindowY

            // How fast the image moves in response to the drag gesture
            property double dragFactor: 1.25

            // The image is initially centered on the container
            horizontalAlignment: HorizontalAlignment.Center
            verticalAlignment: VerticalAlignment.Center

            imageSource: "asset:///images/picture1.png"

            // Drag gesture
            onTouch: {
                // Determine the location inside the image that was touched,
                // relative to the container, and move it accordingly
                if (pinchHappening) {
                    // A pinch was started by touching the image with a second finger
                    // so interrupt any ongoing drag gesture
                    dragHappening = false
                } else {
                    if (event.isDown()) {
                        // Start a dragging gesture
                        dragHappening = true
                        initialWindowX = event.windowX
                        initialWindowY = event.windowY
                    } else if (dragHappening && event.isMove()) {
                        // Move the image and record its new position
                        translationX += (event.windowX - initialWindowX) * dragFactor
                        translationY += (event.windowY - initialWindowY) * dragFactor
                        initialWindowX = event.windowX
                        initialWindowY = event.windowY
                    } else {
                        // Event type is Up or Cancel
                        // Interrupt any ongoing drag gesture
                        dragHappening = false
                    }
                }
            }

            gestureHandlers: [
                // Add a handler for pinch gestures
                PinchHandler {
                    onPinchStarted: {
                        // Save the initial scale and rotation of the image
                        myImage.initialScale = myImage.scaleX
                        myImage.initialRotationZ = myImage.rotationZ
                        // Prevent a drag gesture from starting during pinch
                        myImage.pinchHappening = true
                    }
                    onPinchUpdated: {
                        // Rescale and rotate as the pinch expands/contracts/rotates
                        myImage.scaleX = myImage.initialScale + ((event.pinchRatio - 1) * myImage.scaleFactor)
                        myImage.scaleY = myImage.initialScale + ((event.pinchRatio - 1) * myImage.scaleFactor)
                        myImage.rotationZ = myImage.initialRotationZ + ((event.rotation) * myImage.rotationFactor)
                    }
                    onPinchEnded: {
                        // Allow a drag gesture to begin
                        myImage.pinchHappening = false
                    }
                }
            ]
        } // end of ImageView
    } // end of Container
}// end of Page

 

Please use plain text.
Developer
kunal_one
Posts: 145
Registered: ‎12-23-2012
My Device: BB10 Dev Alpha
My Carrier: wifi

Re: Pinch and Translate QML Controls through Gestures

thnaks for sharing code
Please use plain text.
New Contributor
mikemags11
Posts: 2
Registered: ‎04-10-2013
My Device: Z10-STL100-3
My Carrier: Rogers

Re: Pinch and Translate QML Controls through Gestures

I'd Like to add to this code as it REALLY helped me accomplish what i was trying to do . I took out the rotation as i simply wanted to replicate the scroll view properties. 

 

Here's what ive come up with to bound the image from over scrolling:

 

ImageView {
id: myImage
imageSource: "asset:///images/myImage.png"

// Flag to prevent a drag gesture from starting during pinch
property bool pinchHappening: false

// The scale of the image when a pinch gesture begins
property double initialScale: 1.0

// How fast the image grows/shrinks in response to the pinch gesture
property double scaleFactor: 1.5

property double minScale: 0.95
// Flag to prevent dragging when a pinch ends but the two fingers are
// not taken off the screen simultaneously
property bool dragHappening: false

// The position of the image when a drag gesture begins
property double initialWindowX
property double initialWindowY

// How fast the image moves in response to the drag gesture
property double dragFactor: 1.25
property double initialWidth: 720.0
property double initialHeight: 720.0
property double currentWidth: 0.0
property double currentHeight: 0.0
property double maxTransX: 0.0
property double maxTransY: 0.0

// The image is initially centered on the container
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center

 

// Drag gesture
onTouch: {
// Determine the location inside the image that was touched,
// relative to the container, and move it accordingly
if (! (scaleX <= 1.0)) {
if (pinchHappening) {
// A pinch was started by touching the image with a second finger
// so interrupt any ongoing drag gesture
dragHappening = false
} else {
if (event.isDown()) {
// Start a dragging gesture
dragHappening = true
initialWindowX = event.windowX
initialWindowY = event.windowY
} else if (dragHappening && event.isMove()) {
// Move the image and record its new position

//moving Along X axis
//moving left
if (((event.windowX - initialWindowX) * dragFactor ) < 0) {
//bound right edge
if ((translationX + (event.windowX - initialWindowX) * dragFactor) > (-1 * maxTransX)) {
//(myImage.currentWidth - myImage.initialWidth) / 2
translationX += (event.windowX - initialWindowX) * dragFactor
initialWindowX = event.windowX
}

} //moving Right
else if (((event.windowX - initialWindowX) * dragFactor ) > 0) {
//Bound Left Edge
if ((translationX + (event.windowX - initialWindowX) * dragFactor) < (maxTransX)) {
translationX += (event.windowX - initialWindowX) * dragFactor
initialWindowX = event.windowX
}

} else {

}
// End Of X Axis Bounding

//moving Along Y axis
//moving Down
if (((event.windowY - initialWindowY) * dragFactor ) < 0) {
//bound Top edge
if ((translationY + (event.windowY - initialWindowY) * dragFactor) > (-1 * maxTransY)) {
//(myImage.currentWidth - myImage.initialWidth) / 2
translationY += (event.windowY - initialWindowY) * dragFactor
initialWindowY = event.windowY
}

} //moving Right
else if (((event.windowY - initialWindowY) * dragFactor ) > 0) {
//Bound Left Edge
if ((translationY + (event.windowY - initialWindowY) * dragFactor) < (maxTransY)) {
translationY += (event.windowY - initialWindowY) * dragFactor
initialWindowY = event.windowY
}

} else {

}
// End Of Y AYis Bounding

//translationX += (event.windowX - initialWindowX) * dragFactor
//initialWindowX = event.windowX

// translationY += (event.windowY - initialWindowY) * dragFactor
//initialWindowY = event.windowY

} else {
// Event type is Up or Cancel
// Interrupt any ongoing drag gesture
dragHappening = false
}
}
}
}// End Of OnTouch handler

 

 

gestureHandlers: [
// Add a handler for pinch gestures
PinchHandler {
onPinchStarted: {
// Save the initial scale and rotation of the image
myImage.initialScale = myImage.scaleX
//myImage.initialRotationZ = myImage.rotationZ
// Prevent a drag gesture from starting during pinch
myImage.pinchHappening = true
}
onPinchUpdated: {
// Rescale and rotate as the pinch expands/contracts/rotates

myImage.scaleX = myImage.initialScale + ((event.pinchRatio - 1) * myImage.scaleFactor)
myImage.scaleY = myImage.initialScale + ((event.pinchRatio - 1) * myImage.scaleFactor)

// myImage.rotationZ = myImage.initialRotationZ + ((event.rotation) * myImage.rotationFactor)
}
onPinchEnded: {

if (myImage.scaleX < myImage.minScale || myImage.scaleY < myImage.minScale) {
myImage.scaleX = 1.0
myImage.scaleY = 1.0
myImage.translationX = 0
myImage.translationY = 0
}

myImage.currentWidth = myImage.scaleX * myImage.initialWidth
myImage.currentHeight = myImage.scaleX * myImage.initialHeight
myImage.maxTransY = (myImage.currentHeight - myImage.initialHeight) / 2
myImage.maxTransX = (myImage.currentWidth - myImage.initialWidth) / 2
// Allow a drag gesture to begin
myImage.pinchHappening = false
}
}
]

Please use plain text.