Giter Club home page Giter Club logo

google-maps-react's Introduction

Fullstack React Google Maps Tutorial

Google Map React Component Tutorial Dolpins

A declarative Google Map React component using React, lazy-loading dependencies, current-location finder and a test-driven approach by the Fullstack React team.

See the demo and accompanying blog post.

Quickstart

First, install the library:

npm install --save google-maps-react

Automatically Lazy-loading Google API

The library includes a helper to wrap around the Google maps API. The GoogleApiWrapper Higher-Order component accepts a configuration object which must include an apiKey. See lib/GoogleApi.js for all options it accepts.

import {GoogleApiWrapper} from 'google-maps-react';

// ...

export class MapContainer extends React.Component {}

export default GoogleApiWrapper({
  apiKey: (YOUR_GOOGLE_API_KEY_GOES_HERE)
})(MapContainer)

Alternatively, the GoogleApiWrapper Higher-Order component can be configured by passing a function that will be called with whe wrapped component's props and should returned the configuration object.

export default GoogleApiWrapper(
  (props) => ({
    apiKey: props.apiKey,
    language: props.language,
  }
))(MapContainer)

If you want to add a loading container other than the default loading container, simply pass it in the HOC, like so:

const LoadingContainer = (props) => (
  <div>Fancy loading container!</div>
)

export default GoogleApiWrapper({
  apiKey: (YOUR_GOOGLE_API_KEY_GOES_HERE),
  LoadingContainer: LoadingContainer
})(MapContainer)

Sample Usage With Lazy-loading Google API:

import {Map, InfoWindow, Marker, GoogleApiWrapper} from 'google-maps-react';

export class MapContainer extends Component {
  render() {
    return (
      <Map google={this.props.google} zoom={14}>

        <Marker onClick={this.onMarkerClick}
                name={'Current location'} />

        <InfoWindow onClose={this.onInfoWindowClose}>
            <div>
              <h1>{this.state.selectedPlace.name}</h1>
            </div>
        </InfoWindow>
      </Map>
    );
  }
}

export default GoogleApiWrapper({
  apiKey: (YOUR_GOOGLE_API_KEY_GOES_HERE)
})(MapContainer)

Note: Marker and InfoWindow components are disscussed below.

Examples

Check out the example site at: http://fullstackreact.github.io/google-maps-react

Additional Map Props

The Map component takes a number of optional props.

Zoom: (Shown Above) takes a number with the higher value representing a tighter focus on the map's center.

Style: Takes CSS style object - commonly width and height.

const style = {
  width: '100%',
  height: '100%'
}

Container Style: Takes CSS style object - optional, commonly when you want to change from the default of position "absolute".

const containerStyle = {
  position: 'relative',  
  width: '100%',
  height: '100%'
}
    <Map
          containerStyle={containerStyle}

initialCenter: Takes an object containing latitude and longitude coordinates. Sets the maps center upon loading.

    <Map
          google={this.props.google}
          style={style}
          initialCenter={{
            lat: 40.854885,
            lng: -88.081807
          }}
          zoom={15}
          onClick={this.onMapClicked}
        >

center: Takes an object containing latitude and longitude coordinates. Use this if you want to re-render the map after the initial render.

    <Map
          google={this.props.google}
          style={style}
          center={{
            lat: 40.854885,
            lng: -88.081807
          }}
          zoom={15}
          onClick={this.onMapClicked}
        >

bounds: Takes a google.maps.LatLngBounds() object to adjust the center and zoom of the map.

var points = [
    { lat: 42.02, lng: -77.01 },
    { lat: 42.03, lng: -77.02 },
    { lat: 41.03, lng: -77.04 },
    { lat: 42.05, lng: -77.02 }
]
var bounds = new this.props.google.maps.LatLngBounds();
for (var i = 0; i < points.length; i++) {
  bounds.extend(points[i]);
}
return (
    <Map
        google={this.props.google}
        initialCenter={{
            lat: 42.39,
            lng: -72.52
        }}
        bounds={bounds}>
    </Map>
);

The following props are boolean values for map behavior: scrollwheel, draggable, keyboardShortcuts, disableDoubleClickZoom

The following props are boolean values for presence of controls on the map: zoomControl, mapTypeControl, scaleControl, streetViewControl, panControl, rotateControl, fullscreenControl

The following props are object values for control options such as placement of controls on the map: zoomControlOptions, mapTypeControlOptions, streetViewControlOptions See Google Maps Controls for more information.

It also takes event handlers described below:

Events

The <Map /> component handles events out of the box. All event handlers are optional.

onReady

When the <Map /> instance has been loaded and is ready on the page, it will call the onReady prop, if given. The onReady prop is useful for fetching places or using the autocomplete API for places.

fetchPlaces(mapProps, map) {
  const {google} = mapProps;
  const service = new google.maps.places.PlacesService(map);
  // ...
}

render() {
  return (
    <Map google={this.props.google}
      onReady={this.fetchPlaces}
      visible={false}>
        <Listing places={this.state.places} />
    </Map>
  )
}

onClick

To listen for clicks on the <Map /> component, pass the onClick prop:

mapClicked(mapProps, map, clickEvent) {
  // ...
}

render() {
  return (
    <Map google={this.props.google}
      onClick={this.mapClicked} />
  )
}

onDragend

When our user changes the map center by dragging the Map around, we can get a callback after the event is fired with the onDragend prop:

centerMoved(mapProps, map) {
  // ...
}

render() {
  return (
    <Map google={this.props.google}
      onDragend={this.centerMoved} />
  )
}

The <Map /> component also listens to onRecenter, onBounds_changed, onCenter_changed, onDblclick, onDragstart, onHeading_change, onIdle, onMaptypeid_changed, onMousemove, onMouseout, onMouseover, onProjection_changed, onResize, onRightclick, onTilesloaded, onTilt_changed, and onZoom_changed events. See Google Maps Events for more information.

Visibility

You can control the visibility of the map by using the visible prop. This is useful for situations when you want to use the Google Maps API without a map. The <Map /> component will load like normal. See the Google places demo

For example:

<Map google={this.props.google}
    visible={false}>
  <Listing places={this.state.places} />
</Map>

Subcomponents

The <Map /> api includes subcomponents intended on being used as children of the Map component. Any child can be used within the Map component and will receive the three props (as children):

  • map - the Google instance of the map
  • google - a reference to the window.google object
  • mapCenter - the google.maps.LatLng() object referring to the center of the map instance

Marker

To place a marker on the Map, include it as a child of the <Map /> component.

<Map google={this.props.google}
    style={{width: '100%', height: '100%', position: 'relative'}}
    className={'map'}
    zoom={14}>
  <Marker
    title={'The marker`s title will appear as a tooltip.'}
    name={'SOMA'}
    position={{lat: 37.778519, lng: -122.405640}} />
  <Marker
    name={'Dolores park'}
    position={{lat: 37.759703, lng: -122.428093}} />
  <Marker />
  <Marker
    name={'Your position'}
    position={{lat: 37.762391, lng: -122.439192}}
    icon={{
      url: "/path/to/custom_icon.png",
      anchor: new google.maps.Point(32,32),
      scaledSize: new google.maps.Size(64,64)
    }} />
</Map>

The <Marker /> component accepts a position prop that defines the location for the position on the map. It can be either a raw object or a google.maps.LatLng() instance.

If no position is passed in the props, the marker will default to the current position of the map, i.e. the mapCenter prop.

You can also pass any other props you want with the <Marker />. It will be passed back through marker events.

The marker component can also accept a child InfoMarker component for situations where there is only 1 marker and 1 infowindow.

   moveMarker(props, marker, e) {
        console.log(e.latLng.lat(), e.latLng.lng()) // get the new coordinates after drag end
    }
<Marker
  title="Location"
  id={1}
  position={markerCenter}
  draggable={true}
  onDragend={this.moveMarker.bind(this)}
  >
  <InfoWindow
    visible={showInfoWindow}
    style={styles.infoWindow}
    >
      <div className={classes.infoWindow}>
        <p>Click on the map or drag the marker to select location where the incident occurred</p>
      </div>
  </InfoWindow>
</Marker>

Events

The <Marker /> component listens for events, similar to the <Map /> component.

onClick

You can listen for an onClick event with the (appropriately named) onClick prop.

onMarkerClick(props, marker, e) {
  // ..
}

render() {
  return (
    <Map google={this.props.google}>
      <Marker onClick={this.onMarkerClick}
          name={'Current location'} />
    </Map>
  )
}

mouseover

You can also pass a callback when the user mouses over a <Marker /> instance by passing the onMouseover callback:

onMouseoverMarker(props, marker, e) {
  // ..
}

render() {
  return (
    <Map google={this.props.google}>
      <Marker onMouseover={this.onMouseoverMarker}
          name={'Current location'} />
    </Map>
  )
}

Polygon

To place a polygon on the Map, set <Polygon /> as child of Map component.

render() {
  const triangleCoords = [
    {lat: 25.774, lng: -80.190},
    {lat: 18.466, lng: -66.118},
    {lat: 32.321, lng: -64.757},
    {lat: 25.774, lng: -80.190}
  ];

  return(
    <Map google={this.props.google}
        style={{width: '100%', height: '100%', position: 'relative'}}
        className={'map'}
        zoom={14}>
        <Polygon
          paths={triangleCoords}
          strokeColor="#0000FF"
          strokeOpacity={0.8}
          strokeWeight={2}
          fillColor="#0000FF"
          fillOpacity={0.35} />
    </Map>
  )
}

Events

The <Polygon /> component listens to onClick, onMouseover and onMouseout events.

Polyline

To place a polyline on the Map, set <Polyline /> as child of Map component.

render() {
  const triangleCoords = [
    {lat: 25.774, lng: -80.190},
    {lat: 18.466, lng: -66.118},
    {lat: 32.321, lng: -64.757},
    {lat: 25.774, lng: -80.190}
  ];

  return(
    <Map google={this.props.google}
        style={{width: '100%', height: '100%', position: 'relative'}}
        className={'map'}
        zoom={14}>
        <Polyline
          path={triangleCoords}
          strokeColor="#0000FF"
          strokeOpacity={0.8}
          strokeWeight={2} />
    </Map>
  )
}

Events

The <Polyline /> component listens to onClick, onMouseover and onMouseout events.

InfoWindow

The <InfoWindow /> component included in this library is gives us the ability to pop up a "more info" window on our Google map.

The visibility of the <InfoWindow /> component is controlled by a visible prop. The visible prop is a boolean (PropTypes.bool) that shows the <InfoWindow /> when true and hides it when false.

There are two ways how to control a position of the <InfoWindow /> component. You can use a position prop or connect the <InfoWindow /> component directly to an existing <Marker /> component by using a marker prop.

//note: code formatted for ES6 here
export class MapContainer extends Component {
  state = {
    showingInfoWindow: false,
    activeMarker: {},
    selectedPlace: {},
  };

  onMarkerClick = (props, marker, e) =>
    this.setState({
      selectedPlace: props,
      activeMarker: marker,
      showingInfoWindow: true
    });

  onMapClicked = (props) => {
    if (this.state.showingInfoWindow) {
      this.setState({
        showingInfoWindow: false,
        activeMarker: null
      })
    }
  };

  render() {
    return (
      <Map google={this.props.google}
          onClick={this.onMapClicked}>
        <Marker onClick={this.onMarkerClick}
                name={'Current location'} />

        <InfoWindow
          marker={this.state.activeMarker}
          visible={this.state.showingInfoWindow}>
            <div>
              <h1>{this.state.selectedPlace.name}</h1>
            </div>
        </InfoWindow>
      </Map>
    )
  }
}

Events

The <InfoWindow /> throws events when it's showing/hiding. Every event is optional and can accept a handler to be called when the event is fired.

<InfoWindow
  onOpen={this.windowHasOpened}
  onClose={this.windowHasClosed}
  visible={this.state.showingInfoWindow}>
    <div>
      <h1>{this.state.selectedPlace.name}</h1>
    </div>
</InfoWindow>

onClose

The onClose event is fired when the <InfoWindow /> has been closed. It's useful for changing state in the parent component to keep track of the state of the <InfoWindow />.

onOpen

The onOpen event is fired when the window has been mounted in the Google map instance. It's useful for keeping track of the state of the <InfoWindow /> from within the parent component.

Circle

A red slightly transparent circle on a Google Map.  The map is centered around an area in Sao Paulo, Brazil and there is a peculiar lake on the map that is shaped like a man.

To place a circle on the Map, set <Circle /> as child of Map component.

render() {
  const coords = { lat: -21.805149, lng: -49.0921657 };

  return (
    <Map
      initialCenter={coords}
      google={this.props.google}
      style={{width: 500, height: 500, position: 'relative'}}
      zoom={14}
    >
      <Circle
        radius={1200}
        center={coords}
        onMouseover={() => console.log('mouseover')}
        onClick={() => console.log('click')}
        onMouseout={() => console.log('mouseout')}
        strokeColor='transparent'
        strokeOpacity={0}
        strokeWeight={5}
        fillColor='#FF0000'
        fillOpacity={0.2}
      />
    </Map>
  );
}

Events

The <Circle /> component listens to onClick, onMouseover and onMouseout events.

The GoogleApiWrapper automatically passes the google instance loaded when the component mounts (and will only load it once).

Custom Map Style

To set your own custom map style, import your custom map style in JSON format.

const mapStyle = [
  {
    featureType: 'landscape.man_made',
    elementType: 'geometry.fill',
    stylers: [
      {
        color: '#dceafa'
      }
    ]
  },
  ]

 _mapLoaded(mapProps, map) {
    map.setOptions({
       styles: mapStyle
    })
 }

render() {
  return (
    <Map
      style={style}
      google={this.props.google}
      zoom={this.state.zoom}
      initialCenter={this.state.center}
      onReady={(mapProps, map) => this._mapLoaded(mapProps, map)}
    >
      ...
    </Map>
   );
 }
      

Manually loading the Google API

If you prefer not to use the automatic loading option, you can also pass the window.google instance as a prop to your <Map /> component.

<Map google={window.google} />

Issues?

If you have some issues, please make an issue on the issues tab and try to include an example. We've had success with https://codesandbox.io

An example template might look like: https://codesandbox.io/s/rzwrk2854

Contributing

git clone https://github.com/fullstackreact/google-maps-react.git
cd google-maps-react
npm install
make dev

The Google Map React component library uses React and the Google API to give easy access to the Google Maps library.


Fullstack React Book

Fullstack React Book

This Google Map React component library was built alongside the blog post How to Write a Google Maps React Component.

This repo was written and is maintained by the Fullstack React team. In the book we cover many more projects like this. We walk through each line of code, explain why it's there and how it works.

This app is only one of several apps we have in the book. If you're looking to learn React, there's no faster way than by spending a few hours with the Fullstack React book.

License

MIT

google-maps-react's People

Contributors

40818419 avatar adrienlina avatar americool avatar andrewgouin avatar artokun avatar auser avatar austinwillis avatar awulder avatar basantech89 avatar bevali avatar blainegarrett avatar chrissargent avatar dmeenhuis avatar garno avatar gburgett avatar hugofqueiros avatar jackpilowsky avatar jashmenn avatar lepirlouit avatar manuszep avatar martinerko avatar nickfoden avatar peterlau avatar rangoo94 avatar richardnias avatar senbenito avatar simondell avatar sonaye avatar talymo avatar zomars avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

google-maps-react's Issues

Bug: Boolean Props set to false are not passed to the mapConfig

If you set a boolean prop to false, it gets deleted on Line 155/156:

if (!mapConfig[key]) { 
    delete mapConfig[key]; 
} 

https://github.com/fullstackreact/google-maps-react/blob/master/src/index.js#L155

This would be fine if the defaults for these options were always false, but a lot of the UI options (such as draggable) default to true. So thereโ€™s pretty much no way to set them to false and actually have the option get passed to the map upon instantiation.

I can submit a PR for thisโ€” itโ€™s a pretty simple fix (mapConfig[key] == null). Just wanted to flag it as a bug first.

Thanks!

How to import GoogleApiComponent?

Hi there,
I've just started with React and am reading through the blog post where this package is used.

The article says we can simply install this package and then use the GoogleApiComponent in our Map Container. But none of the code snippets in the article or in this package show how this function is actually imported.

This is what I am trying:

import {GoogleApiComponent} from 'google-maps-react'

// [...] container class "MapContainer" declared here

export default GoogleApiComponent({
  apikey: 'blabla'
})(MapContainer)

This container is then imported in my main app like this:

import MapContainer from './containers/MapContainer'

// [...]

But the browser console keeps complaining with
Uncaught TypeError: (0 , _googleMapsReact.GoogleApiComponent) is not a function, pointing at the line where I export the GoogleApiComponent.

I'm sure I am importing that function wrong, but it's not explained anywhere?

Maps config : streetViewControl can't be disabled

Hi, I would like to disable streetViewControl, but it is not possible because mapConfig is cleaned of falsy values.

# node_modules/google-maps-react/dist/index.js: line 216
            var mapConfig = Object.assign({}, {
              mapTypeId: mapTypeIds[mapTypeFromProps],
              center: center,
              zoom: _this4.props.zoom,
              maxZoom: _this4.props.maxZoom,
              minZoom: _this4.props.maxZoom,
              clickableIcons: _this4.props.clickableIcons,
              disableDefaultUI: _this4.props.disableDefaultUI,
              zoomControl: _this4.props.zoomControl,
              mapTypeControl: _this4.props.mapTypeControl,
              scaleControl: _this4.props.scaleControl,
              streetViewControl: _this4.props.streetViewControl,
              panControl: _this4.props.panControl,
              rotateControl: _this4.props.rotateControl,
              scrollwheel: _this4.props.scrollwheel,
              draggable: _this4.props.draggable,
              keyboardShortcuts: _this4.props.keyboardShortcuts,
              disableDoubleClickZoom: _this4.props.disableDoubleClickZoom,
              noClear: _this4.props.noClear,
              styles: _this4.props.styles
            });

            Object.keys(mapConfig).forEach(function (key) {
              if (!mapConfig[key]) {
                delete mapConfig[key];
              }
            });

Could you update the cleaner with typeof mapConfig[key] === 'undefined' ?
Many thx

Custom Marker ie: AirBnB Style

I'd like to create a custom Marker that would display some information instead of the default red marker and on click it would have some additional information about the object defined by the marker.

styling is overwritten from the javascript

I am not sure how you managed to apply the styles in the yelp clone demo.

The JS keeps applying 100% to width and height and position: absolute every time a Map is rendered.

How to have groups of markers as a component?

I have a few collections of markers that each have their own life-cycles, states and stores, independent of other groups or the map itself. I feel this could be easily managed if I could make a parent component for each type of marker, but not sure how or even if it's the best way.

Does anyone have any thoughts on this?

Cheers

Where to Pass API Key?

Before I begin, please forgive me as I'm relatively new, but...

Where does one pass the API key when using this repository? I've poured over all of the the documentation both here and on Full Stack React and see nothing regarding where to actually pass one's Google Maps API Key.

So far, the only conclusion I've come to is on line 32 of GoogleApi.js in the node modules folder where the default argument of opts.hasOwnProperty() is 'apikey'.

If anyone could tell me if I'm close or totally wrong and why I'd be most grateful. Thanks!

import component with error of window is not defined

I am going to import the the component which cause the following errors:

[2] [dev:server]
[2] [dev:server] /Users/imink/workspace/AlwaysAround/aa_admin/node_modules/google-maps-react/dist/lib/ScriptCache.js:5
[2]         factory(exports);
[2]         ^
[2] [dev:server] ReferenceError: window is not defined
[2]     at /Users/imink/workspace/AlwaysAround/aa_admin/node_modules/google-maps-react/dist/lib/ScriptCache.js:20:9
[2]     at Object.defineProperty.value (/Users/imink/workspace/AlwaysAround/aa_admin/node_modules/google-maps-react/dist/lib/ScriptCache.js:5:9)
[2]     at Object.<anonymous> (/Users/imink/workspace/AlwaysAround/aa_admin/node_modules/google-maps-react/dist/lib/ScriptCache.js:13:3)
[2]     at Module._compile (module.js:570:32)
[2]     at Object.Module._extensions..js (module.js:579:10)
[2]     at Module.load (module.js:487:32)
[2]     at tryModuleLoad (module.js:446:12)
[2]     at Function.Module._load (module.js:438:3)
[2]     at Module.require (module.js:497:17)
[2]     at require (internal/module.js:20:19)

My custom component is:

import React, { PropTypes as T } from 'react'
import Map, {GoogleApiWrapper, Marker} from 'google-maps-react'


let moved = false;

export class MapComp extends React.Component {


  render() {
    if (!this.props.loaded) {
      return <div>Loading...</div>
    }
    return (
      <div>Map will go here</div>
    )
  }
}

export default GoogleApiWrapper({
  apiKey: "my_own_key"
})(MapComp)

Any thoughts?

Wrap GoogleApiWrapper with react-redux's connect

Hello,

How would i wrap the GoogleApiWrapper with react-redux's connect?

I would imagine I have to have wrap export GoogleApiWrapper with the connect's mapStateToProps and mapDispatchToProps. Like so:

export default GoogleApiWrapper({
  apiKey: __APIKEY___
}, mapStateToProps, mapDispatchToProps)(Container)

But it is not working. Do I have to change how the GoogleApiWrapper's exports? Anyone can point me to the right direction? @auser

Thanks!

How do I use mapCenter?

I'm having a terrible time getting my map to center, and I am assuming that I have misunderstood and this is not how the mapCenter prop is meant to be used. Can anybody point me in the right direction here?

import React, { Component } from 'react'
import { observer } from 'mobx-react'
import style from './Home.styl'
import axios from 'axios'

// import _ from '../../stores/_Store'
// import _ from '../../stores/_Store'
// import _ from '../../stores/_Store'

import Map, { Marker } from 'google-maps-react'

@observer class Home extends Component {
  constructor(props) {
    super(props)
    this.state = {}
  }

  componentWillMount() {}
  componentDidMount() {}
  componentWillUpdate() {}
  componentDidUpdate() {}

  render() {
    return(
      <div className="Home">
        <div id="googleMap">
          <Map google={window.google} mapCenter={{lat: 32.4331976, lng: -97.7828788}}>
            <Marker
              name={'Place One'}
              position={{lat: 32.4331976, lng: -97.7828788}}
            />
          </Map>
        </div>
      </div>
    )
  }
}

export default Home

npm install breaks down

Hi, great repo! Just not sure why its not allowing me to npm install?

Any thought? I cloned the repo on my machine with node and npm installed as well as webpack
error

Dynamically updating marker icon svg fill color

Hi,

I'm injecting some svg code inline to the icon prop on the Marker component. When I click it I want to highlight the marker by changing the fill color on the 's inside the . In the browser I can see that the component's icon svg code is updating, but visually it stays the same. Any ideas why?

Here's some of the code: (and yes, i'm updating the state on click, so it re-renders the component).

<Marker
    onClick={this.onMarkerClick.bind(this, item)}
    icon={`data:image/svg+xml;utf-8, <svg width="50" height="50" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><circle fill="${fillVariable}" opacity="0.25" cx="50%" cy="50%" r="${radiusVariable}"/></svg>`}
/>

Map not rendering

So my map isn't rendering, it displays the "Loading page.." dialogue until all the functions are completed then the words vanish and no map shows up. In the console, it does show that my loadMap() is running and at the end it returns the this.map object...
This is my code, any insight would be greatly appreciated!

import React, { PropTypes as T } from 'react'
import classnames from 'classnames'
import {GoogleApiWrapper, Marker} from 'google-maps-react'
import AppBar from './app-bar';
import GOOGLEMAPSAPIKEY from './GOOGLEMAPSAPIKEY.js';
import ReactDOM from 'react-dom';

class Map extends React.Component {
  componentDidUpdate(prevProps, prevState) {
    if (prevProps.google !== this.props.google) {
      this.loadMap();
    }
  }
  loadMap() {
    console.log('loading map')
    if (this.props && this.props.google) {
      const { google } = this.props;
      const maps = google.maps;
      const mapRef = this.refs.map;
      console.log(mapRef);
      const node = ReactDOM.findDOMNode(mapRef);
      let crd;
      const position = navigator.geolocation.getCurrentPosition((pos) => {
        const zoom = 16;
        crd = pos.coords;
        console.log(`Latitude : ${crd.latitude}`);
        console.log(`Longitude: ${crd.longitude}`);
        const center = new maps.LatLng(crd.latitude, crd.longitude)
        const mapConfig = Object.assign({}, {
          center: center,
          zoom: zoom
        })
        this.map = new maps.Map(node, mapConfig);
        console.log('this.map::', this.map);
        return this.map
      })
    }
  }
  render() {
    return (
      <div ref='map'>
        Loading map..
      </div>
    )
  }
}

export class MapComponent extends React.Component {
  render() {
    const style = {
      width: '100vw',
      height: '100vh'
    }
    return (
      <div ref="map" style={style}>
        <h1>Explore</h1>
        <Map google={this.props.google} />
      </div>
    );
  }
}

export default GoogleApiWrapper({ apiKey: GOOGLEMAPSAPIKEY })(MapComponent);

npm module status

@auser Per - #59, I'm trying to look into why the Marker component is not accessible and we need the workaround discussed at the end of that issue. I'm trying to build my cloned fork and am unclear exactly what the steps you used to publish this on npm.

When I try to build from webpack I get the following error looking for a dist:

ERROR in ./examples/Container.js
Module not found: Error: Cannot resolve 'file' or 'directory' ../dist in /Users/abe/Desktop/google-maps-react/examples
 @ ./examples/Container.js 32:21-39

I'm generally just looking for some insight, but am eager to help out.

Google Places wrong results location

I cannot figure this out...

The results coming back from Google Places search is always in California, but the location I am giving it is in Texas.

37.774929, -122.41941600000001

Anybody now how to fix this?

const google = window.google
const service = new google.maps.places.PlacesService(map)
const location = new google.maps.LatLng(center.lat(), center.lng())
const request = {
    location,
    radius: '500',
    type: ['food']
}

 service.nearbySearch(request, (results, status, pagination) => {
  if (status == google.maps.places.PlacesServiceStatus.OK) {

    this.setState({
      places: results
    })
  }
})

ref: https://github.com/fullstackreact/google-maps-react/blob/master/examples/components/places.js

onBoundsChanged or onZoom?

I'm filtering some data based the visibility of markets in the view area (using getBounds on the markers lat/longs). I can easily do this for dragging using mapDragEnd, but is there an action related to the bounds_changed event? Or some other way to listen to viewport changes/zoom level changes?

I see actions being dynamically defined here
https://github.com/fullstackreact/google-maps-react/blob/master/src/index.js#L174
but onBoundsChanged does not work.

EDIT:

Hmm, actually, I see my codebase differs from 1.0.18. My package.json says I'm on 1.0.19, and, in this version, all these events do not exist.

I added bounds_changed here:

# index.js

var evtNames = ['ready', 'click', 'dragend', 'recenter', 'bounds_changed'];

 evtNames.forEach(function (e) {
    return Map.propTypes[(0, _String.camelize)(e)] = _react.PropTypes.func;
  });

and, though the prop is called onBounds_changed, it's working for me now. Not sure what's up with the version numbers, but I'll try... downgrading(?) to the latest?

getPlace() function not firing correctly

I'm trying to use the Api wrapper to lazy-load the Google API and rebuild this example: https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete-addressform

But when I do this, I cannot seem to have getPlace() fire correctly. I get this error: Uncaught TypeError: Cannot read property 'getPlace' of undefined

How would I need to set this up to have getPlace() fire on the autocomplete object and return the PlaceResult object? My code below:

import React from 'react';

export default class GoogleAutoComplete extends React.Component {
  static propTypes = {
    }
  constructor(props) {
    super(props);
    }

    componentDidMount() {
      this.initAutocomplete();
    }


    initAutocomplete() {
      this.autocomplete = new google.maps.places.Autocomplete((this.refs.autoCompletePlaces), {types: ['geocode']});

      this.autocomplete.addListener('place_changed', this.fillInAddress);

    }

    geolocate() {
      if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function(position) {
          const geolocation = {
            lat: position.coords.latitude,
            lng: position.coords.longitude
          };
        });
      }
    }

    fillInAddress() {
      this.componentForm = {
        street_number: 'short_name',
        route: 'long_name',
        locality: 'long_name',
        administrative_area_level_1: 'short_name',
        country: 'long_name',
        postal_code: 'short_name'
      };
    // Get the place details from the autocomplete object.
      this.place = this.autocomplete.getPlace();
      for (let component in this.componentForm) {
        this.refs.component.value = '';
        this.refs.component.disabled = false;
      }

    // Get each component of the address from the place details
    // and fill the corresponding field on the form.
    for (let i = 0; i < this.place.address_components.length; i++) {
      const addressType = this.place.address_components[i].types[0];
      if (this.componentForm[addressType]) {
        const val = this.place.address_components[i][this.componentForm[addressType]];
        this.refs.addressType.value = val;
      }
    }
  }

Undocumented props

I had to do a bit of digging to find that <Map> takes the props initialCenter and mapType. What should we do for docs? Just add them to the main README?

Cannot read property 'setMap' of undefined

I am getting an error caused by Marker.js, using the google-maps-react downloaded from npm. The code I have is below:

import React from 'react'
import {InfoWindow, Marker, Map, GoogleApiWrapper} from 'google-maps-react'

class RegionalMap extends React.Component {
	constructor(props){
		super(props);
		this.state = {
			showingInfoWindow: false,
			activeMarker: {},
			selectedPlace: {},
		};
	}

	onMarkerClick = (props, marker, e) => {
		this.setState({
			selectedPlace: props,
			activeMarker: marker,
			showingInfoWindow: true
		});
	};

	onInfoWindowClose = () => {
		this.setState({
			showingInfoWindow: false,
			activeMarker: null
		});
	};

	onMapClicked = (props) => {
		if (this.state.showingInfoWindow) {
			this.setState({
				showingInfoWindow: false,
				activeMarker: null
			});
		}
	};

	render() {
		return (
			<div id="google-map-holder">
				<Map google={this.props.google}
						style={{width: '100%', height: '100%', position: 'inherit'}}
						className={'map'}
						zoom={14}
						onClick={this.onMapClicked}>
					<Marker
						mapCenter="aarr"
						onClick={this.onMarkerClick}
						name={'SOMA'}
						position={{lat: 37.778519, lng: -122.405640}} />
					<Marker
						onClick={this.onMarkerClick}
						name={'Dolores park'}
						position={{lat: 37.759703, lng: -122.428093}} />

					<InfoWindow
						marker={this.state.activeMarker}
						visible={this.state.showingInfoWindow}
						onClose={this.onInfoWindowClose}>
							<div>
								<h1>{this.state.selectedPlace.name}</h1>
							</div>
					</InfoWindow>
				</Map>
		</div>
		)
	}
}

export default GoogleApiWrapper({
	apiKey: MY_API_KEY
})(RegionalMap);

I get an error in the componentDidUpdate function, caused by the line this.marker.setMap(null);. It appears that this error message is occurring because inside the renderMarker function, the google variable is undefined:

				if (!google) {
					return null;
				}

The funny thing is that when I remove the Marker code from the render function, it works perfectly:

import React from 'react'
import {InfoWindow, Marker, Map, GoogleApiWrapper} from 'google-maps-react'

class RegionalMap extends React.Component {
	constructor(props){
		super(props);
		this.state = {
			showingInfoWindow: false,
			activeMarker: {},
			selectedPlace: {},
		};
	}

	onMarkerClick = (props, marker, e) => {
		this.setState({
			selectedPlace: props,
			activeMarker: marker,
			showingInfoWindow: true
		});
	};

	onInfoWindowClose = () => {
		this.setState({
			showingInfoWindow: false,
			activeMarker: null
		});
	};

	onMapClicked = (props) => {
		if (this.state.showingInfoWindow) {
			this.setState({
				showingInfoWindow: false,
				activeMarker: null
			});
		}
	};

	render() {
		return (
			<div id="google-map-holder">
				<Map google={this.props.google}
						style={{width: '100%', height: '100%', position: 'inherit'}}
						className={'map'}
						zoom={14}
						onClick={this.onMapClicked}>

					<InfoWindow
						marker={this.state.activeMarker}
						visible={this.state.showingInfoWindow}
						onClose={this.onInfoWindowClose}>
							<div>
								<h1>{this.state.selectedPlace.name}</h1>
							</div>
					</InfoWindow>
				</Map>
		</div>
		)
	}
}

Any help?

Maps component should handle gestureHandling prop

I'm having an issue on mobile browsers where the user is forced to use two fingers to move the map:

two-fingers-to-move-map-issue

The solution is to allow the Maps component to handle a gestureHandling prop that can then be assigned to the mapConfig object. The gestureHandling prop can accept strings of 'greedy', 'cooperative', 'none', or 'auto'.

I've made the changes and will open a PR. Thanks!

Unclear documentation

I've read through the code for the demo, the documentation and I still don't have a clear understanding of required google prop. I think replacing this joke line with a more clear breakdown would help people trying to use this project. Thanks.

The component requires a google prop be included to work. Without the google prop, it will explode.

Missing invariant dependency

I'm trying to bundle this component using npm2 and it's complaining about a missing invariant dependency - since invariant is directly required by this module, it should be moved into dependencies.

It might be accidentally relying on npm3's behaviour of moving transitive dependencies into require() scope.

Markers Question

Hello,

I've been trying to follow along your tutorial. I'm attempting to expand upon it and apply it towards a special use-case that I have.

I have created a map using your tutorial and centered over Europe. What I'd like to do now is just display simple Markers over various cities. At the moment, I just want to hard code the positions in. Later, I might load the positions in dynamically.

It seems like I should be able to achieve that with something like this, however, I cannot get the Marker to display on my map:

<Map google={this.props.google}>
 <Marker name={'London'}  position={{lat: 51.5073509, lng: -0.1277583}} />
</Map>

Can you give me any guidance on how I might do this?

Thanks!

InfoWindow javascript events not triggering for within window

None of the buttons ... A ,B ,C ,D do not fire... i ahve been trying links, buttons and header elements all do not fire events

                <InfoWindow
                        marker={this.state.activeMarker}
                        visible={this.state.showingInfoWindow}>
                            <div>
                                <button onClick={() => {this.setState({ showingInfoWindow:false });}}>A</button>
                                <button onClick={(e) => {this.setState({ showingInfoWindow:false });}}>B</button>
                                <button onClick={(e) => {e.preventDefault();console.log(e);}}>C</button>
                                <button onClick={this.onClickMarkerAgentName}>D</button>                                    
                            </div>
                </InfoWindow>

The history module needs to be included in the package.json

Can't shrinkwrap a project using this package while history is considered an extraneous package.

A quick npm i -S history will do it. Thanks!

For now, although ugly, this will get the job done (in your project root) -

$ cd node_modules/google-maps-react
$ npm i -S history
$ cd ../..
$ npm shrinkwrap --dev

ReferenceError: window is not defined

I'm getting this error while trying to follow Ari's tutorial.

ReferenceError: window is not defined
at /home/drstein/projects/react-tests/node_modules/google-maps-react/dist/lib/ScriptCache.js:20:21
at Object.defineProperty.value (/home/drstein/projects/react-tests/node_modules/google-maps-react/dist/lib/ScriptCache.js:5:9)
at Object.<anonymous> (/home/drstein/projects/react-tests/node_modules/google-maps-react/dist/lib/ScriptCache.js:13:3)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.require (module.js:498:17)
at require (internal/module.js:20:19)
at Object.defineProperty.value (/home/drstein/projects/react-tests/node_modules/google-maps-react/dist/GoogleApiComponent.js:5:66)
at Object.<anonymous> (/home/drstein/projects/react-tests/node_modules/google-maps-react/dist/GoogleApiComponent.js:13:3)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
/home/drstein/projects/react-tests/tools/runServer.js:80
      throw new Error(`Server terminated unexpectedly with code: ${ code } signal: ${ signal }`);
      ^

Error: Server terminated unexpectedly with code: 1 signal: null
at ChildProcess.server.once (/home/drstein/projects/react-tests/tools/runServer.js:54:17)
at ChildProcess.g (events.js:292:16)
at emitTwo (events.js:106:13)
at ChildProcess.emit (events.js:191:7)
at Process.ChildProcess._handle.onexit (internal/child_process.js:215:12)
error Command failed with exit code 1.

This is my MapLocation.js:

import React from 'react';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import {Map, GoogleApiWrapper} from 'google-maps-react';
import s from './MapLocation.css';

export class MapLocation extends React.Component {
 render () {
      if (!this.props.loaded) {
              return (<div>Loading...</div>)
      }

      return (<div> Hello </div>)
  }
}

export default GoogleApiWrapper({
  apiKey: __GAPI_KEY__
})(MapLocation)

Any ideas? Thank you very much.

window.google object is gone after unmount and mount the Lazy-loading Wrapper Component.

I don't really sure why.
When the component is unmounted, the window.google is still. But, when the wrapper component is mounted again, the window.google becomes null for unknown reason.
I look through the implementation of wrapper and found that the ScriptCache.js loads the Google map script only once and no hope to reload it even if the window.google object is gone away from browser.
The solution I've temporally did is to recreate my own wrapper with this add-on function.

componentWillUnmount() {
  window._scriptMap.delete("google");
}

However, I don't think it is a good idea to do so.
Could you figure out why the window.google object is gone when remounting and fix it?

Markers do not clear out when you render with a new set of markers

After the initial set of markers if I render with a new set of markers, every subsequent set gets stuck on the map. Example: original marker is Texas, I render with only California and Texas goes away, so only one marker is left. Now I render with only Arkansas, at this point California is visible along with Arkansas.

The re-render that occurs when using the info window does not cause this issue.

I am able to replicate this on the demo as well in the Autocomplete section. But that might be the intended functionality in the demo.

Isomorphic App Error

Can anyone suggest a way to make this work for Isomorphic applications?

error given was: ReferenceError: window is not defined [1] at /Users/xxxx/Develop/autogravity-web-app/node_modules/google-maps-react/dist/lib/ScriptCache.js:20:21 [1] at Object.defineProperty.value (/Users/xxxx/Develop/autogravity-web-app/node_modules/google-maps-react/dist/ lib/ScriptCache.js:5:9) [1] at Object.<anonymous> (/Users/xxxx/Develop/autogravity-web-app/node_modules/google-maps-react/dist/lib/Scrip tCache.js:13:3)

Trivial Documentation Enhancement

Might seem small, but clearly lining out the exports might make entry a little easier (especially if NOT coming from the blog post). It could be as easy as just example code

import { Map } from 'google-maps-react';

I get laying them out as 'the components included', but then something like

import { GoogleApiWrapper } from 'GoogleMapsReactComponent'

// ...

export class Container extends React.Component {}

export default GoogleApiWrapper({
  apiKey: __GAPI_KEY__
})(Container)

might get a little confusing since it doesn't reference the repo itself.

Uncaught TypeError: Constructor Map requires 'new'

When testing this out and just loading up a basic map, I get the error message:

ReactCompositeComponent.js:306 Uncaught TypeError: Constructor Map requires 'new'

I've tried both ES6 and React.createClass methods. Here's what it looks like now:

import React from 'react'

const MapContainer = React.createClass({
  render() {
    return (
      <Map google={this.props.google}/>
    )
  }
})

export default MapContainer

Or in ES6

import React from 'react'

const MapContainer = ({google}) => (
  <Map google={google}/>
)

export default MapContainer

Element type is invalid problem

Hi,
I have installed your package via command line. I put these lines:

<Marker onClick={this.onMarkerClick} name={'Current location'} /> <InfoWindow onClose={this.onInfoWindowClose}> <div> <h1></h1> </div> </InfoWindow> </Map>

in my render function, but I have this error:

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object

Why? Obviously I have declared:

var Map = require('google-maps-react'); var Marker = Map.Marker; var InfoWindow = Map.InfoWindow;

Publish v1.0.19

The latest merges, including #27, have some critical patches. Could we please tag and publish a new release? Thanks for the outstanding project.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.