Controls
Data Inspector

Data Inspector Control

A data inspector control allows you to view the underlying data for each visible map layer that supports feature queries. It is configured to appear when the user clicks or taps on the map. When the control is visible, it will display a tooltip containing the data values for each layer at the current map coordinate.

Data inspector control with multiple layers

You can add a data inspector control to your map using the addDataInspectorControl() method on the MapController instance. This method requires the host view to which the control will be inserted into and constrained to, typically the main map view instance. The method returns the created DataInspectorControl instance.

// Adds a data inspector control to the map, returning the control instance
let control = controller.addDataInspectorControl(constrainedTo: mapView)
 
// Removes the data inspector control
controller.removeDataInspectorControl()

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

Data Presentation

Data inspector controls use data presentations to format and display the data values for each layer. A data presentation consists of a title and a formatting function that takes the raw data value and returns a formatted string for display in the control. You can create custom data presentations to change how the data is shown to the user.

The MapsGL SDK already includes several built-in data presentation configurations associated with the available weather layers (opens in a new tab). However, you may want to override these in order to format the data values differently or provide additional content in the output. There are two ways to set custom data presentations for layers: including it when adding a weather layer to the map, or afterwards by setting it directly on the data inspector control.

Customizing via Weather Layer Overrides

When you add a weather layer to the map, you can optionally override the default configuration to customize the layer. For example, providing a custom data presentations for the .temperatures weather layer would be similar to:

var tempsConfig = WeatherService.Temperatures(service: mapController.service)
 
// Create custom data presentation for the layer
tempsConfig.presentation = .init(title: "Temperature (°F)", format: { features in
    guard features.isEmpty == false else { return nil }
    
    // Encoded raster data values are always returned as the first feature
    guard let value = features[0].properties["value"] as? Float else { return nil }
    
    // MapsGL data values are always in Metric units, with temperature in Celsius
    let tempC = Measurement(value: Double(value), unit: UnitTemperature.celsius)
    
    // Return formatted output
    return String(format: "%.1f", tempC.converted(to: .fahrenheit).value)
})
 
// Add the weather layer with the custom configuration
try mapController.addWeatherLayer(config: tempsConfig)

Note that for the temperatures layer, the resulting value is a simple float value stored on the value key of the feature's properties. However, some layers consist of multiple values, like those related to winds and other vector data. For these layers, the feature's properties will contain values for both value and angle keys:

var windsConfig = WeatherService.WindSpeeds(service: mapController.service)
 
// Create custom data presentation for the layer
windsConfig.presentation = .init(title: "Winds (mph)", format: { features in
    guard features.isEmpty == false else { return nil }
    
    // encoded raster data values are always returned as the first feature
    guard let value = features[0].properties["value"] as? Float, 
            let angle = features[0].properties["angle"] as? Float else { return nil }
    
    // Stored angle is the direction wind is moving **to**, but with weather wind direction is the opposite **from** direction.
    // So reverse the angle for the wind direction in degrees.
    let fromAngle = angle - 180
    
    // MapsGL data values are always in Metric units, with wind speed in meters per second
    let windsMS = Measurement(value: Double(value), unit: UnitSpeed.metersPerSecond)
    
    // Return formatted output
    return String(format: "%.1f, %.0f degrees", windsMS.converted(to: .milesPerHour).value, fromAngle)
})
 
// Add the weather layer with the custom configuration
try mapController.addWeatherLayer(config: windsConfig)

Customizing via the Data Inspector Control

Alternatively, you can change a layer's data presentation after it has already been added to the map by setting it directly on the map's data inspector control. Just use the setPresentation(for:presentation:) method on the control and provide the unique identifier for the layer you want to update and the data presentation configuration to want to use:

// Create a custom data presentation for the temperatures layer
let tempsPresentation = DataInspectorPresentation(title: "Temperature (°F)", format: { features in
    guard features.isEmpty == false else { return nil }
    
    // Encoded raster data values are always returned as the first feature
    guard let value = features[0].properties["value"] as? Float else { return nil }
    
    // MapsGL data values are always in Metric units
    let tempC = Measurement(value: Double(value), unit: UnitTemperature.celsius)
    
    // Return formatted output
    return String(format: "%.1f", tempC.converted(to: .fahrenheit).value)
})
 
// Set the custom presentation on the data inspector control for the temperatures layer. We need to get the layer's 
// identifier first based on the weather layer code.
if let tempsLayer = mapController.weatherLayer(for: .temperatures) {
    control.setPresentation(for: tempsLayer.id, presentation: tempsPresentation)
}