Skip to Content
ReferenceMap Controller

MapsGL iOS - Map Controller

A map controller acts as an adapter to a third-party mapping library and provides a consistent interface between the functionality of MapsGL and the underlying implementation of a third-party mapping library. All MapsGL-related data, such as data sources, weather layers, custom layers, and animation timeline information, is managed by the map controller.

Supported Mapping Libraries

MapsGL SDK for Apple Platforms currently supports integration with the following third-party mapping libraries:

Library + VersionControllerAdapter Library
Mapbox Maps , v11.x.xMapboxMapControllerMapsGLMapbox
MapLibre Native for iOS , v6.18.0+MapLibreMapControllerMapsGLMapLibre

Read more about setting up and using a map controller with third-party mapping libraries.

Example

The following example creates a Mapbox map instance and initializes a MapsGL MapController with the map. If you are using MapLibre as your map provider, use MapLibreMapController from MapsGLMapLibre instead.

import UIKit import Combine import MapsGLMaps import MapsGLMapbox import MapboxMaps final class ViewController: UIViewController { private var mapView: MapView! private var mapController: MapboxMapController! private var cancellables: Set<AnyCancellable> = [] override func viewDidLoad() { super.viewDidLoad() // Create a Mapbox map let cameraOptions = CameraOptions( center: CLLocationCoordinate2D(latitude: 39.654, longitude: -93.102), zoom: 5) let options = MapInitOptions(cameraOptions: cameraOptions) mapView = MapView(frame: view.bounds, mapInitOptions: options) try! mapView.mapboxMap.setProjection(.init(name: .mercator)) // Set 2D map projection mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(mapView) // Create a MapsGL map controller let xweatherAccount = XweatherAccount(id: "CLIENT_ID", secret: "CLIENT_SECRET") mapController = MapboxMapController(map: mapView, account: xweatherAccount) // Once the map has completed initial load… mapController.onLoad.observe { _ in // Add weather layers... }.store(in: &cancellables) } }

Refer to the MapController API reference for more information about the available properties and methods.

Map Units

A map controller owns the display units shared by everything on the map that renders a measured value — weather text layers that label sampled values, legends, the data inspector, and any custom UI of your own. Reading and changing them in one place keeps map labels and legends from disagreeing.

OptionDescriptionDefault
unitsType: MeasurementUnits (read-only)The display units currently in use. Change them with setUnits(_:) so every consumer stays in sync..imperial
onUnitsChangeType: Signal<MeasurementUnits> (read-only)Fired after units changes, carrying the new units.

MeasurementUnits.metric and MeasurementUnits.imperial provide complete unit sets:

mapController.setUnits(.metric)

Because consumers seed themselves from units when they attach and follow onUnitsChange afterwards, a legend or layer added after a change comes up in the current unit system automatically. Observe the signal to keep your own interface in step:

mapController.onUnitsChange.observe { units in // Update any custom UI that displays measured values. }.store(in: &cancellables)

Measurements

Start from .metric or .imperial and override the individual measurements you want to differ:

var units = MeasurementUnits.metric units.temperature = .fahrenheit mapController.setUnits(units)

The following measurements are configurable, each typed as a Foundation Dimension so any unit of that dimension can be used:

MeasurementTypeMetricImperialDescription
temperatureUnitTemperature.celsius.fahrenheitAmbient and feels-like temperature readings.
temperatureDeltaUnitTemperatureDelta.celsius.fahrenheitTemperature differences, such as temperature change over time. Converted without the temperature scale’s zero offset.
speedUnitSpeed.kilometersPerHour.milesPerHourSpeed-based quantities, including wind and motion.
pressureUnitPressure.millibars.inchesOfMercuryAtmospheric pressure readings.
distanceUnitLength.kilometers.milesDistances between locations.
heightUnitLength.meters.feetVertical lengths, such as wave height.
precipitationUnitLength.millimeters.inchesLiquid-equivalent precipitation totals.
snowfallUnitLength.centimeters.inchesSnow accumulation depths.
directionUnitAngle.degrees.degreesBearing and heading values.
timeUnitDuration.hours.hoursDurations and intervals.
rateUnitSpeed.millimetersPerHour.inchesPerHourRates of distance over time, such as precipitation rates.
intensityUnitRadarReflectivity.dbz.dbzRadar reflectivity intensity values.
concentrationUnitConcentrationMass.microgramsPerCubicMeter.microgramsPerCubicMeterMass concentration values, such as air quality pollutants.
ratioUnitProportion.percent.percentPercentage and proportional values.

Refer to the MeasurementUnits API reference for more information.

Registering Custom Images

If you need to use a custom image with symbol-based styling, such as a custom icon for a GridLayerDescriptor, register it with addImage(id:image:sdf:) before adding the layer:

let image = UIImage(named: "my-grid-icon")! try mapController.addImage(id: "my-grid-icon", image: image)

You can then reference the registered image id from your layer paint configuration:

let layer = GridLayerDescriptor( id: "custom-grid", source: source.id, paint: .init( sample: samplePaint, icon: .init( image: .constant("my-grid-icon"), size: .constant(CGSize(width: 24, height: 24)) ) ) )
© 2026 Xweather (opens in a new tab)Terms of Service (opens in a new tab)Privacy Policy (opens in a new tab)