Google Maps JavaScript API Samples

repository·main·Indexed 21 days ago

https://github.com/googlemaps/js-samples

A collection of code samples and a practical reference for developers implementing features of the Google Maps JavaScript API. Includes examples for initializing maps, using AdvancedMarkerElement with accessibility and altitude data, customizing marker visuals with PinElement, and implementing animations using CSS and IntersectionObserver.

Tokens
114.6K
Snippets
283
Records
308
Agent score
70%

What's inside @googlemaps/js-samples

  1. Test and lint js-samples

    main

    Run tests to verify outputs. You can also run linting and formatting to maintain code quality. If you are using Playwright for playground testing, you can update snapshots using specific flags.

    # Run tests
    npm test
    
    # Fix lint issues
    npm run lint
    
    # Format code
    npm run format
    
    # Update Playwright snapshots (only differing ones)
    npm run test:playwright:playground:update-snapshots
    
    # Update ALL Playwright snapshots
    npm run test:playwright:playground:update-snapshots -- --update-snapshots
    
    # Update snapshots for a specific sample
    npm run test:playwright:playground:update-snapshots -g <sample-name>
  2. Install and run a JS sample in Google Cloud Shell

    main

    To run a Google Maps Platform JS sample using TypeScript and Vite within Google Cloud Shell, follow these steps:

    1. Open Cloud Shell from the Google Cloud Console.
    2. Install dependencies using npm i.
    3. Start the Vite development server on port 8080 using npm start -- --port=8080.
    4. Use the Web Preview button in Cloud Shell to view the application on port 8080.
    npm i
    npm start -- --port=8080
  3. Apply custom styles to Data-Driven Styling feature layers

    main

    You can style feature layers by assigning a google.maps.FeatureStyleOptions object or a styling function to the layer's style property.

    • Static Styling: Apply the same style to every feature in the layer.
    • Dynamic Styling: Provide a function that receives feature parameters and returns different FeatureStyleOptions based on the feature's properties (e.g., highlighting a specific placeId).

    Note: To use Data-Driven Styling, your Map must be initialized with a mapId that has a style configured in the Google Cloud Console to enable the desired feature types.

    // Static style
    countryLayer.style = {
        fillColor: 'white',
        fillOpacity: 0.1,
        strokeColor: '#FF0000',
        strokeOpacity: 1.0,
        strokeWeight: 2.0,
    };
    
    // Dynamic style based on placeId
    const targetPlaceId = 'SOME_PLACE_ID';
    countryLayer.style = (params) => {
        if (params.feature.placeId === targetPlaceId) {
            return {
                fillColor: 'blue',
                fillOpacity: 0.5,
                strokeColor: 'blue',
                strokeOpacity: 1.0,
                strokeWeight: 2.0,
            };
        } else {
            return {
                fillColor: 'white',
                fillOpacity: 0.1,
                strokeColor: 'black',
                strokeOpacity: 1.0,
                strokeWeight: 1.0,
            };
        }
    };
  4. Create a custom overlay by extending OverlayView

    main

    To add custom HTML or images to a Google Map that move and scale with the map, extend the google.maps.OverlayView class. You must implement four key lifecycle methods to manage the overlay's presence and positioning:

    1. constructor: Initialize your custom properties (e.g., image URLs, bounds).
    2. onAdd(): Called when the overlay is added to the map. Use this to create your DOM elements and append them to one of the map's panes via this.getPanes(). Common panes include overlayLayer.
    3. draw(): Called when the map's projection changes (e.g., zoom or pan). Use this.getProjection() to convert LatLng coordinates to pixel coordinates using fromLatLngToDivPixel(). This allows you to position and resize your DOM elements correctly.
    4. onRemove(): Called when the overlay is removed from the map. Use this to clean up your DOM elements to prevent memory leaks.

    Once the class is defined, instantiate it and call .setMap(map) to display it.

    class MyCustomOverlay extends google.maps.OverlayView {
      private div_: HTMLElement | null = null;
      private bounds_: google.maps.LatLngBounds;
    
      constructor(bounds: google.maps.LatLngBounds) {
        super();
        this.bounds_ = bounds;
      }
    
      onAdd() {
        this.div_ = document.createElement("div");
        const panes = this.getPanes()!;
        panes.overlayLayer.appendChild(this.div_);
      }
    
      draw() {
        const projection = this.getProjection()!;
        const sw = projection.fromLatLngToDivPixel(this.bounds_.getSouthWest())!;
        const ne = projection.fromLatLngToDivPixel(this.bounds_.getNorthEast())!;
    
        if (this.div_) {
          this.div_.style.left = sw.x + "px";
          this.div_.style.top = sw.y + "px"; // Note: logic depends on coordinate system
          this.div_.style.width = (ne.x - sw.x) + "px";
          this.div_.style.height = (ne.y - sw.y) + "px";
        }
      }
    
      onRemove() {
        if (this.div_) {
          this.div_.parentNode?.removeChild(this.div_);
          this.div_ = null;
        }
      }
    }
    
    const overlay = new MyCustomOverlay(bounds);
    overlay.setMap(map);
  5. Handle Google Maps LatLng equality in React

    main

    When using Google Maps objects (like LatLng or LatLngLiteral) as dependencies in React hooks (e.g., useEffect), standard shallow comparison or even standard deep comparison may fail or trigger unnecessary updates.

    To solve this, implement a custom equality check using google.maps.LatLng.equals(). This ensures that two different object instances representing the same coordinates are treated as equal by React's dependency tracking.

    import { isLatLngLiteral } from "@googlemaps/typescript-guards";
    import { createCustomEqual } from "fast-equals";
    
    const deepCompareEqualsForMaps = createCustomEqual(
      (deepEqual) => (a: any, b: any) => {
        if (
          isLatLngLiteral(a) ||
          a instanceof google.maps.LatLng ||
          isLatLngLiteral(b) ||
          b instanceof google.maps.LatLng
        ) {
          return new google.maps.LatLng(a).equals(new google.maps.LatLng(b));
        }
        return deepEqual(a, b);
      }
    );
  6. Lifecycle methods for google.maps.OverlayView

    main

    When subclassing google.maps.OverlayView, you must implement these methods to manage the overlay's lifecycle:

    • onAdd(): Triggered when the overlay is added to the map. Use this.getPanes() to access map panes (like overlayLayer) and append your custom HTML elements.
    • draw(): Triggered when the map is redrawn or the projection changes. Use this.getProjection() to convert LatLng coordinates to pixel coordinates via fromLatLngToDivPixel() to position and size your elements.
    • onRemove(): Triggered when setMap(null) is called. Use this to remove your custom elements from the DOM to prevent memory leaks.
  7. Handle Deck.gl mouse events from Google Maps events

    main

    To make Deck.gl layers interactive (e.g., pickable: true) while they are overlaid on a Google Map, you must intercept Google Maps mouse events and convert them into Deck.gl events.

    1. Coordinate Projection: Use deck.getViewports()[0].project([lng, lat]) to convert the Google Maps latLng into the pixel coordinates expected by Deck.gl.
    2. Event Mapping: Map Google Maps event types to Deck.gl types:
      • click $\rightarrow$ click (Note: You may need to manually trigger pickObject for click events if not using pointer events).
      • dblclick $\rightarrow$ click with tapCount: 2.
      • mousemove $\rightarrow$ pointermove.
      • mouseout $\rightarrow$ pointerleave.
    3. Redraw: Call this.requestRedraw() after handling events to ensure the Deck.gl layer updates its visual state (like highlights).
    handleMouseEvent(deck: any, type: string, event: google.maps.MapMouseEvent) {
      const point = deck.getViewports()[0].project([
        event.latLng!.lng(), 
        event.latLng!.lat()
      ]);
      
      const deckEvent = {
        type,
        offsetCenter: { x: point[0], y: point[1] },
        srcEvent: event,
      };
    
      // Map types and call deck._onEvent or deck._onPointerMove
      // ...
      
      this.requestRedraw();
    }