JiriHoffmann / react-native-clusterer

React Native clustering library using C++ Supercluster implementation
MIT License
159 stars 20 forks source link

Points become little blue dots #40

Open Denissavv opened 8 months ago

Denissavv commented 8 months ago

When I zoom-in or zoom-out, some points feels like trying to become cluster, but turn on into a little blue points.

Снимок экрана 2024-03-12 в 11 32 35

When I add key (as it shown in the example - key={item.properties?.cluster_id ?? point-${item.properties?.id}} - blue points appear, when I remove key - the issue is fix, but I guess that clusters and points re-render every map changing position.

JiriHoffmann commented 8 months ago

This is most likely an issue with your rendering of map markers - unsure what else could be causing this issue without seeing the code.

Denissavv commented 8 months ago

Sorry for my poor question, let me try to show you the whole implementation:

im using import { YaMap } from 'react-native-yamap';

the thing is - there is no latitudeDelta and longitudeDelta after changing position of maps camera, so I calculated myself.

export const getRegionForZoom = (lat: number, lon: number, zoom: number): MapRegion => {
  const distanceDelta = Math.exp(Math.log(360) - zoom * Math.LN2);
  const { width, height } = Dimensions.get('window');
  const aspectRatio = width / height;
  return {
    latitude: lat,
    longitude: lon,
    latitudeDelta: distanceDelta * aspectRatio,
    longitudeDelta: distanceDelta,
  };
}
const [westLng, setWestLng] = useState(INITIAL_WEST_LNG);
  const [southLat, setSouthLat] = useState(INITIAL_SOUTH_LAT);
  const [eastLng, setEastLng] = useState(INITIAL_EAST_LNG);
  const [northLat, setNorthLat] = useState(INITIAL_NORTH_LAT);

  const convertedArray: IFeature[] = points
    .filter((data) => data.location.longitude !== '0' || data.location.latitude !== '0')
    .map((item) => ({
      type: 'Feature' as const,
      geometry: {
        type: 'Point' as const,
        coordinates: [+item.location.longitude, +item.location.latitude],
      },
      properties: {
        ...item,
        ...item.location,
        ...item.owner,
        id: item._id,
        data: item,
      },
    }));

  const superCluster = new Supercluster(superclusterOptions);
  superCluster.load(convertedArray);

  const clustersAndPoints = superCluster.getClusters([westLng, southLat, eastLng, northLat], zoom);

my render is looks like:

  return (
    <YaMap
      ref={mapRef}
      logoPadding={{ vertical: 670, horizontal: 30 }}
      showUserPosition={false}
      initialRegion={{ lon: MoscowPoint.lon, lat: MoscowPoint.lat }}
      style={RN.StyleSheet.absoluteFillObject}
      onLayout={() => setMapIsReady(true)}
      onCameraPositionChangeEnd={(event) => {
        if (event.nativeEvent.finished) {
          setWestLng(INITIAL_WEST_LNG);
          setSouthLat(INITIAL_SOUTH_LAT);
          setEastLng(INITIAL_EAST_LNG);
          setNorthLat(INITIAL_NORTH_LAT);
          mapRef.current?.getCameraPosition((position) => {
            const { lat, lon } = position.point;
            const { zoom } = position;

            handleChangeRegion({
              ...getRegionForZoom(lat, lon, zoom),
            });
            handleChangeZoom(position.zoom);
          });
        }
      }}
    >
      <UserLocationMarker />
      <Clusterer
        data={clustersAndPoints}
        region={region}
        options={{
          radius: 20,
          extent: 600,
          minPoints: 3,
          minZoom: 0,
        }}
        mapDimensions={MAP_DIMENSIONS}
        renderItem={(item) => {
          const clusterId: number = item.properties?.cluster && item.properties?.cluster_id;
          const markerId: string = item.properties?.id;

          return (
            <ClusterAndMarkerPoint
              points={clustersAndPoints}
              clusterId={clusterId}
              markerId={markerId}
              item={item}
              onPress={
                item?.properties?.cluster &&
                item?.properties?.cluster_id !== null &&
                (() => {
                  const clusterId = item?.properties?.cluster_id;
                  const clusterArr: Array<number> = clustersAndPoints.map((data) => data.properties.cluster_id);
                  const isClusterExist = clusterArr.includes(clusterId);
                  const toCluster = {
                    lon: item?.geometry?.coordinates[0],
                    lat: item?.geometry?.coordinates[1],
                  };
                  if (clusterId !== undefined && isClusterExist) {
                    getClusterZoom(clusterId);
                  } else {
                    if (zoom < 7) {
                      handleChangeZoom(7, toCluster, 0.6);
                    } else if (zoom < 10 && zoom > 7) {
                      handleChangeZoom(10, toCluster, 0.6);
                    } else {
                      handleChangeZoom(zoom + 3, toCluster, 0.6);
                    }
                    console.warn(`No cluster with the specified id: ${clusterId}`);
                  }
                })
              }
            />
          );
        }}
      />
    </YaMap>
  )

and my ClusterAndMarkerPoint:

  export const ClusterAndMarkerPoint: FunctionComponent<Props> = memo(
  ({ item, onPress, clusterId, markerId, points }) => {
    const [logoLoaded, setLogoLoaded] = React.useState(false);

    const clusterArr: Array<number> = points.map((data) => data.properties.cluster_id);

    const handlePress = useRecoilCallback(
      ({ get, set, reset }) =>
        (id: string) => {
          if (get(openedChargePointAtom)) {
            return;
          }

          set(openedChargePointAtom, id);
          chargersScreenBottomSheetsShowablePortal.current?.show(
            `DetailedChargePoint(id=${id})`,
            DetailedStationSheet,
            {
              chargePointId: id,
              onClose: () => {
                reset(openedChargePointAtom);
                mapRef.current?.getCameraPosition((position) => {
                  if (position.zoom > 10) {
                    mapRef.current?.setZoom(position.zoom - 1, 2, 1);
                  } else {
                    mapRef.current?.setZoom(position.zoom, 2, 1);
                  }
                });
              },
            }
          );
        },
      []
    );

    return (
      <YaMarker
        source={item?.properties?.logo_url && { uri: item?.properties?.logo_url }}
        key={clusterId || `${markerId + logoLoaded}`}
        point={{
          lat: +item.geometry.coordinates[1] || Number(item?.properties?.latitude),
          lon: +item.geometry.coordinates[0] || Number(item?.properties?.longitude),
        }}
        onPress={onPress || (() => handlePress(item?.properties?.id))}
      >
        {item?.properties?.cluster && clusterId ? (
          <ClusterComponent key={clusterId} clusterArr={clusterArr} item={item} />
        ) : (
          <>
            {item?.properties?.logo_url && (
              <PointComponent
                key={`${markerId + logoLoaded}`}
                markerId={markerId}
                logoUrl={item?.properties?.logo_url}
                logoLoaded={logoLoaded}
                setLogoLoaded={setLogoLoaded}
              />
            )}
          </>
        )}
      </YaMarker>
    );
  },
  (prevProps, nextProps) =>
    prevProps.item.properties?.cluster_id === nextProps.item.properties?.cluster_id &&
    prevProps.item.properties?.id === nextProps.item.properties?.id &&
    prevProps.item.properties?.point_count === nextProps.item.properties?.point_count &&
    prevProps.item.properties?.onPress === nextProps.item.properties?.onPress &&
    prevProps.item.properties?.getClusterExpansionRegion === nextProps.item.properties?.getClusterExpansionRegion &&
    prevProps.markerId === nextProps.markerId &&
    prevProps.clusterId === nextProps.clusterId
);