diff --git a/docs/api-reference/components/map.md b/docs/api-reference/components/map.md index dde7702e..8d57ca37 100644 --- a/docs/api-reference/components/map.md +++ b/docs/api-reference/components/map.md @@ -18,36 +18,25 @@ const App = () => ( ); ``` -## Controlled and Uncontrolled modes +## Controlled and Uncontrolled Props -The map can operate in three different modes: uncontrolled mode, controlled -mode, (both very similar to form-elements in React), and externally -controlled mode. +The props controlling the camera parameters for the map (center, zoom, +heading and tilt) can all be specified via controlled or uncontrolled values. +For example, the center of the map can be specified via either `center` or +`defaultCenter`. This can even be mixed for the different parameters (for +example, only the zoom value is controlled, while others are free). -### Uncontrolled mode - -The simplest mode can be used if there is no need -for much integration of the map with the rest of your application. -In this mode, the map just receives the `initialCameraProps` and allows -full user-control after that. - -In this mode (i.e., as long as `initialCameraProps` is present in the props), -the other camera props will be ignored completely. +As is the case with React form elements, the default-values will only be +applied when the map is first initialized, while the regular parameters will +make sure the map stays synchronized with the value specified. ```tsx -const INITIAL_CAMERA = { - center: {lat: 40.7, lng: -74}, - zoom: 12 -}; - const UncontrolledMap = () => { - return ; + return ; }; ``` -### Controlled mode - -In this mode, the map will always exactly reflect the +When only controlled props are used, the map will always exactly reflect the values specified for the camera parameters. When interactions occur, the new camera parameters will be published with a `cameraChanged` event and the application can use them to update the values passed to the props of the map. @@ -79,7 +68,7 @@ anything not specified in the camera props. ## Props The `MapProps` type extends the [`google.maps.MapOptions` interface] -[gmp-map-options] and includes all possible options available for a Google +[gmp-map-options] and includes all possible options available for a Google Map as props. The most important of these options are also listed below along with the @@ -130,9 +119,6 @@ style-prop is no longer applied. Coordinates for the center of the map. -The Google Maps API Documentation [has some more information on this topic] -[gmp-coordinates]. - #### `zoom`: number The initial resolution at which to display the map. @@ -145,6 +131,9 @@ is approximately: - `15`: Streets - `20`: Buildings +The Google Maps API Documentation [has some more information on this topic]. +[gmp-coordinates]. + #### `heading`: number The heading of the map in degrees, measured clockwise from cardinal direction @@ -162,13 +151,11 @@ The allowed values are restricted depending on the zoom level of the map: - between 10 and 15.5, it is a piecewise linear interpolation ([see here][get-max-tilt] for details) -#### `initialCameraProps`: MapCameraProps +#### `defaultCenter`, `defaultZoom`, `defaultHeading`, `defaultTilt` -The initial state of the camera. This can be specified to leave the map -component in uncontrolled mode. [See above](#uncontrolled-mode) for more -information about the uncontrolled mode. The `MapCameraProps` type is just -an object with the four properties `center`, `zoom`, `heading` and `tilt` as -described above. +The initial state of the camera. This can be used to leave the map +component in uncontrolled mode. When both a default-value and a controlled +value are present for a parameter, the controlled value takes precedence. #### `initialBounds`: [google.maps.LatLngBoundsLiteral][gmp-llb] diff --git a/examples/_template/src/app.tsx b/examples/_template/src/app.tsx index eea4a41a..f8490f60 100644 --- a/examples/_template/src/app.tsx +++ b/examples/_template/src/app.tsx @@ -10,8 +10,8 @@ const API_KEY = const App = () => ( diff --git a/examples/basic-map/src/app.tsx b/examples/basic-map/src/app.tsx index eea4a41a..191c14e4 100644 --- a/examples/basic-map/src/app.tsx +++ b/examples/basic-map/src/app.tsx @@ -10,8 +10,8 @@ const API_KEY = const App = () => ( diff --git a/examples/change-map-styles/src/app.tsx b/examples/change-map-styles/src/app.tsx index 78515cb2..7dd48317 100644 --- a/examples/change-map-styles/src/app.tsx +++ b/examples/change-map-styles/src/app.tsx @@ -99,10 +99,10 @@ const App = () => { return ( diff --git a/examples/deckgl-overlay/src/app.tsx b/examples/deckgl-overlay/src/app.tsx index 30bd99b3..3f2533aa 100644 --- a/examples/deckgl-overlay/src/app.tsx +++ b/examples/deckgl-overlay/src/app.tsx @@ -27,8 +27,8 @@ const App = () => { return ( diff --git a/examples/directions/src/app.tsx b/examples/directions/src/app.tsx index 471979c4..0dc48303 100644 --- a/examples/directions/src/app.tsx +++ b/examples/directions/src/app.tsx @@ -13,7 +13,11 @@ const API_KEY = const App = () => ( - + diff --git a/examples/geometry/src/app.tsx b/examples/geometry/src/app.tsx index ae443bfd..066f1177 100644 --- a/examples/geometry/src/app.tsx +++ b/examples/geometry/src/app.tsx @@ -24,8 +24,8 @@ const App = () => { return ( { return ( + {/* note that we can also use a mix of controlled (zoom) an + uncontrolled (center) properties here */} setZoom(ev.detail.zoom)}> diff --git a/examples/marker-clustering/src/app.tsx b/examples/marker-clustering/src/app.tsx index 1a47bc31..4b11cf53 100644 --- a/examples/marker-clustering/src/app.tsx +++ b/examples/marker-clustering/src/app.tsx @@ -18,8 +18,10 @@ const App = () => ( + defaultCenter={{lat: 43.64, lng: -79.41}} + defaultZoom={10} + gestureHandling={'greedy'} + disableDefaultUI> diff --git a/examples/markers-and-infowindows/src/app.tsx b/examples/markers-and-infowindows/src/app.tsx index db3e5361..3fb43139 100644 --- a/examples/markers-and-infowindows/src/app.tsx +++ b/examples/markers-and-infowindows/src/app.tsx @@ -22,10 +22,10 @@ const App = () => { + disableDefaultUI> {/* simple marker */} ) => { diff --git a/src/components/map/use-map-camera-params.ts b/src/components/map/use-map-camera-params.ts index 7a32db9a..70fec7f0 100644 --- a/src/components/map/use-map-camera-params.ts +++ b/src/components/map/use-map-camera-params.ts @@ -36,10 +36,6 @@ export function useMapCameraParams( useLayoutEffect(() => { if (!map) return; - // when the map was configured with an initialCameraProps or initialBounds, - // we skip all camera updates here - if (mapProps.initialCameraProps || mapProps.initialBounds) return; - const nextCamera: google.maps.CameraOptions = {}; let needsUpdate = false; diff --git a/src/components/map/use-map-instance.ts b/src/components/map/use-map-instance.ts index 64331167..d853c7c3 100644 --- a/src/components/map/use-map-instance.ts +++ b/src/components/map/use-map-instance.ts @@ -1,4 +1,4 @@ -import {Ref, useEffect, useState} from 'react'; +import {Ref, useEffect, useRef, useState} from 'react'; import {MapProps} from '../map'; import {APIProviderContextValue} from '../api-provider'; @@ -23,12 +23,24 @@ export function useMapInstance( const { id, - initialBounds, - initialCameraProps, + defaultBounds, + defaultCenter, + defaultZoom, + defaultHeading, + defaultTilt, ...mapOptions } = props; + // apply default camera props if available and not overwritten by controlled props + if (!mapOptions.center && defaultCenter) mapOptions.center = defaultCenter; + if (!mapOptions.zoom && Number.isFinite(defaultZoom)) + mapOptions.zoom = defaultZoom; + if (!mapOptions.heading && Number.isFinite(defaultHeading)) + mapOptions.heading = defaultHeading; + if (!mapOptions.tilt && Number.isFinite(defaultTilt)) + mapOptions.tilt = defaultTilt; + // create the map instance and register it in the context useEffect( () => { @@ -40,13 +52,11 @@ export function useMapInstance( setMap(newMap); addMapInstance(newMap, id); - if (initialBounds) { - newMap.fitBounds(initialBounds); + if (defaultBounds) { + newMap.fitBounds(defaultBounds); } - if (initialCameraProps) { - newMap.setOptions(initialCameraProps); - } + // FIXME: When the mapId is changed, we need to maintain the current camera params. return () => { if (!container || !apiIsLoaded) return; @@ -60,7 +70,7 @@ export function useMapInstance( }, // some dependencies are ignored in the list below: - // - initialBounds and initialCameraProps will only be used once, and + // - defaultBounds and the default* camera props will only be used once, and // changes should be ignored // - mapOptions has special hooks that take care of updating the options // eslint-disable-next-line react-hooks/exhaustive-deps