MapConductor React SDK Samples

Post Office Cluster | Google Maps | MapConductor React SDK

MapConductor React SDK Post Office Cluster sample using Google Maps.

This interactive example demonstrates the Post Office Cluster feature through the MapConductor abstraction on Google Maps.

Code example

import { useMemo, useState } from 'react';
import {
  ColorDefaultIcon,
  createGeoPoint,
  createGeoRectBounds,
  createMapCameraPosition,
  createMarkerState,
  type MarkerState,
} from '@mapconductor/js-sdk-core';
import { InfoBubble } from '@mapconductor/js-sdk-react';
import { GoogleMapDesign, GoogleMapView2D, useGoogleMapViewState } from '@mapconductor/react-for-googlemaps';
import { MarkerClusterGroup, type MarkerCluster } from '@mapconductor/react-marker-clustering';


export default function App() {
  // (1) Create the map


  const initialCamera = createMapCameraPosition({
    position: createGeoPoint({ latitude: 43.05, longitude: 141.31 }),
    zoom: 11,
  });


  const mapViewState = useGoogleMapViewState({
    apiKey: 'YOUR_GOOGLE_MAPS_API_KEY',
    mapDesignType: GoogleMapDesign.Normal,
    cameraPosition: initialCamera,
  });


  // (2) Prepare the data and interaction state
  const postOffices = useMemo(() => [
    { id: 'maruyama', lat: 43.043751, lng: 141.305428, name: '円山西町簡易郵便局' },
    { id: 'jingu', lat: 43.057305, lng: 141.311483, name: '北海道神宮前郵便局' },
    { id: 'miyanomori', lat: 43.057305, lng: 141.303150, name: '札幌宮の森郵便局' },
    { id: 'araiyama', lat: 43.050833, lng: 141.298262, name: '札幌荒井山簡易郵便局' },
    { id: 'futagoyama', lat: 43.043085, lng: 141.318733, name: '札幌双子山郵便局' },
  ], []);
  const [selected, setSelected] = useState<MarkerState | null>(null);
  const postOfficeMarkers = useMemo(() => postOffices.map(office => createMarkerState({
    id: office.id,
    position: createGeoPoint({ latitude: office.lat, longitude: office.lng }),
    extra: office.name,
    onClick: markerState => setSelected(markerState),
  })), [postOffices]);
  const clusterIconProvider = (count: number) => new ColorDefaultIcon({
    fillColor: '#dc2626', label: String(count), labelTextColor: '#ffffff',
  });
  const zoomToCluster = (cluster: MarkerCluster) => {
    const bounds = createGeoRectBounds();
    postOfficeMarkers.filter(marker => cluster.markerIds.includes(marker.id))
      .forEach(marker => bounds.extend(marker.position));
    mapViewState.fitBounds(bounds, 60);
  };


  // (3) Render the map and its overlays


  return (
    <div style={{ height: 500, position: 'relative', display: 'flex', flexDirection: 'column' }}>
      <GoogleMapView2D mapId="DEMO_MAP_ID" state={mapViewState} onMapClick={() => setSelected(null)}>
        <MarkerClusterGroup
          markers={postOfficeMarkers}
          clusterIconProvider={clusterIconProvider}
          onClusterClick={zoomToCluster}
          minClusterSize={3}
          clusterRadiusPx={80}
        />
        {selected && <InfoBubble marker={selected}>{selected.extra as string}</InfoBubble>}
      </GoogleMapView2D>
    </div>
  );
}

How the code works

Cluster a large marker collection and provide a custom cluster icon and click behavior through the extension API.

The same postOfficeMarkers array feeds MarkerClusterGroup instead of <Markers>, so nearby offices are grouped automatically as the map zooms out.

clusterIconProvider draws the cluster badge, onClusterClick runs zoomToCluster to open a group, and minClusterSize with clusterRadiusPx tune how aggressively points merge.