Teiki
Teiki

Reputation: 200

Display GeoJSON on MapBox Android vs iOS

I use mapbox to display a geojson on an iOS and Android app.

The same geojson is display differently on both platform. I think some shapes hide others on iOS.

There is no MGLGeoJSONSource on mapbox ios sdk, it's look like they remove it. So it's longer a lot to achieve the same result.

Maybe someone has a better way to dot it?

Here is my java code:

JSONArray features = json.getJSONArray("features");
for (int i = 0; i < features.length(); i++) {
    JSONObject feature = features.getJSONObject(i);

    GeoJsonSource geoJsonSource = new GeoJsonSource(i, feature.toString());

    JSONObject properties = feature.getJSONObject("properties");
    int rounded_value = (int)Math.round(properties.getDouble("value"););

    list_value_geojson.add(new AbstractMap.SimpleEntry<>(rounded_value, geoJsonSource));
}

for (int i=0; i < list_value_geojson.size(); i++){
    Map.Entry<Integer, GeoJsonSource> entry = list_value_geojson.get(i);

    mapboxMap.addSource(entry.getValue());

    FillLayer fillLayer = new FillLayer(entry.getValue().getId(), entry.getValue().getId());
    fillLayer.setProperties(PropertyFactory.fillColor(Color.parseColor(hashMapColors.get(entry.getKey()))));

    mapboxMap.addLayer(fillLayer);
}

And here is my Swift code:

if let features = jsonDict["features"] as? NSArray {
    var sourceIndex = 0
    for feature in features {
        if let feature = feature as? NSDictionary {
            if let geometry = feature["geometry"] as? NSDictionary {
                let coordinates_array_of_array = geometry["coordinates"] as! NSArray
                for coordinates_array in coordinates_array_of_array{

                    var coordinates_collection : [CLLocationCoordinate2D] = []

                    let locations = coordinates_array as? [[Double]]

                    for location in locations! {
                        // Make a CLLocationCoordinate2D with the lat, lng
                        let coordinate = CLLocationCoordinate2D(latitude: location[1], longitude: location[0])

                        // Add coordinate to coordinates array
                        coordinates_collection.append(coordinate)
                    }

                    if let properties = feature["properties"] as? NSDictionary {
                        let mglpf = MGLPolygonFeature(coordinates: coordinates_collection, count: UInt(coordinates_collection.count))


                        mglpf.title = String(properties["value"] as! Int32)

                        mglpf.attributes = ["color":getColorFromValue(value: mglpf.title!)]

                        let source = MGLShapeSource(identifier: "shapeSource"+String(sourceIndex), features: [mglpf], options: nil)

                        mapbox?.style?.addSource(source)
                        sourceIndex = sourceIndex + 1

                        let layer = MGLFillStyleLayer(identifier: "layer"+String(sourceIndex), source: source)
                        layer.fillColor = MGLStyleValue<UIColor>(rawValue: Util.hexStringToUIColor(hex: getColorFromValue(value: mglpf.title!)))
                        mapbox?.style?.addLayer(layer)
                    }

                }
            }
        }
    }
}

iOS iOS Mapbox

Android Andorid Mapbox

Upvotes: 1

Views: 2313

Answers (2)

Teiki
Teiki

Reputation: 200

Here is how I finally made it: First I parse JSON in order to get every color and the associate value, then I create a FillStyleLayer for every color and set predicate attribute to restrict the color to a specific value.

let url = URL(fileURLWithPath: jsonPath)
do {  
// Load and serialize the GeoJSON into a dictionary filled with properly-typed objects
if let jsonDict = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String : AnyObject] {

    // parse json to Get all colors with their value and put it in the dictionnary
    if let features = jsonDict["features"] as? NSArray {
        for feature in features {
            if let feature = feature as? NSDictionary {
                if let properties = feature["properties"] as? NSDictionary {
                    let color = properties["color"] as! String
                    let value = properties["value"] as! Double

                    if colorByValueArray.index(forKey: value) == nil {
                        colorByValueArray[value] = color
                    }
                }
            }
        }
    }

    //Add GeoJSON to map source
    let mglss = MGLShapeSource(identifier: DrawGeoJSON.TAG_SOURCE_PREFIX + shape_type, url: NSURL(fileURLWithPath: jsonPath) as URL, options: nil)
    mapbox.style?.addSource(mglss)

    //Create color rules with filllayer
    //This will create a fillLayer for each different value/color
    //Some values from geoJSON are not int value. == operator doesn't work with this float value so I had to use < > operators
    for colorDic in colorByValueArray {
        let mglfsl = MGLFillStyleLayer(identifier: DrawGeoJSON.TAG_LAYER_PREFIX + shape_type + String(colorDic.key), source: mglss)
        mglfsl.sourceLayerIdentifier = DrawGeoJSON.TAG_SOURCE_PREFIX + shape_type
        mglfsl.predicate = NSPredicate(format: "value < %d AND value >= %d", Int(colorDic.key)+1, Int(colorDic.key))
        mglfsl.fillColor = MGLStyleValue<UIColor>(rawValue: Util.hexStringToUIColor(hex: colorDic.value))
        mapbox.style?.addLayer(mglfsl)
    }

}
}
catch
{
    print("GeoJSON parsing failed")
}

Upvotes: 1

jmkiley
jmkiley

Reputation: 976

One option is to use a MGLShapeSource to work with GeoJSON data. You can then use that as your source for the MGLFillStyleLayer.

You may also want to look into using the data driven styling that is being introduced in the latest betas of the Android and iOS SDKs. For iOS, you can use a MGLSourceStyleFunction with the fillColor on your MGLFillStyleLayer to style it based on feature attributes.

Upvotes: 2

Related Questions