Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Speedometer
Forum Updated to NodeBB v4.3 + New Features

Speedometer

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
22 Posts 4 Posters 2.7k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • MarkkyboyM Markkyboy

    @Darq - without seeing what code you have so far, I don't know how to answer your question. Please post some working code, or what you have so far. It is much easier to see and have ideas when one can see some code.

    EDIT: As I am already using CircularSlider from arunpkqt in several projects, I can easily adapt my code with your code and possibly work out a way to get what you want.

    D Offline
    D Offline
    Darq
    wrote on last edited by Darq
    #13

    @Markkyboy
    HmiImage {
    id: pointer1
    anchors.centerIn: parent
    source: "icons/abc.png"
    rotation: 2.25*XXX+225
    }

    XXX is my measured value
    225 is an angle where the value is 0
    2.25 is a degrees conversion, so for example, my value indicates 1, which corresponds to 2.25 degrees

    MarkkyboyM 1 Reply Last reply
    0
    • D Darq

      @Markkyboy
      HmiImage {
      id: pointer1
      anchors.centerIn: parent
      source: "icons/abc.png"
      rotation: 2.25*XXX+225
      }

      XXX is my measured value
      225 is an angle where the value is 0
      2.25 is a degrees conversion, so for example, my value indicates 1, which corresponds to 2.25 degrees

      MarkkyboyM Offline
      MarkkyboyM Offline
      Markkyboy
      wrote on last edited by
      #14

      @Darq - this small bit of code is not enough for me to work with.

      Don't just sit there standing around, pick up a shovel and sweep up!

      I live by the sea, not in it.

      D 1 Reply Last reply
      0
      • MarkkyboyM Markkyboy

        @Darq - this small bit of code is not enough for me to work with.

        D Offline
        D Offline
        Darq
        wrote on last edited by
        #15

        @Markkyboy There is almost no more code there. There is only one more HmiImage defining the appearance of the shield (it loads the shields, i.e. a png file). In this code snippet there is only the "source" command which specifies the location of the png file. The png file has a scale drawn on it. The hint is called by the code above, which specifies its position (e.g. point 0 is at 225 degrees, so in the png file 0 is drawn at 225 degrees).

        MarkkyboyM 1 Reply Last reply
        0
        • D Darq

          @Markkyboy There is almost no more code there. There is only one more HmiImage defining the appearance of the shield (it loads the shields, i.e. a png file). In this code snippet there is only the "source" command which specifies the location of the png file. The png file has a scale drawn on it. The hint is called by the code above, which specifies its position (e.g. point 0 is at 225 degrees, so in the png file 0 is drawn at 225 degrees).

          MarkkyboyM Offline
          MarkkyboyM Offline
          Markkyboy
          wrote on last edited by
          #16

          @Darq - sorry, I just don't understand what you're trying to do. I can take plenty of wild guesses but I don't have the time to do so.

          Making a functional speedometer requires a lot more code in my opinion. You could at the very least show an image/screenshot of what you have, otherwise I'm in the dark. At the very least, a mock up image of what you're wanting might be helpful.

          What kind of speedo only functions when hitting 50?, what is the idea of this?, 50 what?, kmh?, mph?, kts?.....?

          What is "icons/abc.png"?, what does it look like?

          What is "hmiImage", where is that code?

          Are you taking ANY cues from arunpkqt's application?

          Seriously now, what you write here gives me very little to go on. I'm not sure I can help you.

          Don't just sit there standing around, pick up a shovel and sweep up!

          I live by the sea, not in it.

          1 Reply Last reply
          0
          • MarkkyboyM Offline
            MarkkyboyM Offline
            Markkyboy
            wrote on last edited by Markkyboy
            #17

            Rather than leave you completely in the dark, Darq, here's some full code to make a working speedometer. Perhaps from this you can make it do what you want/require.

            import QtQuick
            import QtQuick.Controls
            
            Item {
                id: control
            
                property int trackWidth: 20
                property int progressWidth: 20
                property color trackColor: "#505050"
                property color progressColor: "#3a4ec4"
                property bool hideTrack: false
                property bool hideProgress: false
            
                property color handleColor: "#fefefe"
                property int handleWidth: 80
                property int handleHeight: 80
                property int handleRadius: 40
                property int handleVerticalOffset: 0
            
                property real startAngle: 0
                property real endAngle: 360
                property real minValue: 0.0
                property real maxValue: 1.0
            
                property real value: 0.0
                readonly property alias angle: internal.angle
            
            
                property real stepSize: 0
                property bool snap: false
                property Component handle: null
                readonly property alias pressed: trackMouse.pressed
            
                property bool interactive: true
                property alias cursorShape: trackMouse.cursorShape
            
                implicitWidth: 250
                implicitHeight: 250
            
                Binding {
                    target: control
                    property: "value"
                    value: control.snap ? internal.snappedValue : internal.mapFromValue(startAngle, endAngle, minValue, maxValue, internal.angleProxy)
                    when: internal.setUpdatedValue
                }
            
                QtObject {
                    id: internal
            
                    property point centerPt: Qt.point(control.width / 2, control.height / 2)
                    property real baseRadius: Math.min(control.width, control.height) / 2 - Math.max(control.trackWidth, control.progressWidth) / 2
                    property real actualSpanAngle: control.endAngle - control.startAngle
                    property color transparentColor: "transparent"
                    property color trackColor: control.trackColor
                    property bool setUpdatedValue: false
                    property real angleProxy: control.startAngle
                    property real snappedValue: 0.0
                    readonly property real angle: internal.mapFromValue(control.minValue, control.maxValue, control.startAngle, control.endAngle, control.value)
            
                    function mapFromValue(inMin, inMax, outMin, outMax, inValue) {
                        return (inValue - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
                    }
            
                    function updateAngle(angleVal) {
                        if (angleVal < 0)
                            angleVal += 360;
            
                        if ((angleVal >= control.startAngle) && (angleVal <= control.endAngle)) {
                            internal.setUpdatedValue = true;
                            internal.angleProxy = Qt.binding(function() { return angleVal; });
                            if(control.snap) {
                                var mappedValue = internal.mapFromValue(startAngle, endAngle, minValue, maxValue, internal.angleProxy)
                                var range = control.maxValue - control.minValue
                                var effectiveStep = 2
                                var actualVal = control.stepSize * Math.round(mappedValue / control.stepSize)
                                internal.snappedValue = actualVal
                            }
                            internal.setUpdatedValue = false;
                        }
                    }
                }
            
                MouseArea {
                    anchors.fill: parent
                    enabled: control.interactive
                    onClicked: {
                        var outerRadius = Math.min(control.width, control.height)/ 2
                        var innerRadius = outerRadius - Math.max(control.trackWidth, 20);
                        var clickedDistance = (mouseX - internal.centerPt.x) * (mouseX - internal.centerPt.x) + (mouseY - internal.centerPt.y) * (mouseY - internal.centerPt.y);
                        var innerRadius2 = (innerRadius * innerRadius);
                        var outerRadius2 = (outerRadius * outerRadius);
                        var isOutOfInnerRadius = clickedDistance > innerRadius2;
                        var inInSideOuterRadius = clickedDistance <= outerRadius2;
                        if (inInSideOuterRadius && isOutOfInnerRadius) {
                            var angleDeg = Math.atan2(mouseY - internal.centerPt.y, mouseX - internal.centerPt.x) * 180 / Math.PI + 90;
                            internal.updateAngle(angleDeg);
                        }
                    }
                }
            
                // Handle Item
                Item {
                    id: handleItem
                    visible: control.interactive
            
                    x: control.width / 2 - width / 2
                    y: control.height / 2 - height / 2
                    // make sure that the slider handle is always on top as we can set custom track or progress items
                    z: 2
                    width: control.handleWidth
                    height: control.handleHeight
                    antialiasing: true
                    transform: [
                        Translate {
                            y: -(Math.min(control.width, control.height) / 2) + Math.max(control.trackWidth, control.progressWidth) / 2 + control.handleVerticalOffset
                        },
                        Rotation {
                            angle: control.angle
                            origin.x: handleItem.width / 2
                            origin.y: handleItem.height / 2
                        }
                    ]
            
                    MouseArea {
                        id: trackMouse
                        enabled: control.interactive
            
                        function getVal() {
                            var handlePoint = mapToItem(control, trackMouse.mouseX, trackMouse.mouseY);
                            // angle in degrees
                            var angleDeg = Math.atan2(handlePoint.y - internal.centerPt.y, handlePoint.x - internal.centerPt.x) * 180 / Math.PI + 90;
                            internal.updateAngle(angleDeg);
                        }
            
                        anchors.fill: parent
                        onPositionChanged: getVal()
                        onClicked: getVal()
                        cursorShape: Qt.ArrowCursor
                    }
            
                    Loader {
                        id: handleLoader
            
                        sourceComponent: control.handle ? handle : handleComponent
                    }
                }
            
                /// Default handle component
                Component {
                    id: handleComponent
            
                    Rectangle {
                        width: control.handleWidth
                        height: control.handleHeight
                        color: control.handleColor
                        radius: control.handleRadius
                        antialiasing: true
                    }
                }
            }
            
            
            import QtQuick
            import QtQuick.Controls
            import "../components"
            
            Page {
                id: darqSpeedo
            
                allowedOrientations: Orientation.All // this is specific to SailfishOS and can likely be omitted.
            
                // imported from "../components"
                CircularSlider {
                    id: speedometer
                    interactive: false
                    anchors.centerIn: parent
                    width: 1000
                    height: width
                    value: 0
                    startAngle: -108
                    endAngle: 108
                    minValue: 0
                    maxValue: 180
                    anchors {
                        verticalCenterOffset: 200
                        verticalCenter: parent.verticalCenter
                        horizontalCenter: parent.horizontalCenter
                    }
                    // Tickmarks around gauge
                    Repeater {
                        model: 37
                        Rectangle {
                            id: ones
                            width: 6
                            height: index % 4 === 0 ? 50 : 25
                            color: index % 4 === 0 ? "white" : "silver"
                            property real angle: index * 6
                            transform: [ Translate { x: parent.width / 2 - width / 2; y: -155 },
                                Rotation {
                                    origin.x: parent.width / 2
                                    origin.y: parent.height / 2
                                    angle: ones.angle + parent.startAngle
                                }
                            ]
                        }
                    }
                    // Numbers around gauge
                    Repeater {
                        model: 10
                        Label {
                            id: digits
                            text: index * 20
                            color: "white"
                            font { bold: true; pixelSize: 48 }
                            property real angle: index * 24
                            transform: [
                                Translate {
                                    x: parent.width / 2 - width / 2
                                    y: -75 // distance from tickmarks
                                },
                                Rotation {
                                    origin.x: parent.width / 2
                                    origin.y: parent.height / 2
                                    angle: digits.angle + parent.startAngle
                                }
                            ]
                            // keeps numbers horizontal
                            rotation: -digits.angle - parent.startAngle
                        }
                    }
                    // Needle hub
                    Rectangle {
                        anchors.centerIn: speedometer
                        width: 100
                        height: width
                        radius: width/2
                        color: "#a0545454"
                    }
                    // Needle/pointer
                    Repeater {
                        model: 1
                        Rectangle {
                            id: needle
                            width: 20
                            height: 450
                            color: "orange"
                            radius: 20
                            transform: [
                                Translate {
                                    x: speedometer.width / 2 - width / 2
                                    y: 50 // needle distance from centre
                                },
                                Rotation {
                                    origin.x: speedometer.width / 2
                                    origin.y: speedometer.height / 2
                                    angle: speedometer.angle
                                }
                            ]
                        }
                    }
                    // Animation for demo purposes
                    SequentialAnimation on value {
                        id: animation
                        loops: Animation.Infinite
                        running: true
                        NumberAnimation { from: 0; to: 180; duration: 2000 }
                        NumberAnimation { from: 180; to: 0; duration: 2000 }
                    }
                }
            }
            
            

            NOTE: I use Page, as my apps are built for my mobile phone using SailfishOS. You don't have to use Page, you can likely swap it for Item instead.

            Screenshot_20231114_001.png

            Don't just sit there standing around, pick up a shovel and sweep up!

            I live by the sea, not in it.

            D S 2 Replies Last reply
            0
            • MarkkyboyM Markkyboy

              Rather than leave you completely in the dark, Darq, here's some full code to make a working speedometer. Perhaps from this you can make it do what you want/require.

              import QtQuick
              import QtQuick.Controls
              
              Item {
                  id: control
              
                  property int trackWidth: 20
                  property int progressWidth: 20
                  property color trackColor: "#505050"
                  property color progressColor: "#3a4ec4"
                  property bool hideTrack: false
                  property bool hideProgress: false
              
                  property color handleColor: "#fefefe"
                  property int handleWidth: 80
                  property int handleHeight: 80
                  property int handleRadius: 40
                  property int handleVerticalOffset: 0
              
                  property real startAngle: 0
                  property real endAngle: 360
                  property real minValue: 0.0
                  property real maxValue: 1.0
              
                  property real value: 0.0
                  readonly property alias angle: internal.angle
              
              
                  property real stepSize: 0
                  property bool snap: false
                  property Component handle: null
                  readonly property alias pressed: trackMouse.pressed
              
                  property bool interactive: true
                  property alias cursorShape: trackMouse.cursorShape
              
                  implicitWidth: 250
                  implicitHeight: 250
              
                  Binding {
                      target: control
                      property: "value"
                      value: control.snap ? internal.snappedValue : internal.mapFromValue(startAngle, endAngle, minValue, maxValue, internal.angleProxy)
                      when: internal.setUpdatedValue
                  }
              
                  QtObject {
                      id: internal
              
                      property point centerPt: Qt.point(control.width / 2, control.height / 2)
                      property real baseRadius: Math.min(control.width, control.height) / 2 - Math.max(control.trackWidth, control.progressWidth) / 2
                      property real actualSpanAngle: control.endAngle - control.startAngle
                      property color transparentColor: "transparent"
                      property color trackColor: control.trackColor
                      property bool setUpdatedValue: false
                      property real angleProxy: control.startAngle
                      property real snappedValue: 0.0
                      readonly property real angle: internal.mapFromValue(control.minValue, control.maxValue, control.startAngle, control.endAngle, control.value)
              
                      function mapFromValue(inMin, inMax, outMin, outMax, inValue) {
                          return (inValue - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
                      }
              
                      function updateAngle(angleVal) {
                          if (angleVal < 0)
                              angleVal += 360;
              
                          if ((angleVal >= control.startAngle) && (angleVal <= control.endAngle)) {
                              internal.setUpdatedValue = true;
                              internal.angleProxy = Qt.binding(function() { return angleVal; });
                              if(control.snap) {
                                  var mappedValue = internal.mapFromValue(startAngle, endAngle, minValue, maxValue, internal.angleProxy)
                                  var range = control.maxValue - control.minValue
                                  var effectiveStep = 2
                                  var actualVal = control.stepSize * Math.round(mappedValue / control.stepSize)
                                  internal.snappedValue = actualVal
                              }
                              internal.setUpdatedValue = false;
                          }
                      }
                  }
              
                  MouseArea {
                      anchors.fill: parent
                      enabled: control.interactive
                      onClicked: {
                          var outerRadius = Math.min(control.width, control.height)/ 2
                          var innerRadius = outerRadius - Math.max(control.trackWidth, 20);
                          var clickedDistance = (mouseX - internal.centerPt.x) * (mouseX - internal.centerPt.x) + (mouseY - internal.centerPt.y) * (mouseY - internal.centerPt.y);
                          var innerRadius2 = (innerRadius * innerRadius);
                          var outerRadius2 = (outerRadius * outerRadius);
                          var isOutOfInnerRadius = clickedDistance > innerRadius2;
                          var inInSideOuterRadius = clickedDistance <= outerRadius2;
                          if (inInSideOuterRadius && isOutOfInnerRadius) {
                              var angleDeg = Math.atan2(mouseY - internal.centerPt.y, mouseX - internal.centerPt.x) * 180 / Math.PI + 90;
                              internal.updateAngle(angleDeg);
                          }
                      }
                  }
              
                  // Handle Item
                  Item {
                      id: handleItem
                      visible: control.interactive
              
                      x: control.width / 2 - width / 2
                      y: control.height / 2 - height / 2
                      // make sure that the slider handle is always on top as we can set custom track or progress items
                      z: 2
                      width: control.handleWidth
                      height: control.handleHeight
                      antialiasing: true
                      transform: [
                          Translate {
                              y: -(Math.min(control.width, control.height) / 2) + Math.max(control.trackWidth, control.progressWidth) / 2 + control.handleVerticalOffset
                          },
                          Rotation {
                              angle: control.angle
                              origin.x: handleItem.width / 2
                              origin.y: handleItem.height / 2
                          }
                      ]
              
                      MouseArea {
                          id: trackMouse
                          enabled: control.interactive
              
                          function getVal() {
                              var handlePoint = mapToItem(control, trackMouse.mouseX, trackMouse.mouseY);
                              // angle in degrees
                              var angleDeg = Math.atan2(handlePoint.y - internal.centerPt.y, handlePoint.x - internal.centerPt.x) * 180 / Math.PI + 90;
                              internal.updateAngle(angleDeg);
                          }
              
                          anchors.fill: parent
                          onPositionChanged: getVal()
                          onClicked: getVal()
                          cursorShape: Qt.ArrowCursor
                      }
              
                      Loader {
                          id: handleLoader
              
                          sourceComponent: control.handle ? handle : handleComponent
                      }
                  }
              
                  /// Default handle component
                  Component {
                      id: handleComponent
              
                      Rectangle {
                          width: control.handleWidth
                          height: control.handleHeight
                          color: control.handleColor
                          radius: control.handleRadius
                          antialiasing: true
                      }
                  }
              }
              
              
              import QtQuick
              import QtQuick.Controls
              import "../components"
              
              Page {
                  id: darqSpeedo
              
                  allowedOrientations: Orientation.All // this is specific to SailfishOS and can likely be omitted.
              
                  // imported from "../components"
                  CircularSlider {
                      id: speedometer
                      interactive: false
                      anchors.centerIn: parent
                      width: 1000
                      height: width
                      value: 0
                      startAngle: -108
                      endAngle: 108
                      minValue: 0
                      maxValue: 180
                      anchors {
                          verticalCenterOffset: 200
                          verticalCenter: parent.verticalCenter
                          horizontalCenter: parent.horizontalCenter
                      }
                      // Tickmarks around gauge
                      Repeater {
                          model: 37
                          Rectangle {
                              id: ones
                              width: 6
                              height: index % 4 === 0 ? 50 : 25
                              color: index % 4 === 0 ? "white" : "silver"
                              property real angle: index * 6
                              transform: [ Translate { x: parent.width / 2 - width / 2; y: -155 },
                                  Rotation {
                                      origin.x: parent.width / 2
                                      origin.y: parent.height / 2
                                      angle: ones.angle + parent.startAngle
                                  }
                              ]
                          }
                      }
                      // Numbers around gauge
                      Repeater {
                          model: 10
                          Label {
                              id: digits
                              text: index * 20
                              color: "white"
                              font { bold: true; pixelSize: 48 }
                              property real angle: index * 24
                              transform: [
                                  Translate {
                                      x: parent.width / 2 - width / 2
                                      y: -75 // distance from tickmarks
                                  },
                                  Rotation {
                                      origin.x: parent.width / 2
                                      origin.y: parent.height / 2
                                      angle: digits.angle + parent.startAngle
                                  }
                              ]
                              // keeps numbers horizontal
                              rotation: -digits.angle - parent.startAngle
                          }
                      }
                      // Needle hub
                      Rectangle {
                          anchors.centerIn: speedometer
                          width: 100
                          height: width
                          radius: width/2
                          color: "#a0545454"
                      }
                      // Needle/pointer
                      Repeater {
                          model: 1
                          Rectangle {
                              id: needle
                              width: 20
                              height: 450
                              color: "orange"
                              radius: 20
                              transform: [
                                  Translate {
                                      x: speedometer.width / 2 - width / 2
                                      y: 50 // needle distance from centre
                                  },
                                  Rotation {
                                      origin.x: speedometer.width / 2
                                      origin.y: speedometer.height / 2
                                      angle: speedometer.angle
                                  }
                              ]
                          }
                      }
                      // Animation for demo purposes
                      SequentialAnimation on value {
                          id: animation
                          loops: Animation.Infinite
                          running: true
                          NumberAnimation { from: 0; to: 180; duration: 2000 }
                          NumberAnimation { from: 180; to: 0; duration: 2000 }
                      }
                  }
              }
              
              

              NOTE: I use Page, as my apps are built for my mobile phone using SailfishOS. You don't have to use Page, you can likely swap it for Item instead.

              Screenshot_20231114_001.png

              D Offline
              D Offline
              Darq
              wrote on last edited by
              #18

              @Markkyboy I don't mean the code for the entire speedometer. I want to restrict only this part of the code " rotation: 2.25*XXX+225 " to move in the angle range, e.g. from 225 to 135. I want there to be no movement in the range from 136 to 224 degrees. I don't know how to specify this in the code.

              MarkkyboyM 1 Reply Last reply
              0
              • D Darq

                @Markkyboy I don't mean the code for the entire speedometer. I want to restrict only this part of the code " rotation: 2.25*XXX+225 " to move in the angle range, e.g. from 225 to 135. I want there to be no movement in the range from 136 to 224 degrees. I don't know how to specify this in the code.

                MarkkyboyM Offline
                MarkkyboyM Offline
                Markkyboy
                wrote on last edited by
                #19

                @Darq said in Speedometer:

                ...... I want there to be no movement in the range from 136 to 224 degrees. I don't know how to specify this in the code.

                Sorry, right now I have no idea how to get what you want. I guess, like me, you will have to keep trying and playing until you succeed. I found little to no help with my own endeavours but fumbled my way through the code you see above. If I have an epiphany, I'll post it here but I make no promise.

                Could you explain why you want such a feature?

                Don't just sit there standing around, pick up a shovel and sweep up!

                I live by the sea, not in it.

                D 1 Reply Last reply
                0
                • MarkkyboyM Markkyboy

                  @Darq said in Speedometer:

                  ...... I want there to be no movement in the range from 136 to 224 degrees. I don't know how to specify this in the code.

                  Sorry, right now I have no idea how to get what you want. I guess, like me, you will have to keep trying and playing until you succeed. I found little to no help with my own endeavours but fumbled my way through the code you see above. If I have an epiphany, I'll post it here but I make no promise.

                  Could you explain why you want such a feature?

                  D Offline
                  D Offline
                  Darq
                  wrote on last edited by
                  #20

                  @Markkyboy Commands like "CircularSlider" don't work for me. This shield is called as png. The only problem is with the limitation of the "Rotation" command, so that the rotation is only within a specific range.

                  1 Reply Last reply
                  0
                  • JonBJ JonB referenced this topic on
                  • MarkkyboyM Markkyboy

                    Rather than leave you completely in the dark, Darq, here's some full code to make a working speedometer. Perhaps from this you can make it do what you want/require.

                    import QtQuick
                    import QtQuick.Controls
                    
                    Item {
                        id: control
                    
                        property int trackWidth: 20
                        property int progressWidth: 20
                        property color trackColor: "#505050"
                        property color progressColor: "#3a4ec4"
                        property bool hideTrack: false
                        property bool hideProgress: false
                    
                        property color handleColor: "#fefefe"
                        property int handleWidth: 80
                        property int handleHeight: 80
                        property int handleRadius: 40
                        property int handleVerticalOffset: 0
                    
                        property real startAngle: 0
                        property real endAngle: 360
                        property real minValue: 0.0
                        property real maxValue: 1.0
                    
                        property real value: 0.0
                        readonly property alias angle: internal.angle
                    
                    
                        property real stepSize: 0
                        property bool snap: false
                        property Component handle: null
                        readonly property alias pressed: trackMouse.pressed
                    
                        property bool interactive: true
                        property alias cursorShape: trackMouse.cursorShape
                    
                        implicitWidth: 250
                        implicitHeight: 250
                    
                        Binding {
                            target: control
                            property: "value"
                            value: control.snap ? internal.snappedValue : internal.mapFromValue(startAngle, endAngle, minValue, maxValue, internal.angleProxy)
                            when: internal.setUpdatedValue
                        }
                    
                        QtObject {
                            id: internal
                    
                            property point centerPt: Qt.point(control.width / 2, control.height / 2)
                            property real baseRadius: Math.min(control.width, control.height) / 2 - Math.max(control.trackWidth, control.progressWidth) / 2
                            property real actualSpanAngle: control.endAngle - control.startAngle
                            property color transparentColor: "transparent"
                            property color trackColor: control.trackColor
                            property bool setUpdatedValue: false
                            property real angleProxy: control.startAngle
                            property real snappedValue: 0.0
                            readonly property real angle: internal.mapFromValue(control.minValue, control.maxValue, control.startAngle, control.endAngle, control.value)
                    
                            function mapFromValue(inMin, inMax, outMin, outMax, inValue) {
                                return (inValue - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
                            }
                    
                            function updateAngle(angleVal) {
                                if (angleVal < 0)
                                    angleVal += 360;
                    
                                if ((angleVal >= control.startAngle) && (angleVal <= control.endAngle)) {
                                    internal.setUpdatedValue = true;
                                    internal.angleProxy = Qt.binding(function() { return angleVal; });
                                    if(control.snap) {
                                        var mappedValue = internal.mapFromValue(startAngle, endAngle, minValue, maxValue, internal.angleProxy)
                                        var range = control.maxValue - control.minValue
                                        var effectiveStep = 2
                                        var actualVal = control.stepSize * Math.round(mappedValue / control.stepSize)
                                        internal.snappedValue = actualVal
                                    }
                                    internal.setUpdatedValue = false;
                                }
                            }
                        }
                    
                        MouseArea {
                            anchors.fill: parent
                            enabled: control.interactive
                            onClicked: {
                                var outerRadius = Math.min(control.width, control.height)/ 2
                                var innerRadius = outerRadius - Math.max(control.trackWidth, 20);
                                var clickedDistance = (mouseX - internal.centerPt.x) * (mouseX - internal.centerPt.x) + (mouseY - internal.centerPt.y) * (mouseY - internal.centerPt.y);
                                var innerRadius2 = (innerRadius * innerRadius);
                                var outerRadius2 = (outerRadius * outerRadius);
                                var isOutOfInnerRadius = clickedDistance > innerRadius2;
                                var inInSideOuterRadius = clickedDistance <= outerRadius2;
                                if (inInSideOuterRadius && isOutOfInnerRadius) {
                                    var angleDeg = Math.atan2(mouseY - internal.centerPt.y, mouseX - internal.centerPt.x) * 180 / Math.PI + 90;
                                    internal.updateAngle(angleDeg);
                                }
                            }
                        }
                    
                        // Handle Item
                        Item {
                            id: handleItem
                            visible: control.interactive
                    
                            x: control.width / 2 - width / 2
                            y: control.height / 2 - height / 2
                            // make sure that the slider handle is always on top as we can set custom track or progress items
                            z: 2
                            width: control.handleWidth
                            height: control.handleHeight
                            antialiasing: true
                            transform: [
                                Translate {
                                    y: -(Math.min(control.width, control.height) / 2) + Math.max(control.trackWidth, control.progressWidth) / 2 + control.handleVerticalOffset
                                },
                                Rotation {
                                    angle: control.angle
                                    origin.x: handleItem.width / 2
                                    origin.y: handleItem.height / 2
                                }
                            ]
                    
                            MouseArea {
                                id: trackMouse
                                enabled: control.interactive
                    
                                function getVal() {
                                    var handlePoint = mapToItem(control, trackMouse.mouseX, trackMouse.mouseY);
                                    // angle in degrees
                                    var angleDeg = Math.atan2(handlePoint.y - internal.centerPt.y, handlePoint.x - internal.centerPt.x) * 180 / Math.PI + 90;
                                    internal.updateAngle(angleDeg);
                                }
                    
                                anchors.fill: parent
                                onPositionChanged: getVal()
                                onClicked: getVal()
                                cursorShape: Qt.ArrowCursor
                            }
                    
                            Loader {
                                id: handleLoader
                    
                                sourceComponent: control.handle ? handle : handleComponent
                            }
                        }
                    
                        /// Default handle component
                        Component {
                            id: handleComponent
                    
                            Rectangle {
                                width: control.handleWidth
                                height: control.handleHeight
                                color: control.handleColor
                                radius: control.handleRadius
                                antialiasing: true
                            }
                        }
                    }
                    
                    
                    import QtQuick
                    import QtQuick.Controls
                    import "../components"
                    
                    Page {
                        id: darqSpeedo
                    
                        allowedOrientations: Orientation.All // this is specific to SailfishOS and can likely be omitted.
                    
                        // imported from "../components"
                        CircularSlider {
                            id: speedometer
                            interactive: false
                            anchors.centerIn: parent
                            width: 1000
                            height: width
                            value: 0
                            startAngle: -108
                            endAngle: 108
                            minValue: 0
                            maxValue: 180
                            anchors {
                                verticalCenterOffset: 200
                                verticalCenter: parent.verticalCenter
                                horizontalCenter: parent.horizontalCenter
                            }
                            // Tickmarks around gauge
                            Repeater {
                                model: 37
                                Rectangle {
                                    id: ones
                                    width: 6
                                    height: index % 4 === 0 ? 50 : 25
                                    color: index % 4 === 0 ? "white" : "silver"
                                    property real angle: index * 6
                                    transform: [ Translate { x: parent.width / 2 - width / 2; y: -155 },
                                        Rotation {
                                            origin.x: parent.width / 2
                                            origin.y: parent.height / 2
                                            angle: ones.angle + parent.startAngle
                                        }
                                    ]
                                }
                            }
                            // Numbers around gauge
                            Repeater {
                                model: 10
                                Label {
                                    id: digits
                                    text: index * 20
                                    color: "white"
                                    font { bold: true; pixelSize: 48 }
                                    property real angle: index * 24
                                    transform: [
                                        Translate {
                                            x: parent.width / 2 - width / 2
                                            y: -75 // distance from tickmarks
                                        },
                                        Rotation {
                                            origin.x: parent.width / 2
                                            origin.y: parent.height / 2
                                            angle: digits.angle + parent.startAngle
                                        }
                                    ]
                                    // keeps numbers horizontal
                                    rotation: -digits.angle - parent.startAngle
                                }
                            }
                            // Needle hub
                            Rectangle {
                                anchors.centerIn: speedometer
                                width: 100
                                height: width
                                radius: width/2
                                color: "#a0545454"
                            }
                            // Needle/pointer
                            Repeater {
                                model: 1
                                Rectangle {
                                    id: needle
                                    width: 20
                                    height: 450
                                    color: "orange"
                                    radius: 20
                                    transform: [
                                        Translate {
                                            x: speedometer.width / 2 - width / 2
                                            y: 50 // needle distance from centre
                                        },
                                        Rotation {
                                            origin.x: speedometer.width / 2
                                            origin.y: speedometer.height / 2
                                            angle: speedometer.angle
                                        }
                                    ]
                                }
                            }
                            // Animation for demo purposes
                            SequentialAnimation on value {
                                id: animation
                                loops: Animation.Infinite
                                running: true
                                NumberAnimation { from: 0; to: 180; duration: 2000 }
                                NumberAnimation { from: 180; to: 0; duration: 2000 }
                            }
                        }
                    }
                    
                    

                    NOTE: I use Page, as my apps are built for my mobile phone using SailfishOS. You don't have to use Page, you can likely swap it for Item instead.

                    Screenshot_20231114_001.png

                    S Offline
                    S Offline
                    Sattiy
                    wrote on last edited by
                    #21

                    @Markkyboy Can You Please specify which file is which file so i can integrate it accordingly like which is main.qml file here

                    MarkkyboyM 1 Reply Last reply
                    0
                    • S Sattiy

                      @Markkyboy Can You Please specify which file is which file so i can integrate it accordingly like which is main.qml file here

                      MarkkyboyM Offline
                      MarkkyboyM Offline
                      Markkyboy
                      wrote on last edited by
                      #22

                      The first file is CircularSlider.qml, this forms the basis for the speedometer gauge in a circular fashion.

                      The second file is basically the 'Main.qml', in my case, it is called FirstPage.qml.

                      Don't just sit there standing around, pick up a shovel and sweep up!

                      I live by the sea, not in it.

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved