×
Namespaces

Variants
Actions
Revision as of 19:57, 30 December 2011 by somnathbanik (Talk | contribs)

Google Landmarks on a Nokia Map using Qt Quick

From Nokia Developer Wiki
Jump to: navigation, search

This article demonstrates how to plot nearby landmark using Nokia Map API for Qt.

Article Metadata
Code ExampleTested with
Devices(s): N950
Compatibility
Platform(s): Symbian/ MeeGo
Article
Keywords: Nokia Map/ LandMark
Created: somnathbanik (30 Dec 2014)
Last edited: somnathbanik (30 Dec 2011)

Contents

Introduction

Using Nokia Map API for Qt we can create location-based applications that has cross platform mapping experience. In this article we will see some steps required to locate user location and to plot multiple pushpin on the map in a different way.


Nokia N9 Nokia N9 Nokia N9
Land Mark Category
Pushpin on Landmarks
Land Mark information detail


Nokia Map Nokia Map Nokia Map

Objective

For our educational purpose and to get a real live scenario we combined both Nokia Map API and Google Place API to create this application. We will get the coordinates of the landmark from Google Place API and plot them on Nokia Map with Pushpin. When user clicks on any of the Pushpin it displays a popup with the landmark information and the distance of the landmark from user’s location.


.

Implementation

We create two page item in main.qml file, the first page item has a list of landmark category and the second page displays the map with the landmarks.

page 1 in main.qml

//page 1
Rectangle {
id: page1
width: parent.width
color: "black"
height: parent.height
RssModel {id: feedModelLandmark}
ListView {
id: list
width: parent.width ;
height: parent.height-111;
y:111
model: feedModelLandmark
delegate: CategoryListDelegate {}
}
Rectangle{
id:titleRect
color: "white"
Text {
id: tileText
width:300
height: 40
y:32
text: qsTr("Near Me")
color: "green"
font.pixelSize: 80
}
}
Image {
id: titleImage
source: "maps-icon.png"
height: 80
width: 80
y:30
x:340
}
Rectangle
{
id:underline
color: "white"
y:106
height: 2
width:parent.width
}
states:
State {
name: "Item"; when: appWindow.inFirstScreen == true
PropertyChanges { target: page1; x: 0 }
PropertyChanges { target: page2; x: -(parent.width * 1.5) }
PropertyChanges { target: commonTools; visible:false }
}
transitions: Transition {
NumberAnimation { properties: "x"; duration: 700; easing.type: Easing.InOutQuad }
}
}

page 2 in main.qml

//page 2
Item {
id: page2
width: parent.width
height: parent.height
//display the map
Rectangle{
id: mapRect
anchors.fill: parent
signal xmlMapReady
onXmlMapReady: container.xmlReady = !container.xmlReady
RssModelMap {id: feedModelMap}
MapDelegate {id: container }
}
states:
State {
name: "Item"; when: appWindow.inSecondScreen == true
PropertyChanges { target: page2; x: 0 }
PropertyChanges { target: page1; x: -(parent.width * 1.5) }
PropertyChanges { target: commonTools; visible:true }
}
transitions: Transition {
NumberAnimation { properties: "x"; duration: 700; easing.type: Easing.InOutQuad }
}
}

It also has a toolbar as the back button, which is visible when the map displays

// menu bar
ToolBarLayout {
id: commonTools
visible: false
ToolIcon {
platformIconId: "toolbar-back"
anchors.bottom: (parent === undefined) ? undefined : parent.bottom
onClicked: {
loadFirst()
}
}
}

When user clicks on any of the landmark category it calls the loadLandMark() function, which uses the Google Places API to get the near by landmark information.

function loadLandMark(landmarkname)
{
myLatitude = positionSource.position.coordinate.latitude;
myLongitude = positionSource.position.coordinate.longitude;
console.log("latitude:" +myLatitude + "longitude:" +myLongitude+ "landmark:"+landmarkname );
var url =
"https://maps.googleapis.com/maps/api/place/search/xml?location="+myLatitude+","+myLongitude+"&radius=1000&name="+landmarkname+"&sensor=false&key=AIzaSyBGw0MB3DkFlveLwnCmAv2MlG5DJYxZt2s";
var doc = new XMLHttpRequest();
doc.onreadystatechange = function() {
if (doc.readyState == XMLHttpRequest.HEADERS_RECEIVED) {
}
else if (doc.readyState == XMLHttpRequest.DONE) {
console.log("HttpRequest DONE");
var status = doc.status;
if(status!=200) {
return;
}
var data = doc.responseText;
//console.log("Google Data:\n"+data);
feedModelMap.xmlData = data;
}
}
doc.open("GET", url);
doc.send();
}

In this case we are using XmlListModel instead of LandmarkModel for storing the data. The Google Places API is a HTTPS request so , first we download all the data through loadLandMark () function and then pass the data to the xml property of XmlListModel leaving the source property empty.

RssModelMap.qml

XmlListModel {
id: feedModelMap
property string xmlData:"";
source:""
xml: xmlData
query: "/PlaceSearchResponse/result"
namespaceDeclarations: ""
XmlRole { name: "name"; query: "name/string()" }
XmlRole { name: "vicinity"; query: "vicinity/string()" }
XmlRole { name: "type"; query: "type/string()" }
XmlRole { name: "lat"; query: "geometry/location/lat/string()" }
XmlRole { name: "lng"; query: "geometry/location/lng/string()" }
XmlRole { name: "reference"; query: "reference/string()" }
XmlRole { name: "id"; query: "id/string()" }
onStatusChanged: {
if (status === XmlListModel.Ready) {
console.log("xmlModel OK - count =", count);
mapRect.xmlMapReady();
}
}
}

When the data loading is being completed in XmlListModel it generates a signal which than fetch each landmark information from the XmlListModel and calls the function addPushPin() to plot the coordinates on the map element dynamically.

MapDelegate.qml

onXmlReadyChanged: {
console.log("******", feedModelMap.count);
var locationCount = feedModelMap.count;
for(var i=0; i<locationCount; i++ )
{
var name = feedModelMap.get(i).name;
var address = feedModelMap.get(i).vicinity
var latitude =feedModelMap.get(i).lat;
var longitude =feedModelMap.get(i).lng;
console.log("******",name, latitude, longitude);
map.addPushPin(latitude , longitude, name, address);
}
}

addPushPin() function creates instances of PushPin.qml component dynamically, which is a MapImage, and then calls the method addMapObject() to add the map object to the map.

            function addPushPin( latitude, longitude,name,address ) {
var myArray
var count = map.markers.length
counter++
var component = Qt.createComponent("PushPin.qml");
console.log(component.status + " " + Component.Null);
var object = component.createObject(container,
{ "latid": latitude, "longit": longitude,"name":name, "address":address}
);
if (object.status == Component.Ready) {
console.log("Component ready");
map.addMapObject(object);
object.clicked.connect(pushPinClicked);
myArray = new Array()
for (var i = 0; i<count; i++){
myArray.push(markers[i])
}
myArray.push(object)
markers = myArray
}
if (object.status == Component.Error) {
console.log("Error: " + component.errorString());
}
}


PushPin.qml

MapImage {
id:mapMarker
width: 35
signal clicked(double lat, double lon,string name, string address)
source: "pushpin.png"
property alias latid: mapMarkerCordinate.latitude
property alias longit: mapMarkerCordinate.longitude
property string name:""
property string address:""
coordinate: Coordinate
{
id: mapMarkerCordinate;
}
MapMouseArea {
onClicked: mapMarker.clicked(coordinate.latitude, coordinate.longitude,name,address)
}
}

When user click on the pushpin it displays a popup message with Landmark Name, Address and the approximate distance for the landmark from the User location.

MapDelegate.qml

function pushPinClicked(aLat , aLng,aName,aAddress)
{
myLatitude = positionSource.position.coordinate.latitude;
myLongitude = positionSource.position.coordinate.longitude;
var dist= distance(myLatitude,myLongitude,aLat,aLng);
popup.text = aName + "\n";
popup.text1 =aAddress;
popup.text2 ="You are around "+dist+" away";
popup.posX = 250;
popup.posY = 350;
popup.show();
}

It also has the Pinch Zoom In/Out feature. The user can go back with the back key and select other landmark from the category . We also need to keep in mind that when we add map object on the map element we also need to remove that. Here deleteAllPushPin() method does the same.

Summary

This is a basic Nokia Map API operation, but in a different way. This article also focus on how to use XmlListModel instead of LandmarkModel in Map element , download HTTPS data from Google Places API and Creating a Map Object Dynamically.

  • You can find the Windows Phone 7 version of the application here

Source Code

The full source code of the example is available here: File:NearByQML.zip

375 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×