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 117 | 1x 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='© <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>
);
}
|