Skip to content

Commit 5f8852c

Browse files
authored
feat: optional marker svg (#30)
2 parents acc394e + d9bd19d commit 5f8852c

File tree

10 files changed

+81
-48
lines changed

10 files changed

+81
-48
lines changed

android/src/main/java/com/rngooglemapsplus/GoogleMapsViewImpl.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class GoogleMapsViewImpl(
3232
val reactContext: ThemedReactContext,
3333
val locationHandler: LocationHandler,
3434
val playServiceHandler: PlayServicesHandler,
35-
val markerBuilder: MarkerBuilder,
35+
val markerBuilder: MapMarkerBuilder,
3636
) : FrameLayout(reactContext),
3737
GoogleMap.OnCameraMoveStartedListener,
3838
GoogleMap.OnCameraMoveListener,

android/src/main/java/com/rngooglemapsplus/MapMarkerBuilder.kt

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import com.google.android.gms.maps.model.BitmapDescriptor
1010
import com.google.android.gms.maps.model.BitmapDescriptorFactory
1111
import com.google.android.gms.maps.model.LatLng
1212
import com.google.android.gms.maps.model.MarkerOptions
13+
import com.rngooglemapsplus.extensions.styleHash
1314
import kotlinx.coroutines.CoroutineScope
1415
import kotlinx.coroutines.Dispatchers
1516
import kotlinx.coroutines.Job
@@ -19,7 +20,7 @@ import kotlinx.coroutines.launch
1920
import kotlinx.coroutines.withContext
2021
import kotlin.coroutines.coroutineContext
2122

22-
class MarkerBuilder(
23+
class MapMarkerBuilder(
2324
private val scope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Default),
2425
) {
2526
private val iconCache =
@@ -34,7 +35,7 @@ class MarkerBuilder(
3435

3536
fun build(
3637
m: RNMarker,
37-
icon: BitmapDescriptor,
38+
icon: BitmapDescriptor?,
3839
): MarkerOptions =
3940
MarkerOptions().apply {
4041
position(LatLng(m.coordinate.latitude, m.coordinate.longitude))
@@ -46,10 +47,13 @@ class MarkerBuilder(
4647
fun buildIconAsync(
4748
id: String,
4849
m: RNMarker,
49-
onReady: (BitmapDescriptor) -> Unit,
50+
onReady: (BitmapDescriptor?) -> Unit,
5051
) {
5152
jobsById[id]?.cancel()
52-
53+
if (m.iconSvg == null) {
54+
onReady(null)
55+
return
56+
}
5357
val key = m.styleHash()
5458
iconCache.get(key)?.let { cached ->
5559
onReady(cached)
@@ -98,17 +102,28 @@ class MarkerBuilder(
98102

99103
private suspend fun renderBitmap(m: RNMarker): Bitmap? {
100104
var bmp: Bitmap? = null
105+
if (m.iconSvg == null) {
106+
return null
107+
}
101108
try {
102109
coroutineContext.ensureActive()
103-
val svg = SVG.getFromString(m.iconSvg)
110+
val svg = SVG.getFromString(m.iconSvg.svgString)
104111

105112
coroutineContext.ensureActive()
106-
svg.setDocumentWidth(m.width.dpToPx())
107-
svg.setDocumentHeight(m.height.dpToPx())
113+
svg.setDocumentWidth(m.iconSvg.width.dpToPx())
114+
svg.setDocumentHeight(m.iconSvg.height.dpToPx())
108115

109116
coroutineContext.ensureActive()
110117
bmp =
111-
createBitmap(m.width.dpToPx().toInt(), m.height.dpToPx().toInt(), Bitmap.Config.ARGB_8888)
118+
createBitmap(
119+
m.iconSvg.width
120+
.dpToPx()
121+
.toInt(),
122+
m.iconSvg.height
123+
.dpToPx()
124+
.toInt(),
125+
Bitmap.Config.ARGB_8888,
126+
)
112127

113128
coroutineContext.ensureActive()
114129
val canvas = Canvas(bmp)
@@ -125,22 +140,3 @@ class MarkerBuilder(
125140
}
126141
}
127142
}
128-
129-
fun RNMarker.markerEquals(b: RNMarker): Boolean =
130-
id == b.id &&
131-
zIndex == b.zIndex &&
132-
coordinate == b.coordinate &&
133-
anchor == b.anchor &&
134-
markerStyleEquals(b)
135-
136-
fun RNMarker.markerStyleEquals(b: RNMarker): Boolean =
137-
width == b.width &&
138-
height == b.height &&
139-
iconSvg == b.iconSvg
140-
141-
fun RNMarker.styleHash(): Int =
142-
arrayOf<Any?>(
143-
width,
144-
height,
145-
iconSvg,
146-
).contentHashCode()

android/src/main/java/com/rngooglemapsplus/RNGoogleMapsPlusView.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import com.google.android.gms.maps.model.LatLng
88
import com.google.android.gms.maps.model.MapStyleOptions
99
import com.margelo.nitro.core.Promise
1010
import com.rngooglemapsplus.extensions.circleEquals
11+
import com.rngooglemapsplus.extensions.markerEquals
12+
import com.rngooglemapsplus.extensions.markerStyleEquals
1113
import com.rngooglemapsplus.extensions.polygonEquals
1214
import com.rngooglemapsplus.extensions.polylineEquals
1315
import com.rngooglemapsplus.extensions.toCameraPosition
@@ -23,7 +25,7 @@ class RNGoogleMapsPlusView(
2325
private var locationHandler = LocationHandler(context)
2426
private var playServiceHandler = PlayServicesHandler(context)
2527

26-
private val markerBuilder = MarkerBuilder()
28+
private val markerBuilder = MapMarkerBuilder()
2729
private val polylineBuilder = MapPolylineBuilder()
2830
private val polygonBuilder = MapPolygonBuilder()
2931
private val circleBuilder = MapCircleBuilder()
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.rngooglemapsplus.extensions
2+
3+
import com.rngooglemapsplus.RNMarker
4+
5+
fun RNMarker.markerEquals(b: RNMarker): Boolean =
6+
id == b.id &&
7+
zIndex == b.zIndex &&
8+
coordinate == b.coordinate &&
9+
anchor == b.anchor &&
10+
markerStyleEquals(b)
11+
12+
fun RNMarker.markerStyleEquals(b: RNMarker): Boolean = iconSvg == b.iconSvg
13+
14+
fun RNMarker.styleHash(): Int =
15+
arrayOf<Any?>(
16+
iconSvg,
17+
).contentHashCode()

example/ios/Podfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2356,7 +2356,7 @@ PODS:
23562356
- React-perflogger (= 0.82.0-rc.4)
23572357
- React-utils (= 0.82.0-rc.4)
23582358
- SocketRocket
2359-
- RNGoogleMapsPlus (1.0.3-dev.0):
2359+
- RNGoogleMapsPlus (1.1.0-dev.1):
23602360
- boost
23612361
- DoubleConversion
23622362
- fast_float
@@ -2708,7 +2708,7 @@ SPEC CHECKSUMS:
27082708
ReactAppDependencyProvider: 1202b833d8cca6c917dabcf679837c34a9ca5723
27092709
ReactCodegen: 19febbd1fdc8928493972f8d5290f2952e14c9d2
27102710
ReactCommon: 2caf7281b37aa1ca389e18839dd594099efb1489
2711-
RNGoogleMapsPlus: f9d77f78190272ae61db89e5e424d735342fcddc
2711+
RNGoogleMapsPlus: 45deb9a3ba72d6557af3bfbf970f51de523364a1
27122712
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
27132713
SVGKit: 1ad7513f8c74d9652f94ed64ddecda1a23864dea
27142714
Yoga: 2fb906b2084fd388a52edae73c54c39c3f50e86c

example/src/App.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -251,9 +251,14 @@ export const makeMarker = (id: number): RNMarker => ({
251251
zIndex: id,
252252
coordinate: randomCoordinates(37.7749, -122.4194, 0.2),
253253
anchor: { x: 0.5, y: 1.0 },
254-
width: (64 / 100) * 50,
255-
height: (88 / 100) * 50,
256-
iconSvg: makeSvgIcon(64, 88),
254+
iconSvg:
255+
id % 2 === 0
256+
? {
257+
width: (64 / 100) * 50,
258+
height: (88 / 100) * 50,
259+
svgString: makeSvgIcon(64, 88),
260+
}
261+
: undefined,
257262
});
258263

259264
export default function App() {

ios/MapMarkerBuilder.swift

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ final class MapMarkerBuilder {
1111
attributes: .concurrent
1212
)
1313

14-
func build(_ m: RNMarker, icon: UIImage) -> GMSMarker {
14+
func build(_ m: RNMarker, icon: UIImage?) -> GMSMarker {
1515
let marker = GMSMarker(
1616
position: CLLocationCoordinate2D(
1717
latitude: m.coordinate.latitude,
@@ -40,6 +40,11 @@ final class MapMarkerBuilder {
4040
) {
4141
tasks[id]?.cancel()
4242

43+
if m.iconSvg == nil {
44+
onReady(nil)
45+
return
46+
}
47+
4348
let key = m.styleHash()
4449
if let cached = iconCache.object(forKey: key) {
4550
onReady(cached)
@@ -85,7 +90,6 @@ final class MapMarkerBuilder {
8590

8691
if !prev.markerStyleEquals(next) {
8792
buildIconAsync(next.id, next) { img in
88-
guard let img else { return }
8993
m.tracksViewChanges = true
9094
m.icon = img
9195
if prev.anchor?.x != next.anchor?.x || prev.anchor?.y != next.anchor?.y {
@@ -117,21 +121,26 @@ final class MapMarkerBuilder {
117121
}
118122

119123
private func renderUIImage(_ m: RNMarker) async -> UIImage? {
120-
await withTaskCancellationHandler(
124+
guard let iconSvg = m.iconSvg else {
125+
return nil
126+
}
127+
128+
return await withTaskCancellationHandler(
121129
operation: {
122-
await withCheckedContinuation { cont in
130+
await withCheckedContinuation {
131+
(cont: CheckedContinuation<UIImage?, Never>) in
123132
queue.async {
124133
if Task.isCancelled {
125134
cont.resume(returning: nil)
126135
return
127136
}
128137

129-
let targetW = max(1, Int(CGFloat(m.width)))
130-
let targetH = max(1, Int(CGFloat(m.height)))
138+
let targetW = max(1, Int(CGFloat(iconSvg.width)))
139+
let targetH = max(1, Int(CGFloat(iconSvg.height)))
131140
let size = CGSize(width: targetW, height: targetH)
132141

133142
guard
134-
let data = m.iconSvg.data(using: .utf8),
143+
let data = iconSvg.svgString.data(using: .utf8),
135144
let svgImg = SVGKImage(data: data)
136145
else {
137146
cont.resume(returning: nil)

ios/RNGoogleMapsPlusView.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ final class RNGoogleMapsPlusView: HybridRNGoogleMapsPlusViewSpec {
140140
}
141141
} else {
142142
markerBuilder.buildIconAsync(next.id, next) { icon in
143-
guard let icon else { return }
144143
let marker = self.markerBuilder.build(next, icon: icon)
145144
self.impl.addMarker(id: id, marker: marker)
146145
}

ios/extensions/RNMarker+Extension.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@ extension RNMarker {
1010
}
1111

1212
func markerStyleEquals(_ b: RNMarker) -> Bool {
13-
width == b.width && height == b.height
14-
&& iconSvg == b.iconSvg
13+
iconSvg?.width == b.iconSvg?.width && iconSvg?.height == b.iconSvg?.height
14+
&& iconSvg?.svgString == b.iconSvg?.svgString
15+
1516
}
1617

1718
func styleHash() -> NSString {
1819
var hasher = Hasher()
19-
hasher.combine(width)
20-
hasher.combine(height)
21-
hasher.combine(iconSvg)
20+
hasher.combine(iconSvg?.width)
21+
hasher.combine(iconSvg?.height)
22+
hasher.combine(iconSvg?.svgString)
2223
return String(hasher.finalize()) as NSString
2324
}
2425
}

src/types.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,13 @@ export type RNMarker = {
131131
zIndex?: number;
132132
coordinate: RNLatLng;
133133
anchor?: RNPosition;
134+
iconSvg?: RNMarkerSvg;
135+
};
136+
137+
export type RNMarkerSvg = {
134138
width: number;
135139
height: number;
136-
iconSvg: string;
140+
svgString: string;
137141
};
138142

139143
export type RNPolygon = {

0 commit comments

Comments
 (0)