Skip to content
This repository was archived by the owner on Aug 7, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions components/map/Clusters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { useState } from "react";
import { Marker, useMap } from "react-leaflet";
import useSupercluster from "use-supercluster";
import UserMarker from "./UserMarker";
import styles from "./Clusters.module.css";

export default function Clusters({users}) {
const map = useMap();
const mapB = map.getBounds();
const [bounds, setBounds] = useState([
mapB.getSouthWest().lng,
mapB.getSouthWest().lat,
mapB.getNorthEast().lng,
mapB.getNorthEast().lat
]);
const [zoom, setZoom] = useState(map.getZoom());

function updateMap() {
const b = map.getBounds();
setBounds([
b.getSouthWest().lng,
b.getSouthWest().lat,
b.getNorthEast().lng,
b.getNorthEast().lat
]);
setZoom(map.getZoom());
}

map.on('moveend', function() {
updateMap();
})

const { clusters, supercluster } = useSupercluster({
points: users,
bounds,
zoom,
options: {
radius: zoom < 17 ? 75 : 50,
maxZoom: 18
}
});

const icons = {};
const fetchIcon = (count) => {
const size =
count < 25 ? 'small' :
count < 100 ? 'medium' : 'large';
if (!icons[count]) {
icons[count] = L.divIcon({
html: `<div><span>${count}</span></div>`,
className: `${styles['marker-cluster']} ${styles[size]}`,
iconSize: L.point(40, 40)
});
}
return icons[count];
};

return (
<>
{clusters.map(cluster => {
// every cluster point has coordinates
const [longitude, latitude] = cluster.geometry.coordinates;
// the point may be either a cluster or user
const {
cluster: isCluster,
point_count: pointCount,
username
} = cluster.properties;

// we have a cluster to render
if (isCluster) {
return (
<Marker
key={`cluster-${cluster.id}`}
position={[latitude, longitude]}
icon={fetchIcon(pointCount)}
eventHandlers={{
click: () => {
const expansionZoom = Math.min(
supercluster.getClusterExpansionZoom(cluster.id),
18
);
map.setView([latitude, longitude], expansionZoom, {
animate: true
});
}
}}
/>
);
}

// we have a single point to render
return (
<UserMarker user={cluster} key={username} />
);
})}
</>
)
}
39 changes: 39 additions & 0 deletions components/map/Clusters.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
.small {
background-color: rgba(181, 226, 140, 0.6);
}
.small div {
background-color: rgba(110, 204, 57, 0.6);
}

.medium {
background-color: rgba(241, 211, 87, 0.6);
}
.medium div {
background-color: rgba(240, 194, 12, 0.6);
}

.large {
background-color: rgba(253, 156, 115, 0.6);
}
.large div {
background-color: rgba(241, 128, 23, 0.6);
}

.marker-cluster {
background-clip: padding-box;
border-radius: 20px;
z-index: 100;
}
.marker-cluster div {
width: 30px;
height: 30px;
margin-left: 5px;
margin-top: 5px;

text-align: center;
border-radius: 15px;
font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif;
}
.marker-cluster span {
line-height: 30px;
}
74 changes: 19 additions & 55 deletions components/map/Map.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import { ReactMarkdown } from "react-markdown/lib/react-markdown";
import "leaflet/dist/leaflet.css";

import { MapContainer, TileLayer } from "react-leaflet";
import Link from "@components/Link";
import MarkerCluster from "@components/map/MarkerCluster";
import Clusters from "./Clusters";
import "leaflet/dist/leaflet.css";

export default function Map({ users }) {
const boundsMap = [
Expand All @@ -12,55 +10,21 @@ export default function Map({ users }) {
];

return (
<>
<MapContainer
center={[0, 0]}
zoom={2}
minZoom={2}
zoomControl={true}
scrollWheelZoom={true}
maxBounds={boundsMap}
maxBoundsViscosity={0.7}
style={{ height: "100vh" }}
>
<TileLayer
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://b.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<MarkerCluster>
{users.map((user) => (
<div key={user.username}>
<Marker
icon={L.icon({
className: "rounded-full",
iconUrl: `https://github.com/${user.username}.png`,
popupAnchor: [0, -10],
iconSize: [40, 40],
iconAnchor: [20, 20],
})}
position={[user.location.lat, user.location.lon]}
>
<Popup>
<div className="flex flex-col gap-[5px]">
<h1 className="font-[600]">
<Link
href={`https://linkfree.eddiehub.io/${user.username}`}
>
{user.name}
</Link>
</h1>
<span>{user.location.provided}</span>

<span>
<ReactMarkdown>{user.bio}</ReactMarkdown>
</span>
</div>
</Popup>
</Marker>
</div>
))}
</MarkerCluster>
</MapContainer>
</>
<MapContainer
center={[0, 0]}
zoom={2}
minZoom={2}
zoomControl={true}
scrollWheelZoom={true}
maxBounds={boundsMap}
maxBoundsViscosity={0.7}
style={{ height: "100vh" }}
>
<TileLayer
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://b.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Clusters users={users} />
</MapContainer>
);
}
33 changes: 0 additions & 33 deletions components/map/MarkerCluster.js

This file was deleted.

41 changes: 41 additions & 0 deletions components/map/UserMarker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Marker, Popup } from "react-leaflet";
import { ReactMarkdown } from "react-markdown/lib/react-markdown";
import Link from "@components/Link";

export default function UserMarker({user}) {
// Custom component for rendering links within ReactMarkdown
const LinkRenderer = ({ href, children }) => (
<Link href={href}>
{children}
</Link>
);

return (
<Marker
icon={L.icon({
className: "rounded-full",
iconUrl: `https://github.com/${user.properties.username}.png`,
popupAnchor: [0, -10],
iconSize: [40, 40],
iconAnchor: [20, 20],
})}
position={[user.geometry.coordinates[1], user.geometry.coordinates[0]]}
>
<Popup>
<div className="flex flex-col gap-[5px]">
<h1 className="font-[600]">
<Link
href={`https://linkfree.eddiehub.io/${user.properties.username}`}
>
{user.properties.name}
</Link>
</h1>
<span>{user.properties.location}</span>
<span>
<ReactMarkdown components={{ a: LinkRenderer }}>{user.properties.bio}</ReactMarkdown>
</span>
</div>
</Popup>
</Marker>
)
}
Loading