Search code examples
javascriptandroidiosreact-nativereact-native-maps

Detect if marker is in view point


I am working with react-native-maps. I have a list of items i am displaying it in a map as markers. How can I detect if the marker is in view of the user searching in the map. I tried using react-native-component-inview package, but it is not working. This is my code for the complete MapView

<MapView
  ref={mapRef}
  provider="google"
  initialRegion={tripdata.pickup ? initialRegion : qatarRegion}
  onRegionChange={onRegionChange}
  onRegionChangeComplete={onRegionChangeComplete}
 >
        {mapAds
          ? mapAds.map((item, index) => {
              return (
                <Marker
                  onPress={() => mapEngagement(item.id)}
                  coordinate={{
                    latitude: item.lat ? item.lat : 0.0,
                    longitude: item.lng ? item.lng : 0.0,
                  }}
                  key={index}
                >
                  <TouchableOpacity
                    style={{
                      width: 50,
                      height: 50,
                      backgroundColor: colors.GREY.YELLOW,
                      borderRadius: 100,
                      justifyContent: "center",
                      alignItems: "center",
                    }}
                  >
                    <Image
                      source={{
                        uri: item.logo
                          ? item.logo
                          : "https://firebasestorage.googleapis.com/v0/b/faroutdrive001.appspot.com/o/corporations%2F-McAZ_l4YQ4X4Hg71dTF%2Flogo?alt=media&token=de3aff61-0deb-4cea-a3f0-0e0b491146b1",
                      }}
                      style={{
                        height: 47,
                        width: 47,
                        zIndex: 2,
                        borderRadius: 100,
                      }}
                    />
                    {/* <Text>{visible}</Text> */}
                  </TouchableOpacity>
                  <Callout tooltip>
                    <View style={{ padding: 3 }}>
                      <TouchableOpacity
                        style={{
                          backgroundColor: colors.GREY.YELLOW,
                          justifyContent: "space-evenly",
                          alignItems: "center",
                          minWidth: 120,
                          maxWidth: 150,
                          minHeight: 50,
                          borderRadius: 10,
                        }}
                      >
                        <Text style={{ color: colors.WHITE }}>
                          {item.ad_name ? item.ad_name : "Advertise Here"}
                        </Text>
                        <Text style={{ color: colors.WHITE, fontSize: 12 }}>
                          {item.ad_description ? item.ad_description : ""}
                        </Text>
                      </TouchableOpacity>
                    </View>
                  </Callout>
                </Marker>
              );
            })
          : null}
</MapView>

Solution

  • The problem space you're describing is referred to as the "point in polygon" problem. Basically your map view has implied latitude/longitude boundaries and you need to know whether a point (i.e. your marker) is contained in the polygon (your map view boundaries).

    There are several ways to go about it. Long story short, unless you want to learn about and implement geographical math and algorithms involving geodesics and haversine formulas, I would recommend you instead leverage a good package to do the hard part. I used TurfJS to do this. I don't represent them in any way or their community, but it seems to be well made and I've enjoyed using both the JS and Java implementations to solve problems like this.

    For this particular problem, I'd refer you to here:

    https://www.npmjs.com/package/@turf/boolean-point-in-polygon

    Basically you're going to want to use the example they provided which I'm copying here for posterity in case the link changes:

    var pt = turf.point([-77, 44]);
    var poly = turf.polygon([[
      [-81, 41],
      [-81, 47],
      [-72, 47],
      [-72, 41],
      [-81, 41]
    ]]);
    
    turf.booleanPointInPolygon(pt, poly);
    //= true
    

    NOTE: Be careful to point lat/lng correctly for whatever library you're using!

    For you, polygon will be the Map's boundary points. Note, the library doesn't assume you have a nice, neat "4 pointed square" map view (of course, on earth it's not exactly a square), but you would need to translate the 4 pointed square of your map view into the 5 edge points. (first and last point are the same).

    You would then translate your marker's lat/lng into "pt" and use that to ask the question of the engine.

    The result should be an intuitive true/false for whether your point (the marker) is in the boundary (mapview).

    Another Note. Watch out for how to specify the boundary points. Click through the link in the page where it talks about "Polygon / Multipolygon". You want to follow the Polygon rules for a simple MapView. If you specify the boundary points in a bad order, it may interpret it in an unexpected and completely confusing way.

    The link to Polygon talks about it in excruciating detail, but I would draw your attention to the following part of it:

    3.1.6.  Polygon
    
       To specify a constraint specific to Polygons....
    
       o  A linear ring MUST follow the right-hand rule with respect to the
          area it bounds, i.e., exterior rings are counterclockwise...