Skip to content

📍 MapMetrics iOS Map Features Guide

This guide covers how to:

Add HeatMap

🔧 Prerequisites

Xcode installed (version 13 or newer recommended) A new or existing iOS project Add MapMetrics SDK to your project (via SPM or manual integration)

Example via Swift Package Manager:

: https://github.com/MapMetrics/MapMetrics-iOS

Setting Up the Map

In your ViewController.swift:

swift
class ViewController: UIViewController, MLNMapViewDelegate {
    var mapView: MLNMapView!
    var selectedAnnotation: MLNPointAnnotation?
    var isMarkerSelected = false

    override func viewDidLoad() {
        super.viewDidLoad()

        mapView = MLNMapView(
            frame: view.bounds,
            styleURL: URL(string: "<YOUR_STYLE_URL_HERE>")
        )
        mapView.delegate = self
        view.addSubview(mapView)
                mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        mapView.delegate = self
        
        // This is a better starting position 
        let center = CLLocationCoordinate2D(latitude: 20.0, longitude: 0.0) // More centered globally
        mapView.setCenter(center, zoomLevel: 2, animated: false) // Lower zoom to see more area
        view.addSubview(mapView)

    }
}

Displaying Heatmap from GeoJSON

###Step 1: Add heatmap source

swift
let heatmapSource = MLNShapeSource(
    identifier: "earthquakes",
    url: URL(string: "https://cdn.mapmetrics-atlas.net/Images/heatmap.geojson")!,
    options: [.clustered: false]
)
style.addSource(heatmapSource)

###Step 2: Add heatmap layer

swift
let heatmap = MLNHeatmapStyleLayer(identifier: "earthquakes-heat", source: heatmapSource)

heatmap.heatmapWeight = ...
heatmap.heatmapColor = ...
heatmap.heatmapRadius = ...
heatmap.heatmapOpacity = NSExpression(forConstantValue: 0.8)
heatmap.isVisible = false // initially hidden

style.addLayer(heatmap)

Complete Func

swift
    func setupHeatmap() {
        guard let style = mapView.style else {
            print("🔴 Map style not available")
            return
        }
        
        // 1. Remove any existing source/layer to avoid duplicates
        if let existingSource = style.source(withIdentifier: "earthquakes") {
            style.removeSource(existingSource)
        }
        if let existingLayer = style.layer(withIdentifier: "earthquakes-heat") {
            style.removeLayer(existingLayer)
        }
        
        // 2. Create the source with proper options
        let url = URL(string: "https://cdn.mapmetrics-atlas.net/Images/heatmap.geojson")!
        let source: MLNShapeSource
        
        do {
            source = MLNShapeSource(
                identifier: "earthquakes",
                url: url,
                options: [.clustered: false] // Important for heatmap
            )
            
            style.addSource(source)
            print("🟢 Heatmap source added successfully")
            
            // 3. Create the heatmap layer with proper configuration
            let heatmap = MLNHeatmapStyleLayer(identifier: "earthquakes-heat", source: source)
            
            // Weight based on magnitude with exponential scaling
            heatmap.heatmapWeight = NSExpression(
                forMLNInterpolating: NSExpression(forKeyPath: "mag"),
                curveType: .exponential,
                parameters: NSExpression(forConstantValue: 1.5),
                stops: NSExpression(forConstantValue: [
                    0: 0,
                    1: 0.2,
                    3: 0.4,
                    5: 1.0
                ])
            )
            
            // Dynamic intensity based on zoom level
            heatmap.heatmapIntensity = NSExpression(
                forMLNInterpolating: .zoomLevelVariable,
                curveType: .linear,
                parameters: nil,
                stops: NSExpression(forConstantValue: [
                    0: 0.5,
                    5: 1.5,
                    10: 3.0
                ])
            )
            
            // Color gradient from cool to hot
            heatmap.heatmapColor = NSExpression(
                forMLNInterpolating: NSExpression(forVariable: "heatmapDensity"),
                curveType: .linear,
                parameters: nil,
                stops: NSExpression(forConstantValue: [
                    0: UIColor.blue.withAlphaComponent(0),
                    0.2: UIColor.blue,
                    0.4: UIColor.cyan,
                    0.6: UIColor.green,
                    0.8: UIColor.yellow,
                    1.0: UIColor.red
                ])
            )
            
            // Radius that changes with zoom
            heatmap.heatmapRadius = NSExpression(
                forMLNInterpolating: .zoomLevelVariable,
                curveType: .linear,
                parameters: nil,
                stops: NSExpression(forConstantValue: [
                    0: 5,
                    5: 10,
                    10: 20
                ])
            )
            
            heatmap.heatmapOpacity = NSExpression(forConstantValue: 0.8)
            heatmap.isVisible = false // Start hidden
            
            // 4. Add the layer in the correct position (above base but below labels)
            if let waterLayer = style.layer(withIdentifier: "water") {
                style.insertLayer(heatmap, above: waterLayer)
            } else {
                style.addLayer(heatmap)
            }
            
            print("🟢 Heatmap layer added successfully")
            
        }
    }