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. How to ensure Popup is visible inside a QML Map
Forum Updated to NodeBB v4.3 + New Features

How to ensure Popup is visible inside a QML Map

Scheduled Pinned Locked Moved Solved QML and Qt Quick
qmlmapopenstreetmaps
2 Posts 1 Posters 509 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.
  • M Offline
    M Offline
    MattP2
    wrote on last edited by MattP2
    #1

    Hello,

    I'm building a Qt 5.11 application which embeds an openstreetmap QML component. I just wrote a minimal reproduce case. It consists in displaying objects (five blue dots here) on the map. When hovering the object, a small popup is displayed with some text.

    When objects are close to the edge, the popup is not displayed correctly. I though I would use visibleArea check this, but the property was added in Qt 5.12.

    I can't find a solution for the popup to be fully visible. Is there a workaround in Qt 5.11 that I can do? Here the QML file. Just type qmlscene sample.qml and hover blue dots to view it.

    import QtQuick 2.11
    import QtQuick.Controls 2.4
    import QtLocation 5.11
    import QtPositioning 5.11
    import QtQuick.Window 2.11
    
    Window {
        id: root; width: 800; height: 600;
    
        Plugin { id: mapPlugin; name: "osm"; }
    
        ListModel {
            id: myModel
            ListElement { latitude: 48.2351164;          longitude: 6.8986936;           name: "The point on the center"; }
            ListElement { latitude: 48.235111272600186;  longitude: 6.9007217756551995;  name: "The point on the right"; }
            ListElement { latitude: 48.23512783507458;   longitude: 6.896574932520792;   name: "The point on the left"; }
            ListElement { latitude: 48.23614708436043;   longitude: 6.898623901851295;   name: "The point on the top"; }
            ListElement { latitude: 48.23417574713512;   longitude: 6.898641104398024;   name: "The point on the bottom"; }
        }
    
        Map {
            id: map
            anchors.fill: parent
            plugin: mapPlugin
            center: QtPositioning.coordinate(48.2351164, 6.8986936)
            zoomLevel: 19
    
            MapItemView {
                model: myModel
    
                delegate: MapQuickItem {
                    anchorPoint.x: myRect.width / 2
                    anchorPoint.y: myRect.height / 2
                    width: myRect.width
                    height: myRect.height
    
                    coordinate: QtPositioning.coordinate(model.latitude, model.longitude)
    
                    sourceItem: Rectangle {
                        id: myRect
    
                        readonly property int radius: 10
    
                        width: radius * 2
                        height: radius * 2
                        color: "transparent"
    
                        Canvas {
                            id: myCanvas
                            anchors.fill: parent
    
                            property alias textVisible: myPopup.visible
    
                            onPaint: {
                                var width = myRect.width;
                                var height = myRect.height;
                                var centreX = width / 2;
                                var centreY = height / 2;
                                var ctx = getContext("2d");
                                ctx.reset();
                                ctx.fillStyle = "blue";
                                ctx.globalAlpha = 1;
                                ctx.beginPath();
                                ctx.moveTo(centreX, centreY);
                                ctx.arc(centreX, centreY, myRect.radius, 0, Math.PI * 2, false);
                                ctx.closePath();
                                ctx.fill();
                            }
    
                            MouseArea {
                                x: 0; y: 0;
                                width: myRect.radius * 2
                                height: myRect.radius * 2
                                acceptedButtons: Qt.LeftButton
                                hoverEnabled: true
                                onEntered: { myCanvas.textVisible = true }
                                onExited: { myCanvas.textVisible = false }
                            }
                        }
    
                        Popup {
                            id: myPopup
                            x: myRect.width / 2 - width / 2
                            y: myRect.height / 2 + 20
                            visible: false
                            Label { text: model.name; horizontalAlignment: Text.AlignHCenter; }
                        }
                    }
                }
            }
        }
    }
    

    Any help is greatly appreciated.

    1 Reply Last reply
    0
    • M Offline
      M Offline
      MattP2
      wrote on last edited by
      #2

      After looking for a while, I finally came across these two functions: mapToItem and mapFromItem.

      So, I first need to map the current item point to the map item coordinate system. Then, I must check the point is inside the map viewport. If not, I have to adjust the coordinate, and after that, I map the point back to the current item coordinate system. Popup width and height seem to decrease when approaching bottom and right borders, so I had to use contentHeight, contentWidth and padding properties to get the real popup size.

      And I had to initialize the popup x and y to a value different of zero to allow mouse event to pass on the blue dot.

      Here is the working code, for those who may need it.

      import QtQuick 2.11
      import QtQuick.Controls 2.4
      import QtLocation 5.11
      import QtPositioning 5.11
      import QtQuick.Window 2.11
      
      Window {
          id: root; width: 800; height: 600;
      
          Plugin { id: mapPlugin; name: "osm"; }
      
          ListModel {
              id: myModel
              ListElement { latitude: 48.2351164;          longitude: 6.8986936;           name: "The point on the center"; }
              ListElement { latitude: 48.235111272600186;  longitude: 6.9007217756551995;  name: "The point on the right"; }
              ListElement { latitude: 48.23512783507458;   longitude: 6.896574932520792;   name: "The point on the left"; }
              ListElement { latitude: 48.23614708436043;   longitude: 6.898623901851295;   name: "The point on the top"; }
              ListElement { latitude: 48.23417574713512;   longitude: 6.898641104398024;   name: "The point on the bottom"; }
          }
      
          Map {
              id: map
              anchors.fill: parent
              plugin: mapPlugin
              center: QtPositioning.coordinate(48.2351164, 6.8986936)
              zoomLevel: 19
      
              MapItemView {
                  model: myModel
      
                  delegate: MapQuickItem {
                      anchorPoint.x: myRect.width / 2
                      anchorPoint.y: myRect.height / 2
                      width: myRect.width
                      height: myRect.height
      
                      coordinate: QtPositioning.coordinate(model.latitude, model.longitude)
      
                      sourceItem: Rectangle {
                          id: myRect
      
                          readonly property int radius: 10
      
                          width: radius * 2
                          height: radius * 2
                          color: "transparent"
      
                          Canvas {
                              id: myCanvas
                              anchors.fill: parent
      
                              property alias textVisible: myPopup.visible
      
                              onPaint: {
                                  var width = myRect.width;
                                  var height = myRect.height;
                                  var centreX = width / 2;
                                  var centreY = height / 2;
                                  var ctx = getContext("2d");
                                  ctx.reset();
                                  ctx.fillStyle = "blue";
                                  ctx.globalAlpha = 1;
                                  ctx.beginPath();
                                  ctx.moveTo(centreX, centreY);
                                  ctx.arc(centreX, centreY, myRect.radius, 0, Math.PI * 2, false);
                                  ctx.closePath();
                                  ctx.fill();
                              }
      
                              MouseArea {
                                  x: 0; y: 0;
                                  width: myRect.radius * 2
                                  height: myRect.radius * 2
                                  acceptedButtons: Qt.LeftButton
                                  hoverEnabled: true
      
                                  onPositionChanged: {
                                      myCanvas.textVisible = true;
      
                                      // absolute position in map coordinate system
                                      var absPos = mapToItem(map, mouse.x, mouse.y);
      
                                      // margin between mouse pointer and the popup
                                      var cursorMargin = 10;
                                      // extra margin for right and bottom side
                                      var bottomRightSideExtraMargin = 10;
      
                                      // add the cursor margin to the position
                                      var absPopupX = absPos.x + cursorMargin;
                                      var absPopupY = absPos.y + cursorMargin;
      
                                      // adjust if the popup is out of view on the bottom or right sides
                                      if (absPos.x + myPopup.contentWidth + myPopup.leftPadding + myRect.radius * 2 + bottomRightSideExtraMargin > root.width) {
                                          absPopupX = root.width - (myPopup.contentWidth + myPopup.leftPadding + cursorMargin + bottomRightSideExtraMargin);
                                      }
                                      if (absPos.y + myPopup.contentHeight + myPopup.topPadding + myRect.radius * 2 + bottomRightSideExtraMargin > root.height) {
                                          absPopupY = root.height - (myPopup.contentHeight + myPopup.topPadding + cursorMargin + bottomRightSideExtraMargin);
                                      }
      
                                      // convert back to the current item coordinate system
                                      var popupPos = mapFromItem(map, absPopupX, absPopupY);
                                      myPopup.x = popupPos.x;
                                      myPopup.y = popupPos.y;
                                  }
      
                                  onExited: {
                                      myCanvas.textVisible = false;
                                  }
                              }
                          }
      
                          Popup {
                              id: myPopup
                              // original offset to allow mouse hover
                              x: 20; y: 20;
                              visible: false
                              Label { text: model.name; horizontalAlignment: Text.AlignHCenter; }
                          }
                      }
                  }
              }
          }
      }
      
      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