@granite-js/naver-map 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/GraniteNaverMap.podspec +81 -0
  3. package/android/build.gradle +160 -0
  4. package/android/gradle.properties +5 -0
  5. package/android/src/builtinProvider/java/run/granite/navermap/builtinProvider/BuiltInGraniteNaverMapProvider.kt +549 -0
  6. package/android/src/main/AndroidManifest.xml +3 -0
  7. package/android/src/main/java/run/granite/navermap/GraniteNaverMapEvents.kt +91 -0
  8. package/android/src/main/java/run/granite/navermap/GraniteNaverMapPackage.kt +16 -0
  9. package/android/src/main/java/run/granite/navermap/GraniteNaverMapProvider.kt +242 -0
  10. package/android/src/main/java/run/granite/navermap/GraniteNaverMapRegistry.kt +116 -0
  11. package/android/src/main/java/run/granite/navermap/GraniteNaverMapView.kt +732 -0
  12. package/android/src/newarch/java/run/granite/navermap/GraniteNaverMapViewManager.kt +446 -0
  13. package/android/src/oldarch/java/run/granite/navermap/GraniteNaverMapViewManager.kt +249 -0
  14. package/dist/module/NaverMapView.js +110 -0
  15. package/dist/module/NaverMapView.js.map +1 -0
  16. package/dist/module/index.js +6 -0
  17. package/dist/module/index.js.map +1 -0
  18. package/dist/module/internals/colorUtils.js +624 -0
  19. package/dist/module/internals/colorUtils.js.map +1 -0
  20. package/dist/module/internals/context.js +8 -0
  21. package/dist/module/internals/context.js.map +1 -0
  22. package/dist/module/internals/id.js +10 -0
  23. package/dist/module/internals/id.js.map +1 -0
  24. package/dist/module/internals/useMapOverlay.js +44 -0
  25. package/dist/module/internals/useMapOverlay.js.map +1 -0
  26. package/dist/module/internals/usePreservedReference.js +36 -0
  27. package/dist/module/internals/usePreservedReference.js.map +1 -0
  28. package/dist/module/overlays/ArrowheadPath.js +37 -0
  29. package/dist/module/overlays/ArrowheadPath.js.map +1 -0
  30. package/dist/module/overlays/Circle.js +35 -0
  31. package/dist/module/overlays/Circle.js.map +1 -0
  32. package/dist/module/overlays/GroundOverlay.js +30 -0
  33. package/dist/module/overlays/GroundOverlay.js.map +1 -0
  34. package/dist/module/overlays/InfoWindow.js +32 -0
  35. package/dist/module/overlays/InfoWindow.js.map +1 -0
  36. package/dist/module/overlays/Marker.js +37 -0
  37. package/dist/module/overlays/Marker.js.map +1 -0
  38. package/dist/module/overlays/Path.js +41 -0
  39. package/dist/module/overlays/Path.js.map +1 -0
  40. package/dist/module/overlays/Polygon.js +51 -0
  41. package/dist/module/overlays/Polygon.js.map +1 -0
  42. package/dist/module/overlays/Polyline.js +60 -0
  43. package/dist/module/overlays/Polyline.js.map +1 -0
  44. package/dist/module/overlays/index.js +11 -0
  45. package/dist/module/overlays/index.js.map +1 -0
  46. package/dist/module/package.json +1 -0
  47. package/dist/module/specs/GraniteNaverMapViewNativeComponent.ts +352 -0
  48. package/dist/module/types/Coord.js +2 -0
  49. package/dist/module/types/Coord.js.map +1 -0
  50. package/dist/module/types/index.js +29 -0
  51. package/dist/module/types/index.js.map +1 -0
  52. package/dist/typescript/NaverMapView.d.ts +41 -0
  53. package/dist/typescript/index.d.ts +3 -0
  54. package/dist/typescript/internals/colorUtils.d.ts +10 -0
  55. package/dist/typescript/internals/context.d.ts +8 -0
  56. package/dist/typescript/internals/id.d.ts +1 -0
  57. package/dist/typescript/internals/useMapOverlay.d.ts +15 -0
  58. package/dist/typescript/internals/usePreservedReference.d.ts +6 -0
  59. package/dist/typescript/overlays/ArrowheadPath.d.ts +11 -0
  60. package/dist/typescript/overlays/Circle.d.ts +10 -0
  61. package/dist/typescript/overlays/GroundOverlay.d.ts +11 -0
  62. package/dist/typescript/overlays/InfoWindow.d.ts +14 -0
  63. package/dist/typescript/overlays/Marker.d.ts +16 -0
  64. package/dist/typescript/overlays/Path.d.ts +15 -0
  65. package/dist/typescript/overlays/Polygon.d.ts +10 -0
  66. package/dist/typescript/overlays/Polyline.d.ts +11 -0
  67. package/dist/typescript/overlays/index.d.ts +16 -0
  68. package/dist/typescript/specs/GraniteNaverMapViewNativeComponent.d.ts +92 -0
  69. package/dist/typescript/types/Coord.d.ts +4 -0
  70. package/dist/typescript/types/index.d.ts +55 -0
  71. package/ios/GraniteNaverMap-Bridging-Header.h +20 -0
  72. package/ios/GraniteNaverMapProvider.swift +312 -0
  73. package/ios/GraniteNaverMapRegistry.swift +91 -0
  74. package/ios/GraniteNaverMapView.h +15 -0
  75. package/ios/GraniteNaverMapView.mm +390 -0
  76. package/ios/GraniteNaverMapViewImpl.swift +496 -0
  77. package/ios/GraniteNaverMapViewManager.m +67 -0
  78. package/ios/GraniteNaverMapViewManager.swift +133 -0
  79. package/ios/GraniteNaverMapViewWrapper.swift +215 -0
  80. package/ios/builtinProvider/BuiltInNaverMapProvider.swift +489 -0
  81. package/ios/builtinProvider/GraniteNaverMapMarkerData.swift +66 -0
  82. package/ios/builtinProvider/NMFMarker+Extension.swift +65 -0
  83. package/ios/builtinProvider/RCTConvert+NMFMapView.h +17 -0
  84. package/ios/builtinProvider/RCTConvert+NMFMapView.m +67 -0
  85. package/package.json +103 -0
  86. package/src/NaverMapView.tsx +168 -0
  87. package/src/index.tsx +3 -0
  88. package/src/internals/colorUtils.ts +697 -0
  89. package/src/internals/context.ts +14 -0
  90. package/src/internals/id.ts +9 -0
  91. package/src/internals/useMapOverlay.ts +59 -0
  92. package/src/internals/usePreservedReference.ts +41 -0
  93. package/src/overlays/ArrowheadPath.ts +71 -0
  94. package/src/overlays/Circle.ts +68 -0
  95. package/src/overlays/GroundOverlay.ts +62 -0
  96. package/src/overlays/InfoWindow.ts +68 -0
  97. package/src/overlays/Marker.ts +83 -0
  98. package/src/overlays/Path.ts +87 -0
  99. package/src/overlays/Polygon.ts +83 -0
  100. package/src/overlays/Polyline.ts +93 -0
  101. package/src/overlays/index.ts +23 -0
  102. package/src/specs/GraniteNaverMapViewNativeComponent.ts +352 -0
  103. package/src/types/Coord.ts +4 -0
  104. package/src/types/index.ts +78 -0
@@ -0,0 +1,732 @@
1
+ package run.granite.navermap
2
+
3
+ import android.content.Context
4
+ import android.util.Log
5
+ import android.widget.FrameLayout
6
+ import android.widget.TextView
7
+ import com.facebook.react.bridge.LifecycleEventListener
8
+ import com.facebook.react.bridge.ReactContext
9
+ import com.facebook.react.bridge.ReadableMap
10
+ import com.facebook.react.uimanager.UIManagerHelper
11
+
12
+ /**
13
+ * Provider-based NaverMapView implementation (no direct NMapsMap dependency)
14
+ */
15
+ class GraniteNaverMapView(context: Context) : FrameLayout(context), LifecycleEventListener, GraniteNaverMapProviderDelegate {
16
+
17
+ companion object {
18
+ private const val TAG = "GraniteNaverMapView"
19
+ private var instanceCounter = 0
20
+ }
21
+
22
+ private val instanceId = ++instanceCounter
23
+ private val reactContext: ReactContext = context as ReactContext
24
+
25
+ private var provider: GraniteNaverMapProvider? = null
26
+ private var mapContentView: android.view.View? = null
27
+ private var mapInitialized = false
28
+
29
+ private fun getEventDispatcher(): com.facebook.react.uimanager.events.EventDispatcher? {
30
+ return UIManagerHelper.getEventDispatcherForReactTag(reactContext, id)
31
+ }
32
+
33
+ private fun getSurfaceId(): Int = UIManagerHelper.getSurfaceId(this)
34
+
35
+ init {
36
+ Log.d(TAG, "GraniteNaverMapView init")
37
+ setupProvider()
38
+ }
39
+
40
+ private fun setupProvider() {
41
+ // Create a new provider instance for this view
42
+ val mapProvider = GraniteNaverMapRegistry.createProvider(context)
43
+
44
+ if (mapProvider == null) {
45
+ // No provider factory available - show placeholder
46
+ Log.w(TAG, "No NaverMap provider factory registered")
47
+ val label = TextView(context).apply {
48
+ text = "NaverMap provider not registered"
49
+ textAlignment = TEXT_ALIGNMENT_CENTER
50
+ }
51
+ addView(label, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
52
+ return
53
+ }
54
+
55
+ provider = mapProvider
56
+ mapProvider.setDelegate(this)
57
+
58
+ val mapView = mapProvider.createMapView(context)
59
+ mapContentView = mapView
60
+ addView(mapView, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
61
+ Log.d(TAG, "GraniteNaverMapView[$instanceId] - MapView added via provider")
62
+ }
63
+
64
+ // Fabric requires explicit layout of children
65
+ override fun requestLayout() {
66
+ super.requestLayout()
67
+ post(measureAndLayout)
68
+ }
69
+
70
+ private val measureAndLayout = Runnable {
71
+ measure(
72
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
73
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
74
+ )
75
+ layout(left, top, right, bottom)
76
+ }
77
+
78
+ override fun onAttachedToWindow() {
79
+ Log.d(TAG, "onAttachedToWindow")
80
+ super.onAttachedToWindow()
81
+ reactContext.addLifecycleEventListener(this)
82
+ provider?.onAttachedToWindow()
83
+ }
84
+
85
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
86
+ super.onSizeChanged(w, h, oldw, oldh)
87
+ Log.d(TAG, "onSizeChanged: ${w}x${h} (was ${oldw}x${oldh})")
88
+ provider?.onSizeChanged(w, h)
89
+ }
90
+
91
+ override fun onDetachedFromWindow() {
92
+ Log.d(TAG, "onDetachedFromWindow")
93
+ reactContext.removeLifecycleEventListener(this)
94
+ provider?.onDetachedFromWindow()
95
+ super.onDetachedFromWindow()
96
+ }
97
+
98
+ override fun onHostResume() {
99
+ Log.d(TAG, "onHostResume")
100
+ provider?.onHostResume()
101
+ }
102
+
103
+ override fun onHostPause() {
104
+ Log.d(TAG, "onHostPause")
105
+ provider?.onHostPause()
106
+ }
107
+
108
+ override fun onHostDestroy() {
109
+ Log.d(TAG, "onHostDestroy")
110
+ }
111
+
112
+ // MARK: - GraniteNaverMapProviderDelegate
113
+
114
+ override fun onMapInitialized() {
115
+ getEventDispatcher()?.dispatchEvent(GraniteNaverMapInitializedEvent(getSurfaceId(), id))
116
+ }
117
+
118
+ override fun onCameraChange(position: GraniteNaverMapCameraPosition, contentRegion: List<GraniteNaverMapCoordinate>, coveringRegion: List<GraniteNaverMapCoordinate>) {
119
+ getEventDispatcher()?.dispatchEvent(
120
+ GraniteNaverMapCameraChangeEvent(
121
+ getSurfaceId(),
122
+ id,
123
+ position.target.latitude,
124
+ position.target.longitude,
125
+ position.zoom,
126
+ contentRegion,
127
+ coveringRegion
128
+ )
129
+ )
130
+ }
131
+
132
+ override fun onTouch(reason: Int, animated: Boolean) {
133
+ getEventDispatcher()?.dispatchEvent(GraniteNaverMapTouchEvent(getSurfaceId(), id, reason, animated))
134
+ }
135
+
136
+ override fun onClick(x: Double, y: Double, latitude: Double, longitude: Double) {
137
+ getEventDispatcher()?.dispatchEvent(GraniteNaverMapClickEvent(getSurfaceId(), id, x, y, latitude, longitude))
138
+ }
139
+
140
+ override fun onMarkerClick(id: String) {
141
+ getEventDispatcher()?.dispatchEvent(GraniteNaverMapMarkerClickEvent(getSurfaceId(), this.id, id))
142
+ }
143
+
144
+ // MARK: - Camera Methods
145
+
146
+ fun setCenter(latitude: Double, longitude: Double, zoom: Double, tilt: Double, bearing: Double) {
147
+ val position = GraniteNaverMapCameraPosition(
148
+ target = GraniteNaverMapCoordinate(latitude, longitude),
149
+ zoom = zoom,
150
+ tilt = tilt,
151
+ bearing = bearing
152
+ )
153
+ provider?.moveCamera(position, true)
154
+ }
155
+
156
+ fun animateToCoordinate(latitude: Double, longitude: Double) {
157
+ provider?.animateToCoordinate(GraniteNaverMapCoordinate(latitude, longitude))
158
+ }
159
+
160
+ fun animateToTwoCoordinates(lat1: Double, lng1: Double, lat2: Double, lng2: Double) {
161
+ val bounds = GraniteNaverMapBounds(
162
+ southWest = GraniteNaverMapCoordinate(minOf(lat1, lat2), minOf(lng1, lng2)),
163
+ northEast = GraniteNaverMapCoordinate(maxOf(lat1, lat2), maxOf(lng1, lng2))
164
+ )
165
+ provider?.animateToBounds(bounds, 24)
166
+ }
167
+
168
+ fun animateToRegion(latitude: Double, longitude: Double, latitudeDelta: Double, longitudeDelta: Double) {
169
+ val bounds = GraniteNaverMapBounds(
170
+ southWest = GraniteNaverMapCoordinate(latitude - latitudeDelta / 2, longitude - longitudeDelta / 2),
171
+ northEast = GraniteNaverMapCoordinate(latitude + latitudeDelta / 2, longitude + longitudeDelta / 2)
172
+ )
173
+ provider?.animateToBounds(bounds, 0)
174
+ }
175
+
176
+ // MARK: - Map Properties
177
+
178
+ fun setLayerGroupEnabled(group: String, enabled: Boolean) {
179
+ provider?.setLayerGroupEnabled(group, enabled)
180
+ }
181
+
182
+ fun setShowsMyLocationButton(show: Boolean) {
183
+ provider?.setLocationButtonEnabled(show)
184
+ }
185
+
186
+ fun setCompass(show: Boolean) {
187
+ provider?.setCompassEnabled(show)
188
+ }
189
+
190
+ fun setScaleBar(show: Boolean) {
191
+ provider?.setScaleBarEnabled(show)
192
+ }
193
+
194
+ fun setZoomControl(show: Boolean) {
195
+ provider?.setZoomControlEnabled(show)
196
+ }
197
+
198
+ fun setMapType(type: Int) {
199
+ val mapType = GraniteNaverMapType.values().getOrElse(type) { GraniteNaverMapType.BASIC }
200
+ provider?.setMapType(mapType)
201
+ }
202
+
203
+ fun setBuildingHeight(height: Float) {
204
+ provider?.setBuildingHeight(height)
205
+ }
206
+
207
+ fun setNightMode(enabled: Boolean) {
208
+ provider?.setNightModeEnabled(enabled)
209
+ }
210
+
211
+ fun setMinZoomLevel(level: Double) {
212
+ provider?.setMinZoomLevel(level)
213
+ }
214
+
215
+ fun setMaxZoomLevel(level: Double) {
216
+ provider?.setMaxZoomLevel(level)
217
+ }
218
+
219
+ fun setScrollGesturesEnabled(enabled: Boolean) {
220
+ provider?.setScrollGesturesEnabled(enabled)
221
+ }
222
+
223
+ fun setZoomGesturesEnabled(enabled: Boolean) {
224
+ provider?.setZoomGesturesEnabled(enabled)
225
+ }
226
+
227
+ fun setTiltGesturesEnabled(enabled: Boolean) {
228
+ provider?.setTiltGesturesEnabled(enabled)
229
+ }
230
+
231
+ fun setRotateGesturesEnabled(enabled: Boolean) {
232
+ provider?.setRotateGesturesEnabled(enabled)
233
+ }
234
+
235
+ fun setStopGesturesEnabled(enabled: Boolean) {
236
+ provider?.setStopGesturesEnabled(enabled)
237
+ }
238
+
239
+ fun setLocationTrackingMode(mode: Int) {
240
+ val trackingMode = GraniteNaverMapLocationTrackingMode.values().getOrElse(mode) { GraniteNaverMapLocationTrackingMode.NONE }
241
+ provider?.setLocationTrackingMode(trackingMode)
242
+ }
243
+
244
+ fun setMapPadding(top: Int, left: Int, bottom: Int, right: Int) {
245
+ provider?.setMapPadding(top, left, bottom, right)
246
+ }
247
+
248
+ // MARK: - Marker Methods (Old Architecture - ReadableMap)
249
+
250
+ fun addMarker(identifier: String, markerData: ReadableMap) {
251
+ val data = parseMarkerData(identifier, markerData)
252
+ provider?.addMarker(data)
253
+ }
254
+
255
+ fun updateMarker(identifier: String, markerData: ReadableMap) {
256
+ val data = parseMarkerData(identifier, markerData)
257
+ provider?.updateMarker(data)
258
+ }
259
+
260
+ fun removeMarker(identifier: String) {
261
+ provider?.removeMarker(identifier)
262
+ }
263
+
264
+ private fun parseMarkerData(identifier: String, data: ReadableMap): GraniteNaverMapMarkerData {
265
+ val coord = data.getMap("coordinate")
266
+ return GraniteNaverMapMarkerData(
267
+ identifier = identifier,
268
+ coordinate = GraniteNaverMapCoordinate(
269
+ latitude = coord?.getDouble("latitude") ?: 0.0,
270
+ longitude = coord?.getDouble("longitude") ?: 0.0
271
+ ),
272
+ width = if (data.hasKey("width")) data.getInt("width") else 0,
273
+ height = if (data.hasKey("height")) data.getInt("height") else 0,
274
+ zIndex = if (data.hasKey("zIndex")) data.getInt("zIndex") else 0,
275
+ rotation = if (data.hasKey("rotation")) data.getDouble("rotation").toFloat() else 0f,
276
+ flat = if (data.hasKey("flat")) data.getBoolean("flat") else false,
277
+ alpha = if (data.hasKey("alpha")) data.getDouble("alpha").toFloat() else 1f,
278
+ pinColor = if (data.hasKey("pinColor")) data.getInt("pinColor") else 0,
279
+ image = if (data.hasKey("image")) data.getString("image") ?: "" else ""
280
+ )
281
+ }
282
+
283
+ // MARK: - Marker Methods (New Architecture - direct params)
284
+
285
+ fun addMarkerNew(
286
+ identifier: String,
287
+ latitude: Double,
288
+ longitude: Double,
289
+ width: Int,
290
+ height: Int,
291
+ zIndex: Int,
292
+ rotation: Float,
293
+ flat: Boolean,
294
+ alpha: Float,
295
+ pinColor: Int,
296
+ image: String
297
+ ) {
298
+ Log.d(TAG, "[$instanceId] addMarkerNew: id=$identifier")
299
+ val data = GraniteNaverMapMarkerData(
300
+ identifier = identifier,
301
+ coordinate = GraniteNaverMapCoordinate(latitude, longitude),
302
+ width = width,
303
+ height = height,
304
+ zIndex = zIndex,
305
+ rotation = rotation,
306
+ flat = flat,
307
+ alpha = alpha,
308
+ pinColor = pinColor,
309
+ image = image
310
+ )
311
+ provider?.addMarker(data)
312
+ }
313
+
314
+ fun updateMarkerNew(
315
+ identifier: String,
316
+ latitude: Double,
317
+ longitude: Double,
318
+ width: Int,
319
+ height: Int,
320
+ zIndex: Int,
321
+ rotation: Float,
322
+ flat: Boolean,
323
+ alpha: Float,
324
+ pinColor: Int,
325
+ image: String
326
+ ) {
327
+ val data = GraniteNaverMapMarkerData(
328
+ identifier = identifier,
329
+ coordinate = GraniteNaverMapCoordinate(latitude, longitude),
330
+ width = width,
331
+ height = height,
332
+ zIndex = zIndex,
333
+ rotation = rotation,
334
+ flat = flat,
335
+ alpha = alpha,
336
+ pinColor = pinColor,
337
+ image = image
338
+ )
339
+ provider?.updateMarker(data)
340
+ }
341
+
342
+ // MARK: - Polyline Methods
343
+
344
+ fun addPolyline(
345
+ identifier: String,
346
+ coordsJson: String,
347
+ strokeWidth: Float,
348
+ strokeColor: Int,
349
+ zIndex: Int,
350
+ lineCap: Int,
351
+ lineJoin: Int,
352
+ patternJson: String
353
+ ) {
354
+ Log.d(TAG, "addPolyline: id=$identifier")
355
+ val coords = parseCoordinatesJson(coordsJson)
356
+ if (coords.size < 2) return
357
+
358
+ val data = GraniteNaverMapPolylineData(
359
+ identifier = identifier,
360
+ coordinates = coords,
361
+ strokeWidth = strokeWidth,
362
+ strokeColor = strokeColor,
363
+ zIndex = zIndex,
364
+ lineCap = lineCap,
365
+ lineJoin = lineJoin,
366
+ pattern = parsePatternJson(patternJson)
367
+ )
368
+ provider?.addPolyline(data)
369
+ }
370
+
371
+ fun updatePolyline(
372
+ identifier: String,
373
+ coordsJson: String,
374
+ strokeWidth: Float,
375
+ strokeColor: Int,
376
+ zIndex: Int,
377
+ lineCap: Int,
378
+ lineJoin: Int,
379
+ patternJson: String
380
+ ) {
381
+ val coords = parseCoordinatesJson(coordsJson)
382
+ if (coords.size < 2) return
383
+
384
+ val data = GraniteNaverMapPolylineData(
385
+ identifier = identifier,
386
+ coordinates = coords,
387
+ strokeWidth = strokeWidth,
388
+ strokeColor = strokeColor,
389
+ zIndex = zIndex,
390
+ lineCap = lineCap,
391
+ lineJoin = lineJoin,
392
+ pattern = parsePatternJson(patternJson)
393
+ )
394
+ provider?.updatePolyline(data)
395
+ }
396
+
397
+ fun removePolyline(identifier: String) {
398
+ provider?.removePolyline(identifier)
399
+ }
400
+
401
+ // MARK: - Polygon Methods
402
+
403
+ fun addPolygon(
404
+ identifier: String,
405
+ coordsJson: String,
406
+ holesJson: String,
407
+ fillColor: Int,
408
+ strokeColor: Int,
409
+ strokeWidth: Float,
410
+ zIndex: Int
411
+ ) {
412
+ Log.d(TAG, "addPolygon: id=$identifier")
413
+ val coords = parseCoordinatesJson(coordsJson)
414
+ if (coords.size < 3) return
415
+
416
+ val data = GraniteNaverMapPolygonData(
417
+ identifier = identifier,
418
+ coordinates = coords,
419
+ holes = parseHolesJson(holesJson),
420
+ fillColor = fillColor,
421
+ strokeColor = strokeColor,
422
+ strokeWidth = strokeWidth,
423
+ zIndex = zIndex
424
+ )
425
+ provider?.addPolygon(data)
426
+ }
427
+
428
+ fun updatePolygon(
429
+ identifier: String,
430
+ coordsJson: String,
431
+ holesJson: String,
432
+ fillColor: Int,
433
+ strokeColor: Int,
434
+ strokeWidth: Float,
435
+ zIndex: Int
436
+ ) {
437
+ val coords = parseCoordinatesJson(coordsJson)
438
+ if (coords.size < 3) return
439
+
440
+ val data = GraniteNaverMapPolygonData(
441
+ identifier = identifier,
442
+ coordinates = coords,
443
+ holes = parseHolesJson(holesJson),
444
+ fillColor = fillColor,
445
+ strokeColor = strokeColor,
446
+ strokeWidth = strokeWidth,
447
+ zIndex = zIndex
448
+ )
449
+ provider?.updatePolygon(data)
450
+ }
451
+
452
+ fun removePolygon(identifier: String) {
453
+ provider?.removePolygon(identifier)
454
+ }
455
+
456
+ // MARK: - Circle Methods
457
+
458
+ fun addCircle(
459
+ identifier: String,
460
+ latitude: Double,
461
+ longitude: Double,
462
+ radius: Double,
463
+ fillColor: Int,
464
+ strokeColor: Int,
465
+ strokeWidth: Float,
466
+ zIndex: Int
467
+ ) {
468
+ Log.d(TAG, "addCircle: id=$identifier")
469
+ val data = GraniteNaverMapCircleData(
470
+ identifier = identifier,
471
+ center = GraniteNaverMapCoordinate(latitude, longitude),
472
+ radius = radius,
473
+ fillColor = fillColor,
474
+ strokeColor = strokeColor,
475
+ strokeWidth = strokeWidth,
476
+ zIndex = zIndex
477
+ )
478
+ provider?.addCircle(data)
479
+ }
480
+
481
+ fun updateCircle(
482
+ identifier: String,
483
+ latitude: Double,
484
+ longitude: Double,
485
+ radius: Double,
486
+ fillColor: Int,
487
+ strokeColor: Int,
488
+ strokeWidth: Float,
489
+ zIndex: Int
490
+ ) {
491
+ val data = GraniteNaverMapCircleData(
492
+ identifier = identifier,
493
+ center = GraniteNaverMapCoordinate(latitude, longitude),
494
+ radius = radius,
495
+ fillColor = fillColor,
496
+ strokeColor = strokeColor,
497
+ strokeWidth = strokeWidth,
498
+ zIndex = zIndex
499
+ )
500
+ provider?.updateCircle(data)
501
+ }
502
+
503
+ fun removeCircle(identifier: String) {
504
+ provider?.removeCircle(identifier)
505
+ }
506
+
507
+ // MARK: - Path Methods
508
+
509
+ fun addPath(
510
+ identifier: String,
511
+ coordsJson: String,
512
+ width: Float,
513
+ outlineWidth: Float,
514
+ color: Int,
515
+ outlineColor: Int,
516
+ passedColor: Int,
517
+ passedOutlineColor: Int,
518
+ patternImage: String,
519
+ patternInterval: Int,
520
+ progress: Float,
521
+ zIndex: Int
522
+ ) {
523
+ Log.d(TAG, "addPath: id=$identifier")
524
+ val coords = parseCoordinatesJson(coordsJson)
525
+ if (coords.size < 2) return
526
+
527
+ val data = GraniteNaverMapPathData(
528
+ identifier = identifier,
529
+ coordinates = coords,
530
+ width = width,
531
+ outlineWidth = outlineWidth,
532
+ color = color,
533
+ outlineColor = outlineColor,
534
+ passedColor = passedColor,
535
+ passedOutlineColor = passedOutlineColor,
536
+ patternImage = patternImage,
537
+ patternInterval = patternInterval,
538
+ progress = progress,
539
+ zIndex = zIndex
540
+ )
541
+ provider?.addPath(data)
542
+ }
543
+
544
+ fun updatePath(
545
+ identifier: String,
546
+ coordsJson: String,
547
+ width: Float,
548
+ outlineWidth: Float,
549
+ color: Int,
550
+ outlineColor: Int,
551
+ passedColor: Int,
552
+ passedOutlineColor: Int,
553
+ patternImage: String,
554
+ patternInterval: Int,
555
+ progress: Float,
556
+ zIndex: Int
557
+ ) {
558
+ val coords = parseCoordinatesJson(coordsJson)
559
+ if (coords.size < 2) return
560
+
561
+ val data = GraniteNaverMapPathData(
562
+ identifier = identifier,
563
+ coordinates = coords,
564
+ width = width,
565
+ outlineWidth = outlineWidth,
566
+ color = color,
567
+ outlineColor = outlineColor,
568
+ passedColor = passedColor,
569
+ passedOutlineColor = passedOutlineColor,
570
+ patternImage = patternImage,
571
+ patternInterval = patternInterval,
572
+ progress = progress,
573
+ zIndex = zIndex
574
+ )
575
+ provider?.updatePath(data)
576
+ }
577
+
578
+ fun removePath(identifier: String) {
579
+ provider?.removePath(identifier)
580
+ }
581
+
582
+ // MARK: - ArrowheadPath Methods (delegated to Path)
583
+
584
+ fun addArrowheadPath(
585
+ identifier: String,
586
+ coordsJson: String,
587
+ width: Float,
588
+ outlineWidth: Float,
589
+ color: Int,
590
+ outlineColor: Int,
591
+ headSizeRatio: Float,
592
+ zIndex: Int
593
+ ) {
594
+ // ArrowheadPath uses Path API with default passed colors
595
+ addPath(identifier, coordsJson, width, outlineWidth, color, outlineColor, color, outlineColor, "", 0, 0f, zIndex)
596
+ }
597
+
598
+ fun updateArrowheadPath(
599
+ identifier: String,
600
+ coordsJson: String,
601
+ width: Float,
602
+ outlineWidth: Float,
603
+ color: Int,
604
+ outlineColor: Int,
605
+ headSizeRatio: Float,
606
+ zIndex: Int
607
+ ) {
608
+ updatePath(identifier, coordsJson, width, outlineWidth, color, outlineColor, color, outlineColor, "", 0, 0f, zIndex)
609
+ }
610
+
611
+ fun removeArrowheadPath(identifier: String) {
612
+ removePath(identifier)
613
+ }
614
+
615
+ // MARK: - GroundOverlay Methods (TODO: Add to provider protocol)
616
+
617
+ fun addGroundOverlay(
618
+ identifier: String,
619
+ swLat: Double,
620
+ swLng: Double,
621
+ neLat: Double,
622
+ neLng: Double,
623
+ image: String,
624
+ alpha: Float,
625
+ zIndex: Int
626
+ ) {
627
+ // TODO: Add ground overlay support to provider protocol
628
+ }
629
+
630
+ fun updateGroundOverlay(
631
+ identifier: String,
632
+ swLat: Double,
633
+ swLng: Double,
634
+ neLat: Double,
635
+ neLng: Double,
636
+ image: String,
637
+ alpha: Float,
638
+ zIndex: Int
639
+ ) {
640
+ // TODO: Add ground overlay support to provider protocol
641
+ }
642
+
643
+ fun removeGroundOverlay(identifier: String) {
644
+ // TODO: Add ground overlay support to provider protocol
645
+ }
646
+
647
+ // MARK: - InfoWindow Methods (TODO: Add to provider protocol)
648
+
649
+ fun addInfoWindow(
650
+ identifier: String,
651
+ latitude: Double,
652
+ longitude: Double,
653
+ text: String,
654
+ alpha: Float,
655
+ zIndex: Int,
656
+ offsetX: Int,
657
+ offsetY: Int
658
+ ) {
659
+ // TODO: Add info window support to provider protocol
660
+ }
661
+
662
+ fun updateInfoWindow(
663
+ identifier: String,
664
+ latitude: Double,
665
+ longitude: Double,
666
+ text: String,
667
+ alpha: Float,
668
+ zIndex: Int,
669
+ offsetX: Int,
670
+ offsetY: Int
671
+ ) {
672
+ // TODO: Add info window support to provider protocol
673
+ }
674
+
675
+ fun removeInfoWindow(identifier: String) {
676
+ // TODO: Add info window support to provider protocol
677
+ }
678
+
679
+ // MARK: - JSON Parsing Helpers
680
+
681
+ private fun parseCoordinatesJson(json: String): List<GraniteNaverMapCoordinate> {
682
+ val result = mutableListOf<GraniteNaverMapCoordinate>()
683
+ try {
684
+ val array = org.json.JSONArray(json)
685
+ for (i in 0 until array.length()) {
686
+ val obj = array.getJSONObject(i)
687
+ result.add(GraniteNaverMapCoordinate(
688
+ latitude = obj.getDouble("latitude"),
689
+ longitude = obj.getDouble("longitude")
690
+ ))
691
+ }
692
+ } catch (e: Exception) {
693
+ e.printStackTrace()
694
+ }
695
+ return result
696
+ }
697
+
698
+ private fun parseHolesJson(json: String): List<List<GraniteNaverMapCoordinate>> {
699
+ val result = mutableListOf<List<GraniteNaverMapCoordinate>>()
700
+ try {
701
+ val array = org.json.JSONArray(json)
702
+ for (i in 0 until array.length()) {
703
+ val holeArray = array.getJSONArray(i)
704
+ val hole = mutableListOf<GraniteNaverMapCoordinate>()
705
+ for (j in 0 until holeArray.length()) {
706
+ val obj = holeArray.getJSONObject(j)
707
+ hole.add(GraniteNaverMapCoordinate(
708
+ latitude = obj.getDouble("latitude"),
709
+ longitude = obj.getDouble("longitude")
710
+ ))
711
+ }
712
+ result.add(hole)
713
+ }
714
+ } catch (e: Exception) {
715
+ e.printStackTrace()
716
+ }
717
+ return result
718
+ }
719
+
720
+ private fun parsePatternJson(json: String): List<Int> {
721
+ val result = mutableListOf<Int>()
722
+ try {
723
+ val array = org.json.JSONArray(json)
724
+ for (i in 0 until array.length()) {
725
+ result.add(array.getInt(i))
726
+ }
727
+ } catch (e: Exception) {
728
+ e.printStackTrace()
729
+ }
730
+ return result
731
+ }
732
+ }