canvasqml

QML Dial Label Horizontal align at tickplacement


I have written a qml code to use dial as a selector, which is as follows:

QML

GroupBox {
    // color: "#2b6684"
    Layout.fillHeight: true
    Layout.fillWidth: true
    font.pixelSize: 16
    font.bold: true
    Layout.maximumHeight: 230
    // radius: 5
    title: "Time Management"
    ColumnLayout{
        Layout.fillHeight: true
        Layout.fillWidth: true
        width: parent.width
        height: parent.height
        anchors.fill: parent
        anchors.centerIn: parent

        Item{
            Layout.fillHeight: true
            Layout.fillWidth: true

            Layout.minimumWidth: 210
            Layout.minimumHeight: 210
            Layout.maximumWidth: 210
            Layout.maximumHeight: 210

            Dial {
                id: dial
                anchors.centerIn: parent
                stepSize: 1
                snapMode: Dial.SnapAlways
                from: 1
                to: 4


                //                Layout.fillHeight: true
                //                Layout.fillWidth: true
                width: parent.width *.6
                height: parent.height*.6

                //                Layout.minimumWidth: 200
                //                Layout.minimumHeight: 200

                background: Rectangle {
                    radius: width / 2
                    color: "#5A6268"
                    //                        border.color: "#cccccc"
                }
                onValueChanged: {
                    //                            console.log("value   " + value)
                    if(value === 1)
                    {
                        fbg0axisX.min = 0
                        fbg0axisX.max = 100
                        fbg0axisX.tickCount = 11
                        dynamicSeries.axisX.min = 0
                        dynamicSeries.axisX.max = 100
                        dynamicSeries.axisX.tickCount = 11


                    }
                    if(value === 2)
                    {
                        fbg0axisX.min = 0
                        fbg0axisX.max = 60
                        fbg0axisX.tickCount = 11

                        dynamicSeries.axisX.min = 0
                        dynamicSeries.axisX.max = 100
                        dynamicSeries.axisX.tickCount = 11

                        // scatterGraph.axisX.min = 0
                        // scatterGraph.axisX.max = 100000
                        // scatterGraph2.axisX.min = 0
                        // scatterGraph2.axisX.max = 100000


                    }
                    if(value === 3)
                    {
                        fbg0axisX.min = 0
                        fbg0axisX.max = 10
                        fbg0axisX.tickCount = 11

                        dynamicSeries.axisX.min = 0
                        dynamicSeries.axisX.max = 10
                        dynamicSeries.axisX.tickCount = 11

                        // scatterGraph.axisX.min = 0
                        // scatterGraph.axisX.max = 300000
                        // scatterGraph2.axisX.min = 0
                        // scatterGraph2.axisX.max = 300000



                    }
                    if(value === 4)
                    {
                        fbg0axisX.min = 0
                        fbg0axisX.max = 60
                        fbg0axisX.tickCount = 11

                        dynamicSeries.axisX.min = 0
                        dynamicSeries.axisX.max = 60
                        dynamicSeries.axisX.tickCount = 11

                        // scatterGraph.axisX.min = 0
                        // scatterGraph.axisX.max = 1000000
                        // scatterGraph2.axisX.min = 0
                        // scatterGraph2.axisX.max = 1000000



                    }
                    if(value === 5)
                    {
                        fbg0axisX.min = 0
                        fbg0axisX.max = 8
                        fbg0axisX.tickCount = 9

                        dynamicSeries.axisX.min = 0
                        dynamicSeries.axisX.max = 8
                        dynamicSeries.axisX.tickCount = 9

                        // scatterGraph.axisX.min = 0
                        // scatterGraph.axisX.max = 10000000
                        // scatterGraph2.axisX.min = 0
                        // scatterGraph2.axisX.max = 10000000



                    }
                    if(value === 6)
                    {
                        //                                fbg0axisX.min = 0
                        //                                fbg0axisX.max = 24
                        //                                fbg0axisX.tickCount = 25

                        //                                dynamicSeries.axisX.min = 0
                        //                                dynamicSeries.axisX.max = 24
                        //                                dynamicSeries.axisX.tickCount = 25

                        scatterGraph.axisX.min = 0
                        scatterGraph.axisX.max = 100000000
                        scatterGraph2.axisX.min = 0
                        scatterGraph2.axisX.max = 100000000

                    }
                }


            }

            Canvas {
                id: labelCanvas
                anchors.fill: parent
                onPaint: {

                    var ctx = getContext("2d");
                    ctx.font = "14px Arial";

                    // Dial radius
                    var dialRadius = dial.width / 2;

                    // Offset for text positioning
                    var textOffset = 10;

                    //                        // Draw labels
                    for(var i=0; i<4; i++) {

                        // Calculate angle
                        var angle = i*90 +140;

                        // Save state
                        ctx.save();
                        ctx.translate(100 , 110);
                        ctx.rotate(angle * Math.PI/180);
                        ctx.fillStyle = "#EDEDED";
                        // Offset from dial edge
                        var x = dialRadius + textOffset;
                        var y = 0;

                        //                            Draw text
                        //                            ctx.fillText("" + i, x, y);

                        if(i === 0)
                        {
                            ctx.fillText("1s", x, y);

                            //                                    console.log("iiiii    " + i + "   " + x  + "    " + y + "     " + z)

                        }
                        else if(i === 1)
                        {
                            ctx.fillText("1m",  x, y);
                            //                                    console.log("iiiii    " + i + "   " + x  + "    " + y + "     " + z)

                        }
                        else if(i === 2)
                        {
                            ctx.fillText("10m",  x, y);
                            //                                    console.log("iiiii    " + i + "   " + x  + "    " + y + "     " + z)

                        }
                        else if(i === 3)
                        {
                            ctx.fillText("1h",  x, y);
                            //                                    console.log("iiiii    " + i + "   " + x  + "    " + y + "     " + z)

                        }

                        //                            Restore state
                        ctx.restore();
                    }
                }
            }


        }
    }
}

And the way to display this code in the program is as follows:

enter image description here

The problem starts from where I want the values ​​that I have placed around my dial to be displayed horizontally and not tilted. No matter how hard I tried, unfortunately, I could not find the right document to use it I would be grateful if you could help me to display the texts horizontally instead


Solution

  • You could do it declaratively with two rotations, e.g.

    Repeater {
        model: [[-135,"1m"],[-45,"10m"],[45,"1h"],[135,"1s"]]
        delegate: Item {
            x: 100; y: 100 // center point
            rotation: modelData[0]
            Item {
                x: 70 // offset from center
                Label {
                    anchors.centerIn: parent
                    text: modelData[1]
                    color: "white"
                    rotation: -modelData[0]
                }
            }
        }
    }
    

    HorzontalLabel.png

    You can Try it Online!

    If you want to eliminate the intermediate Item components and use the transform property, you can do it like this:

    Repeater {
        model: [[-135,"1m"],[-45,"10m"],[45,"1h"],[135,"1s"]]
        delegate: Label {
            id: label
            text: modelData[1]
            color: "white"
            rotation: -modelData[0]
            transform: [
                Translate { x: -label.width / 2; y: -label.height / 2 },
                Translate { x: 70 }, // offset from center
                Rotation { angle: modelData[0] },
                Translate { x: 100; y: 100 } // center point
            ]
        }
    }