tomekvenits / react-native-map-clustering

React Native map clustering both for Android and iOS.
700 stars 226 forks source link

Performance Issue #226

Open ezzcodeezzlife opened 3 years ago

ezzcodeezzlife commented 3 years ago

Im loading some markers from the Overpass API (OpenStreetMap) and showing them in a ClusterMap. Although Markers are clustered now, the App has a bad performace and high interactivity latency. Is it possible to get better interactivity?

Expo: https://expo.dev/@ezcodeezlife/markercluster-test

Code:

import React, { useEffect, useState } from 'react';
import { ActivityIndicator, FlatList, Text, View, StyleSheet  } from 'react-native';
import { Marker } from 'react-native-maps'; 
import { ClusterMap, AnimatedRegion  } from 'react-native-cluster-map'; 

//This function was provided here: https://github.com/react-native-maps/react-native-maps/issues/356
export const getBoundByRegion = (region, scale = 1) => {
  /*
  * Latitude : max/min +90 to -90
  * Longitude : max/min +180 to -180
  */
  // Of course we can do it mo compact but it wait is more obvious
  const calcMinLatByOffset = (lng, offset) => {
    const factValue = lng - offset;
    if (factValue < -90) {
      return (90 + offset) * -1;
    }
    return factValue;
  };

  const calcMaxLatByOffset = (lng, offset) => {
    const factValue = lng + offset;
    if (90 < factValue) {
      return (90 - offset) * -1;
    }
    return factValue;
  };

  const calcMinLngByOffset = (lng, offset) => {
    const factValue = lng - offset;
    if (factValue < -180) {
      return (180 + offset) * -1;
    }
    return factValue;
  };

  const calcMaxLngByOffset = (lng, offset) => {
    const factValue = lng + offset;
    if (180 < factValue) {
      return (180 - offset) * -1;
    }
    return factValue;
  };

  const latOffset = region.latitudeDelta / 2 * scale;
  const lngD = (region.longitudeDelta < -180) ? 360 + region.longitudeDelta : region.longitudeDelta;
  const lngOffset = lngD / 2 * scale;

  return {
    minLng: calcMinLngByOffset(region.longitude, lngOffset), // westLng - min lng
    minLat: calcMinLatByOffset(region.latitude, latOffset), // southLat - min lat
    maxLng: calcMaxLngByOffset(region.longitude, lngOffset), // eastLng - max lng
    maxLat: calcMaxLatByOffset(region.latitude, latOffset),// northLat - max lat
  }
}

export default App = () => {
  const [isLoading, setLoading] = useState(true);
  const [data, setData] = useState([]);
  const [region, setRegion] = useState({
    latitude: 50.22364,
    longitude: 8.4491,
    latitudeDelta: 0.0922,
    longitudeDelta: 0.0421,
  });

  const getBenches = async () => {
     try {
      const response = await fetch('https://overpass.openstreetmap.fr/api/interpreter?data=[out:json];(node[%27amenity%27=%27bench%27](50.22364307664712,8.449115594560567,50.24036141038248,8.46567765838438);node[%27leisure%27=%27picnic_table%27](50.22364307664712,8.449115594560567,50.24036141038248,8.46567765838438););out%20body;');
      const json = await response.json();
      setData(json);
    } catch (error) {
      console.error(error);
    } finally {
      setLoading(false);
    }
  }

  const getNewBenches = async (bounds) => {
    try {
     const response = await fetch("https://overpass.openstreetmap.fr/api/interpreter?data=[out:json];node[%27amenity%27=%27bench%27](" + bounds.minLat +"," + bounds.minLng + "," + bounds.maxLat + "," + bounds.maxLng + ");out%20body;");
     const json = await response.json();
     setData(json);
   } catch (error) {
     console.error(error);
   } finally {
   }
 }
  useEffect(() => {
    getBenches();
  }, []);

  if(isLoading == false) {
    return (
      <>
        <View>
          <ClusterMap 
            style={styles.container}
            region={ region }
            mapType={"satellite"}
            onRegionChangeComplete={(region) => {
              setRegion(region);
              getNewBenches(getBoundByRegion(region));
            } }
            //onMapReady={() => onMapReady()}
          >
            {data.elements.map((marker) => (
              <Marker
               tracksViewChanges={false}
               key={marker.id}
               coordinate={{ latitude: marker.lat, longitude:  marker.lon }}
              />
            ))}
        </ClusterMap >
        </View>
      </>
    )
  } else {
    return (
      <View>
        <ActivityIndicator />
      </View>
    )
  }
};

const styles = StyleSheet.create({
  container: {
    position: 'absolute',
    height : 400,
    width : 400,
    justifyContent: 'flex-end',
    alignItems: 'center',
}
}); 
ramisalem commented 3 years ago

Same issue

KHadham commented 1 year ago

same issue here with more than 200.000 data also affected in navigation ,it's become slow

vegetablesalad commented 1 year ago

I have really weird issue on Android. Just with 100 markers map seems to freeze for a second every time clusters are recalculated. iOS runs smooth without any issues. I don't render any custom cluster views, just with the default

0xcD3v commented 1 year ago

Did you guys solved this issue?

ezzcodeezzlife commented 1 year ago

@0xcD3v no not yet :)

0xcD3v commented 1 year ago

@0xcD3v no not yet :)

i tought my problem was not having the tracksViewChanges set to false i tried to set it to false and then my marker doesn't fully render on UI i have a component and an image inside of marker componenet.