I have a shape I'm creating to draw onto my circle. I need to center text which can tell me what angle the wedge I'm drawing on the circle is at. I think the easiest was to explain this will be to show it.
What I need the text to do:
vs
What the text is currently doing:
My code so far in QML:
Item {
id: root
width: size
height: size
layer.enabled: true
layer.samples: 8
property int size: 600
property real arcOffset: 0
property real arcBegin: 90 // start arc angle in degree
property real arcEnd: 105 // end arc angle in degree
property real lineWidth: 80
property string colorCircle: "#CC3333"
property string colorBackground: "#779933"
onArcBeginChanged: canvas.requestPaint()
onArcEndChanged: canvas.requestPaint()
Behavior on arcBegin {
id: animationArcBegin
enabled: true
NumberAnimation {
duration: root.animationDuration
easing.type: Easing.InOutCubic
}
}
Behavior on arcEnd {
id: animationArcEnd
enabled: true
NumberAnimation {
duration: root.animationDuration
easing.type: Easing.InOutCubic
}
}
Canvas {
id: canvas
anchors.fill: parent
rotation: -90 + parent.arcOffset
onPaint: {
var context = getContext("2d")
var x = width /2
var y = height / 2
var start = Math.PI * (parent.arcBegin / 180)
var end = Math.PI * (parent.arcEnd / 180)
context.reset()
context.beginPath();
context.arc(x, y, (width / 2) - parent.lineWidth / 2, 0, Math.PI * 2, false)
context.lineWidth = root.lineWidth
context.strokeStyle = Material.backgroundDimColor
context.stroke()
// context.beginPath();
// context.arc(x, y, (width / 2) - parent.lineWidth / 2, start, end, false)
// context.lineWidth = root.lineWidth
// context.strokeStyle = root.colorCircle
// context.stroke()
}
Shape {
width: 100
height: 100
ShapePath {
strokeWidth: 0
strokeColor: "red"
fillColor: "red"
PathAngleArc {
id: firstArc
centerX: root.width/2
centerY: root.height/2
radiusX: root.width/2
radiusY: root.height/2
startAngle: root.arcBegin
sweepAngle: 15
}
PathAngleArc {
centerX: root.width/2
centerY: root.height/2
radiusX: root.width/2 - root.lineWidth
radiusY: root.height/2 - root.lineWidth
startAngle: firstArc.startAngle + firstArc.sweepAngle -1
sweepAngle: -13
moveToStart: false
}
}
Text {
anchors.centerIn: parent
font.pointSize: 12
text: (root.arcBegin + root.arcEnd)/2 + "\xB0"
}
}
}
}
Any help on this would be appreciated. I know the issue is that the shape has no position. But I don't know how to make the shape's position match the AngleArc's drawn shape. Every anchor I've tried sends the text on a mighty adventure across the world to weird places. I should mention that the location of the 3 wedges won't be fixed. it's based on user input and could be any angle. The the center of the wedge needs to be at the angle specified by the user.
You can use an Item
(or Text
) to fill the circle and then rotate the Item
(or Text
), like the code below.
Item {
anchors.fill: parent
rotation: (root.arcBegin + root.arcEnd)/2
Text {
y: (root.lineWidth - height)/2
x: (parent.width - width)/2
rotation: -parent.rotation // I suggest not rotating the text
text: parent.rotation.toFixed(1) + '\u00B0'
}
}
You may also just set Text
x
and y
directly using cos
and sin
.
Text {
property real angle: (root.arcBegin + root.arcEnd)/2
property real rad: (root.width - root.lineWidth)/2
x: rad * Math.cos(angle * 0.01746 - 1.57) + root.width/2 - width/2
y: rad * Math.sin(angle * 0.01746 - 1.57) + root.height/2 - height/2
text: angle.toFixed(1) + '\u00B0'
}
However, I'm sure there is a better way to implement this.
So I created one arc using the code below, but you can reuse the Shape
component to create more arcs.
In the Shape
component, the angle of the arc is defined as property real angle
.
Rectangle {
id: root
width: parent.width
height: width
radius: width
color: 'transparent'
border { color: '#777'; width: 25 }
Rectangle { // This rect's border simply uses a lighter hue to fill the border of its parent rect.
anchors { fill: parent; margins: 1 }
radius: width
color: 'transparent'
border { color: '#f0f0f0'; width: root.border.width - 2 }
}
Shape {
// The arc in green is this (wedge).
// It can be separated into an outside component and then reused. (recommended)
id: shape
anchors.fill: parent
property real angle: 0
Item { // Text goes here; all that is required is a simple rotation of the parent item.
anchors.fill: parent
rotation: shape.angle
Text {
y: (root.border.width - height)/2
x: (parent.width - width)/2
rotation: -shape.angle
text: shape.angle.toFixed(1) + '\u00B0'
}
}
component Arc: PathAngleArc {
centerX: root.width/2; centerY: root.height/2
radiusX: root.width/2 - shapePath.strokeWidth/2 - 1
radiusY: radiusX
startAngle: -90 - sweepAngle/2 + shape.angle
sweepAngle: 30
}
ShapePath { // This is the dotted line
strokeWidth: 1
strokeColor: "#777"
fillColor: 'transparent'
strokeStyle: ShapePath.DashLine
dashPattern: [ 2, 2 ]
startX: 20 * Math.cos(shape.angle * 0.01746 - 1.57) + root.width/2
startY: 20 * Math.sin(shape.angle * 0.01746 - 1.57) + root.width/2
PathLine {
x: (root.width/2 - shapePath.strokeWidth - 4) * Math.cos(shape.angle * 0.01746 - 1.57) + root.width/2
y: (root.width/2 - shapePath.strokeWidth - 4) * Math.sin(shape.angle * 0.01746 - 1.57) + root.height/2
}
}
ShapePath { // This is the arc border (actually background)
strokeWidth: root.border.width
strokeColor: "#777"
fillColor: 'transparent'
capStyle: ShapePath.FlatCap
Arc {
startAngle: arc.startAngle-0.5
sweepAngle: arc.sweepAngle+1
}
}
ShapePath { // And this is arc foreground
id: shapePath
strokeWidth: root.border.width - 2
strokeColor: "#8fbf8f"
fillColor: 'transparent'
capStyle: ShapePath.FlatCap
Arc { id: arc }
}
}
}