Map control
Version 0.9 - December 12th, 2016
Sourcecode
Please see the UgMapControl project for the source code created in this chapter. See Installing examples for information on how to download the examples.
Introduction
Many mobile apps need a map control. We wrapped the native map control from iOS and Android respectively and access its functionality using one common interface and API. Functionality includes
- positioning map control freely
- zooming in and out by setting the size of the area that the control displays
- moving to certain location
- using annotations to position image, i.e. drop your location pin
Overview of map classes and structures
SCDPlatformLocationCoordinate
Property/method | Description | Comment/Example |
---|---|---|
latitude:NSNumber | Sets the lattitude | |
longitude:NSNumber | Sets the longitude |
let location = SCDPlatformLocationCoordinate(latitude:44.061334,longitude:-79.454920)
SCDWidgetsMapWidget
Property/method | Description | Comment/Example |
---|---|---|
mapType | Set the map type | SCDWidgetsMapType.standard,satellite,hybrid |
setRegion( SCDPlatformLocationCoordinate, latitudinalMeters:Int, longitudinalMeters:Int) | Sets the region you want to display | Uses SCDWidgetsMapRegion |
userLocation | Current user location | Type is SCDPlatformLocationCoordinate |
isShowUserLocation : Bool | Checks if user location can be shown |
SCDWidgetsMapRegion
Property/ method | Description | Comment / Example |
---|---|---|
center | Centers the region around this coordinate | specify location using SCDPlatformLocationCoordinate |
latitudinalMeters | Width of the region in meters | 1000 (map control will cover 1000 meters horizontally) |
longitudinalMeters | Height of the region in meters | 1000 (map control will cover 1000 meters vertically) |
self.mapWidget.setRegion(location, latitudinalMeters:1000,longitudinalMeters:1000)
Minimal map application
- Drag and drop the map control on the main page
- Drag three buttons below the map control and name them Torronto, Current Location and Sushi
- Drag three buttons below the map control and name them Standard, Satellite and Hybrid
Add this minimal code to initialize the map control to the main.page.swift (easiest is to replace existing code)
import ScadeKit
class MainPageAdapter: SCDLatticePageAdapter {
var mapWidget : SCDWidgetsMapWidget!
// set coordinates
let perfectlySoftLocation = SCDPlatformLocationCoordinate(latitude:44.061334,longitude:-79.454920)
let bestSushiLocation = SCDPlatformLocationCoordinate(latitude:43.655156,longitude:-79.385293)
// page adapter initialization
override func load(_ path: String) {
super.load(path)
self.mapWidget = self.page!.getWidgetByName("mapwidget1") as! SCDWidgetsMapWidget
let button = self.page!.getWidgetByName("btnToronto") as! SCDWidgetsButton
button.onClick.append(SCDWidgetsEventHandler{ _ in self.self.goto(coordinates:self.perfectlySoftLocation) })
let btnCurrLoc = self.page!.getWidgetByName("btnCurrLoc") as! SCDWidgetsButton
btnCurrLoc.onClick.append(SCDWidgetsEventHandler{_ in self.gotoCurrentLocation()})
let btnSushi = self.page!.getWidgetByName("btnSushi") as! SCDWidgetsButton
btnSushi.onClick.append(SCDWidgetsEventHandler{_ in self.goto(coordinates:self.bestSushiLocation)})
// let add buttons for setting map type
let btnStandard = self.page!.getWidgetByName("btnStandard") as! SCDWidgetsButton
btnStandard.onClick.append(SCDWidgetsEventHandler{_ in self.setMapType(btnStandard.name)})
let btnHybrid = self.page!.getWidgetByName("btnSatellite") as! SCDWidgetsButton
btnHybrid.onClick.append(SCDWidgetsEventHandler{_ in self.setMapType(btnHybrid.name)})
let btnSatellite = self.page!.getWidgetByName("btnHybrid") as! SCDWidgetsButton
btnSatellite.onClick.append(SCDWidgetsEventHandler{_ in self.setMapType(btnSatellite.name)})
}
func setMapType(_ name:String) {
switch(name) {
case "btnHybrid":
self.mapWidget.mapType = SCDWidgetsMapType.hybrid
case "btnSatellite":
self.mapWidget.mapType = SCDWidgetsMapType.satellite
case "btnStandard":
self.mapWidget.mapType = SCDWidgetsMapType.standard
default:
print("not covered")
}
}
func goto(coordinates:SCDPlatformLocationCoordinate) {
self.mapWidget.setRegion(coordinates,latitudinalMeters:1000,longitudinalMeters:1000)
}
}
Setting the map type
The type of the map can easily be set using SCDWidgetsMapType.
func setMapType(_ name:String) {
switch(name) {
case "btnHybrid":
self.mapWidget.mapType = SCDWidgetsMapType.hybrid
case "btnSatellite":
self.mapWidget.mapType = SCDWidgetsMapType.satellite
case "btnStandard":
self.mapWidget.mapType = SCDWidgetsMapType.standard
default:
print("not covered")
}
}
Setting the zoom level
Setting the zoom level is easy. Just set new values for latitudinalMeters and longitudinalMeters, the zoom respectively around the center coordinate.
// Use the meters metric to set the zoom level. Make sure to use a new instance
// set new region
self.mapWidget.setRegion(coordinates,latitudinalMeters:1000,longitudinalMeters:1000)
Getting and going to current location
The current location is stored in the map widget's userLocation variable. However, you should first check the permission using isShowUserLocation() before going to the current location using moveToUserLocation()
func gotoCurrentLocation() {
// currently, the desktop returns isShowUserLocation==false
if(mapWidget.isShowUserLocation) {
let curr = mapWidget.userLocation
print(curr.latitude)
print(curr.longitude)
mapWidget.moveToUserLocation()
}
}
Map annotations
Annotations position images and are zoom agnostic
Annotations are a common concept on both iOS and Android. The most common use case is for instance setting a pin to indicate a location Info
Follow these steps:
- Use a SVG graphic to represent the annotation, i.e. the pin
- Always set the width and height, these parameters are mandatory
- Use the xhref field to set the relative location of the SVG file
- Create an annotation at a specific location using the location field
- and assign the image in the drawing field
- Finally, add the annotation to the widget's list of annotations: .annotations
func setPinAsAnnotaton(coordinate:SCDPlatformLocationCoordinate, imagePath:String) {
// We will further simplify the API
let svgImage = SCDSvgImage(width:SCDSvgUnit(value:25),height:SCDSvgUnit(value:25))
svgImage.xhref = imagePath
let ann = SCDWidgetsMapAnnotation(location:coordinate)
ann.drawing = svgImage
self.mapWidget.annotations.append(ann)
}
Map overlays
Overlays are images on a map that adjust to the zoom level
Depending on weather you zoom in or out, the image adjusts to the current zoom and increases or decreases in size.
Follow these steps:
- Convert your usual coordinates into the coordinate system of your mobile os using the convert method
- Create a scalable image. We use a circle in this example. Make sure to use a color.
- Create a map overlay and set the image to use using the drawing field
- Append the overlay to the list of overlays
func setOverlayAroundSushiPlace() {
// get the map specific coordinates
let coor2d = mapWidget.convert(fromGeoLocation: bestSushiLocation)
// Create overlay circle of radius 1000m
let overlayCircle = SCDSvgCircle(cx:SCDSvgUnit(value:coor2d.x),cy:SCDSvgUnit(value:coor2d.y),r:SCDSvgUnit(value:1000))
overlayCircle.fill = SCDSvgRGBColor(a:0.2,r:1,g:0,b:0)
// Create an overlay
let overlay = SCDWidgetsMapOverlay()
overlay.drawing = overlayCircle
// Add overlay onto the map
mapWidget.overlays.append(overlay)
}
Troubleshooting
GoogleMaps in China
Please understand that Google Maps is not or only partially supported in China and the MapWidget won't work on Android
Updated almost 8 years ago