This repository was archived by the owner on Aug 7, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Change Map Clustering #7653
Merged
Merged
Change Map Clustering #7653
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
63c9b7a
Use supercluster for map clustering
dan-mba 17765a1
Handle missing bio or tags
dan-mba fe72692
fix overlap & update styling
dan-mba 7e919de
add preview workflow
dan-mba 9c8fb03
Setup push to preview
dan-mba 4e61422
Speed up isr for testing
dan-mba 4c1caf9
Change max zoom in for cluster onclick
dan-mba 09cbca2
adjust cluster radius
dan-mba 71bb950
attempt to spread out clusters at full zoom
dan-mba 4be84c2
Increase spread to try to elimnate clusters at full zoom
dan-mba ae8fe05
apply offset to 4 quadrants
dan-mba e46eec7
use seperate offsets for lat & lon
dan-mba 8e224fa
adjust cluster radius based on zoom level
dan-mba f24d987
fix marker link to profile
dan-mba d409c0f
fix maker popup link styling
dan-mba 7d00098
Update components/map/Clusters.module.css
dan-mba f0a5031
remove leaflet.markercluster
dan-mba ac99a87
remove preview deployment
dan-mba 93f8d23
remove testing isr revalidate time
dan-mba File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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} /> | ||
); | ||
})} | ||
</> | ||
) | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
) | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.