React.js Google Maps integration component library providing comprehensive Google Maps functionality through React components
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Data visualization component for displaying heatmaps and other visual representations of geographic data on Google Maps. Requires the visualization library.
Component for displaying heatmap visualizations of geographic data points with density-based coloring.
/**
* Heatmap layer component for data visualization
* Requires: visualization library in Google Maps API URL
*/
class HeatmapLayer extends Component<HeatmapLayerProps> {
/** Returns the heatmap data array */
getData(): google.maps.MVCArray<google.maps.LatLng | google.maps.visualization.WeightedLocation>;
}
interface HeatmapLayerProps {
// Default props
defaultData?: google.maps.MVCArray<google.maps.LatLng | google.maps.visualization.WeightedLocation> | Array<google.maps.LatLng | google.maps.visualization.WeightedLocation>;
defaultOptions?: google.maps.visualization.HeatmapLayerOptions;
// Controlled props
data?: google.maps.MVCArray<google.maps.LatLng | google.maps.visualization.WeightedLocation> | Array<google.maps.LatLng | google.maps.visualization.WeightedLocation>;
options?: google.maps.visualization.HeatmapLayerOptions;
}Usage Example:
import HeatmapLayer from "react-google-maps/lib/components/visualization/HeatmapLayer";
const HeatmapVisualization = () => {
// Sample data points for San Francisco crime data
const [heatmapData] = useState([
{ location: new google.maps.LatLng(37.782551, -122.445368), weight: 0.5 },
{ location: new google.maps.LatLng(37.782745, -122.444586), weight: 2 },
{ location: new google.maps.LatLng(37.782842, -122.443688), weight: 3 },
{ location: new google.maps.LatLng(37.782919, -122.442815), weight: 2 },
{ location: new google.maps.LatLng(37.782992, -122.442112), weight: 3 },
{ location: new google.maps.LatLng(37.783100, -122.441461), weight: 0.5 },
{ location: new google.maps.LatLng(37.783206, -122.440829), weight: 2 },
{ location: new google.maps.LatLng(37.783273, -122.440324), weight: 3 },
{ location: new google.maps.LatLng(37.783316, -122.440023), weight: 3 },
{ location: new google.maps.LatLng(37.783357, -122.439794), weight: 2 },
// ... more data points
]);
const [heatmapOptions, setHeatmapOptions] = useState({
radius: 20,
opacity: 0.6,
gradient: [
'rgba(0, 255, 255, 0)',
'rgba(0, 255, 255, 1)',
'rgba(0, 191, 255, 1)',
'rgba(0, 127, 255, 1)',
'rgba(0, 63, 255, 1)',
'rgba(0, 0, 255, 1)',
'rgba(0, 0, 223, 1)',
'rgba(0, 0, 191, 1)',
'rgba(0, 0, 159, 1)',
'rgba(0, 0, 127, 1)',
'rgba(63, 0, 91, 1)',
'rgba(127, 0, 63, 1)',
'rgba(191, 0, 31, 1)',
'rgba(255, 0, 0, 1)'
]
});
return (
<div>
{/* Heatmap controls */}
<div style={{ padding: '10px', backgroundColor: '#f5f5f5' }}>
<div style={{ marginBottom: '10px' }}>
<label style={{ marginRight: '10px' }}>
Radius: {heatmapOptions.radius}
<input
type="range"
min="10"
max="50"
value={heatmapOptions.radius}
onChange={(e) => setHeatmapOptions(prev => ({
...prev,
radius: parseInt(e.target.value)
}))}
style={{ marginLeft: '10px' }}
/>
</label>
<label style={{ marginLeft: '20px' }}>
Opacity: {heatmapOptions.opacity}
<input
type="range"
min="0.1"
max="1"
step="0.1"
value={heatmapOptions.opacity}
onChange={(e) => setHeatmapOptions(prev => ({
...prev,
opacity: parseFloat(e.target.value)
}))}
style={{ marginLeft: '10px' }}
/>
</label>
</div>
</div>
<GoogleMap
defaultZoom={13}
defaultCenter={{ lat: 37.7831, lng: -122.4421 }}
style={{ height: '500px' }}
>
<HeatmapLayer
data={heatmapData}
options={heatmapOptions}
/>
</GoogleMap>
</div>
);
};The visualization components require the visualization library to be loaded:
// Include 'visualization' in the libraries parameter
const googleMapURL = `https://maps.googleapis.com/maps/api/js?key=${API_KEY}&libraries=places,visualization`;
const MapWithVisualization = withScriptjs(withGoogleMap(() => (
<GoogleMap defaultZoom={10} defaultCenter={{ lat: 37.7749, lng: -122.4194 }}>
<HeatmapLayer data={heatmapData} />
</GoogleMap>
)));
<MapWithVisualization
googleMapURL={googleMapURL}
loadingElement={<div style={{ height: "100%" }} />}
containerElement={<div style={{ height: "400px" }} />}
mapElement={<div style={{ height: "100%" }} />}
/>The heatmap accepts data in multiple formats:
// Simple LatLng array
const simpleData = [
new google.maps.LatLng(37.782551, -122.445368),
new google.maps.LatLng(37.782745, -122.444586),
new google.maps.LatLng(37.782842, -122.443688)
];
// Weighted locations with intensity values
const weightedData = [
{ location: new google.maps.LatLng(37.782551, -122.445368), weight: 0.5 },
{ location: new google.maps.LatLng(37.782745, -122.444586), weight: 2.0 },
{ location: new google.maps.LatLng(37.782842, -122.443688), weight: 3.0 }
];
// Using plain objects (will be converted to LatLng)
const objectData = [
{ lat: 37.782551, lng: -122.445368 },
{ lat: 37.782745, lng: -122.444586 },
{ lat: 37.782842, lng: -122.443688 }
];Customize heatmap appearance through options:
const heatmapOptions = {
// Point radius in pixels
radius: 20,
// Layer opacity (0-1)
opacity: 0.6,
// Maximum intensity for color mapping
maxIntensity: 100,
// Dissipating effect (points fade over time)
dissipating: true,
// Custom color gradient
gradient: [
'rgba(0, 255, 255, 0)', // Transparent cyan
'rgba(0, 255, 255, 1)', // Cyan
'rgba(0, 191, 255, 1)', // Light blue
'rgba(0, 127, 255, 1)', // Blue
'rgba(0, 63, 255, 1)', // Dark blue
'rgba(0, 0, 255, 1)', // Pure blue
'rgba(0, 0, 223, 1)', // Dark blue
'rgba(0, 0, 191, 1)', // Darker blue
'rgba(0, 0, 159, 1)', // Even darker blue
'rgba(0, 0, 127, 1)', // Very dark blue
'rgba(63, 0, 91, 1)', // Purple-blue
'rgba(127, 0, 63, 1)', // Purple
'rgba(191, 0, 31, 1)', // Red-purple
'rgba(255, 0, 0, 1)' // Red
]
};Update heatmap data based on user interactions or time:
const DynamicHeatmap = () => {
const [allData, setAllData] = useState([]); // Complete dataset
const [filteredData, setFilteredData] = useState([]);
const [timeRange, setTimeRange] = useState({ start: 0, end: 24 });
useEffect(() => {
// Load data from API
fetchHeatmapData().then(data => {
setAllData(data);
setFilteredData(data);
});
}, []);
const filterDataByTime = (start, end) => {
const filtered = allData.filter(point => {
const hour = point.timestamp.getHours();
return hour >= start && hour <= end;
});
setFilteredData(filtered);
};
return (
<div>
<div style={{ padding: '10px' }}>
<label>
Time Range: {timeRange.start}:00 - {timeRange.end}:00
</label>
<input
type="range"
min="0"
max="23"
value={timeRange.start}
onChange={(e) => {
const start = parseInt(e.target.value);
setTimeRange(prev => ({ ...prev, start }));
filterDataByTime(start, timeRange.end);
}}
/>
<input
type="range"
min="0"
max="23"
value={timeRange.end}
onChange={(e) => {
const end = parseInt(e.target.value);
setTimeRange(prev => ({ ...prev, end }));
filterDataByTime(timeRange.start, end);
}}
/>
</div>
<GoogleMap defaultZoom={12} defaultCenter={{ lat: 37.7749, lng: -122.4194 }}>
<HeatmapLayer
data={filteredData.map(point => ({
location: new google.maps.LatLng(point.lat, point.lng),
weight: point.intensity
}))}
/>
</GoogleMap>
</div>
);
};Display different categories of data with toggleable layers:
const MultiCategoryHeatmap = () => {
const [categories] = useState({
crime: { color: ['rgba(255,0,0,0)', 'rgba(255,0,0,1)'], data: crimeData },
traffic: { color: ['rgba(0,255,0,0)', 'rgba(0,255,0,1)'], data: trafficData },
business: { color: ['rgba(0,0,255,0)', 'rgba(0,0,255,1)'], data: businessData }
});
const [visibleCategories, setVisibleCategories] = useState({
crime: true,
traffic: false,
business: false
});
const toggleCategory = (categoryName) => {
setVisibleCategories(prev => ({
...prev,
[categoryName]: !prev[categoryName]
}));
};
return (
<div>
<div style={{ padding: '10px' }}>
{Object.keys(categories).map(categoryName => (
<label key={categoryName} style={{ marginRight: '20px' }}>
<input
type="checkbox"
checked={visibleCategories[categoryName]}
onChange={() => toggleCategory(categoryName)}
/>
{categoryName.charAt(0).toUpperCase() + categoryName.slice(1)}
</label>
))}
</div>
<GoogleMap defaultZoom={12} defaultCenter={{ lat: 37.7749, lng: -122.4194 }}>
{Object.entries(categories).map(([categoryName, category]) =>
visibleCategories[categoryName] && (
<HeatmapLayer
key={categoryName}
data={category.data}
options={{
radius: 25,
opacity: 0.6,
gradient: category.color
}}
/>
)
)}
</GoogleMap>
</div>
);
};Stream real-time data to update heatmap visualization:
const RealtimeHeatmap = () => {
const [heatmapData, setHeatmapData] = useState([]);
const [isStreaming, setIsStreaming] = useState(false);
useEffect(() => {
let interval;
if (isStreaming) {
interval = setInterval(() => {
// Simulate real-time data updates
const newPoint = {
location: new google.maps.LatLng(
37.7749 + (Math.random() - 0.5) * 0.1,
-122.4194 + (Math.random() - 0.5) * 0.1
),
weight: Math.random() * 5
};
setHeatmapData(prevData => {
const updatedData = [...prevData, newPoint];
// Keep only last 100 points for performance
return updatedData.slice(-100);
});
}, 1000);
}
return () => {
if (interval) clearInterval(interval);
};
}, [isStreaming]);
return (
<div>
<div style={{ padding: '10px' }}>
<button onClick={() => setIsStreaming(!isStreaming)}>
{isStreaming ? 'Stop' : 'Start'} Real-time Updates
</button>
<span style={{ marginLeft: '20px' }}>
Data Points: {heatmapData.length}
</span>
</div>
<GoogleMap defaultZoom={12} defaultCenter={{ lat: 37.7749, lng: -122.4194 }}>
<HeatmapLayer
data={heatmapData}
options={{
radius: 30,
opacity: 0.8,
dissipating: true,
maxIntensity: 10
}}
/>
</GoogleMap>
</div>
);
};Combine heatmap with statistical analysis:
const AnalyticalHeatmap = () => {
const [heatmapData, setHeatmapData] = useState([]);
const [statistics, setStatistics] = useState({});
const analyzeData = (data) => {
const weights = data.map(point => point.weight || 1);
const total = weights.reduce((sum, weight) => sum + weight, 0);
const average = total / weights.length;
const max = Math.max(...weights);
const min = Math.min(...weights);
return {
totalPoints: data.length,
totalWeight: total.toFixed(2),
averageWeight: average.toFixed(2),
maxWeight: max.toFixed(2),
minWeight: min.toFixed(2)
};
};
useEffect(() => {
if (heatmapData.length > 0) {
setStatistics(analyzeData(heatmapData));
}
}, [heatmapData]);
return (
<div style={{ display: 'flex' }}>
<div style={{ flex: 1 }}>
<GoogleMap defaultZoom={12} defaultCenter={{ lat: 37.7749, lng: -122.4194 }}>
<HeatmapLayer data={heatmapData} />
</GoogleMap>
</div>
<div style={{ width: '300px', padding: '20px', backgroundColor: '#f5f5f5' }}>
<h3>Data Analysis</h3>
<table style={{ width: '100%' }}>
<tbody>
<tr>
<td>Total Points:</td>
<td>{statistics.totalPoints || 0}</td>
</tr>
<tr>
<td>Total Weight:</td>
<td>{statistics.totalWeight || 0}</td>
</tr>
<tr>
<td>Average Weight:</td>
<td>{statistics.averageWeight || 0}</td>
</tr>
<tr>
<td>Max Weight:</td>
<td>{statistics.maxWeight || 0}</td>
</tr>
<tr>
<td>Min Weight:</td>
<td>{statistics.minWeight || 0}</td>
</tr>
</tbody>
</table>
</div>
</div>
);
};Install with Tessl CLI
npx tessl i tessl/npm-react-google-maps