Dokumentation / Erweiterungsebenen / GeoJSON-Ebene

GeoJSON-Ebene

Erweiterungspaket, um GeoJSON direkt über eine Karte zu legen. Da Features in Kacheln gerastert und gezeichnet werden, müssen selbst bei Zehntausenden von Elementen keine Objekte pro Feature erstellt werden. API-Namen, Standardwerte für Stile und das Verhalten von Hit-Tests sind unter Android, iOS und React vereinheitlicht.

ANDROID
com.mapconductor:geojson
IOS
MapConductorGeoJSON
REACT
@mapconductor/react-geojson-layer
Zeichnungsverfahren
Rasterkacheln
Plattform

01 · Übersicht

GeoJSON wird geparst und in ein leichtgewichtiges Feature-Modell konvertiert, dann über die Rasterkachel-Pipeline von MapConductor gezeichnet. Egal welcher Anbieter (Google Maps, MapLibre, MapKit, HERE usw.), der Code und das Aussehen sind identisch.

Perspektive

01

FeatureCollection, einzelne Features, rohe Geometrien sowie Textfolgen nach RFC 8142 werden unterstützt. Es gibt auch einen Streaming-Parser.

Kacheln zeichnen

02

Features werden in 512px-Kacheln gerastert und als Rasterebene in die Karte eingefügt. Nicht abhängig von der Vektorfunktion des Anbieters.

Hit-Test

03

Klick-Erkennung mit denselben Koordinaten wie beim Zeichnen. Unterstützt Polygone mit Löchern, mehrteilige Geometrien und Geometriesammlungen.

Point
MultiPoint
LineString
MultiLineString
Polygon
MultiPolygon
GeometryCollection

Alle Geometrietypen werden auf den drei Plattformen identisch unterstützt.

02 · Grundlegende Verwendung

Platzieren Sie die Ebene einfach im content-Bereich der Kartenansicht. Das Parsen erfolgt im Hintergrund, das Ergebnis wird an features übergeben.

build.gradle.kts
dependencies {
    implementation("com.mapconductor:geojson:<version>")
}
com.mapconductor.geojson · Compose
val mapViewState = rememberMapLibreMapViewState(
    cameraPosition = MapCameraPosition(
        position = GeoPoint.fromLongLat(139.7671, 35.6812),
        zoom = 12.0,
    ),
)

val layerState = remember { GeoJSONLayerState() }
var features by remember { mutableStateOf(emptyList<GeoJSONFeature>()) }

LaunchedEffect(Unit) {
    features = withContext(Dispatchers.IO) {
        assets.open("wards.geojson").use(GeoJSONParser::parseStream)
    }
}

MapLibreMapView(state = mapViewState) {
    GeoJSONLayer(state = layerState, features = features)
}

Wenn sich der Inhalt oder der Stil eines Features ändert, macht die Ebene die interne Kachel-URL ungültig. Das Raster-Cache des Karten-SDK gibt keine veralteten Bilder zurück.

03 · Bestimmung des Stils

Der Stil wird in drei Schichten aufgelöst

Drei Schichten: „Standardwerte für die gesamte Ebene“, „Überschreibungen pro Feature“ und „dynamische Festlegung durch StyleProvider“. Untere Schichten sind stärker; nicht angegebene Elemente werden von höheren Schichten geerbt. Grundlegendes Vorgehen: beginnen Sie nur mit den Ebenen-Standards und fügen Sie bei Bedarf schrittweise untere Schichten hinzu.

Abbildung · Reihenfolge der Auflösung
LAYER 1
Ebenen-Standardwerte
GeoJSONLayerState
Die Grundlage für jedes Feature: strokeColor, fillColor, strokeWidth, pointRadius.
LAYER 2
Überschreibung je Feature
GeoJSONFeature.strokeColor …
Gleichnamige Felder am jeweiligen Feature. Bleiben sie null, gilt der Standardwert der Ebene unverändert.
LAYER 3
Dynamische Auflösung
GeoJSONStyleProvider
Wird einmal pro Feature aufgerufen und liefert den endgültigen Stil — hier liegt die Einfärbung nach Properties.
Ist kein Provider gesetzt, greift DefaultGeoJSONStyleProvider: Wert des Features, wenn vorhanden, sonst Standardwert der Ebene. Die dritte Schicht ist also eigentlich ein Weg, genau dieses Verhältnis zu ersetzen.

3-1. Styleigenschaften

Es werden nur vier Eigenschaften behandelt. Zusätzlich stehen auf Ebenenebene opacity, visible und minZoom / maxZoom für die Anzeigesteuerung zur Verfügung.

Eigenschaft
Typ
Standardwert
Beschreibung
strokeColor
ARGB Int / UIColor / number
#FF1E88E5
Farbe von Linien und Polygonumrissen.
fillColor
ARGB Int / UIColor / number
#801E88E5
Füllfarbe von Polygonen und Farbe der Kreise von Punkten. Standardmäßig halbtransparent.
strokeWidth
Float / CGFloat / number
2.0
Linienbreite (Pixel). Da in Kacheln gerastert, bleibt die Breite beim Zoomen konstant.
pointRadius
Float / CGFloat / number
8.0
Radius des Kreises, mit dem ein Punkt gezeichnet wird (Pixel).
opacity
Float / Double / number
1.0
Opazität der gesamten Rasterebene. Wirkt zusätzlich zum Alpha der einzelnen Farben.
visible
Boolean
true
Wird sowohl beim Zeichnen als auch beim Hit-Test ausgeschlossen. Auf Feature-Seite gibt es ebenfalls ein gleichnamiges Feld.
minZoom / maxZoom
Int / number
0 / 22
Zoom-Bereich, in dem die erzeugte Rasterebene angezeigt wird. Außerhalb des Bereichs wird auch keine Kachelerzeugung ausgeführt.

3-2. Ebenen-Standardwerte festlegen

Beginnen Sie hier zuerst. Der an `GeoJSONLayerState` übergebene Wert ist die Basis für alle Features. Da der Zustand observable ist, wird bei späterer Zuweisung neu gezeichnet.

Kotlin · ARGB Int
val layerState = remember {
    GeoJSONLayerState(
        strokeColor = Color.argb(220, 30, 136, 229),
        fillColor   = Color.argb(60, 30, 136, 229),
        strokeWidth = 1.5f,
        pointRadius = 8f,
        opacity     = 1f,
        minZoom = 8, maxZoom = 22,
    )
}

// Der State ist observable: später zuweisen und die Kacheln werden neu erzeugt
layerState.fillColor = Color.argb(90, 214, 64, 69)

Farbspezifikationsformate

Android und React verwenden 32-Bit-Ganzzahlen im ARGB-Format (Alpha ist das höchstwertige Byte), iOS verwendet `UIColor` mit Alpha in der Farbe selbst. React verfügt über die Hilfsfunktionen `colorArgb(a,r,g,b)` / `colorRgb(r,g,b)` / `argbToCss()` in derselben Reihenfolge wie `Color.argb()` unter Android. Die Standardfarben auf allen drei Plattformen sind einheitlich auf #1E88E5 (Linien deckend, Füllung Alpha 128) festgelegt.

Für jedes Feature überschreiben

Ein Feature kann selbst `strokeColor` / `fillColor` / `strokeWidth` / `pointRadius` / `visible` enthalten. Bleibt es `null`, gilt der Standardwert, ist ein Wert vorhanden, gewinnt dieser. Wenn der Stil beim Laden der Daten feststeht (und sich später nicht ändert), ist dies der unkomplizierteste und schnellste Weg.

Kotlin · GeoJSONFeature.copy
val parsed = GeoJSONParser.parseStream(input)

// Nach dem Parsen die Eigenschaften lesen und den Stil einbrennen
val styled = parsed.map { f ->
    when (f.properties["status"]) {
        "alert"  -> f.copy(fillColor = Color.argb(120, 214, 64, 69), strokeWidth = 3f)
        "closed" -> f.copy(visible = false)
        else     -> f   // Bleibt null, also wird der Ebenen-Standard verwendet
    }
}

GeoJSONLayer(state = layerState, features = styled)

Dynamisch mit StyleProvider festlegen

Stile, die nach „Regeln“ bestimmt werden – z. B. Farben basierend auf Werten aus `properties`, nur das ausgewählte Feature hervorheben, Schwellenwerte über die UI ändern –, werden im `StyleProvider` definiert. Er wird für jedes einzelne Feature aufgerufen, empfängt die Ebenen-Standardwerte und gibt den endgültigen Stil zurück.

Übergebenes

Feature-Objekt (einschließlich properties) und die aktuellen Standardwerte der Ebene. Üblicherweise kopiert man die Standardwerte und ändert nur einen Teil.

Rückgabe

Ein LayerStyle, in dem alle 4 Elemente ausgefüllt sind. Für Elemente, die nicht angefasst werden, können einfach die Standardwerte zurückgegeben werden, damit die Einstellungen der ersten Ebene wirksam bleiben.

Kotlin · GeoJSONStyleProviderInterface
// Es ist ein fun interface, also genügt ein Lambda
val densityStyle = GeoJSONStyleProviderInterface { feature, defaultStyle ->
    val pop = (feature.properties["population"] as? Number)?.toInt() ?: 0
    val fill = when {
        pop > 500_000 -> Color.argb(150, 173, 20, 87)
        pop > 200_000 -> Color.argb(120, 244, 143, 177)
        else          -> Color.argb(80, 248, 187, 208)
    }
    defaultStyle.copy(fillColor = fill)   // Was Sie nicht anfassen, behält seinen Standardwert
}

val layerState = remember {
    GeoJSONLayerState(styleProvider = densityStyle)
}

// Ein späterer Austausch wertet alle Features neu aus
layerState.styleProvider = DefaultGeoJSONStyleProvider

Wenn der `StyleProvider` ausgetauscht wird oder sich der referenzierte Zustand ändert, werden die Stile aller Features neu bewertet und die Tiles neu erstellt. Da er für jedes einzelne Feature aufgerufen wird, sollten Sie rechenintensive Vorgänge (reguläre Ausdrücke, Netzwerk, Datumsparsing usw.) außerhalb des Providers vorab berechnen.

3-5. Was verwenden?

Methode
Geeignete Szenarien
Hinweise
LayerState
Gesamte Daten mit einem einzigen Aussehen zeichnen.
Am leichtesten. Hier zuerst beginnen.
Feature override
Der Stil steht beim Laden fest und ändert sich danach nicht.
Nur das Parsing-Ergebnis mappen. Keine Kosten für Provider-Aufrufe.
StyleProvider
Der Stil wird durch Regeln bestimmt. Die Regeln selbst ändern sich während der Ausführung.
Logik an einem Ort bündeln. In RN ist eine native Registrierung erforderlich.

04 · Tap-Erkennung

Da `MapConductor` nur einen einzelnen Click-Listener hat, erfolgt die Weiterleitung an die Ebene durch die App. Eine automatische Registrierung erfolgt nicht absichtlicherweise. `processClick` gibt nur dann `true` zurück, wenn ein Feature getroffen wurde.

Kotlin
val layerState = remember {
    GeoJSONLayerState(
        onClick = { feature, position -> selected = feature },
    )
}

MapLibreMapView(
    state = mapViewState,
    onMapClick = { point ->
        // Trefferprüfung mit 15 px Toleranz, die dem Zoom folgt
        val consumed = layerState.processClick(point, 15.0, mapViewState.zoom)
        if (!consumed) selected = null
    },
) {
    GeoJSONLayer(state = layerState, features = features)
}

Pixel-Toleranz

Wenn Sie processClick eine Toleranz in Pixeln und den aktuellen Zoom übergeben, erfolgt die Erkennung zoomabhängig. Ohne Angabe ist es die Standardtoleranz in Weltkoordinaten (ca. 0,0002°).

Bei Überlappung

Es wird das zuletzt gezeichnete Feature (also das oberste) zurückgegeben.

Unterstützte Geometrien

Punkte, Linien, Polygone mit Löchern, mehrteilige Geometriesammlungen.

05 · Datenvolumen und Laden

Verwenden Sie für große Daten einen Streaming-Parser und parsen Sie im Hintergrund. Es gibt zwei Möglichkeiten, Features zu speichern.

Statisch, für große Mengen

GeoJSONFeature

Unveränderliche Datenobjekte. Leichtgewichtig, da selbst bei zehntausenden Elementen keine Zustandsobjekte erstellt werden. Für große GeoJSON-Dateien verwenden Sie dies.

Für wenige, häufig wechselnde

GeoJSONFeatureState

Kann einzeln reaktiv aktualisiert werden. Bei vielen Elementen schlagen die Kosten der Zustandsverwaltung zu Buche, also nur so viele wie nötig verwenden.

Kotlin · streaming
// parseStream für eine große FeatureCollection
val features = withContext(Dispatchers.IO) {
    GeoJSONParser.parseStream(input)
}

// GeoJSON Text Sequences nach RFC 8142
val seq = withContext(Dispatchers.IO) { GeoJSONSeqParser.parse(file) }
GeoJSONSeqParser.streamParse(file) { feature -> buffer.add(feature) }
Implementierung im Video · Android + MapLibreKotlin · Jetpack Compose
val layerState = remember { GeoJSONLayerState() }
var features by remember { mutableStateOf(emptyList<GeoJSONFeature>()) }
var loading by remember { mutableStateOf(true) }

// parseStream returns immutable GeoJSONFeature values — no state object per feature
LaunchedEffect(Unit) {
    features = withContext(Dispatchers.IO) {
        context.assets.open("tokyo-buildings.geojson")
            .use(GeoJSONParser::parseStream)
    }
    loading = false
}

MapLibreMapView(state = mapViewState) {
    GeoJSONLayer(state = layerState, features = features)
}

if (loading) {
    LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
}
Beispielvideo · Large GeoJSON als Kacheln laden
Video noch nicht aufgenommenTiles werden beim Scrollen nacheinander geladen und die Zeichnung füllt sich auf. Dass die Bedienung auch bei zunehmender Datenmenge nicht stoppt, lässt sich mit einem statischen Bild nicht vermitteln.

06 · Aktuelle Einschränkungen

Keine automatische Registrierung von Click-Listenern für Layer. Bitte an `processClick` weiterleiten (beabsichtigtes Design).
Die Standardtoleranz für Linien und Punkte bei Hit-Tests ist eine interne Konstante. Sie kann angepasst werden, indem bei jedem Aufruf eine Pixeltoleranz übergeben wird.
Da als Raster-Tiles gezeichnet wird, werden die nativen Vektor-Feature-Abfragen des Map-SDK nicht verwendet.
Der Parser wirft bei ungültiger Eingabe keine Ausnahme, sondern gibt ein leeres Feature-Array zurück (iOS).

Verwandte Seiten