Select platform: [Android](https://developers.google.com/maps/documentation/android-sdk/shapes.md.txt "View this page for the Android platform docs.") [iOS](https://developers.google.com/maps/documentation/ios-sdk/shapes.md.txt "View this page for the iOS platform docs.") [JavaScript](https://developers.google.com/maps/documentation/javascript/shapes.md.txt "View this page for the JavaScript platform docs.")

You can add various shapes to your map. A shape is an object on the map,
tied to a latitude/longitude coordinate. The following shapes are available:
[lines](https://developers.google.com/maps/documentation/javascript/shapes.md.txt#polylines), [polygons](https://developers.google.com/maps/documentation/javascript/shapes.md.txt#polygons),
[circles](https://developers.google.com/maps/documentation/javascript/shapes.md.txt#circles) and [rectangles](https://developers.google.com/maps/documentation/javascript/shapes.md.txt#rectangles). You
can also configure your shapes so that [users can edit
or drag them](https://developers.google.com/maps/documentation/javascript/shapes#user-editable), or combine shapes with the
[Geometry library](https://developers.google.com/maps/documentation/javascript/geometry.md.txt)
([`google.maps.GeometryLibrary`](https://developers.google.com/maps/documentation/javascript/reference/library-interfaces.md.txt#GeometryLibrary))
to check [geofences and safe-zone boundaries](https://developers.google.com/maps/documentation/javascript/shapes.md.txt#geofences).

## Polylines

To draw a line on your map, use a polyline. The
[`Polyline`](https://developers.google.com/maps/documentation/javascript/reference.md.txt#Polyline) class defines a linear overlay of connected line
segments on the map. A `Polyline` object consists of an array of
`LatLng` locations, and creates a series of line segments that
connect those locations in an ordered sequence.

### Add a polyline

The `Polyline` constructor takes a set of
`PolylineOptions` specifying the `LatLng`
coordinates of the line and a set of styles to adjust the polyline's
visual behavior.

`Polyline` objects are drawn as a series of straight segments on
the map. You can specify custom colors, weights, and opacities for the stroke
of the line within the `PolylineOptions` when
constructing your line, or you can change those properties after construction.
A polyline supports the following stroke styles:

- `strokeColor` specifies a hexadecimal HTML color of the format `"#FFFFFF"`. The `Polyline` class does not support named colors.
- `strokeOpacity` specifies a numerical value between `0.0` and `1.0` to determine the opacity of the line's color. The default is `1.0`.
- `strokeWeight` specifies the width of the line in pixels.

The polyline's `editable` property specifies whether users can
edit the shape. See [user-editable shapes](https://developers.google.com/maps/documentation/javascript/shapes.md.txt#user-editable)
below. Similarly, you can set the `draggable` property to allow
users to [drag the line](https://developers.google.com/maps/documentation/javascript/shapes.md.txt#draggable).

This example creates a two-pixel-wide red polyline that shows the path of
the first trans-Pacific flight between Oakland, CA, and Brisbane, Australia.
<iframe src="https://maps-docs-team.web.app/samples/polyline-simple/dist/" allow="fullscreen; "></iframe>

### TypeScript

```typescript
// This example creates a 2-pixel-wide red polyline showing the path of
// the first trans-Pacific flight between Oakland, CA, and Brisbane,
// Australia which was made by Charles Kingsford Smith.
const mapElement = document.querySelector('gmp-map')!;
let innerMap: google.maps.Map;

async function init() {
    const { Polyline } = await google.maps.importLibrary('maps');
    innerMap = mapElement.innerMap;

    const flightPlanCoordinates = [
        { lat: 37.772, lng: -122.214 },
        { lat: 21.291, lng: -157.821 },
        { lat: -18.142, lng: 178.431 },
        { lat: -27.467, lng: 153.027 },
    ];
    const flightPath = new Polyline({
        path: flightPlanCoordinates,
        geodesic: true,
        strokeColor: '#FF0000',
        strokeOpacity: 1.0,
        strokeWeight: 2,
    });

    flightPath.setMap(innerMap);
}

void init();
```

### JavaScript

```javascript
// This example creates a 2-pixel-wide red polyline showing the path of
// the first trans-Pacific flight between Oakland, CA, and Brisbane,
// Australia which was made by Charles Kingsford Smith.
const mapElement = document.querySelector('gmp-map');
let innerMap;

async function init() {
    const { Polyline } = await google.maps.importLibrary('maps');
    innerMap = mapElement.innerMap;

    const flightPlanCoordinates = [
        { lat: 37.772, lng: -122.214 },
        { lat: 21.291, lng: -157.821 },
        { lat: -18.142, lng: 178.431 },
        { lat: -27.467, lng: 153.027 },
    ];
    const flightPath = new Polyline({
        path: flightPlanCoordinates,
        geodesic: true,
        strokeColor: '#FF0000',
        strokeOpacity: 1.0,
        strokeWeight: 2,
    });

    flightPath.setMap(innerMap);
}

void init();
```
[View example](https://developers.google.com/maps/documentation/javascript/examples/polyline-simple.md.txt)

### Try Sample

[JSFiddle.net](https://jsfiddle.net/gh/get/library/pure/googlemaps-samples/js-api-samples/tree/main/dist/samples/polyline-simple/jsfiddle)

### Remove a polyline

To remove a polyline from the map, call the `setMap()` method
passing `null` as the argument. In the following example,
`flightPath` is a polyline object:

```javascript
flightPath.setMap(null);
```

Note that the above method does not delete the polyline. It removes
the polyline from the map. If instead you wish to delete the polyline,
you should remove it from the map, and then set the
polyline itself to `null`.

### Inspect a polyline

A polyline specifies a series of coordinates as an array of
`LatLng` objects. These coordinates determine the line's path.
To retrieve the coordinates, call `getPath()`, which will
return an array of type `MVCArray`. You can
manipulate and inspect the array using the following operations:

- `getAt()` returns the `LatLng` at a given zero-based index value.
- `insertAt()` inserts a passed `LatLng` at a given zero-based index value. Note that any existing coordinates at that index value are moved forward.
- `removeAt()` removes a `LatLng` at a given zero-based index value.

> [!NOTE]
> **Note:** You cannot retrieve the *i* th element of an array by using the syntax `mvcArray[i]`. You must use `mvcArray.getAt(i)`.

The following example demonstrates constructing a polyline based on clicks (click the map to
add a vertex).
<iframe src="https://maps-docs-team.web.app/samples/polyline-complex/dist/" allow="fullscreen; "></iframe>

### TypeScript

```typescript
/**
 * This example creates an interactive map which constructs a polyline based on
 * user clicks. Note that the polyline only appears once its path property
 * contains two LatLng coordinates.
 */

let poly: google.maps.Polyline;
const mapElement = document.querySelector('gmp-map')!;
let innerMap: google.maps.Map;

async function init() {
    // Import the needed libraries.
    const [{ Polyline }, { AdvancedMarkerElement }] = await Promise.all([
        google.maps.importLibrary('maps'),
        google.maps.importLibrary('marker'),
    ]);

    innerMap = mapElement.innerMap;

    poly = new Polyline({
        strokeColor: '#000000',
        strokeOpacity: 1.0,
        strokeWeight: 3,
    });
    poly.setMap(innerMap);

    // Handles click events on a map, and adds a new point to the Polyline.
    innerMap.addListener('click', (event: google.maps.MapMouseEvent) => {
        const latLng = event.latLng;
        if (!latLng) return;

        const path = poly.getPath();

        // Because path is an MVCArray, we can simply append a new coordinate
        // and it will automatically appear.
        path.push(latLng);

        // Add a new marker at the new plotted point on the polyline.
        new AdvancedMarkerElement({
            position: latLng,
            title: '#' + path.getLength(),
            map: innerMap,
        });
    });
}

void init();
```

### JavaScript

```javascript
/**
 * This example creates an interactive map which constructs a polyline based on
 * user clicks. Note that the polyline only appears once its path property
 * contains two LatLng coordinates.
 */

let poly;
const mapElement = document.querySelector('gmp-map');
let innerMap;

async function init() {
    // Import the needed libraries.
    const [{ Polyline }, { AdvancedMarkerElement }] = await Promise.all([
        google.maps.importLibrary('maps'),
        google.maps.importLibrary('marker'),
    ]);

    innerMap = mapElement.innerMap;

    poly = new Polyline({
        strokeColor: '#000000',
        strokeOpacity: 1.0,
        strokeWeight: 3,
    });
    poly.setMap(innerMap);

    // Handles click events on a map, and adds a new point to the Polyline.
    innerMap.addListener('click', (event) => {
        const latLng = event.latLng;
        if (!latLng) return;

        const path = poly.getPath();

        // Because path is an MVCArray, we can simply append a new coordinate
        // and it will automatically appear.
        path.push(latLng);

        // Add a new marker at the new plotted point on the polyline.
        new AdvancedMarkerElement({
            position: latLng,
            title: '#' + path.getLength(),
            map: innerMap,
        });
    });
}

void init();
```
[View example](https://developers.google.com/maps/documentation/javascript/examples/polyline-complex.md.txt)

### Try Sample

[JSFiddle.net](https://jsfiddle.net/gh/get/library/pure/googlemaps-samples/js-api-samples/tree/main/dist/samples/polyline-complex/jsfiddle)

### Customize a polyline

You can add vector-based images to a polyline in the form of symbols. With a
combination of symbols and the `PolylineOptions` class,
you have a lot of control over the look and feel of polylines on your map.
See [Symbols](https://developers.google.com/maps/documentation/javascript/symbols.md.txt) for information
about [arrows](https://developers.google.com/maps/documentation/javascript/symbols.md.txt#arrows),
[dashed lines](https://developers.google.com/maps/documentation/javascript/symbols.md.txt#dashed_lines),
[custom symbols](https://developers.google.com/maps/documentation/javascript/symbols.md.txt#custom_paths)
and [animated symbols](https://developers.google.com/maps/documentation/javascript/symbols.md.txt#animate).

## Polygons

A polygon represents an area enclosed by a closed path (or loop), which is
defined by a series of coordinates.
[`Polygon`](https://developers.google.com/maps/documentation/javascript/reference.md.txt#Polygon) objects are similar to `Polyline` objects
in that they consist of a series of coordinates in an ordered sequence.
Polygons are drawn with a stroke and a fill. You can define custom colors,
weights, and opacities for the edge of the polygon (the stroke) and custom
colors and opacities for the enclosed area (the fill). Colors should be
indicated in hexadecimal HTML format. Color names are not supported.

To show or shade administrative areas such as countries, states, cities, or
postal codes, use
[data-driven
styling for boundaries](https://developers.google.com/maps/documentation/javascript/dds-boundaries/overview).

`Polygon` objects can describe complex shapes, including:

- Multiple non-contiguous areas defined by a single polygon.
- Areas with holes in them.
- Intersections of one or more areas.

To define a complex shape, you use a polygon with multiple paths.

**Note:** The Data layer provides a simple way
of drawing polygons. It handles polygon winding for you, making it easier
to draw polygons with holes. See the
[documentation for
the Data layer](https://developers.google.com/maps/documentation/javascript/datalayer#polygon).

### Add a polygon

Because a polygonal area may include several separate paths, the
`Polygon` object's `paths` property specifies
an array of arrays, each of type `MVCArray`. Each array defines a
separate sequence of ordered `LatLng` coordinates.

For simple polygons consisting of only one path, you can
construct a `Polygon` using a single array of
`LatLng` coordinates. The Maps JavaScript API will convert
the simple array into an array of arrays upon construction when storing it
within the `paths` property. The API provides a simple
`getPath()` method for polygons consisting of one path.

> [!NOTE]
> **Note:** If you construct a simple polygon in this manner, you will still need to retrieve values from the polygon by manipulating the path as an `MVCArray`.

The polygon's `editable` property specifies whether users can edit
the shape. See [user-editable shapes](https://developers.google.com/maps/documentation/javascript/shapes.md.txt#user-editable) below.
Similarly, you can set the `draggable` property to allow users to
[drag the shape](https://developers.google.com/maps/documentation/javascript/shapes.md.txt#draggable).
<iframe src="https://geo-devrel-javascript-samples.web.app/samples/polygon-simple/app/dist/" allow="fullscreen; "></iframe>

### TypeScript

```typescript
// This example creates a simple polygon representing the Bermuda Triangle.

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 5,
      center: { lat: 24.886, lng: -70.268 },
      mapTypeId: "terrain",
    }
  );

  // Define the LatLng coordinates for the polygon's path.
  const triangleCoords = [
    { lat: 25.774, lng: -80.19 },
    { lat: 18.466, lng: -66.118 },
    { lat: 32.321, lng: -64.757 },
    { lat: 25.774, lng: -80.19 },
  ];

  // Construct the polygon.
  const bermudaTriangle = new google.maps.Polygon({
    paths: triangleCoords,
    strokeColor: "#FF0000",
    strokeOpacity: 0.8,
    strokeWeight: 2,
    fillColor: "#FF0000",
    fillOpacity: 0.35,
  });

  bermudaTriangle.setMap(map);
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;
```

> [!NOTE]
> **Note:** Read the [guide](https://developers.google.com/maps/documentation/javascript/using-typescript.md.txt) on using TypeScript and Google Maps.

### JavaScript

```javascript
// This example creates a simple polygon representing the Bermuda Triangle.
function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 5,
    center: { lat: 24.886, lng: -70.268 },
    mapTypeId: "terrain",
  });
  // Define the LatLng coordinates for the polygon's path.
  const triangleCoords = [
    { lat: 25.774, lng: -80.19 },
    { lat: 18.466, lng: -66.118 },
    { lat: 32.321, lng: -64.757 },
    { lat: 25.774, lng: -80.19 },
  ];
  // Construct the polygon.
  const bermudaTriangle = new google.maps.Polygon({
    paths: triangleCoords,
    strokeColor: "#FF0000",
    strokeOpacity: 0.8,
    strokeWeight: 2,
    fillColor: "#FF0000",
    fillOpacity: 0.35,
  });

  bermudaTriangle.setMap(map);
}

window.initMap = initMap;
```

> [!NOTE]
> **Note:** The JavaScript is compiled from the TypeScript snippet.

[View example](https://developers.google.com/maps/documentation/javascript/examples/polygon-simple.md.txt)

#### Polygon auto-completion

The `Polygon` in the example above consists of four sets of
`LatLng` coordinates, but notice that the first and last sets
define the same location, which completes the loop. In practice, however,
since polygons define closed areas, you don't need to specify the last
set of coordinates. The Maps JavaScript API will automatically complete
the polygon by drawing a stroke connecting the last location back to the first
location for any given path.

The following example is identical to the previous one, except
that the last `LatLng` is omitted:
[view example](https://developers.google.com/maps/documentation/javascript/examples/polygon-autoclose.md.txt).

### Remove a polygon

To remove a polygon from the map, call the `setMap()` method
passing `null` as the argument. In the following example,
`bermudaTriangle` is a polygon object:

```javascript
bermudaTriangle.setMap(null);
```

Note that the above method does not delete the polygon. It removes
the polygon from the map. If instead you wish to delete the polygon,
you should remove it from the map, and then set the
polygon itself to `null`.

> [!NOTE]
> Removing a polygon is similar to removing a polyline. To see the code in action for a polyline: [view example](https://developers.google.com/maps/documentation/javascript/examples/polyline-remove.md.txt).

### Inspect a polygon

A polygon specifies its series of coordinates as an array
of arrays, where each array is of type `MVCArray`. Each
"leaf" array is an array of `LatLng` coordinates
specifying a single path. To retrieve these coordinates, call the
`Polygon` object's `getPaths()` method. Since the
array is an `MVCArray` you will need to manipulate and
inspect it using the following operations:

- `getAt()` returns the `LatLng` at a given zero-based index value.
- `insertAt()` inserts a passed `LatLng` at a given zero-based index value. Note that any existing coordinates at that index value are moved forward.
- `removeAt()` removes a `LatLng` at a given zero-based index value.

> [!NOTE]
> **Note:** You cannot retrieve the *i* th element of an array by using the syntax `mvcArray[i]`. You must use `mvcArray.getAt(i)`.

<iframe src="https://geo-devrel-javascript-samples.web.app/samples/polygon-arrays/app/dist/" allow="fullscreen; "></iframe>

### TypeScript

```typescript
// This example creates a simple polygon representing the Bermuda Triangle.
// When the user clicks on the polygon an info window opens, showing
// information about the polygon's coordinates.

let map: google.maps.Map;

let infoWindow: google.maps.InfoWindow;

function initMap(): void {
  map = new google.maps.Map(document.getElementById("map") as HTMLElement, {
    zoom: 5,
    center: { lat: 24.886, lng: -70.268 },
    mapTypeId: "terrain",
  });

  // Define the LatLng coordinates for the polygon.
  const triangleCoords: google.maps.LatLngLiteral[] = [
    { lat: 25.774, lng: -80.19 },
    { lat: 18.466, lng: -66.118 },
    { lat: 32.321, lng: -64.757 },
  ];

  // Construct the polygon.
  const bermudaTriangle = new google.maps.Polygon({
    paths: triangleCoords,
    strokeColor: "#FF0000",
    strokeOpacity: 0.8,
    strokeWeight: 3,
    fillColor: "#FF0000",
    fillOpacity: 0.35,
  });

  bermudaTriangle.setMap(map);

  // Add a listener for the click event.
  bermudaTriangle.addListener("click", showArrays);

  infoWindow = new google.maps.InfoWindow();
}

function showArrays(event: any) {
  // Since this polygon has only one path, we can call getPath() to return the
  // MVCArray of LatLngs.
  // @ts-ignore
  const polygon = this as google.maps.Polygon;
  const vertices = polygon.getPath();

  let contentString =
    "<b>Bermuda Triangle polygon</b><br>" +
    "Clicked location: <br>" +
    event.latLng.lat() +
    "," +
    event.latLng.lng() +
    "<br>";

  // Iterate over the vertices.
  for (let i = 0; i < vertices.getLength(); i++) {
    const xy = vertices.getAt(i);

    contentString +=
      "<br>" + "Coordinate " + i + ":<br>" + xy.lat() + "," + xy.lng();
  }

  // Replace the info window's content and position.
  infoWindow.setContent(contentString);
  infoWindow.setPosition(event.latLng);

  infoWindow.open(map);
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;
```

> [!NOTE]
> **Note:** Read the [guide](https://developers.google.com/maps/documentation/javascript/using-typescript.md.txt) on using TypeScript and Google Maps.

### JavaScript

```javascript
// This example creates a simple polygon representing the Bermuda Triangle.
// When the user clicks on the polygon an info window opens, showing
// information about the polygon's coordinates.
let map;
let infoWindow;

function initMap() {
  map = new google.maps.Map(document.getElementById("map"), {
    zoom: 5,
    center: { lat: 24.886, lng: -70.268 },
    mapTypeId: "terrain",
  });

  // Define the LatLng coordinates for the polygon.
  const triangleCoords = [
    { lat: 25.774, lng: -80.19 },
    { lat: 18.466, lng: -66.118 },
    { lat: 32.321, lng: -64.757 },
  ];
  // Construct the polygon.
  const bermudaTriangle = new google.maps.Polygon({
    paths: triangleCoords,
    strokeColor: "#FF0000",
    strokeOpacity: 0.8,
    strokeWeight: 3,
    fillColor: "#FF0000",
    fillOpacity: 0.35,
  });

  bermudaTriangle.setMap(map);
  // Add a listener for the click event.
  bermudaTriangle.addListener("click", showArrays);
  infoWindow = new google.maps.InfoWindow();
}

function showArrays(event) {
  // Since this polygon has only one path, we can call getPath() to return the
  // MVCArray of LatLngs.
  // @ts-ignore
  const polygon = this;
  const vertices = polygon.getPath();
  let contentString =
    "<b>Bermuda Triangle polygon</b><br>" +
    "Clicked location: <br>" +
    event.latLng.lat() +
    "," +
    event.latLng.lng() +
    "<br>";

  // Iterate over the vertices.
  for (let i = 0; i < vertices.getLength(); i++) {
    const xy = vertices.getAt(i);

    contentString +=
      "<br>" + "Coordinate " + i + ":<br>" + xy.lat() + "," + xy.lng();
  }

  // Replace the info window's content and position.
  infoWindow.setContent(contentString);
  infoWindow.setPosition(event.latLng);
  infoWindow.open(map);
}

window.initMap = initMap;
```

> [!NOTE]
> **Note:** The JavaScript is compiled from the TypeScript snippet.

[View example](https://developers.google.com/maps/documentation/javascript/examples/polygon-arrays.md.txt)

### Put a hole in a polygon

To create an empty area within a polygon, you need to create two paths,
one inside the other. To create the hole, the coordinates defining the inner
path must be in the opposite order to those defining the outer path.
For example, if the coordinates of the outer path are in clockwise order
then the inner path must be counter-clockwise.

**Note:** The Data layer handles the order of the
inner and outer paths for you, making it easier to draw polygons with holes.
See the
[documentation
for the Data layer](https://developers.google.com/maps/documentation/javascript/datalayer#polygon).

The following example draws a polygon with two paths, with the inner path
wound in the opposite direction to the outer path.
<iframe src="https://geo-devrel-javascript-samples.web.app/samples/polygon-hole/app/dist/" allow="fullscreen; "></iframe>

### TypeScript

```typescript
// This example creates a triangular polygon with a hole in it.

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 5,
      center: { lat: 24.886, lng: -70.268 },
    }
  );

  // Define the LatLng coordinates for the polygon's  outer path.
  const outerCoords = [
    { lat: 25.774, lng: -80.19 },
    { lat: 18.466, lng: -66.118 },
    { lat: 32.321, lng: -64.757 },
  ];

  // Define the LatLng coordinates for the polygon's inner path.
  // Note that the points forming the inner path are wound in the
  // opposite direction to those in the outer path, to form the hole.
  const innerCoords = [
    { lat: 28.745, lng: -70.579 },
    { lat: 29.57, lng: -67.514 },
    { lat: 27.339, lng: -66.668 },
  ];

  // Construct the polygon, including both paths.
  const bermudaTriangle = new google.maps.Polygon({
    paths: [outerCoords, innerCoords],
    strokeColor: "#FFC107",
    strokeOpacity: 0.8,
    strokeWeight: 2,
    fillColor: "#FFC107",
    fillOpacity: 0.35,
  });

  bermudaTriangle.setMap(map);
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;
```

> [!NOTE]
> **Note:** Read the [guide](https://developers.google.com/maps/documentation/javascript/using-typescript.md.txt) on using TypeScript and Google Maps.

### JavaScript

```javascript
// This example creates a triangular polygon with a hole in it.
function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 5,
    center: { lat: 24.886, lng: -70.268 },
  });
  // Define the LatLng coordinates for the polygon's  outer path.
  const outerCoords = [
    { lat: 25.774, lng: -80.19 },
    { lat: 18.466, lng: -66.118 },
    { lat: 32.321, lng: -64.757 },
  ];
  // Define the LatLng coordinates for the polygon's inner path.
  // Note that the points forming the inner path are wound in the
  // opposite direction to those in the outer path, to form the hole.
  const innerCoords = [
    { lat: 28.745, lng: -70.579 },
    { lat: 29.57, lng: -67.514 },
    { lat: 27.339, lng: -66.668 },
  ];
  // Construct the polygon, including both paths.
  const bermudaTriangle = new google.maps.Polygon({
    paths: [outerCoords, innerCoords],
    strokeColor: "#FFC107",
    strokeOpacity: 0.8,
    strokeWeight: 2,
    fillColor: "#FFC107",
    fillOpacity: 0.35,
  });

  bermudaTriangle.setMap(map);
}

window.initMap = initMap;
```

> [!NOTE]
> **Note:** The JavaScript is compiled from the TypeScript snippet.

[View example](https://developers.google.com/maps/documentation/javascript/examples/polygon-hole.md.txt)

## Rectangles

In addition to a generic `Polygon` class, the Google Maps
JavaScript API includes a specific class for
[`Rectangle`](https://developers.google.com/maps/documentation/javascript/reference.md.txt#Rectangle) objects, to simplify their construction.

### Add a rectangle

A `Rectangle` is similar to a `Polygon` in
that you can define custom colors, weights, and opacities for the edge of the
rectangle (the stroke) and custom colors and opacities for the area within the
rectangle (the fill). Colors should be indicated in hexadecimal numeric HTML
style.

Unlike a `Polygon`, you don't define `paths`
for a `Rectangle`. Instead, a rectangle has a `bounds`
property which defines its shape by specifying a
[`google.maps.LatLngBounds`](https://developers.google.com/maps/documentation/javascript/reference.md.txt#LatLngBounds) for the rectangle.

The rectangle's `editable` property specifies whether
users can edit the shape. See [user-editable
shapes](https://developers.google.com/maps/documentation/javascript/shapes#user-editable) below. Similarly, you can set the `draggable` property
to allow users to [drag the rectangle](https://developers.google.com/maps/documentation/javascript/shapes.md.txt#draggable).
<iframe src="https://geo-devrel-javascript-samples.web.app/samples/rectangle-simple/app/dist/" allow="fullscreen; "></iframe>

### TypeScript

```typescript
// This example adds a red rectangle to a map.

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 11,
      center: { lat: 33.678, lng: -116.243 },
      mapTypeId: "terrain",
    }
  );

  const rectangle = new google.maps.Rectangle({
    strokeColor: "#FF0000",
    strokeOpacity: 0.8,
    strokeWeight: 2,
    fillColor: "#FF0000",
    fillOpacity: 0.35,
    map,
    bounds: {
      north: 33.685,
      south: 33.671,
      east: -116.234,
      west: -116.251,
    },
  });
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;
```

> [!NOTE]
> **Note:** Read the [guide](https://developers.google.com/maps/documentation/javascript/using-typescript.md.txt) on using TypeScript and Google Maps.

### JavaScript

```javascript
// This example adds a red rectangle to a map.
function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 11,
    center: { lat: 33.678, lng: -116.243 },
    mapTypeId: "terrain",
  });
  const rectangle = new google.maps.Rectangle({
    strokeColor: "#FF0000",
    strokeOpacity: 0.8,
    strokeWeight: 2,
    fillColor: "#FF0000",
    fillOpacity: 0.35,
    map,
    bounds: {
      north: 33.685,
      south: 33.671,
      east: -116.234,
      west: -116.251,
    },
  });
}

window.initMap = initMap;
```

> [!NOTE]
> **Note:** The JavaScript is compiled from the TypeScript snippet.

[View example](https://developers.google.com/maps/documentation/javascript/examples/rectangle-simple.md.txt)

The following code creates a rectangle each time the user changes the zoom
on the map. The size of the rectangle is determined by the viewport.
<iframe src="https://geo-devrel-javascript-samples.web.app/samples/rectangle-zoom/app/dist/" allow="fullscreen; "></iframe>

### TypeScript

```typescript
// This example creates a rectangle based on the viewport
// on any 'zoom-changed' event.

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 11,
      center: { lat: 40.74852, lng: -73.981687 },
      mapTypeId: "terrain",
    }
  );

  const rectangle = new google.maps.Rectangle();

  map.addListener("zoom_changed", () => {
    // Get the current bounds, which reflect the bounds before the zoom.
    rectangle.setOptions({
      strokeColor: "#FF0000",
      strokeOpacity: 0.8,
      strokeWeight: 2,
      fillColor: "#FF0000",
      fillOpacity: 0.35,
      map,
      bounds: map.getBounds() as google.maps.LatLngBounds,
    });
  });
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;
```

> [!NOTE]
> **Note:** Read the [guide](https://developers.google.com/maps/documentation/javascript/using-typescript.md.txt) on using TypeScript and Google Maps.

### JavaScript

```javascript
// This example creates a rectangle based on the viewport
// on any 'zoom-changed' event.
function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 11,
    center: { lat: 40.74852, lng: -73.981687 },
    mapTypeId: "terrain",
  });
  const rectangle = new google.maps.Rectangle();

  map.addListener("zoom_changed", () => {
    // Get the current bounds, which reflect the bounds before the zoom.
    rectangle.setOptions({
      strokeColor: "#FF0000",
      strokeOpacity: 0.8,
      strokeWeight: 2,
      fillColor: "#FF0000",
      fillOpacity: 0.35,
      map,
      bounds: map.getBounds(),
    });
  });
}

window.initMap = initMap;
```

> [!NOTE]
> **Note:** The JavaScript is compiled from the TypeScript snippet.

[View example](https://developers.google.com/maps/documentation/javascript/examples/rectangle-zoom.md.txt)

### Remove a rectangle

To remove a rectangle from the map, call the `setMap()` method
passing `null` as the argument.

```javascript
rectangle.setMap(null);
```

Note that the above method does not delete the rectangle. It removes
the rectangle from the map. If instead you wish to delete the rectangle,
you should remove it from the map, and then set the
rectangle itself to `null`.

> [!NOTE]
> Removing a rectangle is similar to removing a polyline. To see the code in action for a polyline: [view example](https://developers.google.com/maps/documentation/javascript/examples/polyline-remove.md.txt).

## Circles

In addition to the generic `Polygon` class, the Google Maps
JavaScript API includes a specific class for
[`Circle`](https://developers.google.com/maps/documentation/javascript/reference.md.txt#Circle) objects, to simplify their construction.

### Add a circle

A `Circle` is similar to a `Polygon` in that you can
define custom colors, weights, and opacities for the edge of the circle (the
stroke) and custom colors and opacities for the area within the circle (the
fill). Colors should be indicated in hexadecimal numeric HTML style.

Unlike a `Polygon`, you don't define `paths`
for a `Circle`. Instead, a circle has two additional
properties which define its shape:

- `center` specifies the `google.maps.LatLng` of the center of the circle.
- `radius` specifies the radius of the circle, in meters.

The circle's `editable` property specifies whether users can edit
the shape. See [user-editable shapes](https://developers.google.com/maps/documentation/javascript/shapes.md.txt#user-editable) below.
Similarly, you can set the `draggable` property to allow
users to [drag the circle](https://developers.google.com/maps/documentation/javascript/shapes.md.txt#draggable).

The following example uses circles to show approximate walking times between
locations in Kyoto, Japan. Select the needed distance from the menu, click the
map to re-center the circle, and drag the circle to reposition it.
<iframe src="https://maps-docs-team.web.app/samples/circle-simple/dist/" allow="fullscreen; "></iframe>

### TypeScript

```typescript
const mapElement = document.querySelector('gmp-map')!;
let innerMap: google.maps.Map;

async function init() {
    // Request needed libraries.
    const [{ Circle }, { AdvancedMarkerElement }, { event }] =
        await Promise.all([
            google.maps.importLibrary('maps'),
            google.maps.importLibrary('marker'),
            google.maps.importLibrary('core'),
        ]);

    // Set the initial map center point.
    const initialCenter = { lat: 34.98956821576194, lng: 135.74239981260283 }; // Hotel Emion, Kyoto, Japan

    // Get the inner map.
    innerMap = mapElement.innerMap;

    // Get the buttons.
    const buttons = document.querySelectorAll('input[name="radius"]');

    // Create the circle.
    const walkingCircle = new Circle({
        strokeColor: '#ffdd00ff',
        strokeOpacity: 0.8,
        strokeWeight: 2,
        fillColor: '#ffdd00ff',
        fillOpacity: 0.35,
        map: innerMap,
        center: initialCenter,
        radius: 400,
        draggable: true,
        editable: false,
    });

    // Define a "Crosshair" vector icon
    const parser = new DOMParser();
    const svgString = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="-6 -6 12 12"><path d="M -6,0 L 6,0 M 0,-6 L 0,6" stroke="black" stroke-width="1"/></svg>`;

    const pinSvg = parser.parseFromString(
        svgString,
        'image/svg+xml'
    ).documentElement;

    const centerMarker = new AdvancedMarkerElement({
        position: initialCenter,
        title: 'A marker using a custom SVG image.',
        anchorLeft: '-50%',
        anchorTop: '-50%',
    });
    centerMarker.append(pinSvg);
    mapElement.append(centerMarker);

    // Wait for the map to finish drawing its tiles.
    event.addListenerOnce(innerMap, 'tilesloaded', () => {
        // Get the controls div
        const controls = document.getElementById('control-panel');

        // Display controls once map is loaded.
        if (controls) {
            controls.style.display = 'block';
        }
    });

    // Add event listener to update the radius based on user selection.
    buttons.forEach((button) => {
        button.addEventListener('change', (changeEvent) => {
            const target = changeEvent.target as HTMLInputElement;
            walkingCircle.setRadius(Number(target.value));
        });
    });

    // Handle user click, reset the map center and position the circle.
    innerMap.addListener(
        'click',
        (
            mapsMouseEvent:
                google.maps.MapMouseEvent | google.maps.IconMouseEvent
        ) => {
            const newCenter = mapsMouseEvent.latLng;
            if (!newCenter) return;
            walkingCircle.setCenter(newCenter);
            centerMarker.position = newCenter;
            innerMap.panTo(newCenter);
        }
    );

    // Handle user dragging the circle, update the center marker position.
    walkingCircle.addListener('center_changed', () => {
        centerMarker.position = walkingCircle.getCenter();
    });
}

void init();
```

### JavaScript

```javascript
const mapElement = document.querySelector('gmp-map');
let innerMap;

async function init() {
    // Request needed libraries.
    const [{ Circle }, { AdvancedMarkerElement }, { event }] =
        await Promise.all([
            google.maps.importLibrary('maps'),
            google.maps.importLibrary('marker'),
            google.maps.importLibrary('core'),
        ]);

    // Set the initial map center point.
    const initialCenter = { lat: 34.98956821576194, lng: 135.74239981260283 }; // Hotel Emion, Kyoto, Japan

    // Get the inner map.
    innerMap = mapElement.innerMap;

    // Get the buttons.
    const buttons = document.querySelectorAll('input[name="radius"]');

    // Create the circle.
    const walkingCircle = new Circle({
        strokeColor: '#ffdd00ff',
        strokeOpacity: 0.8,
        strokeWeight: 2,
        fillColor: '#ffdd00ff',
        fillOpacity: 0.35,
        map: innerMap,
        center: initialCenter,
        radius: 400,
        draggable: true,
        editable: false,
    });

    // Define a "Crosshair" vector icon
    const parser = new DOMParser();
    const svgString = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="-6 -6 12 12"><path d="M -6,0 L 6,0 M 0,-6 L 0,6" stroke="black" stroke-width="1"/></svg>`;

    const pinSvg = parser.parseFromString(
        svgString,
        'image/svg+xml'
    ).documentElement;

    const centerMarker = new AdvancedMarkerElement({
        position: initialCenter,
        title: 'A marker using a custom SVG image.',
        anchorLeft: '-50%',
        anchorTop: '-50%',
    });
    centerMarker.append(pinSvg);
    mapElement.append(centerMarker);

    // Wait for the map to finish drawing its tiles.
    event.addListenerOnce(innerMap, 'tilesloaded', () => {
        // Get the controls div
        const controls = document.getElementById('control-panel');

        // Display controls once map is loaded.
        if (controls) {
            controls.style.display = 'block';
        }
    });

    // Add event listener to update the radius based on user selection.
    buttons.forEach((button) => {
        button.addEventListener('change', (changeEvent) => {
            const target = changeEvent.target;
            walkingCircle.setRadius(Number(target.value));
        });
    });

    // Handle user click, reset the map center and position the circle.
    innerMap.addListener('click', (mapsMouseEvent) => {
        const newCenter = mapsMouseEvent.latLng;
        if (!newCenter) return;
        walkingCircle.setCenter(newCenter);
        centerMarker.position = newCenter;
        innerMap.panTo(newCenter);
    });

    // Handle user dragging the circle, update the center marker position.
    walkingCircle.addListener('center_changed', () => {
        centerMarker.position = walkingCircle.getCenter();
    });
}

void init();
```

### CSS

```css
/* 
 * Optional: Makes the sample page fill the window. 
 */
html,
body {
    height: 100%;
    margin: 0;
    padding: 0;
}

#control-panel {
    display: none; /* Set to 'display: block' after the map loads. */
    background-color: #fff;
    border: 2px solid #fff;
    border-radius: 3px;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
    font-family: 'Roboto', sans-serif;
    font-size: medium;
    margin: 10px;
    padding: 10px;
}
```

### HTML

```html
<html>
    <head>
        <title>Circles</title>

        <link rel="stylesheet" type="text/css" href="./style.css" />
        <script type="module" src="./index.js"></script>
        <script>
            // prettier-ignore
            (g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({
                key: "GOOGLE_MAPS_API_KEY"
            });
        </script>
    </head>
    <body>
        <gmp-map
            center="34.98956821576194, 135.74239981260283"
            zoom="15"
            map-id="DEMO_MAP_ID">
            <div id="control-panel" slot="control-inline-start-block-start">
                <input
                    id="short-walk"
                    type="radio"
                    name="radius"
                    value="400"
                    checked />
                <label for="short-walk">Short Walk (~5 minutes)</label><br />
                <input
                    id="medium-walk"
                    type="radio"
                    name="radius"
                    value="800" />
                <label for="medium-walk">Medium Walk (~15 minutes)</label><br />
                <input id="long-walk" type="radio" name="radius" value="1600" />
                <label for="long-walk">Long Walk (~30 minutes) </label>
            </div>
        </gmp-map>
    </body>
</html>
```
[View example](https://developers.google.com/maps/documentation/javascript/examples/circle-simple.md.txt)

### Try Sample

[JSFiddle.net](https://jsfiddle.net/gh/get/library/pure/googlemaps-samples/js-api-samples/tree/main/dist/samples/circle-simple/jsfiddle)

### Remove a circle

To remove a circle from the map, call the `setMap()` method
passing `null` as the argument.

```javascript
circle.setMap(null);
```

Note that the above method does not delete the circle. It removes
the circle from the map. If instead you wish to delete the circle,
you should remove it from the map, and then set the
circle itself to `null`.

> [!NOTE]
> Removing a circle is similar to removing a polyline. To see the code in action for a polyline: [view example](https://developers.google.com/maps/documentation/javascript/examples/polyline-remove.md.txt).

## User-editable and draggable shapes

Making a shape editable adds handles to the shape, which people can use
to reposition, reshape, and resize the shape directly on the map. You can also
make a shape draggable, so people can move it to a different place on the map.

User-made changes to the object do not persist between sessions. If you
want to save the user's edits, you must capture and store the information
yourself.

### Make a shape editable

Any shape (polylines, polygons, circles, and rectangles) can be set
as user-editable, by setting `editable` to `true` in
the shape's options.

```javascript
var bounds = {
  north: 44.599,
  south: 44.490,
  east: -78.443,
  west: -78.649
};

// Define a rectangle and set its editable property to true.
var rectangle = new google.maps.Rectangle({
  bounds: bounds,
  editable: true
});
```
<iframe src="https://geo-devrel-javascript-samples.web.app/samples/user-editable-shapes/app/dist/" allow="fullscreen; "></iframe>

[View example](https://developers.google.com/maps/documentation/javascript/examples/user-editable-shapes.md.txt)

### Make a shape draggable

By default, a shape drawn on the map will be fixed in position. To allow
users to drag a shape to a different location on the map, set
`draggable` to `true` in the shape options.

```javascript
var redCoords = [
  {lat: 25.774, lng: -80.190},
  {lat: 18.466, lng: -66.118},
  {lat: 32.321, lng: -64.757}
];

// Construct a draggable red triangle with geodesic set to true.
new google.maps.Polygon({
  map: map,
  paths: redCoords,
  strokeColor: '#FF0000',
  strokeOpacity: 0.8,
  strokeWeight: 2,
  fillColor: '#FF0000',
  fillOpacity: 0.35,
  draggable: true,
  geodesic: true
});
```

When enabling dragging on a polygon or polyline, you should also consider
making the polygon or polyline geodesic, by setting its `geodesic`
property to `true`.

A geodesic polygon will retain its true geographic shape when it is moved,
causing the polygon to appear distorted as it is moved north or south in the
Mercator projection. Non-geodesic polygons will always retain their initial
appearance on the screen.

In a geodesic polyline, the segments of the polyline are drawn as the
shortest path between two points on the Earth's surface, assuming the Earth is
a sphere, as opposed to straight lines on the Mercator projection.

For more information on coordinate systems, consult the guide to
[map and tile
coordinates](https://developers.google.com/maps/documentation/javascript/coordinates).

The following map shows two triangles of roughly the same size and
dimensions. The red triangle has its `geodesic` property set to
`true`. Notice how its shape changes as it moves north.
<iframe src="https://geo-devrel-javascript-samples.web.app/samples/polygon-draggable/app/dist/" allow="fullscreen; "></iframe>

[View example](https://developers.google.com/maps/documentation/javascript/examples/polygon-draggable.md.txt)

### Listen to editing events

When a shape is edited, an event is fired upon completion of the edit. These
events are listed below.

| Shape | Events |
|---|---|
| Circle | `radius_changed` `center_changed` |
| Polygon | `insert_at` `remove_at` `set_at` The listener must be set on the polygon's path. If the polygon has multiple paths, a listener must be set on each path. |
| Polyline | `insert_at` `remove_at` `set_at` The listener must be set on the polyline's path. |
| Rectangle | `bounds_changed` |

Some useful code snippets:

```javascript
google.maps.event.addListener(circle, 'radius_changed', function() {
  console.log(circle.getRadius());
});

google.maps.event.addListener(outerPath, 'set_at', function() {
  console.log('Vertex moved on outer path.');
});

google.maps.event.addListener(innerPath, 'insert_at', function() {
  console.log('Vertex removed from inner path.');
});

google.maps.event.addListener(rectangle, 'bounds_changed', function() {
  console.log('Bounds changed.');
});
```

See an example of handling an editing event on a rectangle:
[view example](https://developers.google.com/maps/documentation/javascript/examples/rectangle-event.md.txt).

### Listen to dragging events

When a shape is dragged, events are fired upon start and end of the dragging
action as well as during the dragging. The following events are fired for
polylines, polygons, circles and rectangles.

| Event | Description |
|---|---|
| `dragstart` | Fired when the user starts dragging the shape. |
| `drag` | Fired repeatedly while the user is dragging the shape. |
| `dragend` | Fired when the user stops dragging the shape. |

For more about handling events, see the
[documentation on events](https://developers.google.com/maps/documentation/javascript/events.md.txt).

## Geofences and safe-zone boundaries

Google Maps Platform doesn't provide a standalone Geofencing API. To display
a geofence radius or safe zone on a web map and check whether a live
coordinate is inside that boundary, combine shapes with the
[Geometry library](https://developers.google.com/maps/documentation/javascript/geometry.md.txt)
([`google.maps.GeometryLibrary`](https://developers.google.com/maps/documentation/javascript/reference/library-interfaces.md.txt#GeometryLibrary))
loaded through
[`google.maps.importLibrary("geometry")`](https://developers.google.com/maps/documentation/javascript/reference/top-level.md.txt#google.maps.importLibrary):

- **Circular geofence:** Draw a [`google.maps.Circle`](https://developers.google.com/maps/documentation/javascript/reference/polygon.md.txt#Circle) (or pass a [`google.maps.CircleLiteral`](https://developers.google.com/maps/documentation/javascript/reference/coordinates.md.txt#CircleLiteral)) and test whether the coordinate lies inside the circle using [`google.maps.geometry.poly.containsLocation()`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#poly.containsLocation). If you also need the distance in meters from [`Circle.getCenter()`](https://developers.google.com/maps/documentation/javascript/reference/polygon.md.txt#Circle.getCenter), call [`google.maps.geometry.spherical.computeDistanceBetween()`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#spherical.computeDistanceBetween).
- **Polygonal geofence:** Draw a [`google.maps.Polygon`](https://developers.google.com/maps/documentation/javascript/reference/polygon.md.txt#Polygon) and test whether the coordinate lies inside the polygon using [`google.maps.geometry.poly.containsLocation()`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#poly.containsLocation).
- **3D map polygon:** On a 3D map ([Shapes
  and lines](https://developers.google.com/maps/documentation/javascript/3d/shapes-lines#polygons)), draw a [`google.maps.maps3d.Polygon3DElement`](https://developers.google.com/maps/documentation/javascript/reference/3d-map-draw.md.txt#Polygon3DElement) and pass its [`Polygon3DElement.path`](https://developers.google.com/maps/documentation/javascript/reference/3d-map-draw.md.txt#Polygon3DElement.path) coordinates to [`google.maps.Polygon`](https://developers.google.com/maps/documentation/javascript/reference/polygon.md.txt#Polygon) when calling [`google.maps.geometry.poly.containsLocation()`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#poly.containsLocation).

The following example draws a circular safe zone and a polygonal geofence,
then checks whether a live coordinate is inside each boundary:

```javascript
const {Circle, Polygon} = await google.maps.importLibrary("maps");
const {poly} = await google.maps.importLibrary("geometry");

const livePosition = {lat: 37.424, lng: -122.085};

// 1. Circular geofence (500-meter radius)
const circularGeofence = new Circle({
  map,
  center: {lat: 37.422, lng: -122.084},
  radius: 500,
});
const isInsideCircle = poly.containsLocation(livePosition, circularGeofence);

// 2. Polygonal geofence
const polygonGeofence = new Polygon({
  map,
  paths: [
    {lat: 37.420, lng: -122.088},
    {lat: 37.420, lng: -122.080},
    {lat: 37.426, lng: -122.080},
    {lat: 37.426, lng: -122.088},
  ],
});
const isInsidePolygon = poly.containsLocation(livePosition, polygonGeofence);
```