Files:
The Map View example displays a city map overlayed with three sliders that allow you to control altitude, tilt and heading. On top of this it demonstrates its main feature, which is the ability to drop push pins on chosen locations
In this example we'll learn how to use the MapView class of the BB10 framework to change altitude, tilt and heading in combination with the rotation sensor, as well as dropping push pins using MapData.
The UI of this sample application consists of a page with a MapView, several actions such as "Drop Pin", "Remove Pins", and some geographical location choices.
ActionItem { title: qsTr("Drop Pin") imageSource: "asset:///images/pin.png" ActionBar.placement: ActionBarPlacement.OnBar onTriggered: { _mapViewTest.addPinAtCurrentMapCenter(); } }, ActionItem { title: qsTr("Remove Pins") imageSource: "asset:///images/clearpin.png" ActionBar.placement: ActionBarPlacement.OnBar onTriggered: { _mapViewTest.clearPins(); } }, ActionItem { title: qsTr("Center URL") imageSource: "asset:///images/url.png" ActionBar.placement: ActionBarPlacement.InOverflow onTriggered: { status.setText(mapview.url()); } }, ActionItem { title: qsTr("Waterloo") imageSource: "asset:///images/pin.png" ActionBar.placement: ActionBarPlacement.InOverflow onTriggered: { mapview.latitude = 43.468245; mapview.longitude = -80.519603; } }, ActionItem { title: qsTr("Manhattan") imageSource: "asset:///images/pin.png" ActionBar.placement: ActionBarPlacement.InOverflow onTriggered: { mapview.latitude = 40.791556; mapview.longitude = -73.967394; } }
These actions provide ways to manipulate the map view by dropping pins, clearing them or going to a specific location such as Manhattan. These manipulations are done through longitude, latitude to drop them in the user focused area.
MapView { id: mapview objectName: "mapViewObj" altitude: 3000 latitude: 43.449488 longitude: -80.406777 preferredWidth: 768 preferredHeight: 1280 onAltitudeChanged: { alt.setText(qsTr("Alt: %1").arg(newAlt)); } onHeadingChanged: { heading.setText(qsTr("Heading: %1\u00B0").arg(newHeading)); } onLatitudeChanged: { lat.setText(qsTr("Lat: %1").arg(newLat)); } onLongitudeChanged: { lon.setText(qsTr("Lon: %1").arg(newLon)); } onTiltChanged: { tilt.setText(qsTr("Tilt: %1\u00B0").arg(newTilt)); } onMapLongPressed: { status.setText(qsTr("map long pressed")); } onFollowedIdChanged: { status.setText(qsTr("followed id changed to %1").arg(idOfFollowed)); } onFocusedIdChanged: { status.setText(qsTr("focused id changed to %1").arg(idWithFocus)); } onCaptionButtonClicked: { status.setText(qsTr("button clicked %1").arg(focusedId)); } onCaptionLabelTapped: { status.setText(qsTr("label clicked %1").arg(focusedId)); } onLocationTapped: { status.setText(qsTr("location tapped %1").arg(id)); } onLocationLongPressed: { status.setText(qsTr("location long pressed %1").arg(id)); } }
The MapView element is set to the Waterloo, Ontario latitude,longitude location by default. The MapView events, such as latitude, longitude and heading changes update the appropriate labels to display their new values.
Container { layout: StackLayout { orientation: LayoutOrientation.LeftToRight } horizontalAlignment: HorizontalAlignment.Center
Displays the status of the MapView element, such as current atlitude, tilt or latitude, longitude updates and some user actions.
Container { leftPadding: 20 rightPadding: 20 bottomPadding: 20 topPadding: 20 horizontalAlignment: HorizontalAlignment.Right verticalAlignment: VerticalAlignment.Bottom overlapTouchPolicy: OverlapTouchPolicy.Allow ImageView { id: compassImage imageSource: "asset:///images/compass.png" horizontalAlignment: HorizontalAlignment.Center attachedObjects: [ ImplicitAnimationController { // Disable animations to avoid jumps between 0 and 360 degree enabled: false } ] } ToggleButton { id: sensorToggle horizontalAlignment: HorizontalAlignment.Center checked: true onCheckedChanged: { if (checked) { mapview.setFollowedId("device-location-id"); } else { mapview.setFollowedId(""); } } onCreationCompleted: { mapview.setFollowedId("device-location-id"); } } } Compass { property double azimuth: 0 active: sensorToggle.checked axesOrientationMode: Compass.UserOrientation alwaysOn: false onReadingChanged: { // Called when a new compass reading is available mapview.setHeading(reading.azimuth); compassImage.rotationZ = 360 - reading.azimuth; } },
The Container that encapslates a compass image and ToggleButton. This allows us to show the compass positioning and the current map latitude/longitude of your gps location.
RotationSensor { id: rotation property real x: 0 active: sensorToggle.checked alwaysOn: false skipDuplicates: true onReadingChanged: { x = reading.x - 30 if (x <= 40 && x > 0) { mapview.setTilt(x); } } },
The RotationSensor is used to determine the map tilt based on your handhelds rotation around the x-axis/y-axis.
PositionSource { id: positionSource updateInterval: 1000 active: sensorToggle.checked onPositionChanged: { _mapViewTest.updateDeviceLocation(positionSource.position.coordinate.latitude, positionSource.position.coordinate.longitude); } }
The PositionSource is used to update the graphical map pin that represents your current location when your position is changing.
This class deals with the adding and updating of location data for the MapData graphical elements.
MapViewDemo::MapViewDemo(bb::cascades::Application *app) : QObject(app) { // create scene document from main.qml asset // set parent to created document to ensure it exists for the whole application lifetime QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(this); qml->setContextProperty("_mapViewTest", this); // create root object for the UI AbstractPane *root = qml->createRootObject<AbstractPane>(); QObject* mapViewAsQObject = root->findChild<QObject*>(QString("mapViewObj")); if (mapViewAsQObject) { mapView = qobject_cast<bb::cascades::maps::MapView*>(mapViewAsQObject); mapView->setCaptionGoButtonVisible(true); if (mapView) { // creating a data provider just for the device location object. that way, when the clear function is call, this object is not removed. DataProvider* deviceLocDataProv = new DataProvider("device-location-data-provider"); mapView->mapData()->addProvider(deviceLocDataProv); // create a geolocation just for the device's location deviceLocation = new GeoLocation("device-location-id"); deviceLocation->setName("Current Device Location"); deviceLocation->setDescription("<html><a href=\"http://www.blackberry.com\">Hyperlinks</a> are super useful in bubbles.</html>"); // for that location, replace the standard default pin with the provided bulls eye asset Marker bullseye = Marker(UIToolkitSupport::absolutePathFromUrl( QUrl("asset:///images/me.png")), QSize(60, 60), QPoint(29, 29), QPoint(29, 1)); deviceLocation->setMarker(bullseye); deviceLocDataProv->add(deviceLocation); } } // set created root object as a scene app->setScene(root); }
Inside the constructor of the class we create a seperate DataProvider to contain our current location. The reason for this is to seperate the provider containing our location from the default one that contains other location elements we decide to add on the map, so that it may be easier to clear these markers without clearing our location. We also create the Marker which will represent the graphical current position on the map, which is added to the this DataProvider.
void MapViewDemo::addPinAtCurrentMapCenter() { if (mapView) { GeoLocation* newDrop = new GeoLocation(); newDrop->setLatitude(mapView->latitude()); newDrop->setLongitude(mapView->longitude()); QString desc = QString("Coordinates: %1, %2").arg(mapView->latitude(), 0, 'f', 3).arg(mapView->longitude(), 0, 'f', 3); newDrop->setName("Dropped Pin"); newDrop->setDescription(desc); // use the marker in the assets, as opposed to the default marker Marker flag; flag.setIconUri(UIToolkitSupport::absolutePathFromUrl( QUrl("asset:///images/on_map_pin.png"))); flag.setIconSize(QSize(60, 60)); flag.setLocationCoordinate(QPoint(20, 59)); flag.setCaptionTailCoordinate(QPoint(20, 1)); newDrop->setMarker(flag); mapView->mapData()->add(newDrop); } }
The addPinAtCurrentMapCenter method creates GeoLocation instances, with set latitude/longitude values, and corresponding graphical Marker's to graphically represent the current map center. By adding this to the default MapData, they show up on in our MapView.
void MapViewDemo::clearPins() { if (mapView) { // this will remove all pins, except the "device location" pin, as it's in a different data provider mapView->mapData()->defaultProvider()->clear(); } }
The clearPins() method illustrates how to remove all the Marker's associated with a perticular DataProvider. You can group your Marker's with different DataProvider's to be able to manipulate subsets of Marker's depending on functionality.