Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class GoogleMapsViewImpl(
val reactContext: ThemedReactContext,
val locationHandler: LocationHandler,
val playServiceHandler: PlayServicesHandler,
val markerBuilder: MarkerBuilder,
val markerBuilder: MapMarkerBuilder,
) : FrameLayout(reactContext),
GoogleMap.OnCameraMoveStartedListener,
GoogleMap.OnCameraMoveListener,
Expand Down
50 changes: 23 additions & 27 deletions android/src/main/java/com/rngooglemapsplus/MapMarkerBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.google.android.gms.maps.model.BitmapDescriptor
import com.google.android.gms.maps.model.BitmapDescriptorFactory
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
import com.rngooglemapsplus.extensions.styleHash
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
Expand All @@ -19,7 +20,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.coroutines.coroutineContext

class MarkerBuilder(
class MapMarkerBuilder(
private val scope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Default),
) {
private val iconCache =
Expand All @@ -34,7 +35,7 @@ class MarkerBuilder(

fun build(
m: RNMarker,
icon: BitmapDescriptor,
icon: BitmapDescriptor?,
): MarkerOptions =
MarkerOptions().apply {
position(LatLng(m.coordinate.latitude, m.coordinate.longitude))
Expand All @@ -46,10 +47,13 @@ class MarkerBuilder(
fun buildIconAsync(
id: String,
m: RNMarker,
onReady: (BitmapDescriptor) -> Unit,
onReady: (BitmapDescriptor?) -> Unit,
) {
jobsById[id]?.cancel()

if (m.iconSvg == null) {
onReady(null)
return
}
val key = m.styleHash()
iconCache.get(key)?.let { cached ->
onReady(cached)
Expand Down Expand Up @@ -98,17 +102,28 @@ class MarkerBuilder(

private suspend fun renderBitmap(m: RNMarker): Bitmap? {
var bmp: Bitmap? = null
if (m.iconSvg == null) {
return null
}
try {
coroutineContext.ensureActive()
val svg = SVG.getFromString(m.iconSvg)
val svg = SVG.getFromString(m.iconSvg.svgString)

coroutineContext.ensureActive()
svg.setDocumentWidth(m.width.dpToPx())
svg.setDocumentHeight(m.height.dpToPx())
svg.setDocumentWidth(m.iconSvg.width.dpToPx())
svg.setDocumentHeight(m.iconSvg.height.dpToPx())

coroutineContext.ensureActive()
bmp =
createBitmap(m.width.dpToPx().toInt(), m.height.dpToPx().toInt(), Bitmap.Config.ARGB_8888)
createBitmap(
m.iconSvg.width
.dpToPx()
.toInt(),
m.iconSvg.height
.dpToPx()
.toInt(),
Bitmap.Config.ARGB_8888,
)

coroutineContext.ensureActive()
val canvas = Canvas(bmp)
Expand All @@ -125,22 +140,3 @@ class MarkerBuilder(
}
}
}

fun RNMarker.markerEquals(b: RNMarker): Boolean =
id == b.id &&
zIndex == b.zIndex &&
coordinate == b.coordinate &&
anchor == b.anchor &&
markerStyleEquals(b)

fun RNMarker.markerStyleEquals(b: RNMarker): Boolean =
width == b.width &&
height == b.height &&
iconSvg == b.iconSvg

fun RNMarker.styleHash(): Int =
arrayOf<Any?>(
width,
height,
iconSvg,
).contentHashCode()
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MapStyleOptions
import com.margelo.nitro.core.Promise
import com.rngooglemapsplus.extensions.circleEquals
import com.rngooglemapsplus.extensions.markerEquals
import com.rngooglemapsplus.extensions.markerStyleEquals
import com.rngooglemapsplus.extensions.polygonEquals
import com.rngooglemapsplus.extensions.polylineEquals
import com.rngooglemapsplus.extensions.toCameraPosition
Expand All @@ -23,7 +25,7 @@ class RNGoogleMapsPlusView(
private var locationHandler = LocationHandler(context)
private var playServiceHandler = PlayServicesHandler(context)

private val markerBuilder = MarkerBuilder()
private val markerBuilder = MapMarkerBuilder()
private val polylineBuilder = MapPolylineBuilder()
private val polygonBuilder = MapPolygonBuilder()
private val circleBuilder = MapCircleBuilder()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.rngooglemapsplus.extensions

import com.rngooglemapsplus.RNMarker

fun RNMarker.markerEquals(b: RNMarker): Boolean =
id == b.id &&
zIndex == b.zIndex &&
coordinate == b.coordinate &&
anchor == b.anchor &&
markerStyleEquals(b)

fun RNMarker.markerStyleEquals(b: RNMarker): Boolean = iconSvg == b.iconSvg

fun RNMarker.styleHash(): Int =
arrayOf<Any?>(
iconSvg,
).contentHashCode()
4 changes: 2 additions & 2 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2356,7 +2356,7 @@ PODS:
- React-perflogger (= 0.82.0-rc.4)
- React-utils (= 0.82.0-rc.4)
- SocketRocket
- RNGoogleMapsPlus (1.0.3-dev.0):
- RNGoogleMapsPlus (1.1.0-dev.1):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -2708,7 +2708,7 @@ SPEC CHECKSUMS:
ReactAppDependencyProvider: 1202b833d8cca6c917dabcf679837c34a9ca5723
ReactCodegen: 19febbd1fdc8928493972f8d5290f2952e14c9d2
ReactCommon: 2caf7281b37aa1ca389e18839dd594099efb1489
RNGoogleMapsPlus: f9d77f78190272ae61db89e5e424d735342fcddc
RNGoogleMapsPlus: 45deb9a3ba72d6557af3bfbf970f51de523364a1
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
SVGKit: 1ad7513f8c74d9652f94ed64ddecda1a23864dea
Yoga: 2fb906b2084fd388a52edae73c54c39c3f50e86c
Expand Down
11 changes: 8 additions & 3 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,14 @@ export const makeMarker = (id: number): RNMarker => ({
zIndex: id,
coordinate: randomCoordinates(37.7749, -122.4194, 0.2),
anchor: { x: 0.5, y: 1.0 },
width: (64 / 100) * 50,
height: (88 / 100) * 50,
iconSvg: makeSvgIcon(64, 88),
iconSvg:
id % 2 === 0
? {
width: (64 / 100) * 50,
height: (88 / 100) * 50,
svgString: makeSvgIcon(64, 88),
}
: undefined,
});

export default function App() {
Expand Down
23 changes: 16 additions & 7 deletions ios/MapMarkerBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ final class MapMarkerBuilder {
attributes: .concurrent
)

func build(_ m: RNMarker, icon: UIImage) -> GMSMarker {
func build(_ m: RNMarker, icon: UIImage?) -> GMSMarker {
let marker = GMSMarker(
position: CLLocationCoordinate2D(
latitude: m.coordinate.latitude,
Expand Down Expand Up @@ -40,6 +40,11 @@ final class MapMarkerBuilder {
) {
tasks[id]?.cancel()

if m.iconSvg == nil {
onReady(nil)
return
}

let key = m.styleHash()
if let cached = iconCache.object(forKey: key) {
onReady(cached)
Expand Down Expand Up @@ -85,7 +90,6 @@ final class MapMarkerBuilder {

if !prev.markerStyleEquals(next) {
buildIconAsync(next.id, next) { img in
guard let img else { return }
m.tracksViewChanges = true
m.icon = img
if prev.anchor?.x != next.anchor?.x || prev.anchor?.y != next.anchor?.y {
Expand Down Expand Up @@ -117,21 +121,26 @@ final class MapMarkerBuilder {
}

private func renderUIImage(_ m: RNMarker) async -> UIImage? {
await withTaskCancellationHandler(
guard let iconSvg = m.iconSvg else {
return nil
}

return await withTaskCancellationHandler(
operation: {
await withCheckedContinuation { cont in
await withCheckedContinuation {
(cont: CheckedContinuation<UIImage?, Never>) in
queue.async {
if Task.isCancelled {
cont.resume(returning: nil)
return
}

let targetW = max(1, Int(CGFloat(m.width)))
let targetH = max(1, Int(CGFloat(m.height)))
let targetW = max(1, Int(CGFloat(iconSvg.width)))
let targetH = max(1, Int(CGFloat(iconSvg.height)))
let size = CGSize(width: targetW, height: targetH)

guard
let data = m.iconSvg.data(using: .utf8),
let data = iconSvg.svgString.data(using: .utf8),
let svgImg = SVGKImage(data: data)
else {
cont.resume(returning: nil)
Expand Down
1 change: 0 additions & 1 deletion ios/RNGoogleMapsPlusView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ final class RNGoogleMapsPlusView: HybridRNGoogleMapsPlusViewSpec {
}
} else {
markerBuilder.buildIconAsync(next.id, next) { icon in
guard let icon else { return }
let marker = self.markerBuilder.build(next, icon: icon)
self.impl.addMarker(id: id, marker: marker)
}
Expand Down
11 changes: 6 additions & 5 deletions ios/extensions/RNMarker+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@ extension RNMarker {
}

func markerStyleEquals(_ b: RNMarker) -> Bool {
width == b.width && height == b.height
&& iconSvg == b.iconSvg
iconSvg?.width == b.iconSvg?.width && iconSvg?.height == b.iconSvg?.height
&& iconSvg?.svgString == b.iconSvg?.svgString

}

func styleHash() -> NSString {
var hasher = Hasher()
hasher.combine(width)
hasher.combine(height)
hasher.combine(iconSvg)
hasher.combine(iconSvg?.width)
hasher.combine(iconSvg?.height)
hasher.combine(iconSvg?.svgString)
return String(hasher.finalize()) as NSString
}
}
6 changes: 5 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,13 @@ export type RNMarker = {
zIndex?: number;
coordinate: RNLatLng;
anchor?: RNPosition;
iconSvg?: RNMarkerSvg;
};

export type RNMarkerSvg = {
width: number;
height: number;
iconSvg: string;
svgString: string;
};

export type RNPolygon = {
Expand Down
Loading