Below code allows the small red coloured rectangle to be dragged in an area which is a rectangle defined by minimum and maximum drag values.
I want it to go on only up t
So I found some time to provide the aforementioned smoother solution.
import QtQuick 2.5
import QtQuick.Window 2.2
Window {
id: root
visible: true
width: 640
height: 480
title: qsTr("Hello World")
property int radius: 100
Rectangle {
id: circle
width: 2 * radius
height: 2 * radius
radius: root.radius
color: 'blue'
}
Rectangle {
id: mark
width: 20
height: 20
x: (dragObj.dragRadius <= root.radius ? dragObj.x : root.radius + ((dragObj.x - root.radius) * (root.radius / dragObj.dragRadius))) - 10
y: (dragObj.dragRadius <= root.radius ? dragObj.y : root.radius + ((dragObj.y - root.radius) * (root.radius / dragObj.dragRadius))) - 10
color: 'red'
MouseArea {
id: markArea
anchors.fill: parent
drag.target: dragObj
onPressed: {
dragObj.x = mark.x + 10
dragObj.y = mark.y + 10
}
}
}
Item {
id: dragObj
readonly property real dragRadius: Math.sqrt(Math.pow(x - root.radius, 2) + Math.pow(y - root.radius, 2))
x: root.radius
y: root.radius
onDragRadiusChanged: console.log(dragRadius)
}
}
I use the dragObj
to avoid the limitations of my dragging position. This spans a vector from the center of the circle. As long as the dragObj
itself is contained in the circle, I will use it's position as the position of the marker.
But once it leaves the circle, I will project the vector on the circle, so it will stay within the limits.
To ensure, that every drag starts again on the mark, I will reset the position of the dragObj
to the position of the mark, when ever the mouse is pressed again (precondition for a new drag-event)
Have fun with it.
A little bit late, but I was up for some quiz.
Here is a imperfect solution, with some flaws.
import QtQuick 2.5
import QtQuick.Window 2.2
Window {
width: 400; height: 400; visible: true
Rectangle
{
x: 10; y: 10
width: 200; height: 200
radius: 100
color: "blue"
Rectangle {
x: 10; y: 10
width: 20; height: 20
color: "red"
MouseArea
{
id: dragArea
anchors.fill: parent
drag.target: parent
drag.minimumX : Math.ceil(100 - Math.sqrt(200 * parent.y - Math.pow(parent.y, 2)))
drag.maximumX : Math.floor(Math.sqrt(200 * parent.y - Math.pow(parent.y, 2)) + 100)
drag.minimumY : Math.ceil(100 - Math.sqrt(200 * parent.x - Math.pow(parent.x, 2)))
drag.maximumY : Math.floor(Math.sqrt(200 * parent.x - Math.pow(parent.x, 2)) + 100)
}
}
}
}
The idea is, that you calculate the max- and min-values of x and y depending on the current value of y and x (so max-x is depending on current-y, and max-y is depending on current-x)
The function behind that is:
(r - y)² + (r - x)² = r²
What I did not incorporate is the dimension of the small draggable Rectangle. So I only force the top-left corner to stay within the circles bounds. This however should be easy to adapt. To account for that, assume a circle, with half the rectangles width/height less radius, and shift it by half the rectangles width/height.
Another flaw is, that if I reach one of the limits (top, left, right, bottom) the Rectangle might flicker and does not follow the mouse smoothly.
To fix that, you can use an invisible object as helper, that can be freely drawn around, and you then use it's position to calculate the red Rectangles position that is shown.
Maybe I will add an implementation for that later as well. I am pretty sure, this should work pretty smoothly.