0
# Map Controls
1
2
UI controls for map interaction including zoom buttons and other control elements. Controls are positioned overlays that provide user interface elements for map interaction without interfering with map events.
3
4
## Capabilities
5
6
### ZoomControl Component
7
8
Zoom in/out button controls with customizable styling and positioning.
9
10
```typescript { .api }
11
/**
12
* Zoom in/out button controls for map interaction
13
* @param props - Zoom control configuration and styling
14
* @returns JSX.Element representing the zoom controls
15
*/
16
function ZoomControl(props: ZoomProps): JSX.Element;
17
18
interface ZoomProps extends PigeonProps {
19
style?: React.CSSProperties;
20
buttonStyle?: React.CSSProperties;
21
}
22
```
23
24
**Usage Examples:**
25
26
```tsx
27
import React from "react";
28
import { Map, ZoomControl } from "pigeon-maps";
29
30
// Basic zoom controls
31
function MapWithZoomControls() {
32
return (
33
<Map height={400} center={[50.879, 4.6997]} zoom={11}>
34
<ZoomControl />
35
</Map>
36
);
37
}
38
39
// Styled zoom controls
40
function StyledZoomControls() {
41
return (
42
<Map height={400} center={[50.879, 4.6997]} zoom={11}>
43
<ZoomControl
44
style={{
45
position: 'absolute',
46
top: 20,
47
right: 20,
48
left: 'auto' // Override default left positioning
49
}}
50
buttonStyle={{
51
backgroundColor: '#007bff',
52
color: 'white',
53
border: 'none',
54
borderRadius: '4px',
55
fontSize: '18px'
56
}}
57
/>
58
</Map>
59
);
60
}
61
```
62
63
### Custom Positioned Controls
64
65
```tsx
66
function CustomPositionedControls() {
67
return (
68
<Map height={400} center={[50.879, 4.6997]} zoom={11}>
69
{/* Top-right zoom controls */}
70
<ZoomControl
71
style={{
72
position: 'absolute',
73
top: 10,
74
right: 10,
75
left: 'auto'
76
}}
77
/>
78
79
{/* Custom control overlay */}
80
<div style={{
81
position: 'absolute',
82
bottom: 10,
83
left: 10,
84
background: 'white',
85
padding: '8px',
86
borderRadius: '4px',
87
boxShadow: '0 2px 4px rgba(0,0,0,0.2)'
88
}}>
89
Custom Control
90
</div>
91
</Map>
92
);
93
}
94
```
95
96
## Zoom Control Features
97
98
### Button Functionality
99
100
The zoom control provides two buttons:
101
- **Zoom In (+)**: Increases zoom level by 1, respecting `maxZoom` limit
102
- **Zoom Out (–)**: Decreases zoom level by 1, respecting `minZoom` limit
103
104
### Automatic Integration
105
106
Zoom controls automatically:
107
- Access current map state (zoom level, bounds)
108
- Respect map zoom limits (`minZoom`, `maxZoom`)
109
- Use map's zoom animation settings
110
- Call the map's `setCenterZoom` function
111
112
### Default Styling
113
114
```typescript { .api }
115
// Default container style
116
const commonStyle: React.CSSProperties = {
117
position: 'absolute',
118
top: 10,
119
left: 10,
120
};
121
122
// Default button style
123
const commonButtonStyle: React.CSSProperties = {
124
width: 28,
125
height: 28,
126
borderRadius: 2,
127
boxShadow: '0 1px 4px -1px rgba(0,0,0,.3)',
128
background: 'white',
129
lineHeight: '26px',
130
fontSize: '20px',
131
fontWeight: 700,
132
color: '#666',
133
marginBottom: 1,
134
cursor: 'pointer',
135
border: 'none',
136
display: 'block',
137
outline: 'none',
138
};
139
```
140
141
## CSS Classes
142
143
### Default Classes
144
145
```typescript { .api }
146
// Container classes
147
className="pigeon-zoom-buttons pigeon-drag-block"
148
149
// Button classes
150
className="pigeon-zoom-in" // Zoom in button
151
className="pigeon-zoom-out" // Zoom out button
152
```
153
154
The `pigeon-drag-block` class prevents map interactions when clicking on controls.
155
156
### Custom Styling Examples
157
158
```css
159
/* Custom zoom control styling */
160
.pigeon-zoom-buttons {
161
background: rgba(255, 255, 255, 0.9);
162
border-radius: 8px;
163
padding: 4px;
164
}
165
166
.pigeon-zoom-in,
167
.pigeon-zoom-out {
168
background: linear-gradient(to bottom, #f8f8f8, #e8e8e8);
169
border: 1px solid #ccc;
170
transition: all 0.2s;
171
}
172
173
.pigeon-zoom-in:hover,
174
.pigeon-zoom-out:hover {
175
background: linear-gradient(to bottom, #fff, #f0f0f0);
176
border-color: #999;
177
}
178
179
.pigeon-zoom-in:active,
180
.pigeon-zoom-out:active {
181
background: linear-gradient(to bottom, #e8e8e8, #f8f8f8);
182
box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
183
}
184
```
185
186
## Custom Controls
187
188
### Creating Custom Controls
189
190
```tsx
191
import React from "react";
192
import { Map } from "pigeon-maps";
193
194
function CustomMapControls() {
195
const [mapRef, setMapRef] = useState(null);
196
197
// Custom zoom to specific location
198
const zoomToLocation = (center, zoom) => {
199
if (mapRef && mapRef.setCenterZoom) {
200
mapRef.setCenterZoom(center, zoom);
201
}
202
};
203
204
return (
205
<Map
206
height={400}
207
center={[50.879, 4.6997]}
208
zoom={11}
209
ref={setMapRef}
210
>
211
{/* Custom location buttons */}
212
<div style={{
213
position: 'absolute',
214
top: 10,
215
right: 10,
216
display: 'flex',
217
flexDirection: 'column',
218
gap: '4px'
219
}}>
220
<button
221
className="pigeon-drag-block"
222
style={{
223
padding: '8px 12px',
224
background: 'white',
225
border: '1px solid #ccc',
226
borderRadius: '4px',
227
cursor: 'pointer'
228
}}
229
onClick={() => zoomToLocation([50.879, 4.6997], 15)}
230
>
231
Brussels
232
</button>
233
<button
234
className="pigeon-drag-block"
235
style={{
236
padding: '8px 12px',
237
background: 'white',
238
border: '1px solid #ccc',
239
borderRadius: '4px',
240
cursor: 'pointer'
241
}}
242
onClick={() => zoomToLocation([48.8566, 2.3522], 12)}
243
>
244
Paris
245
</button>
246
</div>
247
</Map>
248
);
249
}
250
```
251
252
### Control with Map State
253
254
```tsx
255
function StatefulControls() {
256
const [zoom, setZoom] = useState(11);
257
const [center, setCenter] = useState([50.879, 4.6997]);
258
259
return (
260
<Map
261
height={400}
262
center={center}
263
zoom={zoom}
264
onBoundsChanged={({ center, zoom }) => {
265
setCenter(center);
266
setZoom(zoom);
267
}}
268
>
269
{/* Display current state */}
270
<div style={{
271
position: 'absolute',
272
top: 10,
273
left: 10,
274
background: 'rgba(255, 255, 255, 0.9)',
275
padding: '8px',
276
borderRadius: '4px',
277
fontSize: '12px',
278
fontFamily: 'monospace'
279
}}>
280
<div>Zoom: {zoom.toFixed(2)}</div>
281
<div>Lat: {center[0].toFixed(4)}</div>
282
<div>Lng: {center[1].toFixed(4)}</div>
283
</div>
284
285
<ZoomControl />
286
</Map>
287
);
288
}
289
```
290
291
### Toggle Controls
292
293
```tsx
294
function ToggleControls() {
295
const [showSatellite, setShowSatellite] = useState(false);
296
const [showTraffic, setShowTraffic] = useState(false);
297
298
return (
299
<Map height={400} center={[50.879, 4.6997]} zoom={11}>
300
{/* Toggle control panel */}
301
<div style={{
302
position: 'absolute',
303
bottom: 10,
304
left: 10,
305
background: 'white',
306
padding: '12px',
307
borderRadius: '4px',
308
boxShadow: '0 2px 8px rgba(0,0,0,0.1)'
309
}}>
310
<label style={{ display: 'block', marginBottom: '8px' }}>
311
<input
312
type="checkbox"
313
checked={showSatellite}
314
onChange={(e) => setShowSatellite(e.target.checked)}
315
style={{ marginRight: '8px' }}
316
/>
317
Satellite View
318
</label>
319
<label style={{ display: 'block' }}>
320
<input
321
type="checkbox"
322
checked={showTraffic}
323
onChange={(e) => setShowTraffic(e.target.checked)}
324
style={{ marginRight: '8px' }}
325
/>
326
Traffic Layer
327
</label>
328
</div>
329
330
<ZoomControl />
331
</Map>
332
);
333
}
334
```
335
336
## Accessibility
337
338
### Keyboard Support
339
340
```tsx
341
function AccessibleControls() {
342
const handleKeyDown = (event, action) => {
343
if (event.key === 'Enter' || event.key === ' ') {
344
event.preventDefault();
345
action();
346
}
347
};
348
349
return (
350
<Map height={400} center={[50.879, 4.6997]} zoom={11}>
351
<div style={{
352
position: 'absolute',
353
top: 10,
354
right: 10,
355
display: 'flex',
356
flexDirection: 'column'
357
}}>
358
<button
359
className="pigeon-drag-block"
360
aria-label="Zoom in"
361
tabIndex={0}
362
onKeyDown={(e) => handleKeyDown(e, () => console.log('zoom in'))}
363
style={{
364
width: 32,
365
height: 32,
366
fontSize: '18px',
367
marginBottom: 2
368
}}
369
>
370
+
371
</button>
372
<button
373
className="pigeon-drag-block"
374
aria-label="Zoom out"
375
tabIndex={0}
376
onKeyDown={(e) => handleKeyDown(e, () => console.log('zoom out'))}
377
style={{
378
width: 32,
379
height: 32,
380
fontSize: '18px'
381
}}
382
>
383
–
384
</button>
385
</div>
386
</Map>
387
);
388
}
389
```
390
391
## Performance Considerations
392
393
- Controls are lightweight DOM elements with minimal re-rendering
394
- Use `pigeon-drag-block` class to prevent event conflicts with map
395
- Position controls absolutely to avoid affecting map layout
396
- Consider control visibility at different screen sizes
397
- Group related controls to minimize DOM complexity