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. QML: Custom draggable point delegate for ChartView series
Forum Updated to NodeBB v4.3 + New Features

QML: Custom draggable point delegate for ChartView series

Scheduled Pinned Locked Moved Solved QML and Qt Quick
2 Posts 1 Posters 966 Views 2 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.
  • Aleksey_KA Offline
    Aleksey_KA Offline
    Aleksey_K
    wrote on last edited by
    #1

    Is it possible to use custom delegates for draggable points (i.e. Items, icons, Rectangles, etc) in Qt Charts or other 3rd party libraries like it is easily possible in Qt Location for MapItemView, MapQuickItem and their delegate property? Or it is possible to use some combinations of PathView and ChartView for such purpose? PathView inside ChartView could be a solution, however probably will need to convert chart coordinates to screen coordinates there: also not sure ChartView has methods for this. Need to make some mockup to check this. Had not found any documentation or samples about. Should be obvious and simple like it was implemented in Qt Location however it is not implemented for Qt Charts for some reasons.

    Ideal way could be Map element using from Qt Location where I have all I need: MapItemView, MapQuickItem and MapPolygon or MapPolyline for graphics as I have cartographic information to draw. But again 2 questions:

    • how to draw axis: X - distance km, Y - altitude
    • how to draw chart grid
    • how to draw custom 2D BarSeries imitating terrain elevation (could be MapPolygon however).

    Is it possible to dynamically draw some custom map here? Any ideas?

    Sample chart/terrain elevation

    1 Reply Last reply
    0
    • Aleksey_KA Offline
      Aleksey_KA Offline
      Aleksey_K
      wrote on last edited by
      #2

      Found simple and elegant solution with ChartView with Repeater inside and ChartView mapping functions: mapToPosition and mapToValue to map chart<->screen coordinates easily.

      Mockup:

      import QtQuick 2.12
      import QtCharts 2.3
      
      Item {
          visible: true
          width: 640
          height: 480
      
          ChartView {
              id: chart
              anchors.fill: parent
              antialiasing: true
      
              ValueAxis {
                  id: xAxis
                  min: 0
                  max: 1100
                  tickCount: 12
                  labelFormat: "%.0f"
              }
      
              ValueAxis {
                  id: yAxis
                  min: -50
                  max: 200
                  tickInterval: 50
                  labelFormat: "%.0f"
              }
      
              ListModel {
                  id: lineModel
                  ListElement { x: 50; y: 155; }
                  ListElement { x: 138; y: 175 }
                  ListElement { x: 193; y: 50 }
                  ListElement { x: 271; y: 90 }
                  ListElement { x: 295; y: 90 }
                  ListElement { x: 383; y: 150 }
                  ListElement { x: 529; y: 100 }
                  ListElement { x: 665; y: 150 }
                  ListElement { x: 768; y: 90 }
                  ListElement { x: 794; y: 90 }
                  ListElement { x: 851; y: 50 }
                  ListElement { x: 875; y: 50 }
                  ListElement { x: 925; y: 175 }
                  ListElement { x: 1060; y: 125 }
              }
      
              ListModel {
                  id: areaModel
                  ListElement { x: 0; y: 100 }
                  ListElement { x: 138; y: 125 }
                  ListElement { x: 193; y: 0 }
                  ListElement { x: 271; y: 40 }
                  ListElement { x: 295; y: 40 }
                  ListElement { x: 383; y: 100 }
                  ListElement { x: 529; y: 50 }
                  ListElement { x: 665; y: 100 }
                  ListElement { x: 768; y: 40 }
                  ListElement { x: 794; y: 40 }
                  ListElement { x: 851; y: 0 }
                  ListElement { x: 875; y: 0 }
                  ListElement { x: 925; y: 125 }
                  ListElement { x: 1060; y: 75 }
                  ListElement { x: 1100; y: 60 }
              }
      
              AreaSeries {
                  name: "Terrain"
                  axisX: xAxis
                  axisY: yAxis
                  borderColor: color
                  upperSeries: LineSeries {
                      id: areaSeries
                  }
              }
      
              LineSeries {
                  id: lineSeries
                  name: "Flying path"
                  axisX: xAxis
                  axisY: yAxis
              }
      
              function adjustPosition(item, index) {
                  let point = Qt.point(lineModel.get(index).x, lineModel.get(index).y)
                  let position = chart.mapToPosition(point, lineSeries)
                  item.x = position.x - item.width / 2
                  item.y = position.y - item.height / 2
              }
      
              function adjustValue(item, index) {
                  let position = Qt.point(item.x + item.width / 2, item.y + item.height / 2)
                  let point = chart.mapToValue(position, lineSeries)
                  lineModel.setProperty(index, "y", point.y)  // Change only Y-coordinate
                  lineSeries.replace(lineSeries.at(index).x, lineSeries.at(index).y, // old
                                     lineSeries.at(index).x, point.y)                // new
              }
      
              Repeater {
                  model: lineModel
      
                  Rectangle {
                      id: indicator
                      radius: 100
                      width: radius / 2
                      height: width
                      color: "red"
      
                      property real parentWidth: chart.width
                      property real parentHeight: chart.height
      
                      onParentWidthChanged: chart.adjustPosition(this, index)
                      onParentHeightChanged: chart.adjustPosition(this, index)
      
                      onYChanged: {
                          if(mouseArea.drag.active) {
                              chart.adjustValue(this, index)
                          }
                      }
      
                      Image {
                          id: waypoint
                          anchors.centerIn: parent
                          source: index ? "qrc:/waypoint.svg" : "qrc:/home.svg"
                      }
      
                      MouseArea {
                          id: mouseArea
                          anchors.fill: parent
                          drag.target: indicator
                          drag.axis: Drag.YAxis
                          preventStealing: true
                      }
                  }
              }
      
              Component.onCompleted: {
                  lineSeries.clear()
                  areaSeries.clear()
                  for(let i = 0; i < lineModel.count; i++) {
                      lineSeries.append(lineModel.get(i).x, lineModel.get(i).y)
                  }
      
                  for(let j = 0; j < areaModel.count; j++) {
                      areaSeries.append(areaModel.get(j).x, areaModel.get(j).y)
                  }
              }
          }
      }
      

      Any improvements, optimizations and suggestion like model binding via HXYModelMapper/VXYModelMapper instead of JS model filling are welcome. Will fix the answer.

      Result screenshot:

      enter image description here

      1 Reply Last reply
      1

      • Login

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