ReactJS maps without external dependencies - performance-first React-centric extendable map engine
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
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.
Zoom in/out button controls with customizable styling and positioning.
/**
* Zoom in/out button controls for map interaction
* @param props - Zoom control configuration and styling
* @returns JSX.Element representing the zoom controls
*/
function ZoomControl(props: ZoomProps): JSX.Element;
interface ZoomProps extends PigeonProps {
style?: React.CSSProperties;
buttonStyle?: React.CSSProperties;
}Usage Examples:
import React from "react";
import { Map, ZoomControl } from "pigeon-maps";
// Basic zoom controls
function MapWithZoomControls() {
return (
<Map height={400} center={[50.879, 4.6997]} zoom={11}>
<ZoomControl />
</Map>
);
}
// Styled zoom controls
function StyledZoomControls() {
return (
<Map height={400} center={[50.879, 4.6997]} zoom={11}>
<ZoomControl
style={{
position: 'absolute',
top: 20,
right: 20,
left: 'auto' // Override default left positioning
}}
buttonStyle={{
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '4px',
fontSize: '18px'
}}
/>
</Map>
);
}function CustomPositionedControls() {
return (
<Map height={400} center={[50.879, 4.6997]} zoom={11}>
{/* Top-right zoom controls */}
<ZoomControl
style={{
position: 'absolute',
top: 10,
right: 10,
left: 'auto'
}}
/>
{/* Custom control overlay */}
<div style={{
position: 'absolute',
bottom: 10,
left: 10,
background: 'white',
padding: '8px',
borderRadius: '4px',
boxShadow: '0 2px 4px rgba(0,0,0,0.2)'
}}>
Custom Control
</div>
</Map>
);
}The zoom control provides two buttons:
maxZoom limitminZoom limitZoom controls automatically:
minZoom, maxZoom)setCenterZoom function// Default container style
const commonStyle: React.CSSProperties = {
position: 'absolute',
top: 10,
left: 10,
};
// Default button style
const commonButtonStyle: React.CSSProperties = {
width: 28,
height: 28,
borderRadius: 2,
boxShadow: '0 1px 4px -1px rgba(0,0,0,.3)',
background: 'white',
lineHeight: '26px',
fontSize: '20px',
fontWeight: 700,
color: '#666',
marginBottom: 1,
cursor: 'pointer',
border: 'none',
display: 'block',
outline: 'none',
};// Container classes
className="pigeon-zoom-buttons pigeon-drag-block"
// Button classes
className="pigeon-zoom-in" // Zoom in button
className="pigeon-zoom-out" // Zoom out buttonThe pigeon-drag-block class prevents map interactions when clicking on controls.
/* Custom zoom control styling */
.pigeon-zoom-buttons {
background: rgba(255, 255, 255, 0.9);
border-radius: 8px;
padding: 4px;
}
.pigeon-zoom-in,
.pigeon-zoom-out {
background: linear-gradient(to bottom, #f8f8f8, #e8e8e8);
border: 1px solid #ccc;
transition: all 0.2s;
}
.pigeon-zoom-in:hover,
.pigeon-zoom-out:hover {
background: linear-gradient(to bottom, #fff, #f0f0f0);
border-color: #999;
}
.pigeon-zoom-in:active,
.pigeon-zoom-out:active {
background: linear-gradient(to bottom, #e8e8e8, #f8f8f8);
box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
}import React from "react";
import { Map } from "pigeon-maps";
function CustomMapControls() {
const [mapRef, setMapRef] = useState(null);
// Custom zoom to specific location
const zoomToLocation = (center, zoom) => {
if (mapRef && mapRef.setCenterZoom) {
mapRef.setCenterZoom(center, zoom);
}
};
return (
<Map
height={400}
center={[50.879, 4.6997]}
zoom={11}
ref={setMapRef}
>
{/* Custom location buttons */}
<div style={{
position: 'absolute',
top: 10,
right: 10,
display: 'flex',
flexDirection: 'column',
gap: '4px'
}}>
<button
className="pigeon-drag-block"
style={{
padding: '8px 12px',
background: 'white',
border: '1px solid #ccc',
borderRadius: '4px',
cursor: 'pointer'
}}
onClick={() => zoomToLocation([50.879, 4.6997], 15)}
>
Brussels
</button>
<button
className="pigeon-drag-block"
style={{
padding: '8px 12px',
background: 'white',
border: '1px solid #ccc',
borderRadius: '4px',
cursor: 'pointer'
}}
onClick={() => zoomToLocation([48.8566, 2.3522], 12)}
>
Paris
</button>
</div>
</Map>
);
}function StatefulControls() {
const [zoom, setZoom] = useState(11);
const [center, setCenter] = useState([50.879, 4.6997]);
return (
<Map
height={400}
center={center}
zoom={zoom}
onBoundsChanged={({ center, zoom }) => {
setCenter(center);
setZoom(zoom);
}}
>
{/* Display current state */}
<div style={{
position: 'absolute',
top: 10,
left: 10,
background: 'rgba(255, 255, 255, 0.9)',
padding: '8px',
borderRadius: '4px',
fontSize: '12px',
fontFamily: 'monospace'
}}>
<div>Zoom: {zoom.toFixed(2)}</div>
<div>Lat: {center[0].toFixed(4)}</div>
<div>Lng: {center[1].toFixed(4)}</div>
</div>
<ZoomControl />
</Map>
);
}function ToggleControls() {
const [showSatellite, setShowSatellite] = useState(false);
const [showTraffic, setShowTraffic] = useState(false);
return (
<Map height={400} center={[50.879, 4.6997]} zoom={11}>
{/* Toggle control panel */}
<div style={{
position: 'absolute',
bottom: 10,
left: 10,
background: 'white',
padding: '12px',
borderRadius: '4px',
boxShadow: '0 2px 8px rgba(0,0,0,0.1)'
}}>
<label style={{ display: 'block', marginBottom: '8px' }}>
<input
type="checkbox"
checked={showSatellite}
onChange={(e) => setShowSatellite(e.target.checked)}
style={{ marginRight: '8px' }}
/>
Satellite View
</label>
<label style={{ display: 'block' }}>
<input
type="checkbox"
checked={showTraffic}
onChange={(e) => setShowTraffic(e.target.checked)}
style={{ marginRight: '8px' }}
/>
Traffic Layer
</label>
</div>
<ZoomControl />
</Map>
);
}function AccessibleControls() {
const handleKeyDown = (event, action) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
action();
}
};
return (
<Map height={400} center={[50.879, 4.6997]} zoom={11}>
<div style={{
position: 'absolute',
top: 10,
right: 10,
display: 'flex',
flexDirection: 'column'
}}>
<button
className="pigeon-drag-block"
aria-label="Zoom in"
tabIndex={0}
onKeyDown={(e) => handleKeyDown(e, () => console.log('zoom in'))}
style={{
width: 32,
height: 32,
fontSize: '18px',
marginBottom: 2
}}
>
+
</button>
<button
className="pigeon-drag-block"
aria-label="Zoom out"
tabIndex={0}
onKeyDown={(e) => handleKeyDown(e, () => console.log('zoom out'))}
style={{
width: 32,
height: 32,
fontSize: '18px'
}}
>
–
</button>
</div>
</Map>
);
}pigeon-drag-block class to prevent event conflicts with mapInstall with Tessl CLI
npx tessl i tessl/npm-pigeon-maps