Yfirlit yfir byggingarlagið
MapConductor situr milli forritsins þíns og korta-SDK-anna. Forritið talar aðeins við sameinað korta-API og MapConductor framsendir verkið til þess þjónustuaðila sem þú valdir. Android (Kotlin + Compose), iOS (Swift + SwiftUI) og React (vefur) deila sömu pakkaskiptingu og sömu innri hlutverkum.
01 · Heildarmyndin
Flæðið er eins á hverjum vettvangi: forrit → sameinað korta-API → Core → rekill þjónustuaðila → korta-SDK. Aðeins efstu tvö lögin eru þinn kóði; neðstu tvö má skipta út.
Viðmót og viðskiptalógík
Sameinað korta-API
Kjarnavirkni (kort, merki, form, atburðir)
Reklar þjónustuaðila
Korta-SDK (innbyggt / JavaScript)
Skipti um þjónustuaðila skipta aðeins út neðstu tveimur lögunum. Skjákóðinn er skrifaður gegn sameinaða API-inu og heldur því áfram að virka ósnertur.
02 · Pakkar eftir vettvangi
Core og reklarnir eru gefnir út sem aðskildir pakkar. Forrit reiðir sig á Core auk rekilsins fyrir þá þjónustuaðila sem það raunverulega notar.
android-sdk-core geymir sameiginlega líkanið og mismunareikninginn; android-sdk-compose útvegar stöðuhaldara fyrir Compose. GeoJSON, þyrping og hitakort eru aðskildar einingar (android-geojson-layer / android-marker-clustering / android-heatmap).
ios-sdk-core geymir sameiginlega líkanið og grunninn undir SwiftUI-sýnunum; sýnirnar sjálfar koma úr pökkum þjónustuaðilanna (ios-for-*). MapKit-rekillinn miðar á SDK Apple sjálfs, svo hann þarf hvorki aukagjald né API-lykil.
js-sdk-core er React-lausi TypeScript-kjarninn sem geymir sameiginlega líkanið og mismunareikninginn — nánast eins uppbyggður og Kotlin- og Swift-kjarnarnir. js-sdk-react setur hann á React og útvegar einingarnar: Marker, Polygon, Polyline, Circle, GroundImage, RasterLayer, InfoBubble. Kortasýnin sjálf kemur frá hverjum rekli (react-for-*) sem par af sýn og hook, t.d. MapLibreMapView / MapLibreMapView2D og useMapLibreViewState. GeoJSON, þyrping, hitakort og tákn eru aðskildir pakkar (react-geojson-layer / react-marker-clustering / react-heatmap / react-icons).
03 · Lög
Ábyrgð er skipt í sex lög svo hana megi endurnýta milli vettvanga. Hvert lag veit ekkert um útfærsluna fyrir neðan sig.
Skiptingin gerir kóða sem einbeitir sér að því hvað þú vilt á kortinu — ekki hvaða vettvangi þú ert á — kleift að færast milli umhverfa óbreyttur. Það sem er sértækt fyrir vettvang helst bundið við það hvernig þverpallalagið setur upp og lýsir hlutum.
React Native
React á vefnum og React Native deila því sem forritið skrifar — sömu stöðuhlutir, sömu einingar, aðeins MapView-inu skipt út. Þau greinir að fyrir neðan það. Á vefnum kallar rekillinn á JavaScript-kortasafn í sama keyrsluumhverfi; á React Native afhendir hann yfir brú til innbyggða MapConductor-SDK-sins, og innbyggt korta-SDK sér um teiknunina.
React
React Native
Brúin er lag 3 í töflunni að ofan. Á vefnum birtist hún alls ekki: viðmótið og teiknunin eru í einu keyrsluumhverfi. Á React Native eru þau í tveimur, svo eitthvað verður að bera á milli. Það lag er hið eina sem er ólíkt; allt fyrir ofan það er eins.
Fjórir þjónustuaðilar eru í boði á React Native — Google Maps, MapLibre, ArcGIS og HERE. Þeir eru færri en þrettán á vefnum af því hver þeirra þarf samsvarandi einingu innbyggða megin.
04 · Inni í Core
Core endurtekur sömu sjö hlutverkin fyrir hverja gerð einingar — merki, fjöllínu, marghyrning, hring, jarðmynd, rasterlag. Lærðu eitt og þú lest hin á sama hátt.
Það sem skiptir máli er hvar mörkin liggja. Core-hliðin (State / Entity / Manager / Controller / Overlay) er nánast sami kóði á öllum þremur málunum; fyrir hvern þjónustuaðila skrifar þú aðeins teiknarann og yfirlýsinguna um að einingin sé yfirleitt studd.
PolygonCapableInterface.kt
AbstractPolygonOverlayRenderer.kt
polygon/PolygonOverlayRenderer.swift
polygon/PolygonHoleSplit.swift
polygon/PolygonCapable.ts
AbstractPolygonOverlayRenderer.ts
05 · Hvernig mismunareikningurinn virkar
Forritið þitt réttir aðeins fylkið af því sem á að vera til núna. Core reiknar mismuninn frá síðasta skipti og sendir reklinum það sem bættist við, breyttist og hvarf. Kortahlutir eru aldrei endurbyggðir, svo teiknunin helst stöðug í miklu magni.
export interface OverlayRendererInterface<ActualType, StateType, EntityType> {
onAdd(data: StateType[]): Promise<Array<ActualType | null>> | Array<ActualType | null>;
onChange(data: Array<ChangeParamsInterface<EntityType>>): Promise<Array<ActualType | null>> | Array<ActualType | null>;
onRemove(data: EntityType[]): Promise<void> | void;
onPostProcess(): Promise<void> | void;
}onChange tekur við bæði fyrri entity (prev) og núverandi stöðu (current), svo rekill getur uppfært aðeins þær eigindir sem hreyfðust. Undirskriftin er sú sama í Kotlin og Swift.
06 · Hvað rekill útfærir
Að styðja nýtt korta-SDK takmarkast við að erfa óhlutbundna teiknarann fyrir hverja einingu og fylla út þrjár aðgerðir. Líkan Core og mismunarökvísin eru ósnert.
// Rekillinn erfir frá óhlutbundna teiknaranum og fyllir aðeins út þrjár aðgerðir
internal class GoogleMapPolygonOverlayRenderer(
override val holder: GoogleMapViewHolder,
override val coroutine: CoroutineScope,
) : AbstractPolygonOverlayRenderer<GoogleMapActualPolygon>() {
override suspend fun createPolygon(state: PolygonState) = /* map.addPolygon(...) */
override suspend fun updatePolygonProperties(polygon, current, prev) = /* Beita aðeins mismuninum */
override suspend fun removePolygon(entity: PolygonEntityInterface<GoogleMapActualPolygon>) =
entity.polygon.remove()
}Aðeins að búa til, uppfæra og fjarlægja er bundið þjónustuaðilanum. Mismunareikningur, skráin og smellprófun eru þegar frágengin af Core áður en kallað er.
// Sama form og í Kotlin: erfa frá óhlutbundna teiknaranum og fylla út þrjár aðgerðir
final class MapKitPolygonOverlayRenderer: AbstractPolygonOverlayRenderer<MKPolygon> {
override func createPolygon(state: PolygonState) async -> MKPolygon? { /* MKPolygon(...) */ }
override func updatePolygonProperties(polygon, current, prev) async -> MKPolygon? { /* Beita aðeins mismuninum */ }
override func removePolygon(entity: PolygonEntity<MKPolygon>) async { /* mapView.removeOverlay */ }
}
// Stýringin notar almennu útfærsluna úr Core óbreytta
final class MapKitPolygonController: PolygonController<MKPolygon, MapKitPolygonOverlayRenderer> { }Í Swift er mengi þeirra stýringa sem þjónustuaðili smíðar eiginleikalisti hans. Það sem SDK-ið ræður ekki við — göt í marghyrningum, hreyfingar merkja — er tjáð annaðhvort með því að útfæra ekki þann teiknara, eða með því að falla aftur á staðgengil úr kjarnanum á borð við PolygonHoleSplit, sem klýfur marghyrning með götum í einfalda gatlausa hringi.
// Sama form og í Kotlin og Swift: erfa frá óhlutbundna teiknaranum og fylla út þrjár aðgerðir
export class MapLibrePolygonOverlayRenderer extends AbstractPolygonOverlayRenderer<
MapLibreMapViewHolder,
MapLibreActualPolygon
> {
async createPolygon(state: PolygonState) { /* Búa til GeoJSON-feature-ið */ }
async updatePolygonProperties({ current, prev }) { /* Beita aðeins mismuninum */ }
async removePolygon(entity: PolygonEntity<MapLibreActualPolygon>) { /* Fjarlægja það */ }
// Eftir að mismuninum er beitt, skrifa upprunann aftur út frá þeim entity-um sem eftir standa
override async onPostProcess() { this.layer.draw(this.polygonManager.allEntities()); }
}
// Lýstu því sem rekill ræður við með því að útfæra Capable-viðmótin
export class MapLibreViewController extends BaseMapViewController
implements MapViewControllerInterface, MarkerCapable, PolygonCapable, /* … */ { }Í TypeScript er það líka aðeins að búa til, uppfæra og fjarlægja sem er bundið þjónustuaðilanum. Munur á því hvernig SDK teiknar — MapLibre safnar í lag og endurskrifar því alla uppsprettuna í onPostProcess í stað þess að fjarlægja eitt í einu — helst inni í teiknaranum. Hvað rekill ræður við er tjáð með Capable-viðmótunum sem MapViewController hans útfærir — PolygonCapable og systkini hans — svo framboðið sést í gerðunum.
07 · Þar sem abstraktionin endar
MapConductor reynir ekki að vefja hvern einasta eiginleika hvers korta-SDK. Það einbeitir sér að þeim aðgerðum sem eru almennt notaðar og býður tvær leiðir út fyrir allt umfram þær.
// map í sameiginlega viðmótinu er unknown — þrengdu það að gerð þjónustuaðilans áður en það er notað
const holder = mapViewState.getMapViewHolder();
const map = holder?.map as maplibregl.Map | undefined;
map?.addLayer({ id: 'buildings', type: 'fill-extrusion', source: 'composite' });Sameiginlega API-ið helst einfalt án þess að fórna því sem hver þjónustuaðili er góður í — sjá Innbyggðar viðbætur fyrir nánari umfjöllun.