@exterio/react-native-yamap-lite 1.0.1

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 (141) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +510 -0
  3. package/YamapLite.podspec +21 -0
  4. package/android/build.gradle +101 -0
  5. package/android/gradle.properties +14 -0
  6. package/android/settings.gradle +1 -0
  7. package/android/src/main/AndroidManifest.xml +2 -0
  8. package/android/src/main/java/com/yamaplite/ClusteredYamapLiteViewManager.kt +181 -0
  9. package/android/src/main/java/com/yamaplite/Components/ClusteredYamapLiteView.kt +169 -0
  10. package/android/src/main/java/com/yamaplite/Components/YamapLiteCircleView.kt +145 -0
  11. package/android/src/main/java/com/yamaplite/Components/YamapLiteMarkerView.kt +214 -0
  12. package/android/src/main/java/com/yamaplite/Components/YamapLitePolygon.kt +149 -0
  13. package/android/src/main/java/com/yamaplite/Components/YamapLitePolyline.kt +171 -0
  14. package/android/src/main/java/com/yamaplite/Components/YamapLiteView.kt +678 -0
  15. package/android/src/main/java/com/yamaplite/Events/CameraPositionChangeEvent.kt +38 -0
  16. package/android/src/main/java/com/yamaplite/Events/MapLoadEvent.kt +34 -0
  17. package/android/src/main/java/com/yamaplite/Events/PressEvent.kt +24 -0
  18. package/android/src/main/java/com/yamaplite/Utils/ImageCache.kt +45 -0
  19. package/android/src/main/java/com/yamaplite/Utils/PointParser.kt +39 -0
  20. package/android/src/main/java/com/yamaplite/Utils/ResolveImageHelper.kt +122 -0
  21. package/android/src/main/java/com/yamaplite/Utils/YamapUtils.kt +169 -0
  22. package/android/src/main/java/com/yamaplite/YamapLiteCircleViewManager.kt +67 -0
  23. package/android/src/main/java/com/yamaplite/YamapLiteMarkerViewManager.kt +82 -0
  24. package/android/src/main/java/com/yamaplite/YamapLitePackage.kt +41 -0
  25. package/android/src/main/java/com/yamaplite/YamapLitePolygonViewManager.kt +61 -0
  26. package/android/src/main/java/com/yamaplite/YamapLitePolylineViewManager.kt +75 -0
  27. package/android/src/main/java/com/yamaplite/YamapLiteViewManager.kt +176 -0
  28. package/ios/ClusteredYamapLiteView.h +15 -0
  29. package/ios/ClusteredYamapLiteView.mm +325 -0
  30. package/ios/ClusteredYamapLiteViewManager.mm +17 -0
  31. package/ios/Components/Circle.swift +108 -0
  32. package/ios/Components/ClusteredYamap.swift +190 -0
  33. package/ios/Components/Marker.swift +187 -0
  34. package/ios/Components/Polygon.swift +108 -0
  35. package/ios/Components/Polyline.swift +125 -0
  36. package/ios/Components/Yamap.swift +585 -0
  37. package/ios/Listeners/CameraListener.swift +54 -0
  38. package/ios/Listeners/ClusterListener.swift +38 -0
  39. package/ios/Listeners/MapInputListener.swift +35 -0
  40. package/ios/Listeners/MapLoadListener.swift +35 -0
  41. package/ios/Listeners/MapObjectTap.swift +12 -0
  42. package/ios/Listeners/UserLocationObjectListener.swift +29 -0
  43. package/ios/Models/YamapModels.swift +77 -0
  44. package/ios/Utils/ImageCache.swift +20 -0
  45. package/ios/Utils/PointsEqual.h +45 -0
  46. package/ios/Utils/ResolveImageHelper.swift +142 -0
  47. package/ios/YamapLiteCircleView.h +15 -0
  48. package/ios/YamapLiteCircleView.mm +102 -0
  49. package/ios/YamapLiteMarkerView.h +15 -0
  50. package/ios/YamapLiteMarkerView.mm +102 -0
  51. package/ios/YamapLitePolygonView.h +15 -0
  52. package/ios/YamapLitePolygonView.mm +120 -0
  53. package/ios/YamapLitePolylineView.h +15 -0
  54. package/ios/YamapLitePolylineView.mm +115 -0
  55. package/ios/YamapLiteView.h +15 -0
  56. package/ios/YamapLiteView.mm +361 -0
  57. package/ios/YamapLiteViewManager.mm +17 -0
  58. package/ios/YamapUtils.h +5 -0
  59. package/ios/YamapUtils.mm +205 -0
  60. package/lib/module/@types/index.js +8 -0
  61. package/lib/module/@types/index.js.map +1 -0
  62. package/lib/module/ClusteredYamapLiteViewNativeComponent.ts +98 -0
  63. package/lib/module/Components/Circle.js +20 -0
  64. package/lib/module/Components/Circle.js.map +1 -0
  65. package/lib/module/Components/ClusteredYamap.js +133 -0
  66. package/lib/module/Components/ClusteredYamap.js.map +1 -0
  67. package/lib/module/Components/Marker.js +40 -0
  68. package/lib/module/Components/Marker.js.map +1 -0
  69. package/lib/module/Components/Polygon.js +25 -0
  70. package/lib/module/Components/Polygon.js.map +1 -0
  71. package/lib/module/Components/Polyline.js +25 -0
  72. package/lib/module/Components/Polyline.js.map +1 -0
  73. package/lib/module/Components/Yamap.js +124 -0
  74. package/lib/module/Components/Yamap.js.map +1 -0
  75. package/lib/module/Components/index.js +9 -0
  76. package/lib/module/Components/index.js.map +1 -0
  77. package/lib/module/NativeYamapUtils.js +5 -0
  78. package/lib/module/NativeYamapUtils.js.map +1 -0
  79. package/lib/module/Utils/YamapUtils.js +14 -0
  80. package/lib/module/Utils/YamapUtils.js.map +1 -0
  81. package/lib/module/YamapCircleViewNativeComponent.ts +28 -0
  82. package/lib/module/YamapLiteViewNativeComponent.ts +93 -0
  83. package/lib/module/YamapMarkerViewNativeComponent.ts +32 -0
  84. package/lib/module/YamapPolygonViewNativeComponent.ts +28 -0
  85. package/lib/module/YamapPolylineViewNativeComponent.ts +31 -0
  86. package/lib/module/index.js +7 -0
  87. package/lib/module/index.js.map +1 -0
  88. package/lib/module/package.json +1 -0
  89. package/lib/typescript/package.json +1 -0
  90. package/lib/typescript/src/@types/index.d.ts +257 -0
  91. package/lib/typescript/src/@types/index.d.ts.map +1 -0
  92. package/lib/typescript/src/ClusteredYamapLiteViewNativeComponent.d.ts +82 -0
  93. package/lib/typescript/src/ClusteredYamapLiteViewNativeComponent.d.ts.map +1 -0
  94. package/lib/typescript/src/Components/Circle.d.ts +4 -0
  95. package/lib/typescript/src/Components/Circle.d.ts.map +1 -0
  96. package/lib/typescript/src/Components/ClusteredYamap.d.ts +3 -0
  97. package/lib/typescript/src/Components/ClusteredYamap.d.ts.map +1 -0
  98. package/lib/typescript/src/Components/Marker.d.ts +3 -0
  99. package/lib/typescript/src/Components/Marker.d.ts.map +1 -0
  100. package/lib/typescript/src/Components/Polygon.d.ts +4 -0
  101. package/lib/typescript/src/Components/Polygon.d.ts.map +1 -0
  102. package/lib/typescript/src/Components/Polyline.d.ts +4 -0
  103. package/lib/typescript/src/Components/Polyline.d.ts.map +1 -0
  104. package/lib/typescript/src/Components/Yamap.d.ts +3 -0
  105. package/lib/typescript/src/Components/Yamap.d.ts.map +1 -0
  106. package/lib/typescript/src/Components/index.d.ts +7 -0
  107. package/lib/typescript/src/Components/index.d.ts.map +1 -0
  108. package/lib/typescript/src/NativeYamapUtils.d.ts +30 -0
  109. package/lib/typescript/src/NativeYamapUtils.d.ts.map +1 -0
  110. package/lib/typescript/src/Utils/YamapUtils.d.ts +27 -0
  111. package/lib/typescript/src/Utils/YamapUtils.d.ts.map +1 -0
  112. package/lib/typescript/src/YamapCircleViewNativeComponent.d.ts +20 -0
  113. package/lib/typescript/src/YamapCircleViewNativeComponent.d.ts.map +1 -0
  114. package/lib/typescript/src/YamapLiteViewNativeComponent.d.ts +80 -0
  115. package/lib/typescript/src/YamapLiteViewNativeComponent.d.ts.map +1 -0
  116. package/lib/typescript/src/YamapMarkerViewNativeComponent.d.ts +25 -0
  117. package/lib/typescript/src/YamapMarkerViewNativeComponent.d.ts.map +1 -0
  118. package/lib/typescript/src/YamapPolygonViewNativeComponent.d.ts +20 -0
  119. package/lib/typescript/src/YamapPolygonViewNativeComponent.d.ts.map +1 -0
  120. package/lib/typescript/src/YamapPolylineViewNativeComponent.d.ts +23 -0
  121. package/lib/typescript/src/YamapPolylineViewNativeComponent.d.ts.map +1 -0
  122. package/lib/typescript/src/index.d.ts +5 -0
  123. package/lib/typescript/src/index.d.ts.map +1 -0
  124. package/package.json +189 -0
  125. package/src/@types/index.ts +314 -0
  126. package/src/ClusteredYamapLiteViewNativeComponent.ts +98 -0
  127. package/src/Components/Circle.tsx +22 -0
  128. package/src/Components/ClusteredYamap.tsx +194 -0
  129. package/src/Components/Marker.tsx +50 -0
  130. package/src/Components/Polygon.tsx +27 -0
  131. package/src/Components/Polyline.tsx +27 -0
  132. package/src/Components/Yamap.tsx +176 -0
  133. package/src/Components/index.ts +6 -0
  134. package/src/NativeYamapUtils.ts +47 -0
  135. package/src/Utils/YamapUtils.ts +63 -0
  136. package/src/YamapCircleViewNativeComponent.ts +28 -0
  137. package/src/YamapLiteViewNativeComponent.ts +93 -0
  138. package/src/YamapMarkerViewNativeComponent.ts +32 -0
  139. package/src/YamapPolygonViewNativeComponent.ts +28 -0
  140. package/src/YamapPolylineViewNativeComponent.ts +31 -0
  141. package/src/index.tsx +5 -0
@@ -0,0 +1,181 @@
1
+ package com.yamaplite
2
+
3
+ import com.facebook.react.bridge.ReadableArray
4
+ import com.facebook.react.bridge.ReadableMap
5
+ import com.facebook.react.module.annotations.ReactModule
6
+ import com.facebook.react.uimanager.ThemedReactContext
7
+ import com.facebook.react.uimanager.ViewGroupManager
8
+ import com.facebook.react.uimanager.annotations.ReactProp
9
+ import com.facebook.react.uimanager.ViewManagerDelegate
10
+ import com.facebook.react.viewmanagers.ClusteredYamapLiteViewManagerInterface
11
+ import com.facebook.react.viewmanagers.ClusteredYamapLiteViewManagerDelegate
12
+ import android.view.View
13
+ import android.graphics.Color
14
+ import com.yamaplite.components.ClusteredYamapLiteView
15
+ import com.yamaplite.utils.PointParser
16
+
17
+ class ClusteredYamapLiteViewManager : ViewGroupManager<ClusteredYamapLiteView>(), ClusteredYamapLiteViewManagerInterface<ClusteredYamapLiteView> {
18
+ private val mDelegate: ViewManagerDelegate<ClusteredYamapLiteView>
19
+
20
+ init {
21
+ mDelegate = ClusteredYamapLiteViewManagerDelegate(this)
22
+ }
23
+
24
+ override fun getDelegate(): ViewManagerDelegate<ClusteredYamapLiteView> = mDelegate
25
+
26
+ override fun createViewInstance(context: ThemedReactContext): ClusteredYamapLiteView {
27
+ return ClusteredYamapLiteView(context)
28
+ }
29
+
30
+ override fun onDropViewInstance(view: ClusteredYamapLiteView) {
31
+ view.onDropViewInstance()
32
+ super.onDropViewInstance(view)
33
+ }
34
+
35
+ override fun addView(parent: ClusteredYamapLiteView, child: View, index: Int) {
36
+ parent.addChild(child, index)
37
+ super.addView(parent, child, index)
38
+ }
39
+
40
+ override fun getChildAt(parent: ClusteredYamapLiteView, index: Int): View {
41
+ return parent.getReactChildAt(index) ?: throw IndexOutOfBoundsException("Index $index is out of bounds for child count ${parent.getReactChildCount()}")
42
+ }
43
+
44
+ override fun getChildCount(parent: ClusteredYamapLiteView): Int {
45
+ return parent.getReactChildCount()
46
+ }
47
+
48
+ override fun removeViewAt(parent: ClusteredYamapLiteView, index: Int) {
49
+ val childCount = parent.getReactChildCount()
50
+ if (index >= 0 && index < childCount) {
51
+ parent.removeChild(index)
52
+ super.removeViewAt(parent, index)
53
+ }
54
+ }
55
+
56
+ override fun getName() = "ClusteredYamapLiteView"
57
+
58
+ @ReactProp(name = "userLocationIcon")
59
+ override fun setUserLocationIcon(view: ClusteredYamapLiteView, value: String?) {
60
+ view.setUserLocationIcon(value)
61
+ }
62
+
63
+ @ReactProp(name = "userLocationIconScale")
64
+ override fun setUserLocationIconScale(view: ClusteredYamapLiteView, value: Float) {
65
+ view.setUserLocationIconScale(value)
66
+ }
67
+
68
+ @ReactProp(name = "showUserPosition")
69
+ override fun setShowUserPosition(view: ClusteredYamapLiteView, value: Boolean) {
70
+ view.setShowUserPosition(value)
71
+ }
72
+
73
+ @ReactProp(name = "nightMode")
74
+ override fun setNightMode(view: ClusteredYamapLiteView, value: Boolean) {
75
+ view.setNightMode(value)
76
+ }
77
+
78
+ @ReactProp(name = "mapStyle")
79
+ override fun setMapStyle(view: ClusteredYamapLiteView, value: String?) {
80
+ view.setMapStyle(value)
81
+ }
82
+
83
+ @ReactProp(name = "scrollGesturesEnabled")
84
+ override fun setScrollGesturesEnabled(view: ClusteredYamapLiteView, value: Boolean) {
85
+ view.setScrollGesturesEnabled(value)
86
+ }
87
+
88
+ @ReactProp(name = "zoomGesturesEnabled")
89
+ override fun setZoomGesturesEnabled(view: ClusteredYamapLiteView, value: Boolean) {
90
+ view.setZoomGesturesEnabled(value)
91
+ }
92
+
93
+ @ReactProp(name = "tiltGesturesEnabled")
94
+ override fun setTiltGesturesEnabled(view: ClusteredYamapLiteView, value: Boolean) {
95
+ view.setTiltGesturesEnabled(value)
96
+ }
97
+
98
+ @ReactProp(name = "rotateGesturesEnabled")
99
+ override fun setRotateGesturesEnabled(view: ClusteredYamapLiteView, value: Boolean) {
100
+ view.setRotateGesturesEnabled(value)
101
+ }
102
+
103
+ @ReactProp(name = "fastTapEnabled")
104
+ override fun setFastTapEnabled(view: ClusteredYamapLiteView, value: Boolean) {
105
+ view.setFastTapEnabled(value)
106
+ }
107
+
108
+ @ReactProp(name = "initialRegion")
109
+ override fun setInitialRegion(view: ClusteredYamapLiteView, value: ReadableMap?) {
110
+ if (value != null) {
111
+ val region = mutableMapOf<String, Any>()
112
+ if (value.hasKey("lat")) region["lat"] = value.getDouble("lat")
113
+ if (value.hasKey("lon")) region["lon"] = value.getDouble("lon")
114
+ if (value.hasKey("zoom")) region["zoom"] = value.getDouble("zoom")
115
+ if (value.hasKey("azimuth")) region["azimuth"] = value.getDouble("azimuth")
116
+ if (value.hasKey("tilt")) region["tilt"] = value.getDouble("tilt")
117
+ view.setInitialRegion(region)
118
+ }
119
+ }
120
+
121
+ @ReactProp(name = "maxFps")
122
+ override fun setMaxFps(view: ClusteredYamapLiteView, value: Float) {
123
+ view.setMaxFps(value)
124
+ }
125
+
126
+ @ReactProp(name = "mapType")
127
+ override fun setMapType(view: ClusteredYamapLiteView, value: String?) {
128
+ view.setMapType(value)
129
+ }
130
+
131
+ @ReactProp(name = "logoPosition")
132
+ override fun setLogoPosition(view: ClusteredYamapLiteView, value: ReadableMap?) {
133
+ if (value != null) {
134
+ val position = mutableMapOf<String, Any>()
135
+ if (value.hasKey("vertical")) position["vertical"] = value.getString("vertical") ?: "bottom"
136
+ if (value.hasKey("horizontal")) position["horizontal"] = value.getString("horizontal") ?: "left"
137
+ view.setLogoPosition(position)
138
+ }
139
+ }
140
+
141
+ @ReactProp(name = "logoPadding")
142
+ override fun setLogoPadding(view: ClusteredYamapLiteView, value: ReadableMap?) {
143
+ if (value != null) {
144
+ val horizontalPadding =
145
+ if ((value.hasKey("horizontal") && !value.isNull("horizontal"))) value.getInt("horizontal") else 0
146
+ val verticalPadding =
147
+ if ((value.hasKey("vertical") && !value.isNull("vertical"))) value.getInt("vertical") else 0
148
+ view.setLogoPadding(horizontalPadding, verticalPadding)
149
+ }
150
+ }
151
+
152
+ @ReactProp(name = "userLocationAccuracyFillColor")
153
+ override fun setUserLocationAccuracyFillColor(view: ClusteredYamapLiteView, value: String?) {
154
+ view.setUserLocationAccuracyFillColor(value)
155
+ }
156
+
157
+ @ReactProp(name = "userLocationAccuracyStrokeColor")
158
+ override fun setUserLocationAccuracyStrokeColor(view: ClusteredYamapLiteView, value: String?) {
159
+ view.setUserLocationAccuracyStrokeColor(value)
160
+ }
161
+
162
+ @ReactProp(name = "userLocationAccuracyStrokeWidth")
163
+ override fun setUserLocationAccuracyStrokeWidth(view: ClusteredYamapLiteView, value: Float) {
164
+ view.setUserLocationAccuracyStrokeWidth(value)
165
+ }
166
+
167
+ @ReactProp(name = "clusteredMarkers")
168
+ override fun setClusteredMarkers(view: ClusteredYamapLiteView, points: ReadableArray?) {
169
+ view.setClusteredMarkers(PointParser.parsePoints(points))
170
+ }
171
+
172
+ @ReactProp(name = "clusterColor")
173
+ override fun setClusterColor(view: ClusteredYamapLiteView, value: String?) {
174
+ view.setClusterColor(Color.parseColor(value ?: "#000000"))
175
+ }
176
+
177
+ @ReactProp(name = "followUser")
178
+ override fun setFollowUser(view: ClusteredYamapLiteView, value: Boolean) {
179
+ view.setFollowUser(value)
180
+ }
181
+ }
@@ -0,0 +1,169 @@
1
+ package com.yamaplite.components
2
+
3
+ import android.content.Context
4
+ import android.graphics.Bitmap
5
+ import android.graphics.Canvas
6
+ import android.graphics.Color
7
+ import android.graphics.Paint
8
+ import android.view.View
9
+ import com.yandex.mapkit.geometry.Point
10
+ import com.yandex.mapkit.map.Cluster
11
+ import com.yandex.mapkit.map.ClusterListener
12
+ import com.yandex.mapkit.map.ClusterTapListener
13
+ import com.yandex.mapkit.map.ClusterizedPlacemarkCollection
14
+ import com.yandex.mapkit.map.IconStyle
15
+ import com.yandex.mapkit.map.PlacemarkMapObject
16
+ import com.yandex.runtime.image.ImageProvider
17
+ import kotlin.math.abs
18
+ import kotlin.math.sqrt
19
+
20
+ class ClusteredYamapLiteView(context: Context) :
21
+ YamapLiteView(context), ClusterListener, ClusterTapListener {
22
+ private var clusterCollection: ClusterizedPlacemarkCollection
23
+ private var clusterColor = Color.RED
24
+ private val placemarksMap: HashMap<String?, PlacemarkMapObject?> =
25
+ HashMap<String?, PlacemarkMapObject?>()
26
+ private var pointsList = ArrayList<Point>()
27
+
28
+ init {
29
+ clusterCollection = mapView.mapWindow.map.mapObjects.addClusterizedPlacemarkCollection(this)
30
+ }
31
+
32
+ fun setClusteredMarkers(points: List<Point>) {
33
+ pointsList = ArrayList(points)
34
+ rebuildClusterPlacemarks()
35
+ }
36
+
37
+ fun setClusterColor(color: Int) {
38
+ clusterColor = color
39
+ rebuildClusterPlacemarks()
40
+ }
41
+
42
+ private fun rebuildClusterPlacemarks() {
43
+ clusterCollection.clear()
44
+ placemarksMap.clear()
45
+ val placemarks = clusterCollection.addPlacemarks(pointsList, TextImageProvider(""), IconStyle())
46
+ val childCount = super.getReactChildCount()
47
+ for (i in placemarks.indices) {
48
+ val placemark = placemarks[i]
49
+ val geometry = placemark.geometry
50
+ placemarksMap[geometryKey(geometry.latitude, geometry.longitude)] = placemark
51
+ if (i < childCount) {
52
+ val child = super.getReactChildAt(i)
53
+ if (child is YamapLiteMarkerView) {
54
+ child.setMarkerMapObject(placemark)
55
+ }
56
+ }
57
+ }
58
+ clusterCollection.clusterPlacemarks(50.0, 12)
59
+ }
60
+
61
+ private fun geometryKey(lat: Double, lon: Double): String = "$lat,$lon"
62
+
63
+ fun addChild(child: View, index: Int) {
64
+ if (child is YamapLiteMarkerView) {
65
+ addReactChildToList(child, index)
66
+ val placemark = placemarksMap[geometryKey(child.latitude, child.longitude)]
67
+ if (placemark != null) {
68
+ child.setMarkerMapObject(placemark)
69
+ }
70
+ } else {
71
+ super.addReactChild(child, index)
72
+ }
73
+ }
74
+
75
+ fun removeChild(index: Int) {
76
+ if (index < 0 || index >= super.getReactChildCount()) {
77
+ return
78
+ }
79
+ val child = super.getReactChildAt(index)
80
+ if (child is YamapLiteMarkerView) {
81
+ val clusterPlacemark = placemarksMap.remove(geometryKey(child.latitude, child.longitude))
82
+ if (clusterPlacemark != null && clusterPlacemark.isValid) {
83
+ clusterCollection.remove(clusterPlacemark)
84
+ }
85
+ removeReactChildFromListAt(index)
86
+ } else {
87
+ super.removeReactChildAt(index)
88
+ }
89
+ }
90
+
91
+ override fun onClusterAdded(cluster: Cluster) {
92
+ cluster.appearance.setIcon(TextImageProvider(cluster.size.toString()))
93
+ cluster.addClusterTapListener(this)
94
+ }
95
+
96
+ override fun onClusterTap(cluster: Cluster): Boolean {
97
+ val points = ArrayList<Point?>()
98
+ for (placemark in cluster.placemarks) {
99
+ points.add(placemark.geometry)
100
+ }
101
+ super.fitMarkers(points)
102
+ return true
103
+ }
104
+
105
+ private inner class TextImageProvider(private val text: String) : ImageProvider() {
106
+ override fun getId(): String {
107
+ return "text_$text"
108
+ }
109
+
110
+ override fun getImage(): Bitmap {
111
+ // Scale sizes by display density to match iOS (which uses points that scale automatically)
112
+ val density = this@ClusteredYamapLiteView.context.resources.displayMetrics.density
113
+ val scaledFontSize = Companion.FONT_SIZE * density
114
+ val scaledMarginSize = Companion.MARGIN_SIZE * density
115
+ val scaledStrokeSize = Companion.STROKE_SIZE * density
116
+
117
+ val textPaint = Paint()
118
+ textPaint.textSize = scaledFontSize
119
+ textPaint.textAlign = Paint.Align.CENTER
120
+ textPaint.style = Paint.Style.FILL
121
+ textPaint.isAntiAlias = true
122
+
123
+ val widthF = textPaint.measureText(text)
124
+ val textMetrics = textPaint.fontMetrics
125
+ val heightF = (abs(textMetrics.bottom.toDouble()) + abs(textMetrics.top.toDouble())).toFloat()
126
+ val textRadius = sqrt((widthF * widthF + heightF * heightF).toDouble()).toFloat() / 2
127
+ val internalRadius = textRadius + scaledMarginSize
128
+ val externalRadius = internalRadius + scaledStrokeSize
129
+
130
+ val width = (2 * externalRadius + 0.5).toInt()
131
+
132
+ val bitmap = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888)
133
+ val canvas = Canvas(bitmap)
134
+
135
+ val backgroundPaint = Paint()
136
+ backgroundPaint.isAntiAlias = true
137
+ backgroundPaint.color = clusterColor
138
+ canvas.drawCircle(
139
+ (width / 2).toFloat(),
140
+ (width / 2).toFloat(),
141
+ externalRadius,
142
+ backgroundPaint
143
+ )
144
+
145
+ backgroundPaint.color = Color.WHITE
146
+ canvas.drawCircle(
147
+ (width / 2).toFloat(),
148
+ (width / 2).toFloat(),
149
+ internalRadius,
150
+ backgroundPaint
151
+ )
152
+
153
+ canvas.drawText(
154
+ text,
155
+ (width / 2).toFloat(),
156
+ width / 2 - (textMetrics.ascent + textMetrics.descent) / 2,
157
+ textPaint
158
+ )
159
+
160
+ return bitmap
161
+ }
162
+ }
163
+
164
+ companion object {
165
+ private const val FONT_SIZE = 45f
166
+ private const val MARGIN_SIZE = 9f
167
+ private const val STROKE_SIZE = 9f
168
+ }
169
+ }
@@ -0,0 +1,145 @@
1
+ package com.yamaplite.components
2
+
3
+ import android.content.Context
4
+ import android.graphics.Color
5
+ import android.view.ViewGroup
6
+ import com.facebook.react.bridge.ReactContext
7
+ import com.facebook.react.uimanager.UIManagerHelper
8
+ import com.yamaplite.events.PressEvent
9
+ import com.yandex.mapkit.geometry.Circle
10
+ import com.yandex.mapkit.geometry.Point
11
+ import com.yandex.mapkit.map.CircleMapObject
12
+ import com.yandex.mapkit.map.MapObject
13
+ import com.yandex.mapkit.map.MapObjectTapListener
14
+ import com.yandex.mapkit.mapview.MapView
15
+
16
+ class YamapCircle(context: Context?) : ViewGroup(context), MapObjectTapListener {
17
+ var circle: Circle
18
+
19
+ var rnMapObject: MapObject? = null
20
+ private var mapView: MapView? = null
21
+ private var handled = true
22
+ private var fillColor = Color.BLACK
23
+ private var strokeColor = Color.BLACK
24
+ private var zInd = 1
25
+ private var strokeWidth = 1f
26
+ private var center = Point(0.0, 0.0)
27
+ private var radius = 0f
28
+
29
+ init {
30
+ circle = Circle(center, radius)
31
+ }
32
+
33
+ override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {}
34
+
35
+ // PROPS
36
+ fun setCenter(point: Point) {
37
+ center = point
38
+ updateGeometry()
39
+ if (rnMapObject == null && mapView != null && radius > 0) {
40
+ addToMap(mapView!!)
41
+ } else {
42
+ updateCircle()
43
+ }
44
+ }
45
+
46
+ fun setRadius(_radius: Float) {
47
+ radius = _radius
48
+ updateGeometry()
49
+ if (rnMapObject == null &&
50
+ mapView != null &&
51
+ radius > 0 &&
52
+ (center.latitude != 0.0 || center.longitude != 0.0)
53
+ ) {
54
+ addToMap(mapView!!)
55
+ } else {
56
+ updateCircle()
57
+ }
58
+ }
59
+
60
+ private fun updateGeometry() {
61
+ circle = Circle(center, radius)
62
+ }
63
+
64
+ fun setZInd(_zInd: Int) {
65
+ zInd = _zInd
66
+ updateCircle()
67
+ }
68
+
69
+ fun setHandled(_handled: Boolean) {
70
+ handled = _handled
71
+ }
72
+
73
+ fun setStrokeColor(_color: Int) {
74
+ strokeColor = _color
75
+ updateCircle()
76
+ }
77
+
78
+ fun setFillColor(_color: Int) {
79
+ fillColor = _color
80
+ updateCircle()
81
+ }
82
+
83
+ fun setStrokeWidth(width: Float) {
84
+ strokeWidth = width
85
+ updateCircle()
86
+ }
87
+
88
+ private fun updateCircle() {
89
+ if (rnMapObject != null) {
90
+ (rnMapObject as CircleMapObject).geometry = circle
91
+ (rnMapObject as CircleMapObject).strokeWidth = strokeWidth
92
+ (rnMapObject as CircleMapObject).strokeColor = strokeColor
93
+ (rnMapObject as CircleMapObject).fillColor = fillColor
94
+ (rnMapObject as CircleMapObject).zIndex = zInd.toFloat()
95
+ }
96
+ }
97
+
98
+ fun setCircleMapObject(obj: MapObject?) {
99
+ rnMapObject = obj as CircleMapObject?
100
+ rnMapObject!!.addTapListener(this)
101
+ updateCircle()
102
+ }
103
+
104
+ fun addToMap(mapView: MapView) {
105
+ this.mapView = mapView
106
+ updateGeometry()
107
+ if (!isGeometryValid()) {
108
+ return
109
+ }
110
+ val circleObject = mapView.getMapWindow().map.mapObjects.addCircle(circle)
111
+ rnMapObject = circleObject
112
+ circleObject.addTapListener(this)
113
+ updateCircle()
114
+ }
115
+
116
+ private fun isGeometryValid(): Boolean {
117
+ return radius > 0f && center.latitude.isFinite() && center.longitude.isFinite()
118
+ }
119
+
120
+ fun removeFromMap(mapView: MapView) {
121
+ rnMapObject?.let {
122
+ if (it.isValid) {
123
+ mapView.getMapWindow().map.mapObjects.remove(it)
124
+ }
125
+ }
126
+ rnMapObject = null
127
+ }
128
+
129
+ override fun onMapObjectTap(mapObject: MapObject, point: Point): Boolean {
130
+ val reactContext = context as? ReactContext
131
+ if (reactContext == null) {
132
+ return false
133
+ }
134
+
135
+ val viewId = getId()
136
+ val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
137
+ val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, viewId)
138
+
139
+ if (eventDispatcher != null) {
140
+ val event = PressEvent(surfaceId, viewId, "onCirclePress", point)
141
+ eventDispatcher.dispatchEvent(event)
142
+ }
143
+ return handled
144
+ }
145
+ }
@@ -0,0 +1,214 @@
1
+ package com.yamaplite.components
2
+
3
+ import android.content.Context
4
+ import android.graphics.Bitmap
5
+ import android.graphics.Canvas
6
+ import android.graphics.PointF
7
+ import android.view.View
8
+ import com.facebook.react.bridge.ReactContext
9
+ import com.facebook.react.uimanager.UIManagerHelper
10
+ import com.yamaplite.events.PressEvent
11
+ import com.yamaplite.utils.ResolveImageHelper
12
+ import com.yandex.mapkit.geometry.Point
13
+ import com.yandex.mapkit.map.IconStyle
14
+ import com.yandex.mapkit.map.MapObject
15
+ import com.yandex.mapkit.map.MapObjectTapListener
16
+ import com.yandex.mapkit.map.PlacemarkMapObject
17
+ import com.yandex.mapkit.map.RotationType
18
+ import com.yandex.mapkit.mapview.MapView
19
+ import com.yandex.runtime.image.ImageProvider
20
+ import kotlinx.coroutines.CoroutineScope
21
+ import kotlinx.coroutines.Dispatchers
22
+ import kotlinx.coroutines.cancel
23
+ import kotlinx.coroutines.launch
24
+
25
+ class YamapLiteMarkerView(context: Context) : View(context), MapObjectTapListener {
26
+ var latitude: Double = 0.0
27
+ var longitude: Double = 0.0
28
+ private var iconSource: String? = null
29
+ private var iconBitmap: Bitmap? = null
30
+ var markerScale: Double = 1.0
31
+ var zInd: Float = 0f
32
+ var isVisibleFlag: Boolean = true
33
+ var anchorX: Double = 0.5
34
+ var anchorY: Double = 0.5
35
+ private var _rotated: Boolean = false
36
+ private var _handled: Boolean = false
37
+ private var _size: Int = 25
38
+ private var _childView: View? = null
39
+
40
+ var placemark: PlacemarkMapObject? = null
41
+ private val coroutineScope = CoroutineScope(Dispatchers.Main)
42
+
43
+ private val childLayoutListener = OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
44
+ applyStyle()
45
+ }
46
+
47
+ fun setMarkerMapObject(obj: PlacemarkMapObject?) {
48
+ placemark = obj
49
+ placemark?.userData = this
50
+ placemark?.addTapListener(this)
51
+ placemark?.isVisible = false
52
+ applyStyle()
53
+ }
54
+
55
+ fun addToMap(mapView: MapView) {
56
+ if (!latitude.isFinite() || !longitude.isFinite()) {
57
+ return
58
+ }
59
+ placemark?.let {
60
+ if (it.isValid) {
61
+ mapView.mapWindow.map.mapObjects.remove(it)
62
+ }
63
+ }
64
+ val point = Point(latitude, longitude)
65
+ placemark = mapView.mapWindow.map.mapObjects.addPlacemark(point)
66
+ placemark?.userData = this
67
+ placemark?.addTapListener(this)
68
+ applyStyle()
69
+ }
70
+
71
+ fun onDrop() {
72
+ _childView?.removeOnLayoutChangeListener(childLayoutListener)
73
+ _childView = null
74
+ coroutineScope.cancel()
75
+ }
76
+
77
+ fun removeFromMap(mapView: MapView) {
78
+ placemark?.let {
79
+ if (it.isValid) {
80
+ mapView.mapWindow.map.mapObjects.remove(it)
81
+ }
82
+ }
83
+ placemark = null
84
+ }
85
+
86
+ fun setPoint(lat: Double, lon: Double) {
87
+ latitude = lat
88
+ longitude = lon
89
+ placemark?.geometry = Point(lat, lon)
90
+ }
91
+
92
+ fun setIconSource(name: String?) {
93
+ iconSource = name
94
+ applyStyle()
95
+ }
96
+
97
+ fun setScale(value: Double) {
98
+ markerScale = value
99
+ applyStyle()
100
+ }
101
+
102
+ fun setZInd(value: Int) {
103
+ zInd = value.toFloat()
104
+ applyStyle()
105
+ }
106
+
107
+ fun setVisible(value: Boolean) {
108
+ isVisibleFlag = value
109
+ placemark?.isVisible = value
110
+ }
111
+
112
+ fun setAnchor(x: Double, y: Double) {
113
+ anchorX = x
114
+ anchorY = y
115
+ applyStyle()
116
+ }
117
+
118
+ fun setRotated(value: Boolean) {
119
+ _rotated = value
120
+ applyStyle()
121
+ }
122
+
123
+ fun setHandled(value: Boolean) {
124
+ _handled = value
125
+ }
126
+
127
+ fun getRotated(): Boolean = _rotated
128
+
129
+ fun getHandled(): Boolean = _handled
130
+
131
+ fun setSize(value: Int) {
132
+ _size = value
133
+ applyStyle()
134
+ }
135
+
136
+ fun setChildView(view: View?) {
137
+ if (view == null) {
138
+ _childView?.removeOnLayoutChangeListener(childLayoutListener)
139
+ _childView = null
140
+ applyStyle()
141
+ return
142
+ }
143
+ _childView = view
144
+ _childView!!.addOnLayoutChangeListener(childLayoutListener)
145
+ if (_childView!!.width > 0 && _childView!!.height > 0) {
146
+ applyStyle()
147
+ }
148
+ }
149
+
150
+ private fun applyStyle() {
151
+ if (placemark != null && placemark!!.isValid) {
152
+ (placemark as PlacemarkMapObject).isVisible = false
153
+ val iconStyle = IconStyle()
154
+ iconStyle.setScale(markerScale.toFloat())
155
+ iconStyle.setRotationType(if (_rotated) RotationType.ROTATE else RotationType.NO_ROTATION)
156
+ iconStyle.setVisible(isVisibleFlag)
157
+ iconStyle.setAnchor(PointF(anchorX.toFloat(), anchorY.toFloat()))
158
+ (placemark as PlacemarkMapObject).geometry = Point(latitude, longitude)
159
+ (placemark as PlacemarkMapObject).zIndex = zInd.toFloat()
160
+ (placemark as PlacemarkMapObject).setIconStyle(iconStyle)
161
+
162
+ if (_childView != null && _childView!!.width > 0 && _childView!!.height > 0) {
163
+ try {
164
+ val b =
165
+ Bitmap.createBitmap(
166
+ _childView!!.width,
167
+ _childView!!.height,
168
+ Bitmap.Config.ARGB_8888
169
+ )
170
+ val c = Canvas(b)
171
+ _childView!!.draw(c)
172
+ val resizedBitmap = ResolveImageHelper.getInstance().resizeBitmap(context, b, _size)
173
+ (placemark as PlacemarkMapObject).setIcon(ImageProvider.fromBitmap(resizedBitmap))
174
+ (placemark as PlacemarkMapObject).setIconStyle(iconStyle)
175
+ (placemark as PlacemarkMapObject).isVisible = isVisibleFlag
176
+ } catch (e: Exception) {
177
+ e.printStackTrace()
178
+ }
179
+ }
180
+ if (_childView == null && iconSource?.isNotEmpty() == true) {
181
+ val currentIconStyle = iconStyle
182
+ coroutineScope.launch {
183
+ val icon = ResolveImageHelper.getInstance().resolveImage(context, iconSource!!, _size)
184
+ icon?.let {
185
+ placemark?.let { pm ->
186
+ if (pm.isValid) {
187
+ pm.setIcon(it)
188
+ currentIconStyle.let { pm.setIconStyle(it) }
189
+ pm.isVisible = isVisibleFlag
190
+ }
191
+ }
192
+ }
193
+ }
194
+ }
195
+ }
196
+ }
197
+
198
+ override fun onMapObjectTap(p0: MapObject, p1: Point): Boolean {
199
+ val reactContext = context as? ReactContext
200
+ if (reactContext == null) {
201
+ return _handled
202
+ }
203
+
204
+ val viewId = getId()
205
+ val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
206
+ val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, viewId)
207
+
208
+ if (eventDispatcher != null) {
209
+ val event = PressEvent(surfaceId, viewId, "onMarkerPress", p1)
210
+ eventDispatcher.dispatchEvent(event)
211
+ }
212
+ return _handled
213
+ }
214
+ }