1 | # useSupercluster
|
2 |
|
3 | A hook for using [Supercluster](https://github.com/mapbox/supercluster) with React.
|
4 |
|
5 | ```js
|
6 | const { clusters, supercluster } = useSupercluster({
|
7 | points: [],
|
8 | bounds: [
|
9 | -1.2411810957931664,
|
10 | 52.61208435908725,
|
11 | -1.0083656811012531,
|
12 | 52.64495957533833,
|
13 | ],
|
14 | zoom: 12,
|
15 | options: { radius: 75, maxZoom: 20 },
|
16 | });
|
17 | ```
|
18 |
|
19 | ## Installation
|
20 |
|
21 | You will need to install `supercluster` as a peer dependency of this package.
|
22 |
|
23 | ```txt
|
24 | yarn add supercluster use-supercluster
|
25 | ```
|
26 |
|
27 | ## Examples
|
28 |
|
29 | This package contains an example along with tests, but full examples with instructions in the most popular mapping libraries for React can be found below.
|
30 |
|
31 | ### Mapbox
|
32 |
|
33 | Full instructions and an [example can be found here](https://www.leighhalliday.com/mapbox-clustering).
|
34 |
|
35 | ### Google Maps
|
36 |
|
37 | Full instructions and an [example can be found here](https://www.leighhalliday.com/google-maps-clustering).
|
38 |
|
39 | ### Leaflet
|
40 |
|
41 | Full instructions and an [example can be found here](https://www.leighhalliday.com/leaflet-clustering).
|
42 |
|
43 | ## Configuration
|
44 |
|
45 | The last (fourth) argument passed to the `useSupercluster` hook are options that are passed directly to the instance of Supercluster. You can use any of [Supercluster's options](https://github.com/mapbox/supercluster#options).
|
46 |
|
47 | ### Map & Reduce Options
|
48 |
|
49 | As an example, you can use `map` and `reduce` to keep track of a total value summed up from across the points. In this case we have the total `cost`, the max `severity`, plus another `count` (which is redundant because Supercluster gives us the `point_count` property).
|
50 |
|
51 | ```js
|
52 | const options = {
|
53 | radius: 75,
|
54 | maxZoom: 20,
|
55 | map: (props) => ({
|
56 | cost: props.cost,
|
57 | severity: props.severity,
|
58 | count: 1,
|
59 | }),
|
60 | reduce: (acc, props) => {
|
61 | acc.count += 1;
|
62 | acc.cost += props.cost;
|
63 | acc.severity = Math.max(acc.severity, props.severity);
|
64 | return acc;
|
65 | },
|
66 | };
|
67 | ```
|
68 |
|
69 | I found `map` and `reduce` a little confusing! The value returned from `map` of the first point is used as the initial value passed as the accumulator to the `reduce` function. The only `props` you have available in `reduce` are the ones returned from `map`. You technically don't need to return a value from `reduce` (it's not used), but instead need to mutate the accumulator object.
|
70 |
|
71 | Then these accumulated properties can be used and are available on each cluster:
|
72 |
|
73 | ```jsx
|
74 | <ul>
|
75 | {clusters.map((point) => {
|
76 | const properties = point.properties || {};
|
77 | if (properties.cluster) {
|
78 | return (
|
79 | <li key={point.id}>
|
80 | <h2>Points: {properties.point_count}</h2>
|
81 | <p>Cost: {properties.cost.toFixed(2)}</p>
|
82 | <p>Severity: {properties.severity}</p>
|
83 | <p>Count: {properties.count}</p>
|
84 | </li>
|
85 | );
|
86 | } else {
|
87 | return <li key={properties.crimeId}>{properties.category}</li>;
|
88 | }
|
89 | })}
|
90 | </ul>
|
91 | ```
|