or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

clustering.mdcore-map.mddrawing-shapes.mdindex.mdlayers.mdmarkers-overlays.mdplaces.mdscript-loading.mdservices.md

clustering.mddocs/

0

# Marker Clustering

1

2

Components for grouping nearby markers into clusters to improve performance and user experience with large marker datasets. Includes both community and official Google clustering implementations, plus direct access to the Google Maps MarkerClusterer library.

3

4

## Capabilities

5

6

### MarkerClusterer Component

7

8

Community-driven marker clustering component that groups nearby markers into clusters for better performance and visual clarity.

9

10

```typescript { .api }

11

/**

12

* Groups nearby markers into clusters for better performance

13

* Community implementation with extensive customization options

14

*/

15

interface MarkerClustererProps {

16

children: React.ReactNode;

17

options?: ClustererOptions;

18

19

// Event handlers

20

onClusteringBegin?: (clusterer: Clusterer) => void;

21

onClusteringEnd?: (clusterer: Clusterer) => void;

22

onClick?: (cluster: Cluster) => void;

23

onMouseOver?: (cluster: Cluster) => void;

24

onMouseOut?: (cluster: Cluster) => void;

25

26

// Lifecycle events

27

onLoad?: (clusterer: Clusterer) => void;

28

onUnmount?: (clusterer: Clusterer) => void;

29

}

30

31

interface ClustererOptions {

32

gridSize?: number;

33

maxZoom?: number;

34

zoomOnClick?: boolean;

35

averageCenter?: boolean;

36

minimumClusterSize?: number;

37

styles?: ClusterIconStyle[];

38

calculator?: (markers: google.maps.Marker[], numStyles: number) => ClusterIconInfo;

39

ignoreHidden?: boolean;

40

enableRetinaIcons?: boolean;

41

imageExtension?: string;

42

imagePath?: string;

43

imageSizes?: number[];

44

title?: string;

45

}

46

47

function MarkerClusterer(props: MarkerClustererProps): JSX.Element;

48

function MarkerClustererF(props: MarkerClustererProps): JSX.Element;

49

50

// Community clusterer type definitions

51

interface Clusterer {

52

setAverageCenter(averageCenter: boolean): void;

53

setBatchSizeIE(batchSizeIE: number): void;

54

setCalculator(calculator: TCalculator): void;

55

setClusterClass(clusterClass: string): void;

56

setEnableRetinaIcons(enableRetinaIcons: boolean): void;

57

setGridSize(gridSize: number): void;

58

setIgnoreHidden(ignoreHidden: boolean): void;

59

setImageExtension(imageExtension: string): void;

60

setImagePath(imagePath: string): void;

61

setImageSizes(imageSizes: number[]): void;

62

setMaxZoom(maxZoom: number): void;

63

setMinimumClusterSize(minimumClusterSize: number): void;

64

setStyles(styles: ClusterIconStyle[]): void;

65

setTitle(title: string): void;

66

setZoomOnClick(zoomOnClick: boolean): void;

67

addMarker(marker: google.maps.Marker, nodraw?: boolean): void;

68

addMarkers(markers: google.maps.Marker[], nodraw?: boolean): void;

69

clearMarkers(): void;

70

getCalculator(): TCalculator;

71

getGridSize(): number;

72

getMap(): google.maps.Map;

73

getMarkers(): google.maps.Marker[];

74

getMaxZoom(): number;

75

getStyles(): ClusterIconStyle[];

76

getTotalClusters(): number;

77

getTotalMarkers(): number;

78

}

79

80

interface Cluster {

81

getCenter(): google.maps.LatLng;

82

getSize(): number;

83

getMarkers(): google.maps.Marker[];

84

}

85

86

interface ClusterIconInfo {

87

text: string;

88

index: number;

89

title?: string;

90

}

91

92

type TCalculator = (markers: google.maps.Marker[], numStyles: number) => ClusterIconInfo;

93

```

94

95

**Usage Examples:**

96

97

```typescript

98

import React, { useState, useMemo } from 'react';

99

import { GoogleMap, LoadScript, Marker, MarkerClusterer } from '@react-google-maps/api';

100

101

// Basic marker clustering

102

function BasicMarkerClustering() {

103

const markers = useMemo(() => {

104

const locations = [];

105

const center = { lat: 40.7128, lng: -74.0060 };

106

107

// Generate random markers around NYC

108

for (let i = 0; i < 100; i++) {

109

locations.push({

110

id: i,

111

position: {

112

lat: center.lat + (Math.random() - 0.5) * 0.2,

113

lng: center.lng + (Math.random() - 0.5) * 0.2

114

}

115

});

116

}

117

return locations;

118

}, []);

119

120

return (

121

<LoadScript googleMapsApiKey="YOUR_API_KEY">

122

<GoogleMap

123

center={{ lat: 40.7128, lng: -74.0060 }}

124

zoom={10}

125

mapContainerStyle={{ width: '100%', height: '400px' }}

126

>

127

<MarkerClusterer>

128

{markers.map(marker => (

129

<Marker

130

key={marker.id}

131

position={marker.position}

132

/>

133

))}

134

</MarkerClusterer>

135

</GoogleMap>

136

</LoadScript>

137

);

138

}

139

140

// Custom clustering with styled clusters

141

function CustomStyledClustering() {

142

const [clusterSize, setClusterSize] = useState(40);

143

144

const markers = useMemo(() => {

145

const locations = [];

146

const center = { lat: 40.7128, lng: -74.0060 };

147

148

for (let i = 0; i < 200; i++) {

149

locations.push({

150

id: i,

151

position: {

152

lat: center.lat + (Math.random() - 0.5) * 0.3,

153

lng: center.lng + (Math.random() - 0.5) * 0.3

154

},

155

title: `Marker ${i + 1}`

156

});

157

}

158

return locations;

159

}, []);

160

161

const clusterOptions = {

162

gridSize: clusterSize,

163

styles: [

164

{

165

textColor: 'white',

166

url: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m1.png',

167

height: 53,

168

width: 53

169

},

170

{

171

textColor: 'white',

172

url: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m2.png',

173

height: 56,

174

width: 56

175

},

176

{

177

textColor: 'white',

178

url: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m3.png',

179

height: 66,

180

width: 66

181

}

182

],

183

maxZoom: 15,

184

zoomOnClick: true,

185

averageCenter: true,

186

minimumClusterSize: 2

187

};

188

189

return (

190

<LoadScript googleMapsApiKey="YOUR_API_KEY">

191

<div>

192

<div style={{ padding: '10px', background: '#f0f0f0' }}>

193

<label>

194

Cluster Grid Size: {clusterSize}

195

<input

196

type="range"

197

min="20"

198

max="100"

199

value={clusterSize}

200

onChange={(e) => setClusterSize(parseInt(e.target.value))}

201

style={{ marginLeft: '10px' }}

202

/>

203

</label>

204

</div>

205

206

<GoogleMap

207

center={{ lat: 40.7128, lng: -74.0060 }}

208

zoom={10}

209

mapContainerStyle={{ width: '100%', height: '400px' }}

210

>

211

<MarkerClusterer

212

options={clusterOptions}

213

onLoad={(clusterer) => console.log('Clusterer loaded')}

214

onClick={(cluster) => console.log('Cluster clicked:', cluster.getSize())}

215

>

216

{markers.map(marker => (

217

<Marker

218

key={marker.id}

219

position={marker.position}

220

title={marker.title}

221

/>

222

))}

223

</MarkerClusterer>

224

</GoogleMap>

225

</div>

226

</LoadScript>

227

);

228

}

229

230

// Advanced clustering with custom calculator

231

function AdvancedClustering() {

232

const [showClustering, setShowClustering] = useState(true);

233

234

const markers = useMemo(() => {

235

// Generate markers with different categories

236

const categories = ['restaurant', 'hotel', 'attraction', 'shop'];

237

const locations = [];

238

const center = { lat: 40.7128, lng: -74.0060 };

239

240

for (let i = 0; i < 150; i++) {

241

locations.push({

242

id: i,

243

position: {

244

lat: center.lat + (Math.random() - 0.5) * 0.25,

245

lng: center.lng + (Math.random() - 0.5) * 0.25

246

},

247

category: categories[Math.floor(Math.random() * categories.length)],

248

rating: Math.floor(Math.random() * 5) + 1

249

});

250

}

251

return locations;

252

}, []);

253

254

const customCalculator = (markers: google.maps.Marker[], numStyles: number) => {

255

let index = 0;

256

const count = markers.length;

257

let dv = count;

258

259

while (dv !== 0) {

260

dv = Math.floor(dv / 10);

261

index++;

262

}

263

264

index = Math.min(index, numStyles);

265

266

return {

267

text: count.toString(),

268

index: index,

269

title: `Cluster of ${count} markers`

270

};

271

};

272

273

const clusterStyles = [

274

{

275

textColor: 'white',

276

textSize: 12,

277

url: 'data:image/svg+xml;base64,' + btoa(`

278

<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40">

279

<circle cx="20" cy="20" r="18" fill="#ff6b6b" stroke="white" stroke-width="2"/>

280

</svg>

281

`),

282

height: 40,

283

width: 40

284

},

285

{

286

textColor: 'white',

287

textSize: 14,

288

url: 'data:image/svg+xml;base64,' + btoa(`

289

<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">

290

<circle cx="25" cy="25" r="23" fill="#4285f4" stroke="white" stroke-width="2"/>

291

</svg>

292

`),

293

height: 50,

294

width: 50

295

},

296

{

297

textColor: 'white',

298

textSize: 16,

299

url: 'data:image/svg+xml;base64,' + btoa(`

300

<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60">

301

<circle cx="30" cy="30" r="28" fill="#34a853" stroke="white" stroke-width="2"/>

302

</svg>

303

`),

304

height: 60,

305

width: 60

306

}

307

];

308

309

const clusterOptions = {

310

styles: clusterStyles,

311

calculator: customCalculator,

312

gridSize: 50,

313

maxZoom: 14,

314

zoomOnClick: true,

315

averageCenter: true

316

};

317

318

return (

319

<LoadScript googleMapsApiKey="YOUR_API_KEY">

320

<div>

321

<div style={{ padding: '10px', background: '#f0f0f0' }}>

322

<label>

323

<input

324

type="checkbox"

325

checked={showClustering}

326

onChange={(e) => setShowClustering(e.target.checked)}

327

/>

328

Enable Clustering ({markers.length} markers)

329

</label>

330

</div>

331

332

<GoogleMap

333

center={{ lat: 40.7128, lng: -74.0060 }}

334

zoom={11}

335

mapContainerStyle={{ width: '100%', height: '400px' }}

336

>

337

{showClustering ? (

338

<MarkerClusterer options={clusterOptions}>

339

{markers.map(marker => (

340

<Marker

341

key={marker.id}

342

position={marker.position}

343

title={`${marker.category} (Rating: ${marker.rating})`}

344

icon={`https://maps.google.com/mapfiles/ms/icons/${

345

marker.category === 'restaurant' ? 'red' :

346

marker.category === 'hotel' ? 'blue' :

347

marker.category === 'attraction' ? 'green' : 'yellow'

348

}-dot.png`}

349

/>

350

))}

351

</MarkerClusterer>

352

) : (

353

markers.map(marker => (

354

<Marker

355

key={marker.id}

356

position={marker.position}

357

title={`${marker.category} (Rating: ${marker.rating})`}

358

icon={`https://maps.google.com/mapfiles/ms/icons/${

359

marker.category === 'restaurant' ? 'red' :

360

marker.category === 'hotel' ? 'blue' :

361

marker.category === 'attraction' ? 'green' : 'yellow'

362

}-dot.png`}

363

/>

364

))

365

)}

366

</GoogleMap>

367

</div>

368

</LoadScript>

369

);

370

}

371

```

372

373

### MarkerClustererF Component

374

375

Functional component variant of MarkerClusterer that uses React hooks internally.

376

377

```typescript { .api }

378

/**

379

* Functional variant of MarkerClusterer component using hooks internally

380

*/

381

function MarkerClustererF(props: MarkerClustererProps): JSX.Element;

382

```

383

384

### GoogleMarkerClusterer Component

385

386

Official Google Maps marker clustering implementation with enhanced performance and features.

387

388

```typescript { .api }

389

/**

390

* Official Google marker clustering implementation

391

* Enhanced performance and features compared to community version

392

*/

393

interface GoogleMarkerClustererProps {

394

children: React.ReactNode;

395

options?: google.maps.MarkerClustererOptions;

396

397

// Event handlers

398

onClusterClick?: (event: google.maps.MapMouseEvent, cluster: google.maps.markerclusterer.Cluster, map: google.maps.Map) => void;

399

400

// Lifecycle events

401

onLoad?: (clusterer: google.maps.MarkerClusterer) => void;

402

onUnmount?: (clusterer: google.maps.MarkerClusterer) => void;

403

}

404

405

interface google.maps.MarkerClustererOptions {

406

algorithm?: google.maps.markerclusterer.Algorithm;

407

map?: google.maps.Map;

408

markers?: google.maps.Marker[];

409

renderer?: google.maps.markerclusterer.Renderer;

410

onClusterClick?: (event: google.maps.MapMouseEvent, cluster: google.maps.markerclusterer.Cluster, map: google.maps.Map) => void;

411

}

412

413

function GoogleMarkerClusterer(props: GoogleMarkerClustererProps): JSX.Element;

414

```

415

416

**Usage Examples:**

417

418

```typescript

419

import React, { useMemo } from 'react';

420

import {

421

GoogleMap,

422

LoadScript,

423

Marker,

424

GoogleMarkerClusterer

425

} from '@react-google-maps/api';

426

427

// Basic Google marker clustering

428

function BasicGoogleClustering() {

429

const markers = useMemo(() => {

430

const locations = [];

431

const center = { lat: 40.7128, lng: -74.0060 };

432

433

for (let i = 0; i < 1000; i++) {

434

locations.push({

435

id: i,

436

position: {

437

lat: center.lat + (Math.random() - 0.5) * 0.5,

438

lng: center.lng + (Math.random() - 0.5) * 0.5

439

}

440

});

441

}

442

return locations;

443

}, []);

444

445

return (

446

<LoadScript googleMapsApiKey="YOUR_API_KEY">

447

<GoogleMap

448

center={{ lat: 40.7128, lng: -74.0060 }}

449

zoom={9}

450

mapContainerStyle={{ width: '100%', height: '400px' }}

451

>

452

<GoogleMarkerClusterer

453

onLoad={(clusterer) => console.log('Google clusterer loaded')}

454

onClusterClick={(event, cluster, map) => {

455

console.log('Cluster clicked:', cluster.count);

456

map.fitBounds(cluster.bounds);

457

}}

458

>

459

{markers.map(marker => (

460

<Marker

461

key={marker.id}

462

position={marker.position}

463

/>

464

))}

465

</GoogleMarkerClusterer>

466

</GoogleMap>

467

</LoadScript>

468

);

469

}

470

471

// Google clustering with custom renderer

472

function CustomGoogleClustering() {

473

const markers = useMemo(() => {

474

const locations = [];

475

const center = { lat: 40.7128, lng: -74.0060 };

476

477

for (let i = 0; i < 500; i++) {

478

locations.push({

479

id: i,

480

position: {

481

lat: center.lat + (Math.random() - 0.5) * 0.4,

482

lng: center.lng + (Math.random() - 0.5) * 0.4

483

},

484

weight: Math.floor(Math.random() * 10) + 1

485

});

486

}

487

return locations;

488

}, []);

489

490

// Custom renderer for cluster styling

491

const createCustomRenderer = () => {

492

return {

493

render: ({ count, position }: { count: number; position: google.maps.LatLng }) => {

494

const color = count > 100 ? '#ea4335' : count > 50 ? '#fbbc05' : '#34a853';

495

const size = count > 100 ? 60 : count > 50 ? 50 : 40;

496

497

const svg = `

498

<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 ${size} ${size}">

499

<circle cx="${size/2}" cy="${size/2}" r="${size/2 - 2}" fill="${color}" stroke="white" stroke-width="2"/>

500

<text x="${size/2}" y="${size/2}" text-anchor="middle" dy="0.3em" font-family="Arial" font-size="12" font-weight="bold" fill="white">

501

${count}

502

</text>

503

</svg>

504

`;

505

506

return new google.maps.Marker({

507

position,

508

icon: {

509

url: `data:image/svg+xml;base64,${btoa(svg)}`,

510

scaledSize: new google.maps.Size(size, size),

511

anchor: new google.maps.Point(size / 2, size / 2)

512

},

513

label: {

514

text: count.toString(),

515

color: 'white',

516

fontSize: '12px',

517

fontWeight: 'bold'

518

},

519

zIndex: 1000 + count

520

});

521

}

522

};

523

};

524

525

const clusterOptions = {

526

renderer: createCustomRenderer(),

527

// algorithm: new google.maps.markerclusterer.SuperClusterAlgorithm({

528

// radius: 100,

529

// maxZoom: 16

530

// })

531

};

532

533

return (

534

<LoadScript googleMapsApiKey="YOUR_API_KEY">

535

<GoogleMap

536

center={{ lat: 40.7128, lng: -74.0060 }}

537

zoom={10}

538

mapContainerStyle={{ width: '100%', height: '400px' }}

539

>

540

<GoogleMarkerClusterer

541

options={clusterOptions}

542

onLoad={(clusterer) => console.log('Custom Google clusterer loaded')}

543

onClusterClick={(event, cluster, map) => {

544

console.log('Custom cluster clicked:', cluster);

545

}}

546

>

547

{markers.map(marker => (

548

<Marker

549

key={marker.id}

550

position={marker.position}

551

title={`Weight: ${marker.weight}`}

552

/>

553

))}

554

</GoogleMarkerClusterer>

555

</GoogleMap>

556

</LoadScript>

557

);

558

}

559

```

560

561

### Clustering Performance Comparison

562

563

Performance comparison and recommendations for choosing between clustering implementations.

564

565

```typescript { .api }

566

/**

567

* Performance characteristics of different clustering approaches

568

*/

569

interface ClusteringPerformanceMetrics {

570

markerCount: number;

571

renderTime: number;

572

memoryUsage: number;

573

interactionLatency: number;

574

}

575

576

// Performance testing utility

577

const measureClusteringPerformance = (

578

clusteringComponent: React.ReactElement,

579

markerCount: number

580

): Promise<ClusteringPerformanceMetrics> => {

581

// Implementation would measure actual performance metrics

582

return Promise.resolve({

583

markerCount,

584

renderTime: 0,

585

memoryUsage: 0,

586

interactionLatency: 0

587

});

588

};

589

```

590

591

**Performance Comparison Examples:**

592

593

```typescript

594

// Side-by-side clustering comparison

595

function ClusteringComparison() {

596

const [markerCount, setMarkerCount] = useState(100);

597

const [activeMethod, setActiveMethod] = useState<'community' | 'google'>('community');

598

599

const markers = useMemo(() => {

600

const locations = [];

601

const center = { lat: 40.7128, lng: -74.0060 };

602

603

for (let i = 0; i < markerCount; i++) {

604

locations.push({

605

id: i,

606

position: {

607

lat: center.lat + (Math.random() - 0.5) * 0.3,

608

lng: center.lng + (Math.random() - 0.5) * 0.3

609

}

610

});

611

}

612

return locations;

613

}, [markerCount]);

614

615

return (

616

<LoadScript googleMapsApiKey="YOUR_API_KEY">

617

<div>

618

<div style={{ padding: '10px', background: '#f0f0f0' }}>

619

<div style={{ marginBottom: '10px' }}>

620

<label>

621

Marker Count: {markerCount}

622

<input

623

type="range"

624

min="50"

625

max="2000"

626

step="50"

627

value={markerCount}

628

onChange={(e) => setMarkerCount(parseInt(e.target.value))}

629

style={{ marginLeft: '10px', width: '200px' }}

630

/>

631

</label>

632

</div>

633

634

<div>

635

<label style={{ marginRight: '20px' }}>

636

<input

637

type="radio"

638

value="community"

639

checked={activeMethod === 'community'}

640

onChange={(e) => setActiveMethod(e.target.value as 'community')}

641

/>

642

Community Clusterer

643

</label>

644

<label>

645

<input

646

type="radio"

647

value="google"

648

checked={activeMethod === 'google'}

649

onChange={(e) => setActiveMethod(e.target.value as 'google')}

650

/>

651

Google Clusterer

652

</label>

653

</div>

654

655

<div style={{ marginTop: '10px', fontSize: '12px', color: '#666' }}>

656

Recommendations:

657

<ul style={{ margin: '5px 0', paddingLeft: '20px' }}>

658

<li>Community: Better customization, lighter weight (&lt;1000 markers)</li>

659

<li>Google: Better performance, official support (&gt;1000 markers)</li>

660

</ul>

661

</div>

662

</div>

663

664

<GoogleMap

665

center={{ lat: 40.7128, lng: -74.0060 }}

666

zoom={10}

667

mapContainerStyle={{ width: '100%', height: '400px' }}

668

>

669

{activeMethod === 'community' ? (

670

<MarkerClusterer

671

options={{

672

gridSize: 60,

673

maxZoom: 15,

674

zoomOnClick: true

675

}}

676

>

677

{markers.map(marker => (

678

<Marker key={marker.id} position={marker.position} />

679

))}

680

</MarkerClusterer>

681

) : (

682

<GoogleMarkerClusterer>

683

{markers.map(marker => (

684

<Marker key={marker.id} position={marker.position} />

685

))}

686

</GoogleMarkerClusterer>

687

)}

688

</GoogleMap>

689

</div>

690

</LoadScript>

691

);

692

}

693

694

// Clustering with dynamic data loading

695

function DynamicClusteringExample() {

696

const [markers, setMarkers] = useState<Array<{id: number, position: google.maps.LatLngLiteral}>>([]);

697

const [isLoading, setIsLoading] = useState(false);

698

699

const loadMoreMarkers = async (count: number) => {

700

setIsLoading(true);

701

702

// Simulate API call

703

await new Promise(resolve => setTimeout(resolve, 1000));

704

705

const newMarkers = [];

706

const center = { lat: 40.7128, lng: -74.0060 };

707

const startId = markers.length;

708

709

for (let i = 0; i < count; i++) {

710

newMarkers.push({

711

id: startId + i,

712

position: {

713

lat: center.lat + (Math.random() - 0.5) * 0.5,

714

lng: center.lng + (Math.random() - 0.5) * 0.5

715

}

716

});

717

}

718

719

setMarkers(prev => [...prev, ...newMarkers]);

720

setIsLoading(false);

721

};

722

723

const clearMarkers = () => {

724

setMarkers([]);

725

};

726

727

return (

728

<LoadScript googleMapsApiKey="YOUR_API_KEY">

729

<div>

730

<div style={{ padding: '10px', background: '#f0f0f0' }}>

731

<div>Markers: {markers.length}</div>

732

<button

733

onClick={() => loadMoreMarkers(100)}

734

disabled={isLoading}

735

style={{ marginRight: '10px' }}

736

>

737

{isLoading ? 'Loading...' : 'Add 100 Markers'}

738

</button>

739

<button

740

onClick={() => loadMoreMarkers(500)}

741

disabled={isLoading}

742

style={{ marginRight: '10px' }}

743

>

744

{isLoading ? 'Loading...' : 'Add 500 Markers'}

745

</button>

746

<button onClick={clearMarkers}>

747

Clear All

748

</button>

749

</div>

750

751

<GoogleMap

752

center={{ lat: 40.7128, lng: -74.0060 }}

753

zoom={9}

754

mapContainerStyle={{ width: '100%', height: '400px' }}

755

>

756

<GoogleMarkerClusterer

757

onLoad={(clusterer) => {

758

console.log('Clusterer ready for', markers.length, 'markers');

759

}}

760

>

761

{markers.map(marker => (

762

<Marker

763

key={marker.id}

764

position={marker.position}

765

title={`Marker ${marker.id}`}

766

/>

767

))}

768

</GoogleMarkerClusterer>

769

</GoogleMap>

770

</div>

771

</LoadScript>

772

);

773

}

774

```

775

776

### Clustering Best Practices

777

778

Guidelines for optimal clustering implementation and performance.

779

780

```typescript { .api }

781

/**

782

* Best practices for marker clustering implementation

783

*/

784

interface ClusteringBestPractices {

785

// Performance optimization

786

maxMarkersBeforeClustering: number; // ~500-1000 markers

787

optimalGridSize: number; // 40-80 pixels

788

maxZoomForClustering: number; // 15-17

789

790

// Visual design

791

clusterIconSizes: number[]; // [40, 50, 60] progressive sizes

792

colorScheme: string[]; // Consistent color progression

793

textVisibility: boolean; // Always show count numbers

794

795

// Interaction design

796

zoomOnClusterClick: boolean; // Usually true

797

spiderfyOnClick: boolean; // For overlapping markers

798

showClusterBounds: boolean; // Debug/development only

799

}

800

801

// Example optimized clustering configuration

802

const optimizedClusterConfig = {

803

community: {

804

gridSize: 60,

805

maxZoom: 15,

806

zoomOnClick: true,

807

averageCenter: true,

808

minimumClusterSize: 2,

809

styles: [

810

{ textColor: 'white', url: '/cluster-small.png', height: 40, width: 40 },

811

{ textColor: 'white', url: '/cluster-medium.png', height: 50, width: 50 },

812

{ textColor: 'white', url: '/cluster-large.png', height: 60, width: 60 }

813

]

814

},

815

google: {

816

// Use default algorithm for best performance

817

// Customize renderer for visual consistency

818

}

819

};

820

```

821

822

## GoogleMapsMarkerClusterer Namespace

823

824

Direct access to the official Google Maps MarkerClusterer library with all its classes, algorithms, and renderers.

825

826

### GoogleMapsMarkerClusterer Namespace Export

827

828

Complete namespace re-export providing access to the official `@googlemaps/markerclusterer` library components.

829

830

```typescript { .api }

831

/**

832

* Complete namespace export of @googlemaps/markerclusterer

833

* Provides direct access to Google's official clustering library

834

*/

835

import { GoogleMapsMarkerClusterer } from "@react-google-maps/api";

836

837

// Access to core MarkerClusterer class

838

class MarkerClusterer {

839

constructor(options: {

840

algorithm?: Algorithm;

841

map?: google.maps.Map;

842

markers?: google.maps.Marker[];

843

renderer?: Renderer;

844

onClusterClick?: onClusterClickHandler;

845

});

846

847

addMarker(marker: google.maps.Marker, noDraw?: boolean): void;

848

addMarkers(markers: google.maps.Marker[], noDraw?: boolean): void;

849

clearMarkers(noDraw?: boolean): void;

850

render(): void;

851

setMap(map: google.maps.Map | null): void;

852

}

853

854

// Access to clustering algorithms

855

interface Algorithm {

856

calculate(request: AlgorithmInput): AlgorithmOutput;

857

}

858

859

// Access to cluster renderers

860

interface Renderer {

861

render(cluster: Cluster, stats: ClusterStats): google.maps.Marker;

862

}

863

864

// Cluster statistics for renderer

865

interface ClusterStats {

866

count: number;

867

markers: google.maps.Marker[];

868

}

869

870

// Event handler types

871

type onClusterClickHandler = (

872

event: google.maps.MapMouseEvent,

873

cluster: Cluster,

874

map: google.maps.Map

875

) => void;

876

```

877

878

**Usage Example:**

879

880

```typescript

881

import { GoogleMapsMarkerClusterer } from "@react-google-maps/api";

882

883

// Direct instantiation of Google's MarkerClusterer

884

function MyAdvancedClusteringComponent() {

885

const map = useGoogleMap();

886

887

React.useEffect(() => {

888

if (map && markers.length > 0) {

889

const markerClusterer = new GoogleMapsMarkerClusterer.MarkerClusterer({

890

map,

891

markers,

892

onClusterClick: (event, cluster, map) => {

893

map.fitBounds(cluster.bounds!);

894

}

895

});

896

897

return () => markerClusterer.setMap(null);

898

}

899

}, [map, markers]);

900

901

return null;

902

}

903

```