GeoJSON लेयर
GeoJSON को जैसा-का-तैसा मानचित्र पर ओवरले करने के लिए एक एक्सटेंशन पैकेज है। फीचर को टाइल में रेस्टराइज़ करके रेंडर करने के कारण, दसियों हजारों फीचर के स्तर पर भी 1 फीचर-1 ऑब्जेक्ट बनाने की आवश्यकता नहीं होती है। Android, iOS, और React पर API नाम, स्टाइल डिफ़ॉल्ट मान, और हिट टेस्ट का व्यवहार संरेखित है।
01 · अवलोकन
GeoJSON को पार्स करके हल्के फीचर मॉडल में बदलता है और MapConductor की रेस्टर टाइल पाइपलाइन के माध्यम से रेंडर करता है। प्रदाता (Google Maps, MapLibre, MapKit, HERE आदि) कुछ भी हो, कोड और दिखावट समान रहता है।
पर्सपेक्टिव
FeatureCollection, व्यक्तिगत Feature, और कच्ची ज्यामिति, साथ ही RFC 8142 टेक्स्ट सीक्वेंस का समर्थन करता है। स्ट्रीमिंग पार्सर भी शामिल है।
टाइल रेंडरिंग
फीचर्स को 512px टाइल्स में रैस्टराइज़ करता है और उन्हें एक रैस्टर लेयर के रूप में मैप पर लोड करता है। यह प्रदाता की वेक्टर क्षमताओं पर निर्भर नहीं करता है।
हिट टेस्टिंग
रेंडरिंग में उपयोग किए गए समान निर्देशांकों के साथ क्लिक का पता लगाता है। इसमें छिद्रित बहुभुज, मल्टी-पार्ट, और ज्यामिति संग्रह का समर्थन शामिल है।
सभी ज्यामिति प्रकारों को 3 प्लेटफ़ॉर्म पर समान रूप से समर्थन देता है।
02 · बुनियादी उपयोग
लेयर को बस मैप व्यू के content स्कोप के अंदर रखें। पार्सिंग बैकग्राउंड में की जाती है और परिणाम को features में पास किया जाता है।
dependencies {
implementation("com.mapconductor:geojson:<version>")
}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)
}.package(url: "https://github.com/MapConductor/ios-geojson-layer", from: "<version>") // iOS 15+ / depends on MapConductorCore
@StateObject private var mapViewState = MapKitViewState(
cameraPosition: MapCameraPosition(
position: GeoPoint.fromLongLat(longitude: 139.7671, latitude: 35.6812),
zoom: 12.0
)
)
@StateObject private var layerState = GeoJSONLayerState()
@State private var features: [GeoJSONFeature] = []
var body: some View {
MapKitMapView(state: mapViewState) {
GeoJSONLayer(state: layerState, features: features)
}
.task {
features = GeoJSONParser.parse(fileURL: wardsURL)
}
}npm install @mapconductor/react-geojson \
@mapconductor/js-sdk-core @mapconductor/js-sdk-reactconst state = useMapLibreViewState({
mapDesignType: MapLibreDesign.OsmBrightJa,
cameraPosition: createMapCameraPosition({
position: createGeoPoint({ latitude: 35.6812, longitude: 139.7671 }),
zoom: 12,
}),
});
const layerState = useMemo(() => new GeoJSONLayerState(), []);
const features = useMemo(() => GeoJSONParser.parseFeatures(GEOJSON), []);
return (
<MapLibreMapView2D state={state}>
<GeoJSONLayer state={layerState} features={features} />
</MapLibreMapView2D>
);जब फीचर की सामग्री या स्टाइल बदलती है, तो लेयर आंतरिक रूप से टाइल URL को अमान्य कर देती है। मानचित्र SDK की ओर से रेस्टर कैश पुरानी छवि वापस नहीं करता है।
03 · स्टाइल निर्धारण
स्टाइल 3 स्तरों में हल की जाती है
यह "पूरी लेयर के लिए डिफ़ॉल्ट मान", "प्रति फीचर ओवरराइड", और "StyleProvider द्वारा गतिशील निर्धारण" के 3 स्तर हैं। निचला स्तर जितना अधिक शक्तिशाली होता है, और निर्दिष्ट न किए गए आइटम ऊपर के स्तर से विरासत में मिलते हैं। पहले केवल लेयर डिफ़ॉल्ट मान से शुरू करना और फिर आवश्यकतानुसार निचले स्तरों को जोड़ना मूल दृष्टिकोण है।
3-1. स्टाइल गुण
केवल 4 गुणों का उपयोग किया जाता है। इसके अतिरिक्त, लेयर पक्ष में प्रदर्शन नियंत्रण के लिए opacity, visible, minZoom / maxZoom हैं।
3-2. लेयर डिफ़ॉल्ट तय करना
पहले यहाँ से शुरू करें। GeoJSONLayerState में पास किए गए मान सभी फ़ीचर की नींव बनाते हैं। स्थिति observable है, इसलिए बाद में मान असाइन करने पर फिर से रेंडर होगा।
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,
)
}
// स्टेट अवलोकनीय है: बाद में मान देने पर टाइल दोबारा बनती हैं
layerState.fillColor = Color.argb(90, 214, 64, 69)@StateObject private var layerState = GeoJSONLayerState(
opacity: 1.0,
layerStyle: GeoJSONTileRenderer.LayerStyle(
strokeColor: UIColor(red: 30/255, green: 136/255, blue: 229/255, alpha: 0.86),
fillColor: UIColor(red: 30/255, green: 136/255, blue: 229/255, alpha: 0.24),
strokeWidth: 1.5,
pointRadius: 8.0
)
)
// LayerStyle के फ़ील्ड let हैं, इसलिए पूरा स्ट्रक्ट बदलें (alpha UIColor की ओर है)
layerState.layerStyle = GeoJSONTileRenderer.LayerStyle(
strokeColor: layerState.layerStyle.strokeColor,
fillColor: UIColor.systemRed.withAlphaComponent(0.35),
strokeWidth: layerState.layerStyle.strokeWidth,
pointRadius: layerState.layerStyle.pointRadius
)import { colorArgb, colorRgb, argbToCss } from '@mapconductor/react-geojson';
const layerState = useMemo(() => new GeoJSONLayerState({
strokeColor: colorArgb(220, 30, 136, 229),
fillColor: colorArgb(60, 30, 136, 229),
strokeWidth: 1.5,
pointRadius: 8,
opacity: 1,
minZoom: 8, maxZoom: 22,
}), []);
// अपारदर्शी रंग के लिए colorRgb, CSS में उतारने के लिए argbToCss
const legend = argbToCss(colorRgb(30, 136, 229)); // "rgba(30,136,229,1.0000)"रंग निर्दिष्ट करने का प्रारूप
Android और React ARGB के 32-बिट पूर्णांक (अल्फा सबसे ऊपरी बाइट) का उपयोग करते हैं, iOS UIColor का उपयोग करता है जिसमें अल्फा रंग के साथ ही होता है। React में colorArgb(a,r,g,b) / colorRgb(r,g,b) / argbToCss() हेल्पर हैं, और Android के Color.argb() के समान क्रम है। 3 प्लेटफ़ॉर्म के डिफ़ॉल्ट रंग सभी #1E88E5 (लाइन अपारदर्शी, भराव अल्फा 128) पर सेट हैं।
3-3. प्रति फ़ीचर ओवरराइड करना
फ़ीचर में strokeColor / fillColor / strokeWidth / pointRadius / visible हो सकते हैं। यदि null रहता है तो डिफ़ॉल्ट मान, यदि मान है तो वही मान जीतता है। डेटा लोड होने पर स्टाइल तय हो जाता है (बाद में नहीं बदलता), तो यह तरीका सबसे सीधा और तेज़ तरीका है।
val parsed = GeoJSONParser.parseStream(input)
// पार्स करने के बाद प्रॉपर्टी देखकर स्टाइल पक्की कर दें
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 // null छोड़ा है, इसलिए लेयर का डिफ़ॉल्ट लगता है
}
}
GeoJSONLayer(state = layerState, features = styled)let parsed = GeoJSONParser.parse(data: data)
let styled = parsed.map { f -> GeoJSONFeature in
switch f.properties["status"] as? String {
case "alert":
var copy = f
copy.fillColor = UIColor.systemRed.withAlphaComponent(0.47)
copy.strokeWidth = 3.0
return copy
case "closed":
var copy = f
copy.visible = false
return copy
default:
return f // nil छोड़ने पर लेयर का डिफ़ॉल्ट
}
}const styled = useMemo(() =>
GeoJSONParser.parseFeatures(GEOJSON).map(f => {
const status = f.properties.status;
if (status === 'alert') {
return { ...f, fillColor: colorArgb(120, 214, 64, 69), strokeWidth: 3 };
}
if (status === 'closed') return { ...f, visible: false };
return f; // null छोड़ने पर लेयर का डिफ़ॉल्ट
}), []);
<GeoJSONLayer state={layerState} features={styled} />3-4. StyleProvider से गतिशील रूप से तय करना
properties के मान से रंग अलग करना, केवल चयनित फ़ीचर को जोरदार बनाना, UI से थ्रेशोल्ड बदलना ── इस तरह के "नियम से तय होने वाले स्टाइल" StyleProvider में लिखे जाते हैं। यह हर फ़ीचर के लिए कॉल होता है, लेयर डिफ़ॉल्ट प्राप्त करता है और अंतिम स्टाइल लौटाता है।
पास किया जाने वाला डेटा
फीचर की मुख्य वस्तु (properties सहित) और उस समय की लेयर डिफ़ॉल्ट वैल्यू। डिफ़ॉल्ट वैल्यू की copy करना और केवल कुछ हिस्सों को बदलना एक मानक तरीका है।
वापसी मान
एक LayerStyle जिसमें सभी 4 आइटम भरे हुए हों। जिन आइटम्स को नहीं छुआ गया है, यदि आप डिफ़ॉल्ट वैल्यू वापस कर देते हैं, तो पहली परत की सेटिंग्स प्रभावी होंगी।
// यह fun interface है, इसलिए एक लैम्ब्डा से लिखा जा सकता है
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) // जिन्हें नहीं छूते, वे डिफ़ॉल्ट पर रहते हैं
}
val layerState = remember {
GeoJSONLayerState(styleProvider = densityStyle)
}
// बाद में बदलने पर हर फ़ीचर दोबारा आँका जाता है
layerState.styleProvider = DefaultGeoJSONStyleProviderfinal class DensityStyleProvider: GeoJSONStyleProvider {
func style(
for feature: GeoJSONFeature,
defaultStyle: GeoJSONTileRenderer.LayerStyle
) -> GeoJSONTileRenderer.LayerStyle {
let pop = (feature.properties["population"] as? Int) ?? 0
let fill: UIColor =
pop > 500_000 ? UIColor(red: 173/255, green: 20/255, blue: 87/255, alpha: 0.59)
: pop > 200_000 ? UIColor(red: 244/255, green: 143/255, blue: 177/255, alpha: 0.47)
: UIColor(red: 248/255, green: 187/255, blue: 208/255, alpha: 0.31)
return GeoJSONTileRenderer.LayerStyle(
strokeColor: defaultStyle.strokeColor,
fillColor: fill,
strokeWidth: defaultStyle.strokeWidth,
pointRadius: defaultStyle.pointRadius
)
}
}
layerState.styleProvider = DensityStyleProvider()// वेब पर StyleProvider के बजाय पार्स के नतीजे पर map करके
// हर फ़ीचर को उसकी अपनी स्टाइल दें (नतीजा वही रहता है)
const styleOf = (props: Record<string, unknown>) => {
const pop = Number(props.population ?? 0);
if (pop > 500_000) return colorArgb(150, 173, 20, 87);
if (pop > 200_000) return colorArgb(120, 244, 143, 177);
return colorArgb(80, 248, 187, 208);
};
const features = useMemo(
() => GeoJSONParser.parseFeatures(GEOJSON)
.map(f => ({ ...f, fillColor: styleOf(f.properties) })),
[],
);StyleProvider को बदलने या संदर्भित स्थिति बदलने पर, सभी फ़ीचर के स्टाइल का पुनर्मूल्यांकन होता है और टाइल फिर से बनाई जाती है। चूंकि इसे हर आइटम के लिए कॉल किया जाता है, कृपया भारी प्रक्रियाओं (रेगुलर एक्सप्रेशन, नेटवर्क, दिनांक पार्सिंग आदि) को provider के बाहर पहले से गणना कर लें।
3-5. किसका उपयोग करें
04 · टैप पहचान
MapConductor का क्लिक लिसनर केवल एक ही है, इसलिए लेयर में फॉरवर्डिंग ऐप साइड से की जाती है। जानबूझकर स्वचालित पंजीकरण नहीं किया गया है। processClick, फ़ीचर के मिलने पर ही true लौटाता है।
val layerState = remember {
GeoJSONLayerState(
onClick = { feature, position -> selected = feature },
)
}
MapLibreMapView(
state = mapViewState,
onMapClick = { point ->
// 15 px के बराबर सहनशीलता से जाँच (ज़ूम के साथ बदलती है)
val consumed = layerState.processClick(point, 15.0, mapViewState.zoom)
if (!consumed) selected = null
},
) {
GeoJSONLayer(state = layerState, features = features)
}layerState.onClick = { feature, position in
selected = feature
}
MapKitMapView(
state: mapViewState,
onMapClick: { point in
selected = nil
layerState.processClick(geoPoint: point)
}
) {
GeoJSONLayer(state: layerState, features: features)
}const layerState = useMemo(() => new GeoJSONLayerState({
onClick: (feature, position) => setSelected(feature),
}), []);
// मैप के क्लिक हैंडलर से आगे भेजें
const handleMapClick = (point: GeoPointInterface) => {
const consumed = layerState.processClick(point, 10, state.camera.zoom);
if (!consumed) setSelected(null);
};पिक्सेल सहनशीलता
processClick को सहनशील पिक्सेल और वर्तमान ज़ूम स्तर देने पर, ज़ूम के अनुसार पता लगाना संभव होता है। यदि छोड़ा जाता है, तो यह विश्व निर्देशांकों की डिफ़ॉल्ट सहनशीलता (लगभग 0.0002°) होती है।
ओवरलैप होने पर
अंतिम रूप से रेंडर किया गया (यानी सबसे ऊपर वाला) फीचर वापस आता है।
समर्थित ज्यामिति
बिंदु, रेखा, छिद्रित बहुभुज, मल्टी-पार्ट ज्यामिति संग्रह।
05 · डेटा मात्रा और लोडिंग
बड़े डेटा के लिए स्ट्रीमिंग पार्सर का उपयोग करें और बैकग्राउंड में पार्स करें। फ़ीचर रखने के दो तरीके भी हैं।
स्थैतिक और बड़े मात्रा के लिए
अपरिवर्तनीय डेटा ऑब्जेक्ट। यह हल्का होता है क्योंकि इसमें यहां तक कि हजारों आइटम्स के लिए भी स्टेट ऑब्जेक्ट नहीं बनाया जाता है। बड़े GeoJSON के लिए यही विकल्प है।
थोड़ी संख्या और बार-बार बदलने वाले के लिए
एक-एक करके प्रतिक्रियाशील रूप से अपडेट किया जा सकता है। जब संख्या अधिक होती है, तो स्टेट प्रबंधन की लागत प्रभावी होती है, इसलिए केवल आवश्यक हिस्सों तक सीमित रखें।
// बड़े FeatureCollection के लिए parseStream
val features = withContext(Dispatchers.IO) {
GeoJSONParser.parseStream(input)
}
// RFC 8142 वाले GeoJSON Text Sequences
val seq = withContext(Dispatchers.IO) { GeoJSONSeqParser.parse(file) }
GeoJSONSeqParser.streamParse(file) { feature -> buffer.add(feature) }let features = GeoJSONParser.parse(fileURL: fileURL)
GeoJSONSeqParser.streamParse(fileURL: fileURL) { feature in
// एक-एक करके जोड़ना, बैच में, या स्थायी रूप से
}const features = GeoJSONParser.parseFeatures(text);
const seq = GeoJSONSeqParser.parse(text); // पंक्ति से बँटा अनुक्रम
// tileSize का डिफ़ॉल्ट 512 है; Retina के बराबर बढ़ाया भी जा सकता है
<GeoJSONLayer state={layerState} features={features} tileSize={512} />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())
}