CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-google-map-react

Isomorphic React component for rendering custom React components on Google Maps with full server-side rendering support

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

child-components.mddocs/

Child Components

React components rendered as children of GoogleMapReact are automatically positioned on the map using lat/lng coordinates. The component provides an internal hover system and passes special props to child components.

Capabilities

Child Component Props

Required and automatic props for components rendered on the map.

/**
 * Props interface for components rendered as children of GoogleMapReact
 */
interface MapChildProps {
  // Required positioning props
  lat: number;
  lng: number;
  
  // Automatically injected props
  $hover?: boolean;
  
  // Custom props (any additional props you want to pass)
  [key: string]: any;
}

Basic Usage:

// Simple marker component
const Marker = ({ text, $hover }) => (
  <div style={{
    backgroundColor: $hover ? 'red' : 'blue',
    color: 'white',
    padding: '4px 8px',
    borderRadius: '4px',
    transform: 'translate(-50%, -50%)' // Center the marker
  }}>
    {text}
  </div>
);

// Use in map
<GoogleMapReact
  defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
  defaultZoom={10}
>
  <Marker
    lat={37.7749}
    lng={-122.4194}
    text="San Francisco"
  />
</GoogleMapReact>

Hover System

GoogleMapReact includes an internal hover detection system that automatically manages hover states for child components.

interface HoverSystemProps {
  // Distance function for hover detection
  distanceToMouse?: (
    pt: { x: number; y: number },
    mousePos: { x: number; y: number },
    markerProps: any
  ) => number;
  
  // Maximum distance for hover detection (pixels)
  hoverDistance?: number;
  
  // Whether to debounce hover calculations
  debounced?: boolean;
}

Advanced Hover Example:

const InteractiveMarker = ({ text, $hover, onClick }) => (
  <div
    style={{
      backgroundColor: $hover ? '#ff4444' : '#4444ff',
      color: 'white',
      padding: '8px 12px',
      borderRadius: '8px',
      cursor: 'pointer',
      transform: 'translate(-50%, -50%)',
      transition: 'all 0.2s ease',
      boxShadow: $hover ? '0 4px 8px rgba(0,0,0,0.3)' : '0 2px 4px rgba(0,0,0,0.2)',
      fontSize: $hover ? '14px' : '12px'
    }}
    onClick={onClick}
  >
    {text}
  </div>
);

<GoogleMapReact
  defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
  defaultZoom={10}
  hoverDistance={20}
  debounced={true}
  onChildClick={(childKey, childProps) => {
    console.log('Marker clicked:', childProps.text);
  }}
>
  <InteractiveMarker
    key="sf-marker"
    lat={37.7749}
    lng={-122.4194}
    text="Click me!"
    onClick={() => alert('Marker clicked!')}
  />
</GoogleMapReact>

Positioning and Styling

Guidelines for properly positioning child components on the map.

interface PositioningStyles {
  position?: 'absolute' | 'relative';
  transform?: string;
  transformOrigin?: string;
  left?: string | number;
  top?: string | number;
}

Positioning Examples:

// Centered marker (most common)
const CenteredMarker = ({ children }) => (
  <div style={{
    position: 'absolute',
    transform: 'translate(-50%, -50%)',
    transformOrigin: 'center center'
  }}>
    {children}
  </div>
);

// Bottom-centered marker (pin style)
const PinMarker = ({ children }) => (
  <div style={{
    position: 'absolute',
    transform: 'translate(-50%, -100%)',
    transformOrigin: 'center bottom'
  }}>
    {children}
  </div>
);

// Top-left positioned marker
const TopLeftMarker = ({ children }) => (
  <div style={{
    position: 'absolute',
    transform: 'translate(0, 0)',
    transformOrigin: 'top left'
  }}>
    {children}
  </div>
);

// Usage
<GoogleMapReact defaultCenter={{ lat: 37.7749, lng: -122.4194 }} defaultZoom={10}>
  <CenteredMarker lat={37.7749} lng={-122.4194}>
    <div style={{ backgroundColor: 'red', width: 20, height: 20, borderRadius: '50%' }} />
  </CenteredMarker>
  
  <PinMarker lat={37.7849} lng={-122.4094}>
    <div style={{ backgroundColor: 'blue', width: 0, height: 0, borderLeft: '10px solid transparent', borderRight: '10px solid transparent', borderTop: '20px solid blue' }} />
  </PinMarker>
</GoogleMapReact>

Advanced Patterns

Dynamic Marker Creation

Create markers dynamically from data arrays.

function DynamicMarkers({ locations }) {
  return (
    <GoogleMapReact
      defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
      defaultZoom={10}
    >
      {locations.map((location, index) => (
        <Marker
          key={location.id || index}
          lat={location.lat}
          lng={location.lng}
          text={location.name}
          type={location.type}
        />
      ))}
    </GoogleMapReact>
  );
}

// Usage
const locations = [
  { id: 1, lat: 37.7749, lng: -122.4194, name: 'San Francisco', type: 'city' },
  { id: 2, lat: 37.7849, lng: -122.4094, name: 'North Beach', type: 'neighborhood' },
  { id: 3, lat: 37.7649, lng: -122.4294, name: 'Mission', type: 'neighborhood' }
];

<DynamicMarkers locations={locations} />

Conditional Rendering

Show/hide markers based on zoom level or other conditions.

function ZoomDependentMarkers({ zoom, markers }) {
  return (
    <GoogleMapReact
      zoom={zoom}
      defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
      onChange={({ zoom }) => setZoom(zoom)}
    >
      {markers.map(marker => {
        // Only show detailed markers at high zoom levels
        if (marker.type === 'detailed' && zoom < 12) {
          return null;
        }
        
        // Only show overview markers at low zoom levels
        if (marker.type === 'overview' && zoom > 8) {
          return null;
        }
        
        return (
          <Marker
            key={marker.id}
            lat={marker.lat}
            lng={marker.lng}
            text={marker.name}
          />
        );
      })}
    </GoogleMapReact>
  );
}

Custom Hover Behavior

Implement custom hover detection logic.

function CustomHoverMap() {
  const customDistanceFunction = (pt, mousePos, markerProps) => {
    // Custom distance calculation - larger hover area for important markers
    const baseDistance = Math.sqrt(
      Math.pow(pt.x - mousePos.x, 2) + Math.pow(pt.y - mousePos.y, 2)
    );
    
    // Increase hover distance for VIP markers
    return markerProps.isVIP ? baseDistance * 0.5 : baseDistance;
  };

  return (
    <GoogleMapReact
      defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
      defaultZoom={10}
      distanceToMouse={customDistanceFunction}
      hoverDistance={30}
    >
      <Marker lat={37.7749} lng={-122.4194} text="VIP Location" isVIP={true} />
      <Marker lat={37.7849} lng={-122.4094} text="Regular Location" isVIP={false} />
    </GoogleMapReact>
  );
}

Event Handling

Handle various mouse events on child components.

function EventHandlingMap() {
  const handleChildMouseEnter = (childKey, childProps) => {
    console.log('Mouse entered:', childProps.text);
  };

  const handleChildMouseLeave = (childKey, childProps) => {
    console.log('Mouse left:', childProps.text);
  };

  const handleChildClick = (childKey, childProps) => {
    console.log('Clicked:', childProps.text);
  };

  const handleChildMouseDown = (childKey, childProps) => {
    console.log('Mouse down:', childProps.text);
  };

  const handleChildMouseUp = (childKey, childProps) => {
    console.log('Mouse up:', childProps.text);
  };

  return (
    <GoogleMapReact
      defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
      defaultZoom={10}
      onChildMouseEnter={handleChildMouseEnter}
      onChildMouseLeave={handleChildMouseLeave}
      onChildClick={handleChildClick}
      onChildMouseDown={handleChildMouseDown}
      onChildMouseUp={handleChildMouseUp}
    >
      <InteractiveMarker
        lat={37.7749}
        lng={-122.4194}
        text="Interactive Marker"
      />
    </GoogleMapReact>
  );
}

Performance Considerations

Minimize Re-renders

Use React.memo and stable keys to optimize performance with many markers.

const Marker = React.memo(({ lat, lng, text, $hover }) => (
  <div style={{
    backgroundColor: $hover ? 'red' : 'blue',
    color: 'white',
    padding: '4px 8px',
    borderRadius: '4px',
    transform: 'translate(-50%, -50%)'
  }}>
    {text}
  </div>
));

// Use stable keys and avoid inline object creation
function OptimizedMarkers({ locations }) {
  return (
    <GoogleMapReact defaultCenter={{ lat: 37.7749, lng: -122.4194 }} defaultZoom={10}>
      {locations.map(location => (
        <Marker
          key={location.id} // Stable key
          lat={location.lat}
          lng={location.lng}
          text={location.name}
        />
      ))}
    </GoogleMapReact>
  );
}

docs

advanced-features.md

child-components.md

geographic-utilities.md

index.md

map-component.md

tile-system.md

tile.json