Skip to content

Commit

Permalink
feat(advanced-marker): add support for clickable option (#341)
Browse files Browse the repository at this point in the history
  • Loading branch information
usefulthink committed May 6, 2024
1 parent c148aa8 commit ca96e54
Show file tree
Hide file tree
Showing 6 changed files with 306 additions and 153 deletions.
309 changes: 221 additions & 88 deletions docs/api-reference/components/advanced-marker.md
Original file line number Diff line number Diff line change
@@ -1,117 +1,250 @@
# `<AdvancedMarker>` Component

React component to display
a [Google Maps Advanced Marker Element](https://developers.google.com/maps/documentation/javascript/reference/advanced-markers#AdvancedMarkerElement)
instance.
A component to add an [`AdvancedMarkerElement`][gmp-adv-marker]
to a map. By default, an AdvancedMarker will appear as a balloon-shaped,
red maps-pin at the specified position on the map, but the appearance of the
markers can be fully customized.

## Setup
:::info

To use the Advanced Marker View component, it is necessary to add a custom `mapId`
to the map options. To see how this works, check out the following tutorial:
[Use Map IDs](https://developers.google.com/maps/documentation/get-map-id).
The `AdvancedMarker` can only be used on maps using cloud-based map styling
(i.e. the `Map`-component has a [`mapId`][gmp-mapid] specified).

### APIProvider and Map setup to implement the Advanced Marker View component

```tsx
<APIProvider apiKey={loadingOptions.apiKey}>
<Map
zoom={10}
center={{lat, lng}}
mapId={'<Your custom MapId here>'}>

<AdvancedMarker position={{...}} />
</Map>
</APIProvider>
```
:::

## Usage

Advanced Marker Element can either be as a standalone component or be customized with
the [Pin Element component](./pin.md) or be displayed with custom HTML.

### Simple Advanced Marker Element implementation
By default, the marker will be rendered as the default red balloon pin.
This can be customized in two ways: by specifying custom colors, an icon and
such via a [`Pin`](./pin.md) component, or by creating the complete marker with
html/css (images, svg, animations are all supported).

See also: https://developers.google.com/maps/documentation/javascript/adding-a-google-map
For this, the `AdvancedMarker` component optionally accepts child components that
will be rendered instead of the default pin-element on the map, making it
possible to create simple labels and infowindows with it.

```tsx
const App = () => (
<APIProvider apiKey={'Your API key here'}>
<Map
zoom={12}
center={{lat: 53.54992, lng: 10.00678}}
mapId={'<Your custom MapId here>'}>
<AdvancedMarker position={{lat: 53.54992, lng: 10.00678}} />
</Map>
</APIProvider>
);
export default App;
import {AdvancedMarker} from './advanced-marker';

<Map {...mapProps}>
{/* red default marker */}
<AdvancedMarker position={{lat: 29.5, lng: -81.2}} />

{/* customized green marker */}
<AdvancedMarker position={{lat: 29.5, lng: -81.2}}>
<Pin
background={'#0f9d58'}
borderColor={'#006425'}
glyphColor={'#60d98f'}
/>
</AdvancedMarker>

{/* fully customized marker */}
<AdvancedMarker position={{lat: 29.5, lng: -81.2}}>
<img src={markerImage} width={32} height={32} />
</AdvancedMarker>
</Map>;
```

### Advanced Marker Element with Pin Element component implementation
When anything other than a `Pin` component is specified for the marker, a
div element (the "content element") will be created and the children will be
rendered into that content element via a [portal][react-portal]. The `style`
and `className` props can be used to configure the styling of this content
element.

See also: https://developers.google.com/maps/documentation/javascript/advanced-markers/basic-customization
:::tip

When custom html is specified, the marker will be positioned such that the
`position` on the map is at the bottom center of the content-element.
If you need it positioned differently, you can use css-transforms on
the content element. For example, to have the anchor point in the top-left
corner of the marker (the transform can also be applied via a css class and
specified as `className`):

```tsx
const App = () => (
<APIProvider apiKey={'Your API key here'}>
<Map
zoom={12}
center={{lat: 53.54992, lng: 10.00678}}
mapId={'<Your custom MapId here>'}>
<AdvancedMarker position={{lat: 53.54992, lng: 10.00678}}>
<Pin background={'#FBBC04'} glyphColor={'#000'} borderColor={'#000'} />
</AdvancedMarker>
</Map>
</APIProvider>
);
export default App;
<AdvancedMarker position={...} style={{transform: 'translate(50%, 100%)'}}>
...
</AdvancedMarker>
```

### Advanced Marker Element component with custom HTML implementation
:::

## Props

The `AdvancedMarker` component supports most of the options in
[`google.maps.marker.AdvancedMarkerElementOptions`][gmp-adv-marker-opts]
as props, as well as a couple of others that are specific to React.

### Required

There are no strictly required props for the AdvancedMarker component,
but – for obvious reasons – the position has to be set for the marker to be
shown on the map.

### Content Props

#### `className`: string

A className to be added to the content-element. Since the content-element
isn't created when using the default-pin, this option is only available when
using custom HTML markers.

#### `style`: [CSSProperties][react-dev-styling]

Additional style-rules to apply to the content-element. Since the
content-element isn't created when using the default-pin, this option is
only available when using custom HTML markers.

#### `title`: string

The title of the marker. If provided, an accessibility text (e.g. for use
with screen readers) will be added to the AdvancedMarkerElement with the
provided value.

### Positioning Props

#### `position`: [google.maps.LatLngLiteral][gmp-ll] | [google.maps.LatLngAltitudeLiteral][gmp-lla]

The position of the marker. For maps with tilt enabled, an `AdvancedMarker`
can also be placed at an altitude using the `{lat: number, lng: number,
altitude: number}` format.

#### `zIndex`: number

All markers are displayed on the map in order of their zIndex, with higher
values in front of lower values.

By default, `AdvancedMarker`s are displayed according to their vertical
position on screen, with lower AdvancedMarkerElements appearing in front of
AdvancedMarkerElements farther up the screen.

:::note

The `zIndex` is also used to help determine relative
priority between multiple markers when using collision
behavior `CollisionBehavior.OPTIONAL_AND_HIDES_LOWER_PRIORITY`.
A higher `zIndex` value indicates higher priority.

:::

#### `collisionBehavior`: CollisionBehavior

Defines how the marker behaves when it collides with another marker or with
the basemap labels on a vector map. Specified as one of the
`CollisionBehaviour` constants.

See also: https://developers.google.com/maps/documentation/javascript/advanced-markers/html-markers
Collision between multiple markers works on both raster and vector
maps; however, hiding labels and default-markers of the base map to make
room for the markers will only work on vector maps.

:::note

You should always import the `CollisionBehavior` enum from the
`@vis.gl/react-google-maps` package instead of using the
`google.maps.CollisionBehavior` constants. This will help avoid problems
with using the constants before the maps API has finished loading.

```tsx
const App = () => (
<APIProvider apiKey={'Your API key here'}>
<Map
zoom={12}
center={{lat: 53.54992, lng: 10.00678}}
mapId={'<Your custom MapId here>'}>
<AdvancedMarker
className={customMarker}
position={{lat: 53.54992, lng: 10.00678}}>
<h2>I am so customized</h2>
<p>That is pretty awesome!</p>
</AdvancedMarker>
</Map>
</APIProvider>
);
export default App;
import {AdvancedMarker, CollisionBehavior} from '@vis.gl/react-google-maps';

// ...

<AdvancedMarker
collisionBehavior={CollisionBehavior.REQUIRED_AND_HIDES_OPTIONAL}>
...
</AdvancedMarker>;
```

To apply style to the custom HTML marker, it is possible to add a class via the className property which will add
styling to the Advanced Marker Element container.
:::

See the documentation on [Marker Collision Management][gmp-collisions]
for more information.

### Other Props

#### `clickable`: boolean

Controls if the marker should be clickable. If true, the
marker will be clickable and will be interactive for accessibility purposes
(e.g., allowing keyboard navigation via arrow keys).

By default, this will automatically be set to true when the `onClick` prop
is specified.

#### `draggable`: boolean

Controls if the marker can be repositioned by dragging.

By default, this will be set to true if any of the corresponding
event-handlers (`onDragStart`, `onDrag`, `onDragEnd`) are specified.

:::note

Dragging is only available in 2D. Markers that have an altitude
specified in the position can't be dragged.

:::

### Events

#### `onClick`: (e: [google.maps.marker.AdvancedMarkerClickEvent][gmp-adv-marker-click-ev]) => void

This event is fired when the marker is clicked.

#### `onDragStart`: (e: [google.maps.MapMouseEvent][gmp-map-mouse-ev]) => void

This event is fired when the user starts dragging the marker.

#### `onDrag`: (e: [google.maps.MapMouseEvent][gmp-map-mouse-ev]) => void

This event is repeatedly fired while the user drags the marker.

#### `onDragEnd`: (e: [google.maps.MapMouseEvent][gmp-map-mouse-ev]) => void

This event is fired when the user stops dragging the marker.

## Context

## Hooks

### Draggable Advanced Marker Element component implementation
### `useAdvancedMarkerRef()`

see
also: https://developers.google.com/maps/documentation/javascript/advanced-markers/accessible-markers#make_a_marker_draggable
A hook that can be used to simplify the connection between a marker and an
infowindow. Returns an array containing both a `RefCallback` that can be passed
to the `ref`-prop of the `AdvancedMarker` and the value of the ref as state
variable to be passed to the anchor prop of the `InfoWindow`.

```tsx
const App = () => (
<APIProvider apiKey={'Your API key here'}>
<Map
zoom={12}
center={{lat: 53.54992, lng: 10.00678}}
mapId={'<Your custom MapId here>'}>
<AdvancedMarker
position={{lat: 53.58675649147477, lng: 10.045572975464376}}
draggable={true}></AdvancedMarker>
</Map>
</APIProvider>
);
export default App;
import {
AdvancedMarker,
InfoWindow,
useAdvancedMarkerRef
} from '@vis.gl/react-google-maps';

const MarkerWithInfoWindow = props => {
const [markerRef, marker] = useAdvancedMarkerRef();

return (
<>
<AdvancedMarker position={props.position} ref={markerRef} />
<InfoWindow anchor={marker}>Infowindow Content</InfoWindow>
</>
);
};
```

To see an Advanced Marker Element on the map, the `position` property needs to be set.
## Source

[`./src/components/advanced-marker.tsx`][adv-marker-src]

[gmp-adv-marker]: https://developers.google.com/maps/documentation/javascript/reference/advanced-markers#AdvancedMarkerElement
[gmp-adv-marker-opts]: https://developers.google.com/maps/documentation/javascript/reference/advanced-markers#AdvancedMarkerElementOptions
[gmp-mapid]: https://developers.google.com/maps/documentation/get-map-id
[gmp-ll]: https://developers.google.com/maps/documentation/javascript/reference/coordinates#LatLngLiteral
[gmp-lla]: https://developers.google.com/maps/documentation/javascript/reference/coordinates#LatLngAltitudeLiteral
[gmp-collisions]: https://developers.google.com/maps/documentation/javascript/examples/marker-collision-management
[gmp-adv-marker-click-ev]: https://developers.google.com/maps/documentation/javascript/reference/advanced-markers#AdvancedMarkerClickEvent
[gmp-map-mouse-ev]: https://developers.google.com/maps/documentation/javascript/reference/map#MapMouseEvent
[adv-marker-src]: https://github.com/visgl/react-google-maps/tree/main/src/components/advanced-marker.tsx
[react-portal]: https://react.dev/reference/react-dom/createPortal
[react-dev-styling]: https://react.dev/reference/react-dom/components/common#applying-css-styles
2 changes: 1 addition & 1 deletion docs/api-reference/components/map.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ const MapWithEventHandler = props => {
```

See [the table below](#mapping-of-google-maps-event-names-to-react-props)
for the full list of props and corresponding prop names.
for the full list of events and corresponding prop names.

All event callbacks receive a single argument of type `MapEvent` with the
following properties and methods:
Expand Down
36 changes: 9 additions & 27 deletions docs/api-reference/components/pin.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,22 @@
# `<Pin>` Component

React component to display
a [Pin Element](https://developers.google.com/maps/documentation/javascript/reference/advanced-markers#PinElement)
instance.
The Pin Element Component can only be used together with the Advanced Marker. To see how to implement an Advanced
Marker, please check: [Advanced Marker](advanced-marker.md).
The `Pin` component can be used to customize the appearance of an
[`AdvancedMarker`](./advanced-marker.md) component.

## Usage

The Pin Element component needs to be wrapped inside an Advanced Marker Element component.

```tsx
const App = () => (
<APIProvider apiKey={'Your API key here'}>
<Map
zoom={12}
center={{lat: 53.54992, lng: 10.00678}}
mapId={'<Your custom MapId here>'}>
<AdvancedMarker position={{lat: 53.54992, lng: 10.00678}}>
<Pin background={'#FBBC04'} glyphColor={'#000'} borderColor={'#000'} />
</AdvancedMarker>
</Map>
</APIProvider>
const CustomizedMarker = () => (
<AdvancedMarker position={{lat: 53.54992, lng: 10.00678}}>
<Pin background={'#FBBC04'} glyphColor={'#000'} borderColor={'#000'} />
</AdvancedMarker>
);
export default App;
```

## Props

The Pin Props type mirrors
the [google.maps.PinElementOptions interface](https://developers.google.com/maps/documentation/javascript/reference/advanced-markers#PinElementOptions)
The `PinProps` type mirrors the [`google.maps.PinElementOptions` interface][gmp-pin-element-options]
and includes all possible options available for a Pin Element instance.

```tsx
type PinProps = google.maps.marker.PinElementOptions;
```

To see a Pin on the Map, it has to be wrapped inside an Advanced Marker Element
and the `position` of the marker needs to be set.
[gmp-pin-element]: https://developers.google.com/maps/documentation/javascript/reference/advanced-markers#PinElement
[gmp-pin-element-options]: https://developers.google.com/maps/documentation/javascript/reference/advanced-markers#PinElementOptions
Loading

0 comments on commit ca96e54

Please sign in to comment.