Google Maps Integration
Bring LandMapMagic vector and raster layers into Google Maps without writing your own deck.gl plumbing. Use the one-line landmapmagic/google adapter or fetch /v1/styles?target=google directly.
Prerequisites
- LandMap API key with access to the layers you want (e.g.
clu,cdl). - Google Maps JavaScript API key + a vector-capable Map ID.
deck.gl+@deck.gl/google-maps+@deck.gl/geo-layersas peer dependencies.
npm install landmapmagic deck.gl @deck.gl/google-maps @deck.gl/geo-layers @googlemaps/js-api-loaderOne-line install (Recommended)
The landmapmagic/google adapter fetches a deck.gl-friendly style document and wires up MVTLayer / TileLayer / TextLayer for you, including label deduplication via lmm_label_id.
import { Loader } from '@googlemaps/js-api-loader';
import { GoogleMapsOverlay } from '@deck.gl/google-maps';
import { mountGoogleLandMap } from 'landmapmagic/google';
const loader = new Loader({ apiKey: process.env.GMAPS_KEY!, version: 'weekly' });
await loader.load();
const map = new google.maps.Map(document.getElementById('map')!, {
center: { lat: 41.878, lng: -93.097 },
zoom: 12,
mapId: 'YOUR_VECTOR_MAP_ID',
});
const overlay = new GoogleMapsOverlay({});
overlay.setMap(map);
const handle = await mountGoogleLandMap({
apiKey: 'YOUR_API_KEY',
map,
overlay,
layers: ['clu', 'counties'],
});
// Later: handle.unmount();Manual deck.gl integration
Prefer to keep deck.gl plumbing in your own hands? Fetch a target=google style and turn the descriptors into deck.gl layers yourself.
import { Loader } from '@googlemaps/js-api-loader';
import { GoogleMapsOverlay } from '@deck.gl/google-maps';
import { MVTLayer, TileLayer } from '@deck.gl/geo-layers';
import { BitmapLayer } from '@deck.gl/layers';
const loader = new Loader({ apiKey: process.env.GMAPS_KEY!, version: 'weekly' });
await loader.load();
const map = new google.maps.Map(document.getElementById('map')!, {
center: { lat: 41.878, lng: -93.097 },
zoom: 12,
mapId: 'YOUR_VECTOR_MAP_ID',
});
const response = await fetch(
'https://api.landmapmagic.com/v1/styles?' +
new URLSearchParams({
key: 'YOUR_API_KEY',
target: 'google',
layers: 'clu',
})
);
const { vectorOverlays } = await response.json();
const cluOverlay = vectorOverlays.find((o) => o.id === 'clu');
const polygonSub = cluOverlay.subLayers.find((s) => s.kind === 'polygon');
const overlay = new GoogleMapsOverlay({
layers: [
new MVTLayer({
id: 'clu-outline',
data: cluOverlay.tileUrl,
minZoom: cluOverlay.minZoom,
maxZoom: cluOverlay.maxZoom,
lineWidthMinPixels: 1,
// For full accessor handling (static / by-zoom / by-property),
// use mountGoogleLandMap from landmapmagic/google instead.
getLineColor: polygonSub.accessors.getLineColor.value,
}),
],
});
overlay.setMap(map);Customizing colors and accessors
The styles API has no override query parameters. Mutate the deck.gl-friendly accessor descriptors before you mount, or replace props on the live overlay. See the Customizing Styles guide for full recipes.
const polygonSub = cluOverlay.subLayers.find((s) => s.kind === 'polygon');
polygonSub.accessors.getLineColor = { kind: 'static', value: [255, 107, 53, 255] };
polygonSub.accessors.getLineWidth = { kind: 'static', value: 3 };CDL raster overlays
CDL responses come back as tileLayers entries (raster PNGs over an XYZ schema). Repeat cdl:YYYY to layer multiple years.
const response = await fetch(
'https://api.landmapmagic.com/v1/styles?' +
new URLSearchParams({
key: 'YOUR_API_KEY',
target: 'google',
layers: 'clu,cdl:2024,cdl:2023',
})
);
const { tileLayers, vectorOverlays } = await response.json();
// Use mountGoogleLandMap to mount everything, or handle each yourself.Performance & Quotas
- MVT and PNG tiles are edge-cached via Cloudflare — reuse URLs to maximize cache hits.
- Throttle redraws to idle/tilesloaded events to avoid starving the main thread.
- Restrict client-side API keys by allowed origin in the dashboard.
fetchLandStylecaches per (target, layers) for the session, so repeated calls inside one page load are free.
Troubleshooting
- 401/403 responses — verify the key parameter and allowed origin configuration.
- Empty overlays — confirm zoom >= the layer's minzoom (CLU starts at Z11, parcels at Z14).
- Visual artifacts — make sure your Google Map is using a vector Map ID; raster Map IDs don't support deck.gl overlays.