All files / components/custom SuccessStoryMap.tsx

47.36% Statements 9/19
0% Branches 0/24
80% Functions 4/5
47.36% Lines 9/19

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 1171x                         1x                   1x                                                                         1x       5x                                   10x           1x 1x             1x                                        
"use client";
 
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import MarkerClusterGroup from "react-leaflet-markercluster"; // This is correct
import "leaflet/dist/leaflet.css";
import "leaflet.markercluster/dist/MarkerCluster.css";
import "leaflet.markercluster/dist/MarkerCluster.Default.css";
import L from "leaflet";
import { ZoomControl } from "react-leaflet";
import { Tooltip } from "react-leaflet";
 
 
// Custom marker icon
const customIcon = L.icon({
  iconUrl: "/map-marker.png",
  iconSize: [30, 42],
  iconAnchor: [15, 42],
  popupAnchor: [0, -42],
  shadowUrl: "/shadow.png",
  shadowSize: [40, 40],
});
 
// Function to create a custom cluster icon
const createClusterCustomIcon = (cluster: any) => {
  const count = cluster.getChildCount();
  let size = "small";
  let color = "#007bff"; // Default: Blue
 
  if (count > 50) {
    size = "large";
    color = "#dc3545"; // Red for large clusters
  } else if (count > 20) {
    size = "medium";
    color = "#fd7e14"; // Orange for medium clusters
  }
 
  return L.divIcon({
    html: `
      <div class="cluster-${size}" style="
        background: ${color};
        width: ${size === "large" ? 50 : size === "medium" ? 40 : 30}px;
        height: ${size === "large" ? 50 : size === "medium" ? 40 : 30}px;
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: 50%;
        color: white;
        font-weight: bold;
        font-size: ${size === "large" ? "16px" : size === "medium" ? "14px" : "12px"};
        text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
        box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
      ">
        ${count}
      </div>
    `,
    className: "custom-cluster-icon",
    iconSize: [size === "large" ? 50 : size === "medium" ? 40 : 30, size === "large" ? 50 : size === "medium" ? 40 : 30],
  });
};
 
const defaultPosition: [number, number] = [20, 77]; // India-centered
 
export default function SuccessStoryMap({ markers }: { markers: { lat: string; lon: string; name: string }[] }) {
 
  return (
    <div className="w-full h-96 mb-8">
      <MapContainer center={defaultPosition} zoom={4} className="w-full h-full rounded-md shadow-lg" scrollWheelZoom={true} zoomControl={false}>
        <TileLayer
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
          attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
        />
 
        <MarkerClusterGroup 
          iconCreateFunction={createClusterCustomIcon} 
          spiderfyOnMaxZoom={true} // Disable spiderfying on max zoom (you can enable it if needed)
          maxClusterRadius={40} // Set the max cluster radius in pixels (distance for clustering before de-clustering)
          showCoverageOnHover={true} // Hide coverage on hover
          removeOutsideVisibleBounds={true} // Automatically remove markers outside of visible bounds
          animate={true} // Enabling animation on declusterization
        >
          {markers.map((marker, index) => (
 
            <Marker
              key={index}
              position={[parseFloat(marker.lat), parseFloat(marker.lon)]} // Convert to number
              icon={customIcon}
              eventHandlers={{
                click: (e) => {
                  e.target.openPopup(); // Open popup on marker click
                  e.target.setIcon(L.icon({
                    iconUrl: "/map-marker.svg",
                    iconSize: [40, 52], // Larger size when clicked
                    iconAnchor: [20, 52],
                  }));
                },
                mouseout: (e) => {
                  e.target.setIcon(customIcon); // Revert to original icon on mouseout
                }
              }}
             >
              <Tooltip direction="top" offset={[0, -20]} opacity={1}>
                <span>{marker.name}</span>
              </Tooltip>
              <Popup>
                <strong>{marker.name}</strong> <br />
                Lat: {parseFloat(marker.lat).toFixed(6)}, Lon: {parseFloat(marker.lon).toFixed(6)}
              </Popup>
            </Marker>
 
          ))}
        </MarkerClusterGroup>
        <ZoomControl position="bottomleft" />
      </MapContainer>
    </div>
  );
}