JSFiddle - React, Tailwind, and code Playground
HTML
<div id="controls">
<button id="toggleGrid" class="toggle-button">Show Tiles</button>
</div>
<div id="map"></div>
<script src="https://unpkg.com/deck.gl@8.8.0/dist.min.js"></script>
<script
async
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap"
></script>
CSS
body,
html {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
}
#map {
height: 100vh;
width: 100vw;
position: absolute;
top: 0;
left: 0;
}
#controls {
position: absolute;
top: 10px;
left: 10px;
z-index: 1000;
background-color: white;
padding: 10px;
border-radius: 4px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
.toggle-button {
background-color: #fff;
border: 1px solid #ccc;
border-radius: 4px;
padding: 8px 16px;
cursor: pointer;
font-family: Arial, sans-serif;
font-size: 14px;
transition: all 0.3s ease;
}
.toggle-button:hover {
background-color: #f0f0f0;
}
.toggle-button.active {
background-color: #4285f4;
color: white;
border-color: #4285f4;
}
.tile-label {
color: black;
font-family: Arial, sans-serif;
font-size: 12px;
font-weight: bold;
text-align: center;
background-color: rgba(255, 255, 255, 0.7);
padding: 2px 4px;
border-radius: 2px;
}
JavaScript
const MAPS_API_KEY = "AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg";
const INSIGHTS_API_KEY = "AIzaSyBj5zfC9KuQwBmICZFDoL3hX_MxRvw73ec";
const INSIGHTS_API_URL = "https://areainsights.googleapis.com/v1:computeInsights";
const TARGET_TILE_COUNT = 100; // How many tiles to divide the map into
const POINT_SPACING_METERS = 100; // Spacing between heatmap points
const HEATMAP_RADIUS_PIXELS = 300; // Size of each heatmap point
const INITIAL_VIEW_STATE = {
latitude: 48.8566, // Paris
longitude: 2.3522,
zoom: 15,
};
// Global state variables
let map;
let overlay;
let currentData = [];
let tilesVisible = false;
let currentTileElements = [];
let currentLabels = [];
let debouncedUpdateHeatmap;
/**
* Generates a grid of points within a tile for heatmap visualization
* Each point will have the same weight (count)
*/
function generatePointsInTile(tilePolygon, count) {
const points = [];
// Calculate the bounding box of the tile
const bounds = {
north: Math.max(...tilePolygon.map((p) => p.lat)),
south: Math.min(...tilePolygon.map((p) => p.lat)),
east: Math.max(...tilePolygon.map((p) => p.lng)),
west: Math.min(...tilePolygon.map((p) => p.lng)),
};
const latSize = bounds.north - bounds.south;
const lngSize = bounds.east - bounds.west;
const padding = 0.2; // Padding to avoid points on the edge
const paddedBounds = {
north: bounds.north - latSize * padding,
south: bounds.south + latSize * padding,
east: bounds.east - lngSize * padding,
west: bounds.west + lngSize * padding,
};
// Convert meters to lat/lng degrees (approximate)
const latSpacing = POINT_SPACING_METERS / 111111;
const lngSpacing = POINT_SPACING_METERS / (111111 * Math.cos((bounds.north * Math.PI) / 180));
// Generate a grid of points
for (let lat = paddedBounds.south; lat <= paddedBounds.north; lat += latSpacing) {
for (let lng = paddedBounds.west; lng <= paddedBounds.east; lng +=...