Skip to main content
GuidesAPI ReferenceExamples

Map Compass

|

This example demonstrates how to render a compass icon that displays the heading rotation of an interactive map. The compass indicates the direction where 0 degrees is north, 90 degrees is east, 180 degrees is south, and 270 degrees is west. You will also learn how to rotate the map back to its default north-up orientation.

Initial map rotation angle, north pointing up
Map rotation angle changed, north pointing differently

UI and Map Integration

The MainActivity overrides the onCreate() function which defines the buttonAsStart / buttonAsStop methods used to turn the compass on or off, as well as color the button green / red, respectively, and a listener for that button, btnEnableLiveHeading.setOnClickListener.

The button listener calls startLiveHeading() or stopLiveHeading() to start or stop reading the live compass sensor data from the device, by adding or removing a listener to the compass data source.

MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
increment()

surfaceView = findViewById(R.id.gem_surface)
compass = findViewById(R.id.compass)
btnEnableLiveHeading = findViewById(R.id.btn_enable_live_heading)
statusText = findViewById(R.id.status_text)

// start stop btn
buttonAsStart(this, btnEnableLiveHeading)

btnEnableLiveHeading.setOnClickListener {
isLiveHeadingEnabled.set(!isLiveHeadingEnabled.get())

if (isLiveHeadingEnabled.get())
{
buttonAsStop(this, btnEnableLiveHeading)
statusText.text = getString(R.string.live_heading_enabled)
}
else
{
buttonAsStart(this, btnEnableLiveHeading)
statusText.text = getString(R.string.live_heading_disabled)
}

GemCall.execute {
if (isLiveHeadingEnabled.get())
{
startLiveHeading()
}
else
{
stopLiveHeading()
}
}
}
}

The compass data source listener, when active, reads the compass sensor, smoothed into an average of several readings, and passes this heading to the mapView to rotate the map accordingly, when the device is rotated.

MainActivity.kt
private var dataSourceListener = object : DataSourceListener()
{
override fun onNewData(data: SenseData)
{
GemCall.execute {
// smooth new compass data
val heading = headingSmoother.update(CompassData(data).heading)

// update map view based on the recent changes
surfaceView.mapView?.preferences?.rotationAngle = heading
}
}
}

Compass Functionality

This code sets up a callback onMapDataReady that executes when map data is ready. If the data isn't ready, it exits.

Otherwise, it makes the compass visible and then it links the compass UI:

  • The compass image rotates as the map view rotates
  • Tapping the compass icon makes the map smoothly animate to a north-up orientation.
MainActivity.kt
SdkSettings.onMapDataReady = onMapDataReady@{ isReady ->
if (!isReady) return@onMapDataReady

if(!mainActivityIdlingResource.isIdleNow)
decrement()

compass.visibility = View.VISIBLE
btnEnableLiveHeading.visibility = View.VISIBLE
statusText.visibility = View.VISIBLE

// Get the map view.
surfaceView.mapView?.let { mapView ->
// Change the compass icon rotation based on the map rotation at rendering.
mapView.onMapAngleUpdated = {
compass.rotation = -it.toFloat()
}

// Align the map to north if the compass icon is pressed.
compass.setOnClickListener {
GemCall.execute {
mapView.alignNorthUp(Animation(EAnimation.Linear, 300))
}
}
}
}

The red stop button removes the compass sensor data source listener, thus the heading is no longer updated and the map stops rotating when the device is rotated.

MainActivity.kt
private fun stopLiveHeading() = GemCall.execute {
dataSource?.release()
dataSource = null
}