
Syncfusion React Maps
- 390 installs
- 3 repo stars
- Updated July 28, 2026
- syncfusion/react-ui-components-skills
syncfusion-react-maps is an agent skill that implements Syncfusion React MapsComponent with GeoJSON layers, map providers, markers, bubbles, legends, and choropleth color mapping for developers visualizing location-based
About
syncfusion-react-maps is a Syncfusion agent skill (version 33.1.44) for building MapsComponent dashboards in React with SVG-based geographic visualizations. It supports GeoJSON shape binding, Bing Maps, OpenStreetMap, and Azure Maps base layers, plus markers, bubbles, data labels, navigation lines, annotations, and interactive zoom or pan. The skill documents six map projections, multi-layer and sublayer stacking, color mapping for choropleth charts, and WCAG 2.1 keyboard accessibility. Reference guides span API properties, getting started, layers, markers, and combined data-visualization patterns. Use it when shipping regional analytics, store locators, election maps, or logistics route overlays inside Syncfusion React apps.
- syncfusion-react-maps
Syncfusion React Maps by the numbers
- 390 all-time installs (skills.sh)
- +22 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #1,076 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/syncfusion/react-ui-components-skills --skill syncfusion-react-mapsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 390 |
|---|---|
| repo stars | ★ 3 |
| Last updated | July 28, 2026 |
| Repository | syncfusion/react-ui-components-skills ↗ |
How do you render GeoJSON maps in React?
Use syncfusion-react-maps for development tasks
Who is it for?
React developers on Syncfusion who need interactive choropleth or marker maps with provider tiles and multi-layer GeoJSON overlays.
Skip if: Teams preferring Mapbox GL, deck.gl, or Leaflet without Syncfusion licensing requirements.
When should I use this skill?
User asks for Syncfusion Maps, GeoJSON choropleth, map markers, bubble layers, or Bing or OSM base maps in React.
What you get
React MapsComponent with bound GeoJSON shapes, marker layers, bubble sizing, legends, tooltips, and zoom-pan controls.
- MapsComponent configuration
- GeoJSON-bound shape layers
- marker and bubble data layers
By the numbers
- Syncfusion skill metadata version 33.1.44
- Supports 6 map projections and 3 major tile providers
- Covers markers, bubbles, data labels, navigation lines, and legends
Files
Implementing Syncfusion React Maps
A comprehensive skill for implementing the Syncfusion React Maps component to visualize geographical data with rich interactivity, multiple layers, markers, bubbles, legends, and map provider integration.
When to Use This Skill
Use this skill when you need to:
- Display geographical data on interactive maps
- Visualize location-based information with markers, bubbles, or data labels
- Create choropleth maps with color-coded regions based on data values
- Integrate map providers like Bing Maps, OpenStreetMap, or Azure Maps
- Render custom shapes from GeoJSON data files
- Build multi-layer maps with overlays and sublayers
- Add navigation lines to show routes or connections between locations
- Implement zooming and panning for map exploration
- Display statistical data on geographical regions
- Create interactive legends for data interpretation
- Support multiple projections (Mercator, Miller, Eckert, etc.)
- Handle user interactions like tooltips, selection, and highlighting
Component Overview
The Syncfusion React Maps component is a powerful data visualization tool that renders geographical data using Scalable Vector Graphics (SVG). It supports:
- Any number of layers and sublayers for complex visualizations
- GeoJSON data binding for custom shape rendering
- Map providers (Bing, OpenStreetMap, Azure) as base layers
- 6 types of projections for different map representations
- Visual elements: Markers, Bubbles, Navigation Lines, Annotations, Data Labels, Legends
- Interactive features: Zooming, Panning, Tooltips, Selection, Highlighting
- Accessibility: WCAG 2.1 compliant with keyboard navigation
- Globalization: RTL support, internationalization, localization
Key Capabilities
Data Visualization Elements
- Markers: Pin locations with custom shapes, templates, and clustering
- Bubbles: Display data magnitude with size-based bubbles
- Data Labels: Show information directly on map shapes
- Color Mapping: Apply colors based on data values (equal, range, desaturation)
- Navigation Lines: Draw connections between locations with curves and arrows
- Legends: Provide visual keys for data interpretation
Layer Architecture
- Main Layer: Base map from GeoJSON or map provider
- Sublayers: Overlay additional shapes on top of main layer
- Multi-layer Support: Stack multiple layers for rich visualizations
Map Providers
- Bing Maps: Satellite, aerial, and road views
- OpenStreetMap: Free tile layer provider
- Azure Maps: Microsoft's map service
- Hybrid Approach: Combine GeoJSON shapes with provider tiles
User Interactions
- Zooming: Mouse wheel, double-click, pinch, toolbar controls
- Panning: Drag to explore different regions
- Tooltips: Show data on hover
- Selection: Highlight shapes on click
- Reset: Return to initial view
Documentation and Navigation Guide
API Reference
📄 Read: references/api-reference.md
- Complete MapsComponent properties reference
- All available methods with examples
- Comprehensive events documentation
- Layer, marker, bubble, and data label settings
- Legend, zoom, and tooltip configuration
- Quick reference code examples
- Type definitions and parameters
Getting Started
📄 Read: references/getting-started.md
- Installation and package dependencies
- Basic Maps component implementation
- GeoJSON data structure and binding
- CSS theme imports
- Module injection pattern (feature-based)
- First world map example
- Data source binding with shapeDataPath and shapePropertyPath
Layers and Structure
📄 Read: references/layers-and-sublayers.md
- Understanding layer architecture
- Main layer vs sublayer differences
- Creating multi-layer maps
- Layer types and stacking order
- Layer-specific settings and configuration
- When to use multiple layers
Markers
📄 Read: references/markers.md
- Adding markers to pinpoint locations
- Marker data source structure (latitude, longitude)
- Marker shapes and custom templates
- Marker clustering for dense data
- Dynamic marker updates
- Interactive markers with click events
- Marker tooltips and labels
Data Visualization Elements
📄 Read: references/data-visualization.md
- Bubble visualization for data magnitude
- Configuring bubble size and colors
- Data label setup and formatting
- Smart label modes (trim, hide, none)
- Label templates for custom content
- Combining bubbles with data labels
- Best practices for visual hierarchy
Legend
📄 Read: references/legend.md
- Enabling and configuring legends
- Positioning strategies (absolute, dock)
- Legend alignment options (near, center, far)
- Interactive legends
- Legend modes (default, interactive)
- Customizing legend appearance
- Syncing legends with color mapping
Color Mapping
📄 Read: references/color-mapping.md
- Color mapping types (equal, range, desaturation)
- Applying colors based on data values
- Setting up colorValuePath
- Creating choropleth maps
- Multiple color mapping rules
- Custom color schemes
- Visual data representation strategies
Navigation Lines
📄 Read: references/navigation-lines.md
- Creating lines between locations
- Line styling (width, color, dash array)
- Curved lines and angles
- Arrow indicators for direction
- Use cases (routes, connections, flows)
- Animation effects on lines
Map Providers
📄 Read: references/map-providers.md
- Overview of supported providers
- When to use GeoJSON vs map providers
- Bing Maps setup and API keys
- OpenStreetMap integration (free)
- Azure Maps configuration
- Tile layer types (satellite, aerial, road)
- Hybrid approaches (GeoJSON overlays on provider tiles)
User Interactions
📄 Read: references/user-interactions.md
- Enabling and configuring zooming
- Zoom factor and toolbar controls
- Panning functionality
- Tooltip configuration and templates
- Selection and highlighting shapes
- Mouse wheel and double-click zoom
- Pinch zoom for touch devices
- Reset to initial view
Annotations and Polygons
📄 Read: references/annotations-polygon.md
- Adding custom annotations to maps
- Polygon rendering for custom shapes
- Positioning and alignment
- Interactive annotations
- Use cases for overlays
Customization
- Map projections (Mercator, Miller, Eckert, Winkel Tripel, Aitoff, Equirectangular)
- Title and subtitle configuration
- Border and background styling
- Margin and padding adjustments
- Custom CSS classes
- Theme integration
- Responsive design patterns
Advanced Features
📄 Read: references/advanced-features.md
- Internationalization (i18n)
- Localization (l10n)
- Accessibility (WCAG compliance, keyboard navigation)
- State persistence across sessions
- Printing and export functionality
- Event handling patterns
- Accessing component methods via ref
- Performance optimization techniques
- Migration guide from EJ1 to EJ2
Quick Start Example
import * as React from 'react';
import { MapsComponent, LayersDirective, LayerDirective, Inject, Legend } from '@syncfusion/ej2-react-maps';
import { world_map } from './world-map'; // GeoJSON data
function MapExample() {
const data = [
{ Country: 'United States', Population: 331000000, Membership: 'Permanent' },
{ Country: 'Russia', Population: 145900000, Membership: 'Permanent' },
{ Country: 'China', Population: 1439000000, Membership: 'Permanent' },
{ Country: 'India', Population: 1380000000, Membership: 'Non-Permanent' },
{ Country: 'Brazil', Population: 212500000, Membership: 'Non-Permanent' }
];
return (
<MapsComponent
titleSettings={{ text: 'World Map with Country Membership' }}
legendSettings={{ visible: true }}
>
<Inject services={[Legend]} />
<LayersDirective>
<LayerDirective
shapeData={world_map}
shapeDataPath='Country'
shapePropertyPath='name'
dataSource={data}
shapeSettings={{
colorValuePath: 'Membership',
colorMapping: [
{ value: 'Permanent', color: '#D84444' },
{ value: 'Non-Permanent', color: '#316DB5' }
]
}}
/>
</LayersDirective>
</MapsComponent>
);
}
export default MapExample;Module Injection Guide
Maps features are modular. Inject only the modules you need:
import {
MapsComponent,
Inject,
Legend, // For legends
DataLabel, // For data labels
Marker, // For markers
Bubble, // For bubbles
MapsTooltip, // For tooltips
Zoom, // For zooming and panning
Highlight, // For highlighting shapes
Selection, // For selecting shapes
NavigationLine,// For navigation lines
Annotations, // For annotations
Polygon // For polygons
} from '@syncfusion/ej2-react-maps';
<MapsComponent>
<Inject services={[Legend, Marker, MapsTooltip, Zoom]} />
{/* Your layers */}
</MapsComponent>Only inject modules for features you're using to minimize bundle size.
Common Use Cases
Choropleth Map (Color-Coded Regions)
Goal: Display statistical data with color-coded countries/regions
Approach: 1. Bind data source with dataSource, shapeDataPath, shapePropertyPath 2. Configure shapeSettings.colorValuePath to specify data field 3. Set up colorMapping with value-color pairs 4. Add Legend for interpretation
Example: Population density map, election results, COVID-19 statistics
---
Location Markers Map
Goal: Show specific locations with custom markers
Approach: 1. Add MarkersDirective inside LayerDirective 2. Provide marker data with latitude/longitude 3. Customize marker shapes, sizes, and templates 4. Add tooltips for marker information
Example: Store locator, branch offices, tourist attractions
---
Multi-Layer Overlay
Goal: Highlight specific regions on a base map
Approach: 1. First layer: Base map (e.g., entire country) 2. Additional layers with type="SubLayer": Highlighted regions 3. Style sublayers distinctly (different colors, borders) 4. Control layer visibility and order
Example: State highlights on country map, sales regions
---
Route Visualization
Goal: Show connections or routes between locations
Approach: 1. Add markers for start/end points 2. Use NavigationLineDirective to draw lines 3. Configure line curves, arrows, and styling 4. Optionally animate lines
Example: Flight routes, shipping lanes, migration patterns
---
Map Provider Integration
Goal: Use real-world satellite/street map as base
Approach: 1. Configure layer with urlTemplate for provider 2. Set up API keys (Bing, Azure) if required 3. Overlay GeoJSON shapes as sublayers if needed 4. Add markers and labels on top
Example: Real estate map, delivery tracking, ride-sharing app
Decision Trees
Should I Use GeoJSON or Map Provider?
Use GeoJSON when:
- You need custom shapes or boundaries
- Data is region/country-based (choropleth maps)
- No real-world street-level detail needed
- Offline capability required
- Full control over styling and data binding
Use Map Provider when:
- Need real-world satellite/aerial imagery
- Street-level detail required
- Real-time map updates desired
- Users expect familiar map interface (like Google Maps)
Use Both (Hybrid) when:
- Need real-world base with custom shape overlays
- Combining statistical regions with street context
---
Which Color Mapping Type?
Equal Color Mapping:
- Use when data has discrete categories (e.g., Membership: Permanent/Non-Permanent)
- Each unique value gets a specific color
Range Color Mapping:
- Use when data is numeric and continuous (e.g., Population: 0-1M, 1M-10M, 10M+)
- Values within ranges get assigned colors
Desaturation Color Mapping:
- Use for gradient effects based on numeric values
- Single color with varying saturation levels
---
How Many Layers Should I Use?
Single Layer:
- Simple visualizations with one data dimension
- Basic country/region maps
- When all data fits one layer
Multiple Layers:
- Highlighting specific regions on base map
- Combining different data sources
- Creating visual depth with overlays
- Showing borders, rivers, cities separately
Key Props Reference
MapsComponent
titleSettings: Configure title and subtitlelegendSettings: Legend visibility, position, alignmentzoomSettings: Enable zooming, set initial zoom factorlayers: Array of layer configurations
LayerDirective
shapeData: GeoJSON data for shapesdataSource: Data to bind to shapesshapeDataPath: Field in dataSource matching shapesshapePropertyPath: Field in GeoJSON matching dataSourceshapeSettings: Fill, border, color mappingtype: "Layer" (main) or "SubLayer" (overlay)markerSettings: Marker configurationsbubbleSettings: Bubble visualizationsdataLabelSettings: Label configurationstooltipSettings: Tooltip customizationnavigationLineSettings: Line visualizations
Common Patterns
- Module Injection: Only inject needed services to reduce bundle size
- Data Binding: Use shapeDataPath + shapePropertyPath for automatic matching
- Progressive Enhancement: Start with basic map, add features incrementally
- Responsive Design: Maps auto-resize, but test on different viewports
Troubleshooting Quick Checks
❌ Map not displaying:
- Verify GeoJSON data is correctly imported
- Check console for errors
- Ensure CSS is imported
❌ Colors not applied:
- Confirm
shapeDataPathmatches data field name - Verify
shapePropertyPathmatches GeoJSON property - Check
colorValuePathpoints to correct data field
❌ Markers not showing:
- Inject
Markerservice - Set
visible={true}in MarkerDirective - Verify latitude/longitude values are valid
❌ Zoom not working:
- Inject
Zoomservice - Set
zoomSettings.enable={true} - Check if
enablePanningis needed
❌ Legend not appearing:
- Inject
Legendservice - Set
legendSettings.visible={true} - Ensure color mapping is configured
Next Steps
1. Start Simple: Begin with getting-started.md for basic map 2. Add Data: Follow data-visualization.md for markers/bubbles 3. Style It: Use color-mapping.md for choropleth effects 4. Make Interactive: Implement user-interactions.md for zoom/pan 5. Enhance: Add advanced features as needed
Choose the reference documentation that matches your current implementation phase and specific requirements.
Advanced Features in React Maps
Table of Contents
- Overview
- Internationalization
- Localization
- Accessibility
- State Persistence
- Print and Export
- Event Handling
- Methods and API
- Performance Optimization
Overview
Advanced features for enterprise-grade Maps applications: i18n, accessibility, state management, export, and performance.
Internationalization
RTL Support
<MapsComponent enableRtl={true}>
<LayersDirective>
<LayerDirective shapeData={world_map} />
</LayersDirective>
</MapsComponent>Localization
Load Culture
import { L10n, setCulture } from '@syncfusion/ej2-base';
// Set culture
setCulture('de');
// Load German locale
L10n.load({
'de': {
'maps': {
'ZoomIn': 'Hineinzoomen',
'ZoomOut': 'Rauszoomen',
'Reset': 'Zurücksetzen',
'Pan': 'Schwenken',
'Zoom': 'Zoomen'
}
}
});
function LocalizedMap() {
return (
<MapsComponent locale='de'>
<Inject services={[Zoom]} />
<LayersDirective>
<LayerDirective shapeData={world_map} />
</LayersDirective>
</MapsComponent>
);
}Multiple Languages
L10n.load({
'fr': {
'maps': {
'ZoomIn': 'Agrandir',
'ZoomOut': 'Dézoomer',
'Reset': 'Réinitialiser'
}
},
'es': {
'maps': {
'ZoomIn': 'Acercar',
'ZoomOut': 'Alejar',
'Reset': 'Restablecer'
}
}
});Accessibility
WCAG Compliance
<MapsComponent
titleSettings={{
text: 'World Map',
description: 'Interactive world map showing country data'
}}
>
<LayersDirective>
<LayerDirective
shapeData={world_map}
tooltipSettings={{
visible: true,
format: '${name}: ${value}' // Screen reader friendly
}}
/>
</LayersDirective>
</MapsComponent>Features:
- Keyboard navigation (arrow keys, +/- for zoom)
- Screen reader support
- High contrast mode
- Focus indicators
Keyboard Shortcuts
- Arrow keys: Pan map
- + / =: Zoom in
- - / _: Zoom out
- R: Reset zoom
- Tab: Navigate focusable elements
State Persistence
Enable Persistence
<MapsComponent
id='maps'
enablePersistence={true} // Saves zoom, pan state to localStorage
>Custom State Management
function StatefulMap() {
const [mapState, setMapState] = React.useState({
zoomFactor: 1,
centerPosition: { latitude: 0, longitude: 0 }
});
const handleZoomChange = (args) => {
setMapState({
zoomFactor: args.currentZoomFactor,
centerPosition: args.centerPosition
});
};
return (
<MapsComponent
zoomSettings={{
enable: true,
zoomFactor: mapState.zoomFactor
}}
centerPosition={mapState.centerPosition}
zoom={handleZoomChange}
>
<Inject services={[Zoom]} />
<LayersDirective>
<LayerDirective shapeData={world_map} />
</LayersDirective>
</MapsComponent>
);
}Print and Export
Print Map
import { MapsComponent, Print, ImageExport, PdfExport } from '@syncfusion/ej2-react-maps';
function PrintableMap() {
const mapsRef = React.useRef(null);
const printMap = () => {
mapsRef.current.print();
};
return (
<>
<button onClick={printMap}>Print Map</button>
<MapsComponent ref={mapsRef} allowPrint={true}>
<Inject services={[Print]} />
<LayersDirective>
<LayerDirective shapeData={world_map} />
</LayersDirective>
</MapsComponent>
</>
);
}Export as Image
function ExportableMap() {
const mapsRef = React.useRef(null);
const exportToPNG = () => {
mapsRef.current.export('PNG', 'world-map');
};
const exportToJPEG = () => {
mapsRef.current.export('JPEG', 'world-map');
};
const exportToSVG = () => {
mapsRef.current.export('SVG', 'world-map');
};
return (
<>
<button onClick={exportToPNG}>Export PNG</button>
<button onClick={exportToJPEG}>Export JPEG</button>
<button onClick={exportToSVG}>Export SVG</button>
<MapsComponent ref={mapsRef} allowImageExport={true}>
<Inject services={[ImageExport]} />
<LayersDirective>
<LayerDirective shapeData={world_map} />
</LayersDirective>
</MapsComponent>
</>
);
}Export as PDF
function PDFExportMap() {
const mapsRef = React.useRef(null);
const exportToPDF = () => {
mapsRef.current.export('PDF', 'world-map', 0); // 0 = Portrait, 1 = Landscape
};
return (
<>
<button onClick={exportToPDF}>Export PDF</button>
<MapsComponent ref={mapsRef} allowPdfExport={true}>
<Inject services={[PdfExport]} />
<LayersDirective>
<LayerDirective shapeData={world_map} />
</LayersDirective>
</MapsComponent>
</>
);
}Export Options (PDF Orientation & More)
Maps can export to PNG, JPEG, SVG, or PDF with optional orientation.
mapsRef.current.export("PDF", "world-map", "Landscape");Event Handling
Load Event
<MapsComponent
load={(args) => {
console.log('Map is loading');
}}
loaded={(args) => {
console.log('Map loaded successfully');
}}
>Click Events
<MapsComponent
click={(args) => {
console.log('Map clicked at:', args.x, args.y);
}}
shapeSelected={(args) => {
console.log('Shape selected:', args.data);
}}
>Zoom Events
<MapsComponent
zoom={(args) => {
console.log('Zoom factor:', args.currentZoomFactor);
}}
pan={(args) => {
console.log('Pan to:', args.latitude, args.longitude);
}}
>Animation Events
<MapsComponent
animationComplete={(args) => {
console.log('Animation completed');
}}
>Methods and API
Access component methods using a ref to the MapsComponent. For complete API documentation, API Documentation.
Refresh Map
function RefreshableMap() {
const mapsRef = React.useRef(null);
const refreshMap = () => {
mapsRef.current.refresh();
};
return (
<>
<button onClick={refreshMap}>Refresh</button>
<MapsComponent ref={mapsRef}>
<LayersDirective>
<LayerDirective shapeData={world_map} />
</LayersDirective>
</MapsComponent>
</>
);
}Zoom Methods
function ZoomControlMap() {
const mapsRef = React.useRef(null);
const zoomByPosition = () => {
// Zoom to specific location
mapsRef.current.zoomByPosition(
{ latitude: 40.7128, longitude: -74.0060 },
2 // Zoom factor
);
};
const zoomToCoordinates = () => {
// Zoom to bounds
mapsRef.current.zoomToCoordinates(
25.0, // minLatitude
-125.0, // minLongitude
49.0, // maxLatitude
-66.0 // maxLongitude
);
};
return (
<>
<button onClick={zoomByPosition}>Zoom to NYC</button>
<button onClick={zoomToCoordinates}>Zoom to USA</button>
<MapsComponent ref={mapsRef}>
<Inject services={[Zoom]} />
<LayersDirective>
<LayerDirective shapeData={world_map} />
</LayersDirective>
</MapsComponent>
</>
);
}Pan To Location
function PanControlMap() {
const mapsRef = React.useRef(null);
const panByDirection = (direction) => {
// Pan in specific direction
mapsRef.current.panByDirection(direction);
};
return (
<>
<button onClick={() => panByDirection('Left')}>Pan Left</button>
<button onClick={() => panByDirection('Right')}>Pan Right</button>
<button onClick={() => panByDirection('Top')}>Pan Up</button>
<button onClick={() => panByDirection('Bottom')}>Pan Down</button>
<MapsComponent ref={mapsRef}>
<Inject services={[Zoom]} />
<LayersDirective>
<LayerDirective shapeData={world_map} />
</LayersDirective>
</MapsComponent>
</>
);
}Dynamic Layer Management
function DynamicLayerMap() {
const mapsRef = React.useRef(null);
const addLayer = () => {
// Add a new sublayer dynamically
mapsRef.current.addLayer({
shapeData: stateMap,
type: 'SubLayer',
shapeSettings: {
fill: '#FF6347',
opacity: 0.6
}
});
};
const removeLayer = (index) => {
// Remove layer by index
mapsRef.current.removeLayer(index);
};
return (
<>
<button onClick={addLayer}>Add Layer</button>
<button onClick={() => removeLayer(1)}>Remove Second Layer</button>
<MapsComponent ref={mapsRef}>
<LayersDirective>
<LayerDirective shapeData={world_map} />
</LayersDirective>
</MapsComponent>
</>
);
}Dynamic Marker Management
function DynamicMarkerMap() {
const mapsRef = React.useRef(null);
const addMarkers = () => {
// Add markers to layer 0
mapsRef.current.addMarker(0, [
{
visible: true,
dataSource: [
{ latitude: 40.7128, longitude: -74.0060, name: 'New York' },
{ latitude: 51.5074, longitude: -0.1278, name: 'London' }
],
height: 20,
width: 20,
shape: 'Circle',
fill: '#FF0000'
}
]);
};
return (
<>
<button onClick={addMarkers}>Add Markers</button>
<MapsComponent ref={mapsRef}>
<Inject services={[Marker]} />
<LayersDirective>
<LayerDirective shapeData={world_map} />
</LayersDirective>
</MapsComponent>
</>
);
}Shape Selection
function SelectableMap() {
const mapsRef = React.useRef(null);
const selectShape = (shapeName, select = true) => {
// Select or deselect a shape
mapsRef.current.shapeSelection(
0, // Layer index
'name', // Property name
shapeName, // Shape name
select // true to select, false to deselect
);
};
return (
<>
<button onClick={() => selectShape('United States', true)}>
Select USA
</button>
<button onClick={() => selectShape('United States', false)}>
Deselect USA
</button>
<MapsComponent ref={mapsRef}>
<Inject services={[Selection]} />
<LayersDirective>
<LayerDirective
shapeData={world_map}
selectionSettings={{
enable: true,
fill: '#FF6347'
}}
/>
</LayersDirective>
</MapsComponent>
</>
);
}Programmatic Shape Selection
Shapes can be selected directly via API, without user interaction.
mapsRef.current.shapeSelection(0, "name", "United States", true);Coordinate Conversion
function CoordinateConversionMap() {
const mapsRef = React.useRef(null);
const getLocationFromPixel = (pageX, pageY) => {
// Convert pixel coordinates to lat/long
const latLong = mapsRef.current.pointToLatLong(pageX, pageY);
console.log('Latitude:', latLong.latitude);
console.log('Longitude:', latLong.longitude);
return latLong;
};
const getPixelFromLocation = (layerIndex, lat, long) => {
// Convert lat/long to pixel coordinates (for shape maps)
const geoPosition = mapsRef.current.getGeoLocation(layerIndex, lat, long);
return geoPosition;
};
const handleMapClick = (args) => {
const location = getLocationFromPixel(args.x, args.y);
alert(`Clicked at: ${location.latitude.toFixed(2)}, ${location.longitude.toFixed(2)}`);
};
return (
<MapsComponent ref={mapsRef} click={handleMapClick}>
<LayersDirective>
<LayerDirective shapeData={world_map} />
</LayersDirective>
</MapsComponent>
);
}Tile Geo‑location Conversion
Converts pixel positions from tile-based map providers (OSM/Bing/Azure) into latitude/longitude. Useful for drawing overlays or capturing pointer coordinates.
const loc = mapsRef.current.getTileGeoLocation(pageX, pageY);Projection Coordinate Conversion
Convert latitude/longitude to pixel points
const pt = mapsRef.current.latLongToPoint(40.7128, -74.006)Bing Maps Integration
function BingMapsSetup() {
const mapsRef = React.useRef(null);
React.useEffect(() => {
const setupBingMaps = async () => {
const bingUrl = await mapsRef.current.getBingUrlTemplate(
'Add your URL link'
);
console.log('Bing Maps URL Template:', bingUrl);
};
setupBingMaps();
}, []);
return (
<MapsComponent ref={mapsRef}>
<LayersDirective>
<LayerDirective
urlTemplate="Add your URL link"
/>
</LayersDirective>
</MapsComponent>
);
}Available Methods:
addLayer(layer)- Add layer dynamicallyaddMarker(layerIndex, markerCollection)- Add markers dynamicallydestroy()- Destroy the componentexport(type, fileName, orientation, allowDownload)- Export mapgetBingUrlTemplate(url)- Get Bing Maps URLgetGeoLocation(layerIndex, x, y)- Convert pixels to coordinates (shape maps)getTileGeoLocation(x, y)- Convert pixels to coordinates (tile maps)panByDirection(direction, mouseLocation)- Pan in directionpointToLatLong(pageX, pageY)- Convert pixel to lat/longprint(id)- Print mapremoveLayer(index)- Remove layershapeSelection(layerIndex, propertyName, name, enable)- Select shapezoomByPosition(centerPosition, zoomFactor)- Zoom to positionzoomToCoordinates(minLat, minLong, maxLat, maxLong)- Zoom to bounds
For detailed method signatures and parameters, refer to API Documentation.
Performance Optimization
Lazy Loading
const world_map = React.lazy(() => import('./data/world-map.json'));
function OptimizedMap() {
return (
<React.Suspense fallback={<div>Loading map...</div>}>
<MapsComponent>
<LayersDirective>
<LayerDirective shapeData={world_map} />
</LayersDirective>
</MapsComponent>
</React.Suspense>
);
}Simplify GeoJSON
Before optimization:
// Large GeoJSON with detailed coordinates
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [/* 10000+ coordinate pairs */]
}
}After simplification (use mapshaper or turf.js):
// Reduced GeoJSON
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [/* 500 coordinate pairs */]
}
}Conditional Rendering
function ConditionalMap() {
const [showMarkers, setShowMarkers] = React.useState(false);
return (
<>
<input
type="checkbox"
checked={showMarkers}
onChange={(e) => setShowMarkers(e.target.checked)}
/>
<MapsComponent>
<Inject services={showMarkers ? [Marker] : []} />
<LayersDirective>
<LayerDirective
shapeData={world_map}
markerSettings={showMarkers ? [{
visible: true,
dataSource: markerData
}] : []}
/>
</LayersDirective>
</MapsComponent>
</>
);
}Memoization
const MemoizedMap = React.memo(function Map({ shapeData, dataSource }) {
return (
<MapsComponent>
<LayersDirective>
<LayerDirective
shapeData={shapeData}
dataSource={dataSource}
/>
</LayersDirective>
</MapsComponent>
);
});Troubleshooting
Issue: Slow rendering with large GeoJSON
Solutions: 1. Simplify GeoJSON geometries 2. Reduce coordinate precision 3. Use layer visibility to hide unnecessary layers
Issue: Export not working
Solution: Inject required service
<MapsComponent allowPdfExport={true}>
<Inject services={[PdfExport]} />
</MapsComponent>Issue: State persistence not saving
Solution: Provide unique id attribute
<MapsComponent id='unique-map-id' enablePersistence={true}>Annotations and Polygons in React Maps
Overview
Annotations add custom HTML content at specific positions on maps. Polygons render custom shapes beyond GeoJSON data.
Annotations
Basic Annotations
import {
MapsComponent,
LayersDirective,
LayerDirective,
AnnotationsDirective,
AnnotationDirective,
Inject,
Annotations
} from '@syncfusion/ej2-react-maps';
function AnnotatedMap() {
const annotationTemplate = () => {
return (
<div style={{
background: '#FF6347',
color: 'white',
padding: '10px 20px',
borderRadius: '5px',
fontSize: '14px',
fontWeight: 'bold'
}}>
Pacific Ocean
</div>
);
};
return (
<MapsComponent>
<Inject services={[Annotations]} />
<AnnotationsDirective>
<AnnotationDirective
content={annotationTemplate}
x='50%'
y='50%'
/>
</AnnotationsDirective>
<LayersDirective>
<LayerDirective shapeData={world_map} />
</LayersDirective>
</MapsComponent>
);
}Position Annotations
// Percentage positioning
<AnnotationDirective
content={template}
x='25%' // 25% from left
y='75%' // 75% from top
/>
// Pixel positioning
<AnnotationDirective
content={template}
x='100' // 100px from left
y='200' // 200px from top
/>Multiple Annotations
function MultiAnnotationMap() {
const oceanLabel = () => (
<div style={{background: '#4682B4', color: 'white', padding: '5px 10px', borderRadius: '3px'}}>
Atlantic Ocean
</div>
);
const titleAnnotation = () => (
<h2 style={{color: '#333', textAlign: 'center'}}>
World Oceans Map
</h2>
);
return (
<MapsComponent>
<Inject services={[Annotations]} />
<AnnotationsDirective>
<AnnotationDirective content={titleAnnotation} x='50%' y='5%' />
<AnnotationDirective content={oceanLabel} x='30%' y='40%' />
</AnnotationsDirective>
<LayersDirective>
<LayerDirective shapeData={world_map} />
</LayersDirective>
</MapsComponent>
);
}Polygons
Basic Polygon
import {
MapsComponent,
LayersDirective,
LayerDirective,
Inject,
Polygon
} from '@syncfusion/ej2-react-maps';
function PolygonMap() {
const polygonData = [
{
points: [
{ latitude: 37.0902, longitude: -95.7129 },
{ latitude: 38.7, longitude: -96.0 },
{ latitude: 37.0, longitude: -96.0 }
],
fill: 'rgba(255, 0, 0, 0.4)',
borderColor: '#FF0000',
borderWidth: 2
}
];
return (
<MapsComponent>
<Inject services={[Polygon]} />
<LayersDirective>
<LayerDirective
shapeData={usa_map}
polygonSettings={{
polygons: polygonData
}}
/>
</LayersDirective>
</MapsComponent>
);
}Custom Shape Overlay
const customRegions = [
{
points: [
{ latitude: 40, longitude: -100 },
{ latitude: 42, longitude: -98 },
{ latitude: 41, longitude: -96 },
{ latitude: 39, longitude: -97 }
],
fill: 'rgba(76, 175, 80, 0.3)',
borderColor: '#4CAF50',
borderWidth: 3,
opacity: 0.7
},
{
points: [
{ latitude: 35, longitude: -105 },
{ latitude: 37, longitude: -103 },
{ latitude: 36, longitude: -101 },
{ latitude: 34, longitude: -102 }
],
fill: 'rgba(255, 152, 0, 0.3)',
borderColor: '#FF9800',
borderWidth: 3
}
];
<LayerDirective
shapeData={usa_map}
polygonSettings={{ polygons: customRegions }}
/>Use Cases
Highlighting Search Areas
function SearchAreaMap() {
const searchArea = [
{
points: [
{ latitude: 51.6, longitude: -0.3 },
{ latitude: 51.6, longitude: 0.1 },
{ latitude: 51.4, longitude: 0.1 },
{ latitude: 51.4, longitude: -0.3 }
],
fill: 'rgba(33, 150, 243, 0.2)',
borderColor: '#2196F3',
borderWidth: 2
}
];
return (
<MapsComponent>
<Inject services={[Polygon]} />
<LayersDirective>
<LayerDirective
shapeData={london_map}
polygonSettings={{ polygons: searchArea }}
/>
</LayersDirective>
</MapsComponent>
);
}Territory Zones
const territories = [
{
points: [
/* North territory coordinates */
],
fill: 'rgba(255, 99, 71, 0.3)',
borderColor: '#FF6347',
borderWidth: 2
},
{
points: [
/* South territory coordinates */
],
fill: 'rgba(135, 206, 235, 0.3)',
borderColor: '#87CEEB',
borderWidth: 2
}
];
<LayerDirective
shapeData={region_map}
polygonSettings={{ polygons: territories }}
/>Troubleshooting
Issue: Annotations not appearing
Solution: Inject Annotations service
<MapsComponent>
<Inject services={[Annotations]} />
</MapsComponent>Issue: Polygon not visible
Solutions: 1. Inject Polygon service 2. Verify coordinate points are within map bounds 3. Check fill opacity isn't 0
````markdown
Syncfusion React Maps API Reference
Table of Contents
- MapsComponent
- Properties
- Methods
- Events
- Layer Settings
- Marker Settings
- Bubble Settings
- Data Label Settings
- Legend Settings
- Zoom Settings
- Tooltip Settings
- Quick Reference Examples
MapsComponent
The main React component for rendering interactive maps with geographical data visualization.
<MapsComponent
// Essential properties
id="maps"
width="100%"
height="500px"
// Configuration
titleSettings={{ text: 'World Map' }}
legendSettings={{ visible: true }}
zoomSettings={{ enable: true }}
>
<Inject services={[Legend, Zoom, MapsTooltip]} />
<LayersDirective>
<LayerDirective shapeData={geoJsonData} />
</LayersDirective>
</MapsComponent>---
Properties
allowImageExport
- Type:
boolean - Default:
false - Description: Enables or disables the export to image functionality (PNG, JPEG, SVG)
- Requires:
ImageExportservice injection
import { ImageExport } from '@syncfusion/ej2-react-maps';
<MapsComponent allowImageExport={true}>
<Inject services={[ImageExport]} />
</MapsComponent>allowPdfExport
- Type:
boolean - Default:
false - Description: Enables or disables the export to PDF functionality
- Requires:
PdfExportservice injection
import { PdfExport } from '@syncfusion/ej2-react-maps';
<MapsComponent allowPdfExport={true}>
<Inject services={[PdfExport]} />
</MapsComponent>allowPrint
- Type:
boolean - Default:
false - Description: Enables or disables the print functionality
- Requires:
Printservice injection
import { Print } from '@syncfusion/ej2-react-maps';
<MapsComponent allowPrint={true}>
<Inject services={[Print]} />
</MapsComponent>annotations
- Type:
AnnotationModel[] - Description: Gets or sets the options for customizing annotations in the maps
- Requires:
Annotationsservice injection
<MapsComponent
annotations={[
{
content: '<div>Custom Annotation</div>',
x: '50%',
y: '50%',
horizontalAlignment: 'Center',
verticalAlignment: 'Center'
}
]}
>
<Inject services={[Annotations]} />
</MapsComponent>background
- Type:
string - Default:
null - Description: Gets or sets the background color of the maps container
<MapsComponent background="#F5F5F5">baseLayerIndex
- Type:
number - Default:
0 - Description: Gets or sets the index of the layer that will be the base layer
<MapsComponent baseLayerIndex={0}>
<LayersDirective>
<LayerDirective shapeData={worldMap} />
<LayerDirective type="SubLayer" shapeData={countryMap} />
</LayersDirective>
</MapsComponent>border
- Type:
BorderModel - Description: Gets or sets the options for customizing the border of the maps
<MapsComponent
border={{
color: '#000000',
width: 2
}}
>centerPosition
- Type:
CenterPositionModel - Description: Gets or sets the center position of the maps
<MapsComponent
centerPosition={{
latitude: 23.5937,
longitude: 78.9629
}}
>description
- Type:
string - Default:
null - Description: Gets or sets the description for assistive technology (accessibility)
<MapsComponent
description="Interactive world map showing country populations"
>enablePersistence
- Type:
boolean - Default:
false - Description: Enable or disable persisting component's state between page reloads (localStorage)
<MapsComponent id="maps" enablePersistence={true}>enableRtl
- Type:
boolean - Default:
false - Description: Enable or disable rendering component in right to left direction
<MapsComponent enableRtl={true}>format
- Type:
string - Default:
null - Description: Gets or sets the format to apply internationalization for text
<MapsComponent format="n2">height
- Type:
string - Default:
null - Description: Gets or sets the height in which the maps is to be rendered
<MapsComponent height="600px">
<MapsComponent height="100%">isShapeSelected
- Type:
boolean - Description: Specifies whether the shape is selected in the maps or not (read-only)
layers
- Type:
LayerSettingsModel[] - Description: Gets or sets the options to customize the layers of the maps
<MapsComponent>
<LayersDirective>
<LayerDirective
shapeData={worldMap}
shapeSettings={{ fill: '#E5E5E5' }}
/>
</LayersDirective>
</MapsComponent>legendSettings
- Type:
LegendSettingsModel - Description: Gets or sets the options to customize the legend
- Requires:
Legendservice injection
<MapsComponent
legendSettings={{
visible: true,
position: 'Bottom',
alignment: 'Center'
}}
>
<Inject services={[Legend]} />
</MapsComponent>locale
- Type:
string - Default:
'' - Description: Overrides the global culture and localization value for this component
import { L10n } from '@syncfusion/ej2-base';
L10n.load({
'de': {
'maps': {
'ZoomIn': 'Hineinzoomen',
'ZoomOut': 'Rauszoomen'
}
}
});
<MapsComponent locale="de">mapsArea
- Type:
MapsAreaSettingsModel - Description: Gets or sets the options to customize the area around the map
<MapsComponent
mapsArea={{
background: '#FFFFFF',
border: { color: '#000000', width: 1 }
}}
>margin
- Type:
MarginModel - Description: Gets or sets the options to customize the margin of the maps
<MapsComponent
margin={{
left: 10,
right: 10,
top: 10,
bottom: 10
}}
>projectionType
- Type:
ProjectionType - Default:
'Mercator' - Description: Gets or sets the projection type for rendering the map
- Options:
'Mercator','Equirectangular','Miller','Eckert3','Eckert5','Eckert6','Winkel3','AitOff'
<MapsComponent projectionType="Mercator">
<MapsComponent projectionType="Miller">
<MapsComponent projectionType="Equirectangular">tabIndex
- Type:
number - Default:
0 - Description: Gets or sets the tab index value for the maps (accessibility)
<MapsComponent tabIndex={1}>theme
- Type:
MapsTheme - Default:
'Material' - Description: Gets or sets the theme styles supported for maps
- Options:
'Material','Fabric','Bootstrap','Bootstrap4','Bootstrap5','Tailwind','Fluent','Material3', etc.
<MapsComponent theme="Bootstrap5">
<MapsComponent theme="Material3">
<MapsComponent theme="Tailwind">titleSettings
- Type:
TitleSettingsModel - Description: Gets or sets the options to customize the title of the maps
<MapsComponent
titleSettings={{
text: 'World Population Map',
textStyle: {
size: '18px',
fontWeight: 'Bold',
color: '#000000',
fontFamily: 'Arial'
},
alignment: 'Center',
subtitleSettings: {
text: 'Data as of 2024',
textStyle: { size: '12px' }
}
}}
>tooltipDisplayMode
- Type:
TooltipGesture - Default:
'MouseMove' - Description: Gets or sets the mode in which the tooltip is displayed
- Options:
'MouseMove','Click','DoubleClick'
<MapsComponent tooltipDisplayMode="Click">
<MapsComponent tooltipDisplayMode="MouseMove">useGroupingSeparator
- Type:
boolean - Default:
false - Description: Enables or disables the visibility state of the separator for grouping (thousands separator)
<MapsComponent useGroupingSeparator={true}>
// 1000000 displays as 1,000,000width
- Type:
string - Default:
null - Description: Gets or sets the width in which the maps is to be rendered
<MapsComponent width="800px">
<MapsComponent width="100%">zoomSettings
- Type:
ZoomSettingsModel - Description: Gets or sets the options to customize the zooming operations
- Requires:
Zoomservice injection
<MapsComponent
zoomSettings={{
enable: true,
enablePanning: true,
zoomFactor: 1,
maxZoom: 10,
minZoom: 1,
toolbars: ['Zoom', 'ZoomIn', 'ZoomOut', 'Pan', 'Reset']
}}
>
<Inject services={[Zoom]} />
</MapsComponent>---
Methods
Access methods using a ref to the MapsComponent:
const mapsRef = React.useRef(null);
<MapsComponent ref={mapsRef}>addLayer
Adds layers dynamically to the maps.
const addNewLayer = () => {
mapsRef.current.addLayer({
shapeData: newGeoJson,
type: 'SubLayer',
shapeSettings: { fill: '#FF0000' }
});
};Parameters:
layer(Object): Specifies the layer to be added
Returns: void
addMarker
Adds markers dynamically to the maps.
const addMarkers = () => {
mapsRef.current.addMarker(0, [
{
visible: true,
dataSource: [
{ latitude: 40.7128, longitude: -74.0060, name: 'New York' }
]
}
]);
};Parameters:
layerIndex(optional, number): Specifies the index of the layermarkerCollection(optional, MarkerSettingsModel[]): Specifies the marker settings
Returns: void
destroy
Destroys the maps component and removes all events.
const destroyMap = () => {
mapsRef.current.destroy();
};Returns: void
export
Exports the maps to specified format.
const exportMap = () => {
// Export as PNG
mapsRef.current.export('PNG', 'world-map');
// Export as PDF (Portrait)
mapsRef.current.export('PDF', 'world-map', 0);
// Export as PDF (Landscape)
mapsRef.current.export('PDF', 'world-map', 1);
// Get base64 string instead of download
mapsRef.current.export('PNG', 'world-map', null, false).then((data) => {
console.log(data);
});
};Parameters:
type(ExportType):'PNG','JPEG','SVG','PDF'fileName(string): Name of the exported fileorientation(optional, PdfPageOrientation):0for Portrait,1for LandscapeallowDownload(optional, boolean):trueto download,falseto get base64 string
Returns: Promise<string>
getBingUrlTemplate
Gets the Bing maps URL template.
const setupBingMaps = async () => {
const url = await mapsRef.current.getBingUrlTemplate(
'Add your URL link'
);
console.log('Bing URL:', url);
};Parameters:
url(string): Bing maps URL with API key
Returns: Promise<string>
getGeoLocation
Gets geographical coordinates for pixel location (shape maps).
const getLocation = () => {
const geoPosition = mapsRef.current.getGeoLocation(0, 250, 150);
console.log('Latitude:', geoPosition.latitude);
console.log('Longitude:', geoPosition.longitude);
};Parameters:
layerIndex(number): Index of the layerx(number): X position in pixelsy(number): Y position in pixels
Returns: GeoPosition { latitude: number, longitude: number }
getTileGeoLocation
Gets geographical coordinates for pixel location (online map providers).
const getTileLocation = () => {
const geoPosition = mapsRef.current.getTileGeoLocation(250, 150);
console.log('Latitude:', geoPosition.latitude);
console.log('Longitude:', geoPosition.longitude);
};Parameters:
x(number): X position in pixelsy(number): Y position in pixels
Returns: GeoPosition { latitude: number, longitude: number }
panByDirection
Performs panning in the specified direction.
const panMap = (direction) => {
mapsRef.current.panByDirection(direction);
};
// Usage
<button onClick={() => panMap('Left')}>Pan Left</button>
<button onClick={() => panMap('Right')}>Pan Right</button>
<button onClick={() => panMap('Top')}>Pan Up</button>
<button onClick={() => panMap('Bottom')}>Pan Down</button>Parameters:
direction(PanDirection):'Left','Right','Top','Bottom'mouseLocation(optional, PointerEvent | TouchEvent): Mouse/touch event
Returns: void
pointToLatLong
Converts pixel point to latitude and longitude.
const convertPoint = () => {
const latLong = mapsRef.current.pointToLatLong(300, 200);
console.log('Lat:', latLong.latitude, 'Long:', latLong.longitude);
};Parameters:
pageX(number): X position in pixelspageY(number): Y position in pixels
Returns: Object { latitude: number, longitude: number }
Prints the maps.
const printMap = () => {
// Print current map
mapsRef.current.print();
// Print specific element
mapsRef.current.print('maps-container');
// Print multiple elements
mapsRef.current.print(['map1', 'map2']);
};Parameters:
id(optional, string | string[] | Element): Element(s) to print
Returns: void
removeLayer
Removes a layer from the maps.
const removeSecondLayer = () => {
mapsRef.current.removeLayer(1);
};Parameters:
index(number): Index of the layer to remove
Returns: void
shapeSelection
Selects or deselects a shape in the maps.
const selectShape = () => {
// Select shape
mapsRef.current.shapeSelection(0, 'name', 'United States', true);
// Deselect shape
mapsRef.current.shapeSelection(0, 'name', 'United States', false);
};Parameters:
layerIndex(number): Index of the layerpropertyName(string | string[]): Property name from data sourcename(string): Name of the shape to selectenable(optional, boolean):trueto select,falseto deselect
Returns: void
zoomByPosition
Zooms the map to specified center position.
const zoomToLocation = () => {
mapsRef.current.zoomByPosition(
{ latitude: 40.7128, longitude: -74.0060 },
2 // Zoom factor
);
};Parameters:
centerPosition(Object):{ latitude: number, longitude: number }zoomFactor(number): Zoom factor to apply
Returns: void
zoomToCoordinates
Zooms to the specified coordinate bounds.
const zoomToBounds = () => {
mapsRef.current.zoomToCoordinates(
25.0, // minLatitude
-125.0, // minLongitude
49.0, // maxLatitude
-66.0 // maxLongitude
);
};Parameters:
minLatitude(number): Minimum latitudeminLongitude(number): Minimum longitudemaxLatitude(number): Maximum latitudemaxLongitude(number): Maximum longitude
Returns: void
---
Events
All events are passed as props to the MapsComponent:
<MapsComponent
load={(args) => console.log('Loading')}
loaded={(args) => console.log('Loaded')}
click={(args) => console.log('Clicked')}
>animationComplete
- Type:
EmitType<IAnimationCompleteEventArgs> - Description: Triggers after the animation is completed
<MapsComponent
animationComplete={(args) => {
console.log('Animation completed');
}}
>annotationRendering
- Type:
EmitType<IAnnotationRenderingEventArgs> - Description: Triggers before rendering an annotation
<MapsComponent
annotationRendering={(args) => {
// Customize annotation before rendering
args.content = '<div>Modified Annotation</div>';
}}
>beforePrint
- Type:
EmitType<IPrintEventArgs> - Description: Triggers before the print gets started
<MapsComponent
beforePrint={(args) => {
console.log('Starting print');
}}
>bubbleClick
- Type:
EmitType<IBubbleClickEventArgs> - Description: Triggers when clicking on a bubble element
<MapsComponent
bubbleClick={(args) => {
console.log('Bubble clicked:', args.data);
}}
>bubbleMouseMove
- Type:
EmitType<IBubbleMoveEventArgs> - Description: Triggers when hovering over a bubble element
<MapsComponent
bubbleMouseMove={(args) => {
console.log('Hovering bubble:', args.data);
}}
>bubbleRendering
- Type:
EmitType<IBubbleRenderingEventArgs> - Description: Triggers before the bubble element gets rendered
<MapsComponent
bubbleRendering={(args) => {
// Customize bubble before rendering
if (args.data.population > 1000000) {
args.fill = '#FF0000';
}
}}
>click
- Type:
EmitType<IMouseEventArgs> - Description: Triggers when clicking on an element in maps
<MapsComponent
click={(args) => {
console.log('Clicked at:', args.x, args.y);
}}
>dataLabelRendering
- Type:
EmitType<ILabelRenderingEventArgs> - Description: Triggers before the data-label gets rendered
<MapsComponent
dataLabelRendering={(args) => {
// Customize label before rendering
args.text = args.text.toUpperCase();
}}
>doubleClick
- Type:
EmitType<IMouseEventArgs> - Description: Triggers when double clicking on an element
<MapsComponent
doubleClick={(args) => {
console.log('Double clicked at:', args.x, args.y);
}}
>itemHighlight
- Type:
EmitType<ISelectionEventArgs> - Description: Triggers before shape, bubble, or marker gets highlighted
<MapsComponent
itemHighlight={(args) => {
console.log('Highlighting:', args.shapeData);
}}
>itemSelection
- Type:
EmitType<ISelectionEventArgs> - Description: Triggers before shape, bubble, or marker gets selected
<MapsComponent
itemSelection={(args) => {
console.log('Selected:', args.shapeData);
// Prevent selection
args.cancel = true;
}}
>layerRendering
- Type:
EmitType<ILayerRenderingEventArgs> - Description: Triggers before the maps layer gets rendered
<MapsComponent
layerRendering={(args) => {
console.log('Rendering layer:', args.index);
}}
>legendRendering
- Type:
EmitType<ILegendRenderingEventArgs> - Description: Triggers before the legend gets rendered
<MapsComponent
legendRendering={(args) => {
// Customize legend items
args.fill = '#FF0000';
}}
>load
- Type:
EmitType<ILoadEventArgs> - Description: Triggers before the maps gets rendered
<MapsComponent
load={(args) => {
console.log('Maps loading');
}}
>loaded
- Type:
EmitType<ILoadedEventArgs> - Description: Triggers after the maps gets rendered
<MapsComponent
loaded={(args) => {
console.log('Maps loaded successfully');
}}
>markerClick
- Type:
EmitType<IMarkerClickEventArgs> - Description: Triggers when clicking on a marker element
<MapsComponent
markerClick={(args) => {
console.log('Marker clicked:', args.data);
alert(`Clicked: ${args.data.name}`);
}}
>markerClusterClick
- Type:
EmitType<IMarkerClusterClickEventArgs> - Description: Triggers when clicking on a marker cluster
<MapsComponent
markerClusterClick={(args) => {
console.log('Cluster clicked, count:', args.data.length);
}}
>markerClusterMouseMove
- Type:
EmitType<IMarkerClusterMoveEventArgs> - Description: Triggers when hovering over a marker cluster
<MapsComponent
markerClusterMouseMove={(args) => {
console.log('Hovering cluster');
}}
>markerClusterRendering
- Type:
EmitType<IMarkerClusterRenderingEventArgs> - Description: Triggers before the marker cluster gets rendered
<MapsComponent
markerClusterRendering={(args) => {
// Customize cluster appearance
args.fill = '#FF0000';
}}
>markerDragEnd
- Type:
EmitType<IMarkerDragEventArgs> - Description: Triggers when marker stops dragging
<MapsComponent
markerDragEnd={(args) => {
console.log('Marker dropped at:', args.latitude, args.longitude);
}}
>markerDragStart
- Type:
EmitType<IMarkerDragEventArgs> - Description: Triggers when marker starts dragging
<MapsComponent
markerDragStart={(args) => {
console.log('Started dragging marker:', args.data);
}}
>markerMouseMove
- Type:
EmitType<IMarkerMoveEventArgs> - Description: Triggers when moving mouse over marker element
<MapsComponent
markerMouseMove={(args) => {
console.log('Hovering marker:', args.data);
}}
>markerRendering
- Type:
EmitType<IMarkerRenderingEventArgs> - Description: Triggers before the marker gets rendered
<MapsComponent
markerRendering={(args) => {
// Customize marker before rendering
if (args.data.type === 'capital') {
args.fill = '#FFD700';
args.height = 30;
args.width = 30;
}
}}
>mouseMove
- Type:
EmitType<IMouseMoveEventArgs> - Description: Triggers when mouse pointer moves over the map
<MapsComponent
mouseMove={(args) => {
console.log('Mouse at:', args.x, args.y);
}}
>onclick
- Type:
EmitType<IMouseEventArgs> - Description: Triggers when clicking on an element (alias for click)
pan
- Type:
EmitType<IMapPanEventArgs> - Description: Triggers before performing the panning operation
<MapsComponent
pan={(args) => {
console.log('Panning to:', args.latitude, args.longitude);
// Prevent panning
args.cancel = true;
}}
>panComplete
- Type:
EmitType<IMapPanEventArgs> - Description: Triggers after performing the panning action
<MapsComponent
panComplete={(args) => {
console.log('Pan completed');
}}
>resize
- Type:
EmitType<IResizeEventArgs> - Description: Triggers when the maps is resized
<MapsComponent
resize={(args) => {
console.log('Resized to:', args.currentSize);
}}
>rightClick
- Type:
EmitType<IMouseEventArgs> - Description: Triggers when performing right click operation
<MapsComponent
rightClick={(args) => {
console.log('Right clicked at:', args.x, args.y);
// Show custom context menu
}}
>shapeHighlight
- Type:
EmitType<IShapeSelectedEventArgs> - Description: Triggers before the shape gets highlighted
<MapsComponent
shapeHighlight={(args) => {
console.log('Highlighting shape:', args.data);
}}
>shapeRendering
- Type:
EmitType<IShapeRenderingEventArgs> - Description: Triggers before the shape gets rendered
<MapsComponent
shapeRendering={(args) => {
// Customize shape before rendering
if (args.data.population > 100000000) {
args.fill = '#FF0000';
}
}}
>shapeSelected
- Type:
EmitType<IShapeSelectedEventArgs> - Description: Triggers when a shape is selected
<MapsComponent
shapeSelected={(args) => {
console.log('Shape selected:', args.data);
alert(`Selected: ${args.data.name}`);
}}
>tooltipRender
- Type:
EmitType<ITooltipRenderEventArgs> - Description: Triggers before the tooltip gets rendered
<MapsComponent
tooltipRender={(args) => {
// Customize tooltip content
args.content = `<div style="padding: 10px;">
<b>${args.data.name}</b><br/>
Population: ${args.data.population}
</div>`;
}}
>tooltipRenderComplete
- Type:
EmitType<ITooltipRenderCompleteEventArgs> - Description: Triggers after the tooltip gets rendered
<MapsComponent
tooltipRenderComplete={(args) => {
console.log('Tooltip rendered');
}}
>zoom
- Type:
EmitType<IMapZoomEventArgs> - Description: Triggers before zoom operations (zoom in/out)
<MapsComponent
zoom={(args) => {
console.log('Zooming to factor:', args.currentZoomFactor);
// Prevent zoom
args.cancel = true;
}}
>zoomComplete
- Type:
EmitType<IMapPanEventArgs> - Description: Triggers after the zooming operation is completed
<MapsComponent
zoomComplete={(args) => {
console.log('Zoom completed');
}}
>---
Layer Settings
Configuration for individual map layers:
<LayerDirective
// Data
shapeData={geoJsonData}
dataSource={customData}
shapeDataPath="Country"
shapePropertyPath="name"
// Type
type="Layer" // or "SubLayer"
// Visual Settings
shapeSettings={{
fill: '#E5E5E5',
colorValuePath: 'Population',
colorMapping: [...]
}}
// Features
markerSettings={[...]}
bubbleSettings={[...]}
dataLabelSettings={{...}}
tooltipSettings={{...}}
navigationLineSettings={[...]}
/>---
Marker Settings
<MarkerDirective
visible={true}
dataSource={[
{ latitude: 40.7128, longitude: -74.0060, name: 'NYC' }
]}
// Shape
shape="Circle" // Circle, Diamond, Star, Triangle, etc.
height={20}
width={20}
// Appearance
fill="#FF0000"
opacity={0.8}
border={{ color: '#000000', width: 1 }}
// Template
template={(props) => <div>{props.name}</div>}
// Clustering
clusterSettings={{
allowClustering: true,
shape: 'Circle',
width: 30,
height: 30,
fill: '#4CAF50'
}}
// Tooltip
tooltipSettings={{
visible: true,
valuePath: 'name',
format: '${name}'
}}
/>---
Bubble Settings
<BubbleDirective
visible={true}
dataSource={data}
// Size
valuePath="population"
minRadius={10}
maxRadius={50}
// Appearance
fill="#FF6347"
opacity={0.6}
border={{ color: '#FF0000', width: 1 }}
// Color Mapping
colorValuePath="population"
colorMapping={[
{ from: 0, to: 100000, color: '#C3E6CB' },
{ from: 100000, to: 1000000, color: '#6AB187' }
]}
// Animation
animationDuration={1000}
animationDelay={0}
// Tooltip
tooltipSettings={{
visible: true,
valuePath: 'name'
}}
/>---
Data Label Settings
dataLabelSettings={{
visible: true,
labelPath: 'name',
// Smart Label
smartLabelMode: 'Trim', // Trim, Hide, None
intersectionAction: 'Hide',
// Style
textStyle: {
size: '12px',
color: '#000000',
fontFamily: 'Arial',
fontWeight: 'Normal',
fontStyle: 'Normal',
opacity: 1
},
// Border
border: {
color: '#FFFFFF',
width: 1
},
// Template
template: (props) => <div>{props.name}</div>
}}---
Legend Settings
legendSettings={{
visible: true,
// Position
position: 'Bottom', // Top, Bottom, Left, Right
alignment: 'Center', // Near, Center, Far
// Mode
mode: 'Default', // Default, Interactive
// Appearance
height: '50px',
width: '200px',
background: '#FFFFFF',
border: { color: '#000000', width: 1 },
// Text Style
textStyle: {
size: '12px',
color: '#000000',
fontFamily: 'Arial'
},
// Shape
shape: 'Circle', // Circle, Rectangle, Triangle, etc.
shapeHeight: 15,
shapeWidth: 15,
shapePadding: 5,
// Template
legendTemplate: (props) => <div>{props.text}</div>
}}---
Zoom Settings
zoomSettings={{
enable: true,
enablePanning: true,
enableSelectionZooming: false,
// Zoom Factor
zoomFactor: 1,
maxZoom: 10,
minZoom: 1,
// Zoom On Area
zoomOnClick: false,
// Mouse Wheel
mouseWheelZoom: true,
doubleClickZoom: false,
pinchZooming: true,
// Toolbar
toolbars: ['Zoom', 'ZoomIn', 'ZoomOut', 'Pan', 'Reset'],
// Toolbar Orientation
horizontalAlignment: 'Near', // Near, Center, Far
verticalAlignment: 'Near', // Near, Center, Far
// Toolbar Style
toolbarSettings: {
backgroundColor: '#FFFFFF',
borderColor: '#000000',
borderWidth: 1,
buttonSettings: {
fill: '#FFFFFF',
color: '#000000',
padding: 10
}
}
}}---
Tooltip Settings
tooltipSettings={{
visible: true,
// Content
valuePath: 'name',
format: '${name}: ${population}',
// Template
template: (props) => (
<div>
<b>{props.name}</b><br/>
Population: {props.population}
</div>
),
// Style
fill: '#FFFFFF',
textStyle: {
size: '12px',
color: '#000000',
fontFamily: 'Arial'
},
border: {
color: '#000000',
width: 1
}
}}---
Quick Reference Examples
Complete Feature-Rich Map
import * as React from 'react';
import {
MapsComponent,
LayersDirective,
LayerDirective,
MarkersDirective,
MarkerDirective,
BubblesDirective,
BubbleDirective,
Inject,
Legend,
MapsTooltip,
Zoom,
DataLabel,
Marker,
Bubble,
Selection,
Highlight,
Print,
ImageExport,
PdfExport
} from '@syncfusion/ej2-react-maps';
import { world_map } from './world-map';
function ComprehensiveMap() {
const mapsRef = React.useRef(null);
const countryData = [
{ name: 'United States', population: 331000000, gdp: 21427700 },
{ name: 'China', population: 1439000000, gdp: 14342900 },
{ name: 'India', population: 1380000000, gdp: 2875142 }
];
const cityMarkers = [
{ latitude: 40.7128, longitude: -74.0060, city: 'New York' },
{ latitude: 51.5074, longitude: -0.1278, city: 'London' },
{ latitude: 35.6762, longitude: 139.6503, city: 'Tokyo' }
];
const exportToPNG = () => {
mapsRef.current.export('PNG', 'world-map');
};
const exportToPDF = () => {
mapsRef.current.export('PDF', 'world-map', 0);
};
const printMap = () => {
mapsRef.current.print();
};
return (
<div>
<div style={{ marginBottom: '10px' }}>
<button onClick={exportToPNG}>Export PNG</button>
<button onClick={exportToPDF}>Export PDF</button>
<button onClick={printMap}>Print</button>
</div>
<MapsComponent
ref={mapsRef}
id="maps"
height="600px"
// Export & Print
allowImageExport={true}
allowPdfExport={true}
allowPrint={true}
// Title
titleSettings={{
text: 'World Population & GDP Map',
textStyle: { size: '18px', fontWeight: 'Bold' }
}}
// Zoom
zoomSettings={{
enable: true,
enablePanning: true,
toolbars: ['Zoom', 'ZoomIn', 'ZoomOut', 'Pan', 'Reset']
}}
// Legend
legendSettings={{
visible: true,
position: 'Bottom',
alignment: 'Center'
}}
// Events
load={(args) => console.log('Loading')}
loaded={(args) => console.log('Loaded')}
shapeSelected={(args) => console.log('Selected:', args.data)}
markerClick={(args) => alert(`Clicked: ${args.data.city}`)}
>
<Inject services={[
Legend,
MapsTooltip,
Zoom,
DataLabel,
Marker,
Bubble,
Selection,
Highlight,
Print,
ImageExport,
PdfExport
]} />
<LayersDirective>
<LayerDirective
shapeData={world_map}
dataSource={countryData}
shapeDataPath='name'
shapePropertyPath='name'
// Shape Settings
shapeSettings={{
fill: '#E5E5E5',
colorValuePath: 'population',
colorMapping: [
{ from: 0, to: 100000000, color: '#C3E6CB', label: '< 100M' },
{ from: 100000000, to: 500000000, color: '#6AB187', label: '100M-500M' },
{ from: 500000000, to: 2000000000, color: '#2F7C4F', label: '> 500M' }
]
}}
// Tooltip
tooltipSettings={{
visible: true,
valuePath: 'name',
format: '${name}<br/>Population: ${population}<br/>GDP: $${gdp}M'
}}
// Data Labels
dataLabelSettings={{
visible: true,
labelPath: 'name',
smartLabelMode: 'Trim',
textStyle: { size: '10px' }
}}
// Selection & Highlight
selectionSettings={{
enable: true,
fill: '#FF6347',
opacity: 0.8
}}
highlightSettings={{
enable: true,
fill: '#FFA500',
opacity: 0.5
}}
>
{/* Markers */}
<MarkersDirective>
<MarkerDirective
visible={true}
dataSource={cityMarkers}
shape='Star'
height={20}
width={20}
fill='#FFD700'
tooltipSettings={{
visible: true,
valuePath: 'city'
}}
/>
</MarkersDirective>
{/* Bubbles */}
<BubblesDirective>
<BubbleDirective
visible={true}
dataSource={countryData}
valuePath='gdp'
minRadius={10}
maxRadius={40}
fill='#2196F3'
opacity={0.5}
tooltipSettings={{
visible: true,
format: '${name}<br/>GDP: $${gdp}M'
}}
/>
</BubblesDirective>
</LayerDirective>
</LayersDirective>
</MapsComponent>
</div>
);
}
export default ComprehensiveMap;---
Related Documentation
- Getting Started
- Markers
- Data Visualization
- User Interactions
- Legend
- Color Mapping
- Advanced Features
---
External Resources
````
Color Mapping in React Maps
Table of Contents
- Overview
- Equal Color Mapping
- Range Color Mapping
- Desaturation Color Mapping
- Color Value Path
- Custom Color Schemes
- Visual Strategies
- Common Use Cases
- Troubleshooting
Overview
Color mapping applies colors to map shapes based on data values, creating choropleth maps for visual data analysis.
Three Types: 1. Equal: Discrete categories (e.g., countries by continent) 2. Range: Numeric ranges (e.g., population brackets) 3. Desaturation: Gradient based on values (e.g., temperature scale)
Equal Color Mapping
Assign specific colors to distinct categorical values.
Basic Example
function CategoricalMap() {
const membershipData = [
{ name: 'United States', membership: 'Permanent' },
{ name: 'France', membership: 'Permanent' },
{ name: 'Brazil', membership: 'Non-Permanent' },
{ name: 'Germany', membership: 'Observer' }
];
return (
<MapsComponent>
<LayersDirective>
<LayerDirective
shapeData={world_map}
dataSource={membershipData}
shapeDataPath='name'
shapePropertyPath='name'
shapeSettings={{
colorValuePath: 'membership',
colorMapping: [
{ value: 'Permanent', color: '#D84444' },
{ value: 'Non-Permanent', color: '#316DB5' },
{ value: 'Observer', color: '#FFD700' }
]
}}
/>
</LayersDirective>
</MapsComponent>
);
}With Legend Labels
colorMapping: [
{ value: 'Permanent', color: '#D84444', label: 'Permanent Member' },
{ value: 'Non-Permanent', color: '#316DB5', label: 'Non-Permanent Member' },
{ value: 'Observer', color: '#FFD700', label: 'Observer Status' }
]Multiple Categories Example
const continentData = [
{ country: 'United States', continent: 'North America' },
{ country: 'Brazil', continent: 'South America' },
{ country: 'China', continent: 'Asia' },
{ country: 'France', continent: 'Europe' },
{ country: 'Nigeria', continent: 'Africa' },
{ country: 'Australia', continent: 'Australia' }
];
<LayerDirective
shapeData={world_map}
dataSource={continentData}
shapeDataPath='country'
shapePropertyPath='name'
shapeSettings={{
colorValuePath: 'continent',
colorMapping: [
{ value: 'Asia', color: '#FF6B6B' },
{ value: 'Africa', color: '#4ECDC4' },
{ value: 'Europe', color: '#45B7D1' },
{ value: 'North America', color: '#FFA07A' },
{ value: 'South America', color: '#98D8C8' },
{ value: 'Australia', color: '#F7DC6F' },
{ value: 'Antarctica', color: '#E8E8E8' }
]
}}
/>Range Color Mapping
Apply colors based on numeric value ranges.
Basic Range Example
function PopulationMap() {
const populationData = [
{ country: 'China', population: 1439323776 },
{ country: 'India', population: 1380004385 },
{ country: 'United States', population: 331002651 },
{ country: 'Indonesia', population: 273523615 },
{ country: 'Iceland', population: 341243 }
];
return (
<MapsComponent>
<Inject services={[Legend]} />
<LayersDirective>
<LayerDirective
shapeData={world_map}
dataSource={populationData}
shapeDataPath='country'
shapePropertyPath='name'
shapeSettings={{
fill: '#E5E5E5', // Default color for unmatched shapes
colorValuePath: 'population',
colorMapping: [
{ from: 0, to: 10000000, color: '#C3E6CB', label: '< 10M' },
{ from: 10000000, to: 100000000, color: '#6AB187', label: '10M - 100M' },
{ from: 100000000, to: 500000000, color: '#4A9068', label: '100M - 500M' },
{ from: 500000000, to: 2000000000, color: '#2F7C4F', label: '> 500M' }
]
}}
/>
</LayersDirective>
</MapsComponent>
);
}GDP Classification
colorMapping: [
{ from: 0, to: 1000, color: '#FFE5B4', label: 'Low Income' },
{ from: 1000, to: 4000, color: '#FFB347', label: 'Lower Middle' },
{ from: 4000, to: 12000, color: '#FF8C00', label: 'Upper Middle' },
{ from: 12000, to: 100000, color: '#FF6347', label: 'High Income' }
]Temperature Range
colorMapping: [
{ from: -50, to: 0, color: '#0000FF', label: 'Freezing' },
{ from: 0, to: 10, color: '#4169E1', label: 'Cold' },
{ from: 10, to: 20, color: '#87CEEB', label: 'Cool' },
{ from: 20, to: 30, color: '#FFD700', label: 'Warm' },
{ from: 30, to: 40, color: '#FF8C00', label: 'Hot' },
{ from: 40, to: 60, color: '#FF0000', label: 'Very Hot' }
]Desaturation Color Mapping
Create gradient effect using single color with varying intensity.
Basic Desaturation
function DensityMap() {
const densityData = [
{ country: 'Monaco', density: 26337 },
{ country: 'Singapore', density: 8358 },
{ country: 'Bangladesh', density: 1265 },
{ country: 'United States', density: 36 },
{ country: 'Mongolia', density: 2 }
];
return (
<MapsComponent>
<LayersDirective>
<LayerDirective
shapeData={world_map}
dataSource={densityData}
shapeDataPath='country'
shapePropertyPath='name'
shapeSettings={{
fill: '#E5E5E5',
colorValuePath: 'density',
colorMapping: [
{
from: 0,
to: 30000,
color: '#2E7D32', // Base color
minOpacity: 0.2, // Lowest density
maxOpacity: 1 // Highest density
}
]
}}
/>
</LayersDirective>
</MapsComponent>
);
}How it works:
- Single color with varying opacity/saturation
- Lower values = lighter shade
- Higher values = darker shade
- Smooth gradient effect
Multiple Desaturation Ranges
colorMapping: [
{ from: 0, to: 100, color: '#4CAF50', minOpacity: 0.2, maxOpacity: 0.6 },
{ from: 100, to: 1000, color: '#FF9800', minOpacity: 0.4, maxOpacity: 0.8 },
{ from: 1000, to: 30000, color: '#F44336', minOpacity: 0.6, maxOpacity: 1 }
]Color Value Path
Specifies which data field determines the color.
Single Field
shapeSettings={{
colorValuePath: 'population', // Uses population field
colorMapping: [...]
}}Nested Field
const data = [
{
country: 'USA',
statistics: {
economy: { gdp: 21427 }
}
}
];
shapeSettings={{
colorValuePath: 'statistics.economy.gdp', // Nested path
colorMapping: [...]
}}Computed Values
Use data transformation before binding:
const processedData = countryData.map(item => ({
...item,
gdpPerCapita: item.gdp / item.population
}));
<LayerDirective
dataSource={processedData}
shapeSettings={{
colorValuePath: 'gdpPerCapita',
colorMapping: [...]
}}
/>Custom Color Schemes
Diverging Color Scheme
For data with meaningful midpoint (e.g., election results):
colorMapping: [
{ from: 0, to: 30, color: '#0015BC', label: 'Strong Blue' },
{ from: 30, to: 45, color: '#7DA2D9', label: 'Lean Blue' },
{ from: 45, to: 55, color: '#E8E8E8', label: 'Swing' },
{ from: 55, to: 70, color: '#F4A7A5', label: 'Lean Red' },
{ from: 70, to: 100, color: '#DE0100', label: 'Strong Red' }
]Sequential Color Scheme
Progressive intensity (e.g., unemployment rate):
colorMapping: [
{ from: 0, to: 3, color: '#FFFFCC', label: 'Very Low' },
{ from: 3, to: 5, color: '#C7E9B4', label: 'Low' },
{ from: 5, to: 7, color: '#7FCDBB', label: 'Moderate' },
{ from: 7, to: 10, color: '#41B6C4', label: 'High' },
{ from: 10, to: 15, color: '#2C7FB8', label: 'Very High' },
{ from: 15, to: 30, color: '#253494', label: 'Extreme' }
]Qualitative Color Scheme
Distinct colors for unordered categories:
colorMapping: [
{ value: 'Agriculture', color: '#8DD3C7' },
{ value: 'Manufacturing', color: '#FFFFB3' },
{ value: 'Services', color: '#BEBADA' },
{ value: 'Technology', color: '#FB8072' },
{ value: 'Finance', color: '#80B1D3' },
{ value: 'Healthcare', color: '#FDB462' }
]Visual Strategies
Strategy 1: High Contrast for Key Differences
// Election results - clear distinction
colorMapping: [
{ value: 'Candidate A', color: '#0015BC', label: 'Candidate A' },
{ value: 'Candidate B', color: '#DE0100', label: 'Candidate B' },
{ value: 'No Data', color: '#E8E8E8', label: 'No Data' }
]Strategy 2: Gradient for Continuous Data
// Temperature - smooth transition
colorMapping: [
{ from: -10, to: 0, color: '#08519C' },
{ from: 0, to: 10, color: '#3182BD' },
{ from: 10, to: 20, color: '#6BAED6' },
{ from: 20, to: 30, color: '#9ECAE1' },
{ from: 30, to: 40, color: '#C6DBEF' }
]Strategy 3: Color-Blind Friendly
// Accessible color palette
colorMapping: [
{ value: 'Category 1', color: '#0173B2' }, // Blue
{ value: 'Category 2', color: '#DE8F05' }, // Orange
{ value: 'Category 3', color: '#029E73' }, // Green
{ value: 'Category 4', color: '#CC78BC' } // Purple
]Strategy 4: Default Color for Missing Data
shapeSettings={{
fill: '#F0F0F0', // Light gray for countries without data
colorValuePath: 'value',
colorMapping: [
{ from: 0, to: 100, color: '#4CAF50' }
],
border: {
color: '#CCCCCC',
width: 0.5
}
}}Common Use Cases
Choropleth Map: Population Density
function PopulationDensityMap() {
const densityData = [
{ country: 'Monaco', density: 26337, tier: 'very-high' },
{ country: 'Singapore', density: 8358, tier: 'very-high' },
{ country: 'Bangladesh', density: 1265, tier: 'high' },
{ country: 'India', density: 464, tier: 'medium' },
{ country: 'China', density: 153, tier: 'medium' },
{ country: 'United States', density: 36, tier: 'low' },
{ country: 'Canada', density: 4, tier: 'very-low' }
];
return (
<MapsComponent
titleSettings={{ text: 'Population Density (per km²)' }}
legendSettings={{ visible: true }}
>
<Inject services={[Legend]} />
<LayersDirective>
<LayerDirective
shapeData={world_map}
dataSource={densityData}
shapeDataPath='country'
shapePropertyPath='name'
shapeSettings={{
fill: '#E8E8E8',
colorValuePath: 'density',
colorMapping: [
{ from: 0, to: 50, color: '#FFF5E6', label: '0-50' },
{ from: 50, to: 200, color: '#FFD699', label: '50-200' },
{ from: 200, to: 500, color: '#FFB84D', label: '200-500' },
{ from: 500, to: 2000, color: '#FF9900', label: '500-2000' },
{ from: 2000, to: 30000, color: '#CC7A00', label: '2000+' }
]
}}
/>
</LayersDirective>
</MapsComponent>
);
}Election Results Map
function ElectionMap() {
const results = [
{ state: 'California', winner: 'Democrat', margin: 29.2 },
{ state: 'Texas', winner: 'Republican', margin: 5.6 },
{ state: 'Florida', winner: 'Republican', margin: 3.4 },
{ state: 'Pennsylvania', winner: 'Democrat', margin: 1.2 }
];
return (
<MapsComponent legendSettings={{ visible: true, mode: 'Interactive' }}>
<Inject services={[Legend]} />
<LayersDirective>
<LayerDirective
shapeData={usa_map}
dataSource={results}
shapeDataPath='state'
shapePropertyPath='name'
shapeSettings={{
colorValuePath: 'winner',
colorMapping: [
{ value: 'Democrat', color: '#0015BC', label: 'Democrat' },
{ value: 'Republican', color: '#DE0100', label: 'Republican' }
],
border: { color: 'white', width: 2 }
}}
/>
</LayersDirective>
</MapsComponent>
);
}COVID-19 Cases Map
function CovidMap() {
const covidData = [
{ country: 'United States', cases: 95000000, severity: 'critical' },
{ country: 'India', cases: 44000000, severity: 'high' },
{ country: 'Brazil', cases: 37000000, severity: 'high' },
{ country: 'France', cases: 38000000, severity: 'moderate' }
];
return (
<MapsComponent
titleSettings={{ text: 'COVID-19 Total Cases by Country' }}
legendSettings={{ visible: true, position: 'Right' }}
>
<Inject services={[Legend]} />
<LayersDirective>
<LayerDirective
shapeData={world_map}
dataSource={covidData}
shapeDataPath='country'
shapePropertyPath='name'
shapeSettings={{
fill: '#F0F0F0',
colorValuePath: 'cases',
colorMapping: [
{ from: 0, to: 1000000, color: '#FFF9C4', label: '< 1M' },
{ from: 1000000, to: 10000000, color: '#FFF176', label: '1M - 10M' },
{ from: 10000000, to: 50000000, color: '#FFB300', label: '10M - 50M' },
{ from: 50000000, to: 100000000, color: '#F57C00', label: '50M - 100M' }
]
}}
/>
</LayersDirective>
</MapsComponent>
);
}Troubleshooting
Issue: Colors not applying
Causes & Solutions:
1. colorValuePath doesn't match data field
// ✅ Correct - field names match
const data = [{ country: 'USA', status: 'Active' }];
shapeSettings={{ colorValuePath: 'status' }}
// ❌ Wrong - field name mismatch
const data = [{ country: 'USA', status: 'Active' }];
shapeSettings={{ colorValuePath: 'state' }} // Wrong field2. shapeDataPath/shapePropertyPath mismatch
// ✅ Correct - paths connect data to GeoJSON
shapeDataPath='country' // Field in your data
shapePropertyPath='name' // Field in GeoJSON properties
// ❌ Wrong - paths don't match
shapeDataPath='name' // Doesn't exist in data
shapePropertyPath='country' // Doesn't exist in GeoJSON3. Values don't match color mapping
// ✅ Correct - values match
data: [{ country: 'USA', type: 'Developed' }]
colorMapping: [{ value: 'Developed', color: '#00FF00' }]
// ❌ Wrong - value mismatch (case-sensitive)
data: [{ country: 'USA', type: 'developed' }]
colorMapping: [{ value: 'Developed', color: '#00FF00' }]Issue: Some shapes not colored
Cause: Data missing for those shapes or out of range
Solution:
// Set default color for unmatched shapes
shapeSettings={{
fill: '#E5E5E5', // Default gray
colorValuePath: 'value',
colorMapping: [...]
}}Issue: Range colors not working correctly
Cause: Overlapping or missing ranges
Solution:
// ✅ Correct - continuous non-overlapping ranges
colorMapping: [
{ from: 0, to: 100, color: '#C3E6CB' },
{ from: 100, to: 500, color: '#6AB187' }, // Start where previous ends
{ from: 500, to: 1000, color: '#2F7C4F' }
]
// ❌ Wrong - gaps in ranges
colorMapping: [
{ from: 0, to: 100, color: '#C3E6CB' },
{ from: 200, to: 500, color: '#6AB187' }, // Gap: 100-200 missing
{ from: 600, to: 1000, color: '#2F7C4F' } // Gap: 500-600 missing
]Issue: Desaturation not visible
Cause: minOpacity and maxOpacity too similar
Solution:
// ✅ Good opacity range
{ from: 0, to: 100, color: '#2E7D32', minOpacity: 0.2, maxOpacity: 1 }
// ❌ Poor contrast
{ from: 0, to: 100, color: '#2E7D32', minOpacity: 0.8, maxOpacity: 0.9 }Data Visualization Elements in React Maps
Table of Contents
- Overview
- Bubbles
- Data Labels
- Smart Label Modes
- Label Templates
- Combining Bubbles and Labels
- Visual Hierarchy Best Practices
- Heatmap Layer
- Common Use Cases
- Troubleshooting
Overview
Data visualization elements help display quantitative information directly on maps. Two primary elements:
- Bubbles: Size-based visualization showing data magnitude
- Data Labels: Text labels displaying information on shapes
Bubbles
Bubbles visualize data magnitude using proportional circles. Larger values = larger bubbles.
Enabling Bubbles
import {
MapsComponent,
LayersDirective,
LayerDirective,
BubblesDirective,
BubbleDirective,
Inject,
Bubble
} from '@syncfusion/ej2-react-maps';
function BubbleMap() {
const populationData = [
{ name: 'India', population: 1380000000, latitude: 20.5937, longitude: 78.9629 },
{ name: 'China', population: 1439000000, latitude: 35.8617, longitude: 104.1954 },
{ name: 'USA', population: 331000000, latitude: 37.0902, longitude: -95.7129 }
];
return (
<MapsComponent>
<Inject services={[Bubble]} />
<LayersDirective>
<LayerDirective shapeData={world_map}>
<BubblesDirective>
<BubbleDirective
visible={true}
dataSource={populationData}
valuePath='population'
minRadius={10}
maxRadius={40}
fill='#FF6347'
opacity={0.6}
/>
</BubblesDirective>
</LayerDirective>
</LayersDirective>
</MapsComponent>
);
}Bubble Configuration
<BubbleDirective
visible={true}
dataSource={data}
valuePath='population' // Field determining bubble size
minRadius={5} // Minimum bubble size (px)
maxRadius={50} // Maximum bubble size (px)
fill='#4CAF50' // Bubble color
opacity={0.7} // Transparency (0-1)
border={{
color: '#2E7D32',
width: 1
}}
animationDuration={1000} // Animation duration (ms)
animationDelay={0} // Delay before animation
/>Bubble Color Mapping
Apply different colors based on value ranges:
<BubbleDirective
visible={true}
dataSource={cityData}
valuePath='population'
minRadius={10}
maxRadius={40}
colorValuePath='population'
colorMapping={[
{ from: 0, to: 1000000, color: '#C3E6CB' },
{ from: 1000000, to: 5000000, color: '#6AB187' },
{ from: 5000000, to: 50000000, color: '#2F7C4F' }
]}
/>Multiple Bubble Sets
Display different datasets:
<LayerDirective shapeData={world_map}>
<BubblesDirective>
{/* Population bubbles */}
<BubbleDirective
visible={true}
dataSource={populationData}
valuePath='population'
fill='#2196F3'
minRadius={10}
maxRadius={40}
/>
{/* GDP bubbles */}
<BubbleDirective
visible={true}
dataSource={gdpData}
valuePath='gdp'
fill='#FF9800'
minRadius={8}
maxRadius={35}
/>
</BubblesDirective>
</LayerDirective>Bubble Tooltips
<MapsComponent>
<Inject services={[Bubble, MapsTooltip]} />
<LayersDirective>
<LayerDirective shapeData={world_map}>
<BubblesDirective>
<BubbleDirective
visible={true}
dataSource={data}
valuePath='population'
tooltipSettings={{
visible: true,
valuePath: 'name',
format: '${name}<br/>Population: ${population}'
}}
minRadius={10}
maxRadius={40}
/>
</BubblesDirective>
</LayerDirective>
</LayersDirective>
</MapsComponent>Data Labels
Display text information directly on map shapes.
Basic Data Labels
import {
MapsComponent,
LayersDirective,
LayerDirective,
Inject,
DataLabel
} from '@syncfusion/ej2-react-maps';
function DataLabelMap() {
return (
<MapsComponent>
<Inject services={[DataLabel]} />
<LayersDirective>
<LayerDirective
shapeData={world_map}
dataLabelSettings={{
visible: true,
labelPath: 'name', // Field from GeoJSON properties
smartLabelMode: 'Trim'
}}
/>
</LayersDirective>
</MapsComponent>
);
}Data Label Configuration
dataLabelSettings={{
visible: true,
labelPath: 'name', // Data field to display
smartLabelMode: 'Trim', // Trim, Hide, or None
intersectionAction: 'Hide', // Hide overlapping labels
textStyle: {
size: '12px',
color: '#000000',
fontFamily: 'Arial',
fontWeight: 'Normal',
fontStyle: 'Normal',
opacity: 1
},
border: {
color: '#FFFFFF',
width: 1
}
}}Data Labels with Custom Data
function CustomDataLabelMap() {
const countryData = [
{ name: 'United States', code: 'USA', population: '331M' },
{ name: 'China', code: 'CHN', population: '1.4B' },
{ name: 'India', code: 'IND', population: '1.4B' }
];
return (
<MapsComponent>
<Inject services={[DataLabel]} />
<LayersDirective>
<LayerDirective
shapeData={world_map}
dataSource={countryData}
shapeDataPath='name'
shapePropertyPath='name'
dataLabelSettings={{
visible: true,
labelPath: 'code', // Display country codes
smartLabelMode: 'Trim',
textStyle: {
size: '14px',
fontWeight: 'Bold',
color: '#FFFFFF'
}
}}
/>
</LayersDirective>
</MapsComponent>
);
}Smart Label Modes
Control how labels behave when space is limited.
Trim Mode
Truncates text with ellipsis when it doesn't fit:
dataLabelSettings={{
visible: true,
labelPath: 'name',
smartLabelMode: 'Trim'
}}Result: "United States of America" → "United States..."
Hide Mode
Hides labels that don't fit:
dataLabelSettings={{
visible: true,
labelPath: 'name',
smartLabelMode: 'Hide'
}}Result: Small shapes may have no label visible.
None Mode
Shows full text regardless of space:
dataLabelSettings={{
visible: true,
labelPath: 'name',
smartLabelMode: 'None'
}}Result: Text may overlap or extend beyond shape.
Intersection Action
Control overlapping labels:
dataLabelSettings={{
visible: true,
labelPath: 'name',
smartLabelMode: 'Trim',
intersectionAction: 'Hide' // Options: Hide, Trim, None
}}Label Templates
Create custom label designs:
function TemplateLabelMap() {
const labelTemplate = (props) => {
return (
<div style={{
backgroundColor: 'rgba(0, 0, 0, 0.7)',
color: 'white',
padding: '4px 8px',
borderRadius: '4px',
fontSize: '11px',
fontWeight: 'bold',
border: '1px solid white'
}}>
{props.name}
<div style={{ fontSize: '9px', opacity: 0.8 }}>
Pop: {props.population}
</div>
</div>
);
};
return (
<MapsComponent>
<Inject services={[DataLabel]} />
<LayersDirective>
<LayerDirective
shapeData={world_map}
dataSource={countryData}
shapeDataPath='name'
shapePropertyPath='name'
dataLabelSettings={{
visible: true,
template: labelTemplate
}}
/>
</LayersDirective>
</MapsComponent>
);
}Conditional Label Styling
const conditionalLabelTemplate = (props) => {
const isHighPopulation = props.population > 100000000;
return (
<div style={{
backgroundColor: isHighPopulation ? '#FF6347' : '#4CAF50',
color: 'white',
padding: '3px 6px',
borderRadius: '3px',
fontSize: isHighPopulation ? '12px' : '10px',
fontWeight: isHighPopulation ? 'bold' : 'normal'
}}>
{props.name}
</div>
);
};Combining Bubbles and Labels
Display both bubbles and labels for rich visualization:
function CombinedVisualization() {
const cityData = [
{
name: 'Tokyo',
latitude: 35.6762,
longitude: 139.6503,
population: 37400000
},
{
name: 'Delhi',
latitude: 28.7041,
longitude: 77.1025,
population: 30290000
},
{
name: 'Shanghai',
latitude: 31.2304,
longitude: 121.4737,
population: 27058000
}
];
return (
<MapsComponent>
<Inject services={[Bubble, DataLabel, MapsTooltip]} />
<LayersDirective>
<LayerDirective
shapeData={world_map}
dataLabelSettings={{
visible: true,
labelPath: 'name',
smartLabelMode: 'Trim',
textStyle: {
size: '10px',
color: '#333333'
}
}}
>
<BubblesDirective>
<BubbleDirective
visible={true}
dataSource={cityData}
valuePath='population'
minRadius={15}
maxRadius={50}
fill='#FF6347'
opacity={0.5}
tooltipSettings={{
visible: true,
valuePath: 'name',
format: '${name}<br/>Population: ${population}'
}}
/>
</BubblesDirective>
</LayerDirective>
</LayersDirective>
</MapsComponent>
);
}Visual Hierarchy Best Practices
1. Use Appropriate Sizes
// Small labels for dense areas
dataLabelSettings={{
textStyle: { size: '8px' }
}}
// Large labels for emphasis
dataLabelSettings={{
textStyle: { size: '14px', fontWeight: 'Bold' }
}}2. Color Contrast
// Light labels on dark shapes
dataLabelSettings={{
textStyle: {
color: '#FFFFFF'
}
}}
// Dark labels on light shapes
dataLabelSettings={{
textStyle: {
color: '#000000'
}
}}
// Add border for better visibility
dataLabelSettings={{
textStyle: {
color: '#FFFFFF'
},
border: {
color: '#000000',
width: 1
}
}}3. Bubble Opacity
// Semi-transparent for overlapping bubbles
<BubbleDirective
opacity={0.6} // Allows seeing shapes behind
fill='#2196F3'
/>
// Solid for emphasis
<BubbleDirective
opacity={1}
fill='#FF6347'
/>4. Layering Order
// Bubbles first (background), then labels (foreground)
<LayerDirective shapeData={world_map}>
<BubblesDirective>
<BubbleDirective visible={true} dataSource={data} />
</BubblesDirective>
{/* Labels render on top of bubbles */}
</LayerDirective>Heatmap Layer
Heatmaps visualize density/intensity directly on the map using color gradients. React Maps supports heat map configurations via colorMapping.
<LayerDirective
shapeData={world_map}
dataSource={heatData}
shapeSettings={{
colorValuePath: "intensity",
colorMapping: [
{ from: 0, to: 10, color: "#ffeeee" },
{ from: 10, to: 50, color: "#ff0000" }
]
}}
/>Common Use Cases
Population Density Map
function PopulationDensityMap() {
const densityData = [
{ country: 'Monaco', density: 26337, latitude: 43.7384, longitude: 7.4246 },
{ country: 'Singapore', density: 8358, latitude: 1.3521, longitude: 103.8198 },
{ country: 'Bangladesh', density: 1265, latitude: 23.6850, longitude: 90.3563 }
];
return (
<MapsComponent
titleSettings={{ text: 'Population Density by Country' }}
>
<Inject services={[Bubble, DataLabel, MapsTooltip, Legend]} />
<LayersDirective>
<LayerDirective
shapeData={world_map}
dataLabelSettings={{
visible: true,
labelPath: 'name',
smartLabelMode: 'Trim',
textStyle: { size: '10px' }
}}
>
<BubblesDirective>
<BubbleDirective
visible={true}
dataSource={densityData}
valuePath='density'
minRadius={10}
maxRadius={50}
colorValuePath='density'
colorMapping={[
{ from: 0, to: 100, color: '#C3E6CB', label: 'Low' },
{ from: 100, to: 1000, color: '#6AB187', label: 'Medium' },
{ from: 1000, to: 30000, color: '#2F7C4F', label: 'High' }
]}
tooltipSettings={{
visible: true,
format: '${country}<br/>Density: ${density} per km²'
}}
/>
</BubblesDirective>
</LayerDirective>
</LayersDirective>
</MapsComponent>
);
}Sales Performance Map
function SalesMap() {
const salesData = [
{ region: 'North', sales: 5000000, code: 'NR' },
{ region: 'South', sales: 3500000, code: 'SR' },
{ region: 'East', sales: 4200000, code: 'ER' },
{ region: 'West', sales: 4800000, code: 'WR' }
];
const labelTemplate = (props) => {
return (
<div style={{ textAlign: 'center' }}>
<div style={{
fontSize: '16px',
fontWeight: 'bold',
color: '#2196F3'
}}>
{props.code}
</div>
<div style={{
fontSize: '11px',
color: '#666'
}}>
${(props.sales / 1000000).toFixed(1)}M
</div>
</div>
);
};
return (
<MapsComponent>
<Inject services={[DataLabel]} />
<LayersDirective>
<LayerDirective
shapeData={regionMap}
dataSource={salesData}
shapeDataPath='region'
shapePropertyPath='name'
shapeSettings={{
colorValuePath: 'sales',
colorMapping={[
{ from: 0, to: 4000000, color: '#FFE5B4' },
{ from: 4000000, to: 6000000, color: '#FF8C00' }
]}
}}
dataLabelSettings={{
visible: true,
template: labelTemplate
}}
/>
</LayersDirective>
</MapsComponent>
);
}Troubleshooting
Issue: Bubbles not appearing
Solutions: 1. Inject Bubble service 2. Set visible={true} 3. Ensure data has latitude/longitude fields 4. Check valuePath matches data field
// ✅ Correct
<MapsComponent>
<Inject services={[Bubble]} />
<BubbleDirective visible={true} valuePath='population' dataSource={data} />
</MapsComponent>Issue: Data labels not showing
Solutions: 1. Inject DataLabel service 2. Set visible={true} 3. Verify labelPath matches GeoJSON property or data field
// ✅ Correct
<MapsComponent>
<Inject services={[DataLabel]} />
<LayerDirective
dataLabelSettings={{ visible: true, labelPath: 'name' }}
/>
</MapsComponent>Issue: Labels overlapping or cut off
Solutions:
- Use
smartLabelMode: 'Trim'or'Hide' - Reduce font size
- Set
intersectionAction: 'Hide' - Increase map size
Issue: Bubble sizes not varying
Cause: minRadius and maxRadius too close
Solution:
// ✅ Good range
<BubbleDirective minRadius={10} maxRadius={50} />
// ❌ Too close
<BubbleDirective minRadius={20} maxRadius={22} />Layers and Sublayers in React Maps
Table of Contents
- Overview
- Understanding Layer Architecture
- Main Layer vs Sublayer
- Creating Multiple Layers
- Layer Types
- Layer Configuration
- Stacking and Ordering
- Drill‑Down Navigation
- Use Cases
- Common Patterns
- Troubleshooting
Overview
Layers are the fundamental building blocks of Maps. The component renders content through multiple layers, allowing complex visualizations by stacking shapes, highlighting regions, or combining different data sources.
Understanding Layer Architecture
Maps Component
├── Main Layer (Base)
│ └── World map or country GeoJSON
├── Sublayer 1 (Overlay)
│ └── Highlighted state/region
├── Sublayer 2 (Overlay)
│ └── Another region or data
└── Sublayer N...Key Concepts:
- Main Layer: The base map, typically a larger geographical area
- Sublayers: Overlays that render on top of the main layer
- Stacking: Layers render in the order defined
- Independence: Each layer has its own settings, data, and styling
Main Layer vs Sublayer
Main Layer
The first layer in LayersDirective is the main layer:
<LayersDirective>
<LayerDirective
shapeData={world_map}
// This is the MAIN layer (default type)
/>
</LayersDirective>Characteristics:
- Serves as the base map
- Fills the entire map container
- Usually covers the broadest geographical area
- No
typeproperty needed (defaults to "Layer")
Sublayer
Additional layers with type="SubLayer":
<LayersDirective>
<LayerDirective shapeData={world_map} />
<LayerDirective
shapeData={texas}
type="SubLayer" // This makes it an overlay
/>
</LayersDirective>Characteristics:
- Renders on top of main layer
- Can highlight specific regions
- Transparent areas show base layer underneath
- Requires
type="SubLayer"property
Creating Multiple Layers
Basic Multi-Layer Example
import { usa_map } from './usa-map';
import { california } from './california';
import { texas } from './texas';
function App() {
return (
<MapsComponent>
<LayersDirective>
{/* Main layer: Full USA map */}
<LayerDirective
shapeData={usa_map}
shapeSettings={{
fill: '#E5E5E5',
border: { width: 0.5, color: 'black' }
}}
/>
{/* Sublayer 1: Highlight Texas */}
<LayerDirective
shapeData={texas}
type="SubLayer"
shapeSettings={{
fill: 'rgba(141, 206, 255, 0.6)',
border: { width: 1, color: '#1a9cff' }
}}
/>
{/* Sublayer 2: Highlight California */}
<LayerDirective
shapeData={california}
type="SubLayer"
shapeSettings={{
fill: 'rgba(255, 165, 0, 0.6)',
border: { width: 1, color: '#ff8c00' }
}}
/>
</LayersDirective>
</MapsComponent>
);
}Result: USA map with Texas and California highlighted in different colors.
Multi-Layer with Different Data
function RegionalSalesMap() {
const countryData = [
{ name: 'United States', sales: 5000000 },
{ name: 'Canada', sales: 2000000 }
];
const stateData = [
{ name: 'California', sales: 1500000 },
{ name: 'Texas', sales: 1200000 }
];
return (
<MapsComponent>
<LayersDirective>
{/* Main layer: North America */}
<LayerDirective
shapeData={northAmerica}
dataSource={countryData}
shapeDataPath='name'
shapePropertyPath='name'
shapeSettings={{
colorValuePath: 'sales',
colorMapping: [
{ from: 0, to: 3000000, color: '#C3E6CB' },
{ from: 3000000, to: 6000000, color: '#2F7C4F' }
]
}}
/>
{/* Sublayer: US States detail */}
<LayerDirective
shapeData={usStates}
type="SubLayer"
dataSource={stateData}
shapeDataPath='name'
shapePropertyPath='name'
shapeSettings={{
colorValuePath: 'sales',
colorMapping: [
{ from: 0, to: 1000000, color: '#FFE5B4' },
{ from: 1000000, to: 2000000, color: '#FF8C00' }
]
}}
/>
</LayersDirective>
</MapsComponent>
);
}Layer Types
Type: "Layer" (Default - Main Layer)
<LayerDirective
shapeData={world_map}
// type="Layer" is implicit
/>When to use:
- First layer in your map
- Base geographical area
- Primary data visualization
Type: "SubLayer" (Overlay)
<LayerDirective
shapeData={region}
type="SubLayer"
/>When to use:
- Highlighting specific regions
- Overlaying additional data
- Creating visual emphasis
- Showing nested geographical relationships
Layer Configuration
Individual Layer Settings
Each layer can have unique configurations:
<LayersDirective>
<LayerDirective
shapeData={world_map}
shapeSettings={{
fill: '#f0f0f0',
border: { width: 1, color: '#333' }
}}
dataLabelSettings={{
visible: true,
labelPath: 'name'
}}
/>
<LayerDirective
shapeData={highlighted_countries}
type="SubLayer"
shapeSettings={{
fill: '#ff6b6b',
border: { width: 2, color: '#c92a2a' }
}}
// No data labels on this layer
/>
</LayersDirective>Layer-Specific Features
Each layer can have:
- Markers: Different marker sets per layer
- Bubbles: Unique bubble configurations
- Data Labels: Independent label settings
- Tooltips: Layer-specific tooltip content
- Color Mapping: Different data visualization per layer
<LayersDirective>
{/* Base layer with country data */}
<LayerDirective
shapeData={world_map}
dataSource={countryData}
markerSettings={[
{
visible: true,
dataSource: capitalCities,
shape: 'Circle'
}
]}
/>
{/* Overlay with regional markers */}
<LayerDirective
shapeData={europeRegion}
type="SubLayer"
markerSettings={[
{
visible: true,
dataSource: touristAttractions,
shape: 'Star'
}
]}
/>
</LayersDirective>Per‑Layer Zoom Constraints
You can restrict zooming for individual layers using minimum and maximum zoom levels. Useful for lockstep navigation or multi-layered visualizations.
<LayerDirective
shapeData={usa_map}
layerSettings={{ minZoom: 2, maxZoom: 10 }}
/>Conditional Layer Visibility
Layers can appear or hide dynamically based on current zoom, supporting multi-resolution transitions.
<LayerDirective visible={currentZoom > 4} />Stacking and Ordering
Layers render in the order they're defined:
<LayersDirective>
<LayerDirective shapeData={layer1} /> {/* Bottom */}
<LayerDirective shapeData={layer2} type="SubLayer" /> {/* Middle */}
<LayerDirective shapeData={layer3} type="SubLayer" /> {/* Top */}
</LayersDirective>Visual Result:
Layer 3 (top)
Layer 2 (middle)
Layer 1 (bottom)Drill‑Down Navigation
Drill-down enables transitioning from larger geographical regions to more detailed shapes, such as switching from a world map to a country-level map when a shape is clicked.
const [showDetail, setShowDetail] = React.useState(false);
<MapsComponent>
<LayersDirective>
<LayerDirective shapeData={world_map} />
{showDetail && (
<LayerDirective
shapeData={country_detail}
type="SubLayer"
shapeSettings={{
fill: 'rgba(76, 175, 80, 0.6)'
}}
/>
)}
</LayersDirective>
</MapsComponent>Controlling Visual Hierarchy with Opacity
Use opacity to create depth:
<LayersDirective>
{/* Base: Solid */}
<LayerDirective
shapeData={world_map}
shapeSettings={{
fill: '#E5E5E5',
opacity: 1
}}
/>
{/* Middle: Semi-transparent */}
<LayerDirective
shapeData={continents}
type="SubLayer"
shapeSettings={{
fill: '#4CAF50',
opacity: 0.5
}}
/>
{/* Top: More transparent */}
<LayerDirective
shapeData={countries}
type="SubLayer"
shapeSettings={{
fill: '#2196F3',
opacity: 0.3
}}
/>
</LayersDirective>Use Cases
Use Case 1: Country with Highlighted States
Scenario: Show USA map with specific states highlighted
function USAStateHighlight() {
const highlightedStates = [
{ name: 'California' },
{ name: 'Texas' },
{ name: 'New York' }
];
return (
<MapsComponent>
<LayersDirective>
<LayerDirective
shapeData={usa_map}
shapeSettings={{
fill: '#D3D3D3',
border: { width: 0.5, color: 'black' }
}}
/>
<LayerDirective
shapeData={highlighted_states_geojson}
type="SubLayer"
dataSource={highlightedStates}
shapeSettings={{
fill: '#FFD700',
border: { width: 1.5, color: '#FF8C00' }
}}
/>
</LayersDirective>
</MapsComponent>
);
}Use Case 2: Election Results Map
Scenario: Display election results with winning states colored
function ElectionMap() {
const electionResults = [
{ state: 'California', winner: 'Democrat', votes: 11110000 },
{ state: 'Texas', winner: 'Republican', votes: 8750000 },
{ state: 'Florida', winner: 'Republican', votes: 9700000 }
];
return (
<MapsComponent>
<Inject services={[Legend]} />
<LayersDirective>
<LayerDirective
shapeData={usa_map}
dataSource={electionResults}
shapeDataPath='state'
shapePropertyPath='name'
shapeSettings={{
colorValuePath: 'winner',
colorMapping: [
{ value: 'Democrat', color: '#0015BC' },
{ value: 'Republican', color: '#DE0100' }
]
}}
/>
</LayersDirective>
</MapsComponent>
);
}Use Case 3: Sales Territory Overlay
Scenario: Show sales territories over geographical map
function SalesTerritoryMap() {
return (
<MapsComponent>
<LayersDirective>
{/* Base: Country borders */}
<LayerDirective
shapeData={country_map}
shapeSettings={{
fill: '#f5f5f5',
border: { width: 1, color: '#666' }
}}
/>
{/* Overlay: North Territory */}
<LayerDirective
shapeData={north_territory}
type="SubLayer"
shapeSettings={{
fill: 'rgba(255, 99, 71, 0.4)',
border: { width: 2, color: '#FF6347' }
}}
/>
{/* Overlay: South Territory */}
<LayerDirective
shapeData={south_territory}
type="SubLayer"
shapeSettings={{
fill: 'rgba(135, 206, 235, 0.4)',
border: { width: 2, color: '#4682B4' }
}}
/>
</LayersDirective>
</MapsComponent>
);
}Common Patterns
Pattern 1: Drill-Down Effect
Show progressively more detail:
const [showDetail, setShowDetail] = React.useState(false);
<MapsComponent>
<LayersDirective>
<LayerDirective shapeData={world_map} />
{showDetail && (
<LayerDirective
shapeData={country_detail}
type="SubLayer"
shapeSettings={{
fill: 'rgba(76, 175, 80, 0.6)'
}}
/>
)}
</LayersDirective>
</MapsComponent>Pattern 2: Conditional Layer Visibility
Toggle layers based on user selection:
const [visibleLayers, setVisibleLayers] = React.useState({
population: true,
gdp: false,
climate: false
});
<MapsComponent>
<LayersDirective>
<LayerDirective shapeData={world_map} />
{visibleLayers.population && (
<LayerDirective shapeData={populationData} type="SubLayer" />
)}
{visibleLayers.gdp && (
<LayerDirective shapeData={gdpData} type="SubLayer" />
)}
</LayersDirective>
</MapsComponent>Pattern 3: Multiple Data Overlays
Combine different datasets:
<LayersDirective>
{/* Base geographical data */}
<LayerDirective shapeData={base_map} />
{/* Population density */}
<LayerDirective shapeData={population_layer} type="SubLayer" />
{/* Major cities */}
<LayerDirective
shapeData={cities_layer}
type="SubLayer"
markerSettings={[{ visible: true, dataSource: cityData }]}
/>
{/* Transportation routes */}
<LayerDirective
shapeData={routes_layer}
type="SubLayer"
navigationLineSettings={[{ visible: true, dataSource: routeData }]}
/>
</LayersDirective>Troubleshooting
Issue: Sublayer not visible
Cause: Missing type="SubLayer" or sublayer is fully transparent
Solution:
// ✅ Correct
<LayerDirective
shapeData={overlay}
type="SubLayer"
shapeSettings={{ fill: 'rgba(255, 0, 0, 0.5)' }} // Visible opacity
/>
// ❌ Wrong
<LayerDirective
shapeData={overlay}
// Missing type="SubLayer"
/>Issue: Layers rendering in wrong order
Cause: Layer order in JSX
Solution: Reorder layers - first layer is bottom, last is top
<LayersDirective>
<LayerDirective shapeData={base} /> {/* Bottom */}
<LayerDirective shapeData={middle} type="SubLayer" />
<LayerDirective shapeData={top} type="SubLayer" /> {/* Top */}
</LayersDirective>Issue: Sublayer covers entire map instead of specific region
Cause: Sublayer GeoJSON covers entire map area
Solution: Ensure sublayer GeoJSON only contains the specific region shapes you want to highlight.
Issue: Performance degradation with many layers
Cause: Too many layers or complex GeoJSON data
Solution:
- Simplify GeoJSON geometry
- Reduce number of layers
- Use conditional rendering to show/hide layers
- Consider combining similar layers
Map Providers in React Maps
Table of Contents
- Overview
- When to Use Map Providers
- Bing Maps
- OpenStreetMap
- Azure Maps
- Hybrid Approach
- Common Patterns
- Troubleshooting
Overview
Map providers offer real-world tile-based map layers (satellite, aerial, street views) as alternatives or complements to GeoJSON shapes.
Supported Providers:
- Bing Maps: Microsoft's mapping service (requires API key)
- OpenStreetMap (OSM): Free, open-source maps (no API key needed)
- Azure Maps: Microsoft Azure's mapping service (requires API key)
When to Use Map Providers
Use GeoJSON When:
- Displaying statistical/regional data (choropleth maps)
- Custom boundary visualization
- Offline capability required
- Full control over styling needed
- Data binding to specific regions
Use Map Providers When:
- Need real-world street-level detail
- Satellite/aerial imagery required
- Familiar map interface expected (like Google Maps)
- Real-time navigation context needed
- Displaying POIs and street names
Use Hybrid (Both) When:
- Overlaying custom data on real-world maps
- Combining statistical regions with street context
- Need both geographical shapes and street details
Bing Maps
Setup
import {
MapsComponent,
LayersDirective,
LayerDirective
} from '@syncfusion/ej2-react-maps';
function BingMap() {
return (
<MapsComponent>
<LayersDirective>
<LayerDirective
urlTemplate="https://dev.virtualearth.net/REST/V1/Imagery/Metadata/RoadOnDemand?output=json&uriScheme=https&key=YOUR_BING_MAPS_KEY"
key="YOUR_BING_MAPS_KEY"
/>
</LayersDirective>
</MapsComponent>
);
}Bing Maps URL Template Retrieval
React Maps can auto-fetch the correct URL template for Bing Maps using getBingUrlTemplate(). This removes the need to manually build metadata URLs.
const template = await mapsRef.current.getBingUrlTemplate(
"https://dev.virtualearth.net/REST/V1/Imagery/Metadata/Aerial?output=json&key=YOUR_KEY")Get Bing Maps API Key
1. Visit Bing Maps Dev Center 2. Sign in with Microsoft account 3. Create a new key under "My account" → "My keys" 4. Copy the key and use in your application
Bing Maps Tile Types
// Road map
urlTemplate="https://dev.virtualearth.net/REST/V1/Imagery/Metadata/RoadOnDemand?output=json&uriScheme=https&key=YOUR_KEY"
// Aerial view
urlTemplate="https://dev.virtualearth.net/REST/V1/Imagery/Metadata/Aerial?output=json&uriScheme=https&key=YOUR_KEY"
// Aerial with labels
urlTemplate="https://dev.virtualearth.net/REST/V1/Imagery/Metadata/AerialWithLabels?output=json&uriScheme=https&key=YOUR_KEY"Example with Markers
function BingMapWithMarkers() {
const locations = [
{ latitude: 40.7128, longitude: -74.0060, name: 'New York' },
{ latitude: 34.0522, longitude: -118.2437, name: 'Los Angeles' }
];
return (
<MapsComponent
zoomSettings={{
enable: true,
zoomFactor: 4
}}
centerPosition={{
latitude: 37.0902,
longitude: -95.7129
}}
>
<Inject services={[Marker, Zoom]} />
<LayersDirective>
<LayerDirective
urlTemplate="https://dev.virtualearth.net/REST/V1/Imagery/Metadata/RoadOnDemand?output=json&uriScheme=https&key=YOUR_KEY"
key="YOUR_KEY"
>
<MarkersDirective>
<MarkerDirective
visible={true}
dataSource={locations}
shape='Circle'
fill='#FF0000'
height={20}
width={20}
/>
</MarkersDirective>
</LayerDirective>
</LayersDirective>
</MapsComponent>
);
}OpenStreetMap
Setup (No API Key Required)
function OSMMap() {
return (
<MapsComponent>
<LayersDirective>
<LayerDirective
urlTemplate="Add your URL link"
/>
</LayersDirective>
</MapsComponent>
);
}OSM Tile Servers
// Standard OpenStreetMap
urlTemplate="Add your URL link"
// OpenStreetMap Humanitarian
urlTemplate="Add your URL link"
// OpenTopoMap (topographical)
urlTemplate="Add your URL link"Basic OSM Example
function OpenStreetMapExample() {
return (
<MapsComponent
zoomSettings={{
enable: true,
zoomFactor: 5
}}
centerPosition={{
latitude: 51.5074,
longitude: -0.1278
}}
>
<Inject services={[Zoom]} />
<LayersDirective>
<LayerDirective
urlTemplate="Add your URL link"
/>
</LayersDirective>
</MapsComponent>
);
}OSM with Custom Markers
function OSMStoreLocator() {
const stores = [
{ latitude: 51.5074, longitude: -0.1278, name: 'London Store' },
{ latitude: 48.8566, longitude: 2.3522, name: 'Paris Store' }
];
return (
<MapsComponent
titleSettings={{ text: 'Store Locations' }}
zoomSettings={{ enable: true, zoomFactor: 4 }}
centerPosition={{ latitude: 50, longitude: 1 }}
>
<Inject services={[Marker, Zoom, MapsTooltip]} />
<LayersDirective>
<LayerDirective
urlTemplate="Add your URL link"
>
<MarkersDirective>
<MarkerDirective
visible={true}
dataSource={stores}
shape='Image'
imageUrl='./store-icon.png'
height={30}
width={30}
tooltipSettings={{
visible: true,
valuePath: 'name'
}}
/>
</MarkersDirective>
</LayerDirective>
</LayersDirective>
</MapsComponent>
);
}Azure Maps
Setup
function AzureMap() {
return (
<MapsComponent>
<LayersDirective>
<LayerDirective
urlTemplate="https://atlas.microsoft.com/map/tile?subscription-key=YOUR_AZURE_KEY&api-version=2.0&tilesetId=microsoft.base.road&zoom=level&x=tileX&y=tileY"
key="YOUR_AZURE_KEY"
/>
</LayersDirective>
</MapsComponent>
);
}Get Azure Maps Key
1. Create Azure account at portal.azure.com 2. Create Azure Maps resource 3. Navigate to "Authentication" → "Primary Key" 4. Copy the key
Azure Maps Tile Sets
// Road map
tilesetId=microsoft.base.road
// Satellite
tilesetId=microsoft.imagery
// Hybrid (satellite with labels)
tilesetId=microsoft.base.hybrid
// Dark mode
tilesetId=microsoft.base.darkgreyHybrid Approach
Combine GeoJSON shapes with map provider tiles:
GeoJSON Overlay on OpenStreetMap
function HybridMap() {
const stateData = [
{ name: 'California', population: 39538223 },
{ name: 'Texas', population: 29145505 }
];
return (
<MapsComponent
zoomSettings={{ enable: true, zoomFactor: 5 }}
centerPosition={{ latitude: 37, longitude: -96 }}
>
<Inject services={[Zoom, Legend]} />
<LayersDirective>
{/* Base layer: OpenStreetMap */}
<LayerDirective
urlTemplate="Add your URL link"
/>
{/* Overlay: State boundaries with data */}
<LayerDirective
type="SubLayer"
shapeData={usa_states}
dataSource={stateData}
shapeDataPath='name'
shapePropertyPath='name'
shapeSettings={{
fill: 'transparent',
colorValuePath: 'population',
colorMapping: [
{ from: 0, to: 10000000, color: 'rgba(255,165,0,0.4)' },
{ from: 10000000, to: 50000000, color: 'rgba(255,69,0,0.4)' }
],
border: {
color: '#FF6347',
width: 2
}
}}
/>
</LayersDirective>
</MapsComponent>
);
}Bing Maps with Custom Shapes
function BingHybridMap() {
return (
<MapsComponent zoomSettings={{ enable: true }}>
<Inject services={[Zoom]} />
<LayersDirective>
{/* Base: Bing Maps */}
<LayerDirective
urlTemplate="https://dev.virtualearth.net/REST/V1/Imagery/Metadata/Aerial?output=json&uriScheme=https&key=YOUR_KEY"
key="YOUR_KEY"
/>
{/* Overlay: Custom region */}
<LayerDirective
type="SubLayer"
shapeData={custom_region}
shapeSettings={{
fill: 'rgba(255,0,0,0.3)',
border: { color: '#FF0000', width: 3 }
}}
/>
</LayersDirective>
</MapsComponent>
);
}Common Patterns
Pattern 1: Store Locator on Real Map
function StoreLocatorMap() {
const stores = [
{ lat: 37.7749, lng: -122.4194, name: 'SF Store', address: '123 Market St' },
{ lat: 34.0522, lng: -118.2437, name: 'LA Store', address: '456 Sunset Blvd' }
];
return (
<MapsComponent
titleSettings={{ text: 'Find Our Stores' }}
zoomSettings={{ enable: true, zoomFactor: 7 }}
centerPosition={{ latitude: 36, longitude: -120 }}
>
<Inject services={[Marker, Zoom, MapsTooltip]} />
<LayersDirective>
<LayerDirective
urlTemplate="Add your URL link"
>
<MarkersDirective>
<MarkerDirective
visible={true}
dataSource={stores}
shape='Balloon'
fill='#FF6347'
height={30}
width={30}
tooltipSettings={{
visible: true,
format: '${name}<br/>${address}'
}}
/>
</MarkersDirective>
</LayerDirective>
</LayersDirective>
</MapsComponent>
);
}Pattern 2: Delivery Tracking
function DeliveryTrackingMap() {
const [vehiclePosition, setVehiclePosition] = React.useState([
{ latitude: 40.7128, longitude: -74.0060, vehicle: 'Truck 1' }
]);
return (
<MapsComponent
zoomSettings={{ enable: true, zoomFactor: 12 }}
centerPosition={{ latitude: 40.7128, longitude: -74.0060 }}
>
<Inject services={[Marker, Zoom]} />
<LayersDirective>
<LayerDirective
urlTemplate="Add your URL link"
>
<MarkersDirective>
<MarkerDirective
visible={true}
dataSource={vehiclePosition}
shape='Image'
imageUrl='./truck-icon.png'
height={40}
width={40}
/>
</MarkersDirective>
</LayerDirective>
</LayersDirective>
</MapsComponent>
);
}Pattern 3: Event Venue Map
function EventVenueMap() {
const venue = { latitude: 51.5074, longitude: -0.1278 };
return (
<MapsComponent
zoomSettings={{ enable: true, zoomFactor: 15 }}
centerPosition={{ latitude: 51.5074, longitude: -0.1278 }}
>
<Inject services={[Marker, Zoom]} />
<LayersDirective>
<LayerDirective
urlTemplate="Add your URL link"
>
<MarkersDirective>
<MarkerDirective
visible={true}
dataSource={[venue]}
shape='Star'
fill='#FFD700'
height={40}
width={40}
/>
</MarkersDirective>
</LayerDirective>
</LayersDirective>
</MapsComponent>
);
}Troubleshooting
Issue: Tiles not loading
Causes & Solutions:
1. Invalid URL template
// ✅ Correct OSM template
urlTemplate="your URL links .png"
2. Missing or invalid API key (Bing/Azure)
// ✅ Correct - valid key
<LayerDirective key="YOUR_VALID_KEY" urlTemplate="..." />
// ❌ Wrong - placeholder key
<LayerDirective key="YOUR_KEY" urlTemplate="..." />3. CORS issues
- Check browser console for CORS errors
- Some tile servers may block requests from certain domains
- Use approved tile servers or configure CORS on your server
Issue: Map appears blank
Solutions:
- Set appropriate
zoomFactorandcenterPosition - Check network tab for failed tile requests
- Verify API key permissions and quotas
<MapsComponent
zoomSettings={{ enable: true, zoomFactor: 4 }}
centerPosition={{ latitude: 40, longitude: -100 }}
>Issue: Low zoom shows no detail
Cause: Tile servers have minimum zoom levels
Solution: Increase zoomFactor for street-level detail
zoomSettings={{
enable: true,
zoomFactor: 12, // Higher zoom for more detail
minZoom: 5,
maxZoom: 19
}}Issue: Hybrid overlay not visible
Cause: SubLayer fill not transparent
Solution:
// ✅ Correct - transparent fill shows base map
<LayerDirective
type="SubLayer"
shapeSettings={{
fill: 'transparent', // or rgba(255,0,0,0.3)
border: { color: '#FF0000', width: 2 }
}}
/>Cost Considerations
- OpenStreetMap: Free (respect usage policies)
- Bing Maps: Free tier available, paid for high volume
- Azure Maps: Pay-as-you-go pricing
Always check current pricing and quotas for commercial applications.
Related skills
How it compares
Pick syncfusion-react-maps for licensed Syncfusion dashboards; use D3 or Mapbox stacks when you need vendor-neutral mapping libraries.
FAQ
Which map providers does syncfusion-react-maps support?
syncfusion-react-maps documents Bing Maps, OpenStreetMap, and Azure Maps as tile providers, combinable with GeoJSON shape layers for custom regions. MapsComponent renders SVG layers with markers, bubbles, legends, and zoom or pan controls.
How many projections does Syncfusion React Maps cover?
syncfusion-react-maps lists six projection types for MapsComponent, alongside multi-layer and sublayer architecture for stacking GeoJSON shapes over provider tiles. Reference guides detail shapeDataPath binding and color-mapping modes for choropleth charts.