0
# Addon Extensions
1
2
Third-party addon components that extend Google Maps functionality with enhanced features like marker clustering, custom info boxes, and labeled markers. These components require additional dependencies.
3
4
## Capabilities
5
6
### InfoBox
7
8
Enhanced info window component with advanced styling and positioning options. Requires the `google-maps-infobox` package.
9
10
```javascript { .api }
11
/**
12
* Enhanced info window with advanced styling options
13
* Requires: npm install google-maps-infobox
14
*/
15
class InfoBox extends Component<InfoBoxProps> {}
16
17
interface InfoBoxProps {
18
// Default props
19
defaultOptions?: InfoBoxOptions;
20
defaultPosition?: google.maps.LatLng;
21
defaultVisible?: boolean;
22
defaultZIndex?: number;
23
24
// Controlled props
25
options?: InfoBoxOptions;
26
position?: google.maps.LatLng;
27
visible?: boolean;
28
zIndex?: number;
29
30
// Event handlers
31
onCloseClick?(): void;
32
onContentChanged?(): void;
33
onDomReady?(): void;
34
onPositionChanged?(): void;
35
onZindexChanged?(): void;
36
}
37
```
38
39
**Usage Example:**
40
41
```javascript
42
import InfoBox from "react-google-maps/lib/components/addons/InfoBox";
43
44
<GoogleMap defaultZoom={10} defaultCenter={{ lat: 37.7749, lng: -122.4194 }}>
45
<Marker position={{ lat: 37.7749, lng: -122.4194 }} />
46
47
<InfoBox
48
position={{ lat: 37.7749, lng: -122.4194 }}
49
options={{
50
content: `
51
<div style="background: white; padding: 12px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.2);">
52
<h3 style="margin: 0 0 8px 0;">San Francisco</h3>
53
<p style="margin: 0;">The City by the Bay</p>
54
</div>
55
`,
56
disableAutoPan: false,
57
maxWidth: 0,
58
pixelOffset: { width: -140, height: 0 },
59
zIndex: null,
60
boxStyle: {
61
background: "url('tipbox.gif') no-repeat",
62
opacity: 0.75,
63
width: "280px"
64
},
65
closeBoxMargin: "10px 2px 2px 2px",
66
closeBoxURL: "http://www.google.com/intl/en_us/mapfiles/close.gif",
67
infoBoxClearance: { width: 50, height: 200 }
68
}}
69
onCloseClick={() => {
70
console.log("InfoBox closed");
71
}}
72
/>
73
</GoogleMap>
74
```
75
76
### MarkerClusterer
77
78
Component for clustering markers when they are close together at low zoom levels. Requires the `marker-clusterer-plus` package.
79
80
```javascript { .api }
81
/**
82
* Marker clustering component for managing large numbers of markers
83
* Requires: npm install marker-clusterer-plus
84
*/
85
class MarkerClusterer extends Component<MarkerClustererProps> {}
86
87
interface MarkerClustererProps {
88
// Default clustering options
89
defaultAverageCenter?: boolean;
90
defaultBatchSizeIE?: number;
91
defaultBatchSize?: number;
92
defaultCalculator?: Calculator;
93
defaultClusterClass?: string;
94
defaultEnableRetinaIcons?: boolean;
95
defaultGridSize?: number;
96
defaultIgnoreHidden?: boolean;
97
defaultImageExtension?: string;
98
defaultImagePath?: string;
99
defaultImageSizes?: number[];
100
defaultMaxZoom?: number;
101
defaultMinimumClusterSize?: number;
102
defaultStyles?: ClusterIconStyle[];
103
defaultTitle?: string;
104
defaultZoomOnClick?: boolean;
105
106
// Controlled clustering options
107
averageCenter?: boolean;
108
batchSizeIE?: number;
109
batchSize?: number;
110
calculator?: Calculator;
111
clusterClass?: string;
112
enableRetinaIcons?: boolean;
113
gridSize?: number;
114
ignoreHidden?: boolean;
115
imageExtension?: string;
116
imagePath?: string;
117
imageSizes?: number[];
118
maxZoom?: number;
119
minimumClusterSize?: number;
120
styles?: ClusterIconStyle[];
121
title?: string;
122
zoomOnClick?: boolean;
123
124
// Event handlers
125
onClick?(cluster: Cluster): void;
126
onClusteringBegin?(mc: MarkerClusterer): void;
127
onClusteringEnd?(mc: MarkerClusterer): void;
128
onMouseOut?(c: Cluster): void;
129
onMouseOver?(c: Cluster): void;
130
}
131
```
132
133
**Usage Example:**
134
135
```javascript
136
import MarkerClusterer from "react-google-maps/lib/components/addons/MarkerClusterer";
137
138
const ClusteredMarkers = () => {
139
const [markers] = useState([
140
{ lat: 37.7749, lng: -122.4194, id: 1 },
141
{ lat: 37.7849, lng: -122.4094, id: 2 },
142
{ lat: 37.7649, lng: -122.4294, id: 3 },
143
// ... many more markers
144
]);
145
146
return (
147
<GoogleMap defaultZoom={10} defaultCenter={{ lat: 37.7749, lng: -122.4194 }}>
148
<MarkerClusterer
149
averageCenter={true}
150
enableRetinaIcons={true}
151
gridSize={60}
152
maxZoom={15}
153
minimumClusterSize={2}
154
styles={[
155
{
156
textColor: 'white',
157
url: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m1.png',
158
height: 53,
159
width: 53
160
},
161
{
162
textColor: 'white',
163
url: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m2.png',
164
height: 56,
165
width: 56
166
},
167
{
168
textColor: 'white',
169
url: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m3.png',
170
height: 66,
171
width: 66
172
}
173
]}
174
onClick={(cluster) => {
175
console.log(`Cluster clicked with ${cluster.getMarkers().length} markers`);
176
}}
177
onClusteringEnd={(markerClusterer) => {
178
console.log(`Clustering complete: ${markerClusterer.getClusters().length} clusters`);
179
}}
180
>
181
{markers.map((marker) => (
182
<Marker
183
key={marker.id}
184
position={{ lat: marker.lat, lng: marker.lng }}
185
title={`Marker ${marker.id}`}
186
/>
187
))}
188
</MarkerClusterer>
189
</GoogleMap>
190
);
191
};
192
```
193
194
### MarkerWithLabel
195
196
Enhanced marker component with custom label styling. Requires the `markerwithlabel` package and extends the standard Marker props.
197
198
```javascript { .api }
199
/**
200
* Marker with custom label styling
201
* Requires: npm install markerwithlabel
202
* Extends MarkerProps with additional label properties
203
*/
204
class MarkerWithLabel extends Component<MarkerProps> {}
205
206
// Extends MarkerProps with these additional properties:
207
interface MarkerLabelProps extends MarkerProps {
208
/** Custom label class for styling */
209
labelClass?: string;
210
/** Anchor point for the label */
211
labelAnchor?: google.maps.Point;
212
/** Text content of the label */
213
labelContent?: string;
214
/** Inline styles for the label */
215
labelStyle?: CSSStyleDeclaration;
216
/** Callback when marker with label functionality is ready */
217
markerWithLabel?(): void;
218
}
219
```
220
221
**Usage Example:**
222
223
```javascript
224
import MarkerWithLabel from "react-google-maps/lib/components/addons/MarkerWithLabel";
225
226
<GoogleMap defaultZoom={10} defaultCenter={{ lat: 37.7749, lng: -122.4194 }}>
227
<MarkerWithLabel
228
position={{ lat: 37.7749, lng: -122.4194 }}
229
labelAnchor={new google.maps.Point(0, 0)}
230
labelContent="San Francisco"
231
labelStyle={{
232
backgroundColor: "yellow",
233
fontSize: "14px",
234
padding: "4px",
235
borderRadius: "4px",
236
border: "1px solid #333"
237
}}
238
icon={{
239
url: "https://maps.google.com/mapfiles/ms/icons/blue-dot.png"
240
}}
241
onClick={() => {
242
console.log("Labeled marker clicked");
243
}}
244
/>
245
246
<MarkerWithLabel
247
position={{ lat: 37.7649, lng: -122.4294 }}
248
labelContent="Custom Location"
249
labelClass="custom-label"
250
labelAnchor={new google.maps.Point(30, 0)}
251
icon={{
252
url: "https://maps.google.com/mapfiles/ms/icons/red-dot.png"
253
}}
254
/>
255
</GoogleMap>
256
```
257
258
## Addon Installation and Setup
259
260
### Installing Dependencies
261
262
Each addon requires its corresponding npm package:
263
264
```bash
265
# For InfoBox
266
npm install google-maps-infobox
267
268
# For MarkerClusterer
269
npm install marker-clusterer-plus
270
271
# For MarkerWithLabel
272
npm install markerwithlabel
273
274
# Install all addons
275
npm install google-maps-infobox marker-clusterer-plus markerwithlabel
276
```
277
278
### Importing Addon Components
279
280
Addon components must be imported directly from their specific paths:
281
282
```javascript
283
// Correct imports for addons
284
import InfoBox from "react-google-maps/lib/components/addons/InfoBox";
285
import MarkerClusterer from "react-google-maps/lib/components/addons/MarkerClusterer";
286
import MarkerWithLabel from "react-google-maps/lib/components/addons/MarkerWithLabel";
287
288
// These will NOT work - addons are not in main exports
289
import { InfoBox, MarkerClusterer, MarkerWithLabel } from "react-google-maps"; // ❌
290
```
291
292
## Advanced Addon Patterns
293
294
### Combining Clustering with Custom InfoBox
295
296
```javascript
297
const AdvancedMarkerMap = () => {
298
const [selectedMarker, setSelectedMarker] = useState(null);
299
const [markers] = useState(/* large array of markers */);
300
301
return (
302
<GoogleMap defaultZoom={10} defaultCenter={{ lat: 37.7749, lng: -122.4194 }}>
303
<MarkerClusterer
304
onClick={(cluster) => {
305
// Zoom into cluster
306
const bounds = new google.maps.LatLngBounds();
307
cluster.getMarkers().forEach(marker => {
308
bounds.extend(marker.getPosition());
309
});
310
map.fitBounds(bounds);
311
}}
312
>
313
{markers.map((marker) => (
314
<Marker
315
key={marker.id}
316
position={marker.position}
317
onClick={() => setSelectedMarker(marker)}
318
/>
319
))}
320
</MarkerClusterer>
321
322
{selectedMarker && (
323
<InfoBox
324
position={selectedMarker.position}
325
options={{
326
content: `
327
<div class="custom-infobox">
328
<h3>${selectedMarker.title}</h3>
329
<p>${selectedMarker.description}</p>
330
<button onclick="closeInfoBox()">Close</button>
331
</div>
332
`
333
}}
334
onCloseClick={() => setSelectedMarker(null)}
335
/>
336
)}
337
</GoogleMap>
338
);
339
};
340
```
341
342
### Custom Cluster Styling
343
344
```javascript
345
const customClusterStyles = [
346
{
347
textColor: 'white',
348
textSize: 11,
349
url: 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(`
350
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40">
351
<circle cx="20" cy="20" r="18" fill="#ff6b6b" stroke="#fff" stroke-width="2"/>
352
</svg>
353
`),
354
height: 40,
355
width: 40
356
},
357
{
358
textColor: 'white',
359
textSize: 12,
360
url: 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(`
361
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">
362
<circle cx="25" cy="25" r="23" fill="#4ecdc4" stroke="#fff" stroke-width="2"/>
363
</svg>
364
`),
365
height: 50,
366
width: 50
367
}
368
];
369
370
<MarkerClusterer
371
styles={customClusterStyles}
372
calculator={(markers, numStyles) => {
373
const count = markers.length;
374
let index = 0;
375
if (count > 10) index = 1;
376
if (count > 100) index = 2;
377
return { text: count, index: index };
378
}}
379
>
380
{/* markers */}
381
</MarkerClusterer>
382
```