QML Maps
Overview
The Map type allows the display of a map and placing objects within the map. Various points of interest can be defined and added to the map for display. Also the Map has features to control how the map is displayed. With the Map item you can center the map, zoom, pinch and make the item flickable.
The places to be added to the map are MapItems. The item's position is defined by a coordinate which includes latitude, longitude and altitude. The item is then displayed automatically after it is added to the Map. Interaction with the added items, and the Map itself, is handled by MapMouseArea when items are added as children of the MapItems or Map.
Position on map
All position APIs are part of the QtPositioning module. The basic piece of position information is the coordinate. A coordinate encapsulates data for the latitude, longitude and altitude of the location. Altitude is in meters. It also has a method to determine distance to another coordinate. The coordinate type may also be held within a Location element, this will also have information on a bounding box size to determine sufficient proximity to the location and a location address.
Here is an example of a client that uses a position source to center a map on the current position:
Rectangle { import QtPositioning 5.2 import QtLocation 5.0 ... map : Map { // initialize map ... } PositionSource { onPositionChanged: { // center the map on the current position map.center = position.coordinate } } }
Geocoding
Geocoding is the derivation of geographical coordinates (latitude and longitude) from other geographical references to the locations. For example, this can be a street address. Reverse geocoding is also possible with a street address being used to determine a geographical coordinate. Geocoding is performed by using the GeoCodeModel type.
The following code examples are a small part of the map component in the Map Viewer (QML) example. The snippets demonstrate the declaration of the GeocodeModel component.
In the snippet we see that the geocodeModel property contains the plugin and two signal handlers. One for changes in status (onStatusChanged ) and the other to update the centering of the Map object (onLocationsChanged ).
property GeocodeModel geocodeModel: GeocodeModel { plugin: map.plugin onStatusChanged: { if ((status == GeocodeModel.Ready) || (status == GeocodeModel.Error)) map.geocodeFinished() } onLocationsChanged: { if (count == 1) { map.center.latitude = get(0).coordinate.latitude map.center.longitude = get(0).coordinate.longitude } } } MapItemView { model: geocodeModel delegate: pointDelegate }
These geocoding features are called from a higher level piece of code. In this snippet we see an onGoButtonClicked signal handler that extracts the address from the user interface and then creates a query for the GeocodeModel to process and determine the geographical coordinates.
Address { id: geocodeAddress } onGoButtonClicked: { // manage the UI state transitions page.state = "" messageDialog.state = "" // fill out the Address element geocodeAddress.street = dialogModel.get(0).inputText geocodeAddress.city = dialogModel.get(1).inputText geocodeAddress.state = dialogModel.get(2).inputText geocodeAddress.country = dialogModel.get(3).inputText geocodeAddress.postalCode = dialogModel.get(4).inputText // send the geocode request map.geocodeModel.query = geocodeAddress map.geocodeModel.update() }
Navigation
A very important function of the Map type is navigation from one place to a destination with possible waypoints along the route. The route will be divided up into a series of segments. At the end of each segment is a vertex called a maneuver. The segments contain information about the time and distance to the end of the segment. The maneuvers contain information about what to do next, how to get onto the next segment, if there is one. So a maneuver contains navigational information, for example "turn right now".
To find a suitable route we will need to use a RouteQuery to define the selection criteria and adding any required waypoints. The RouteModel should return a list of RouteSegments that defines the route to the destination complete with navigation advice at the joins between segments, called RouteManeuvers
There are many options that you can add to the query to narrow the criteria. The RouteQuery properties can include
numberAlternativeRoutes | The number of alternative routes |
travelModes | Travel modes |
routeOptimizations | Required route optimizations |
segmentDetail | Level of detail in segments |
maneuverDetail | Level of detail in maneuvers between segments |
waypoints | A list of waypoints |
excludedAreas | A list of excluded areas that the route must not cross |
featureTypes | Relevant map features, for example highway, ferry |
In the following example a default RouteQuery is declared, later to be defined by some user input, and used in routeModel as the query. The routeInfoModel is a ListModel that can be updated using an update() function that we will look at later.
property RouteQuery routeQuery: RouteQuery {} property RouteModel routeModel: RouteModel { plugin : map.plugin query: routeQuery onStatusChanged: { if (status == RouteModel.Ready) { switch (count) { case 0: clearAll() // technically not an error map.routeError() break case 1: routeInfoModel.update() break } } else if (status == RouteModel.Error) { clearAll() map.routeError() } } function clearAll() { routeInfoModel.update() } }
The user enters, via a dialog, some information such as the starting point of the route, some waypoints and the destination. All of these locations are waypoints so the locations from start to finish will be entered as a sequence of waypoints. Then other query properties can be set that may be specific to this trip.
function calculateRoute() { // clear away any old data in the query map.routeQuery.clearWaypoints(); // add the start and end coords as waypoints on the route map.routeQuery.addWaypoint(startCoordinate) map.routeQuery.addWaypoint(endCoordinate) map.routeQuery.travelModes = routeDialog.travelMode map.routeQuery.routeOptimizations = routeDialog.routeOptimization for (var i=0; i<9; i++) { map.routeQuery.setFeatureWeight(i, 0) } for (var i=0; i<routeDialog.features.length; i++) { map.routeQuery.setFeatureWeight(routeDialog.features[i], RouteQuery.AvoidFeatureWeight) } map.routeModel.update(); // center the map on the start coord map.center = startCoordinate; }
The routeInfoModel ListModel is used to grab the results of the query and construct a suitable list for display. The ListModel routeInfoModel contains an update() function that loops through the segments extracting the segment length, instruction text and distance to the next instruction. The extracted data is formatted for display as it is retrieved.
ListModel { id: routeInfoModel property string travelTime property string distance function update() { clear() if (routeModel.count > 0) { for (var i = 0; i < routeModel.get(0).segments.length; i++) { append({ "instruction": routeModel.get(0).segments[i].maneuver.instructionText, "distance": formatDistance(routeModel.get(0).segments[i].maneuver.distanceToNextInstruction) }); } } travelTime = routeModel.count == 0 ? "" : formatTime(routeModel.get(0).travelTime) distance = routeModel.count == 0 ? "" : formatDistance(routeModel.get(0).distance) } } MapItemView { model: routeModel delegate: routeDelegate autoFitViewport: true }
For more information on the example see the Map Viewer (QML) example.
Zoom, Pinch and Flickable
The Map item also supports user interface interactions with the map using tactile and mouse gestures. That is features such as swiping to pan, pinching to zoom.
Enabling and configuring pinch and flickable is easy within the Map type.
Map { id: map zoomLevel: (maximumZoomLevel - minimumZoomLevel)/2 center { latitude: -27.5796 longitude: 153.1003 } // Enable pinch gestures to zoom in and out gesture.flickDeceleration: 3000 gesture.enabled: true }
Zoom can also be controlled by other objects like sliders, as shown in the example, by implementing the onValueChanged handler to update the Map zoomLevel.
Types
Maps
The MapCircle type displays a geographic circle on a Map. | |
The Map type displays a map. | |
MapPinchEvent type provides basic information about pinch event. | |
The MapGestureArea type provides Map gesture interaction. | |
The MapItemView is used to populate Map from a model. | |
The MapMouseArea item enables simple mouse handling. | |
The MapMouseEvent object provides information about a mouse event. | |
The MapQuickItem type displays an arbitrary Qt Quick object on a Map. | |
The MapType type holds information about a map type. | |
The MapPolygon type displays a polygon on a Map | |
The MapPolyline type displays a polyline on a map. | |
The MapRectangle type displays a rectangle on a Map. | |
The MapRoute type displays a Route on a Map. |
Geocoding
The GeocodeModel type provides support for searching operations related to geographic information. |
Routing
The RouteManeuver type represents the information relevant to the point at which two RouteSegments meet. | |
The Route type represents one geographical route. | |
The RouteModel type provides access to routes. | |
The RouteQuery type is used to provide query parameters to a RouteModel. | |
The RouteSegment type represents a segment of a Route. |
Example
The above snippets are taken from the Map Viewer (QML) example.