ember-g-map
Version:
An ember-cli addon for integration with google maps.
438 lines (350 loc) • 15.3 kB
Markdown
# Ember-g-map [](https://travis-ci.org/asennikov/ember-g-map) [](http://emberobserver.com/addons/ember-g-map) [](https://coveralls.io/github/asennikov/ember-g-map?branch=master) [](https://codeclimate.com/github/asennikov/ember-g-map)
An ember-cli add-on for easy integration with Google Maps.
Each object displayed on map is inserted via child component,
so you can easily declare which marker and when to display on map
using `{{#if}}` and `{{#each}}` on template level.
# Installation
* `ember install ember-g-map`
# Configuration
You must define the size of the canvas in which the map is displayed.
Simply add something similar to this to your styles:
```css
.g-map-canvas {
width: 600px;
height: 400px;
}
```
In case you want to make the google map to have full width and height as the parent div, you can do the following:
```css
.g-map{
height: 100%;
}
.g-map-canvas {
width: 100%;
height: 100%;
}
```
In `config/environment.js` you can specify:
- additional Google Maps libraries to be loaded along with this add-on
(check the full list [here](https://developers.google.com/maps/documentation/javascript/libraries)),
- optional API key or client ID for your application (additional info could be found [here](https://developers.google.com/maps/web/)),
- optional [channel](https://developers.google.com/maps/premium/reports/usage-reports#channels),
- optional version number,
- optional exclude parameter, which prevents inclusion of the google maps api script tag into the index.html (in case one wants to handle loading of google maps lib by himself),
- optional language for map localization,
- optional explicit protocol setting.
```javascript
ENV['g-map'] = {
exclude: true,
libraries: ['places', 'geometry'],
key: 'your-unique-google-map-api-key',
client: 'gme-your-unique-google-client-id',
channel: 'my-google-map-api-channel',
version: '3.26',
language: 'ru',
protocol: 'https'
}
```
# Usage
## Simple map
```handlebars
{{g-map lat=37.7833 lng=-122.4167 zoom=12}}
```
## Map with custom options
Any [custom options](https://developers.google.com/maps/documentation/javascript/3.exp/reference#MapOptions)
(except for `center` and `zoom` to avoid conflicts) could be set for
Google Map object on creation and updated on change.
```handlebars
{{g-map lat=37.7833 lng=-122.4167 zoom=12 options=customOptions}}
```
## Map with Markers
Mandatory `context` attribute ties child-elements
with the main `g-map` component. You can also set optional attributes:
- simple title appearing on hover using `title` attribute,
- marker label using `label`,
- `draggable` boolean option,
- `onClick` action to track all `click` events on that marker,
- `onDrag` action to track all `dragend` events on that marker (callback receives new `lat` and `lng` in attributes).
- `viewport` optional google.maps.LatLngBounds, provides an optimized map viewport for the marker. This is generally provided by the [google geocoder](https://developers.google.com/maps/documentation/javascript/3.exp/reference#PlaceGeometry)
```handlebars
{{#g-map lat=37.7833 lng=-122.4167 zoom=12 as |context|}}
{{g-map-marker context lat=37.7933 lng=-122.4167 onClick=(action "handleClick")}}
{{g-map-marker context lat=37.7833 lng=-122.4267 onClick="handleClick" title=titleForSecondMarker}}
{{g-map-marker context lat=37.7733 lng=-122.4067 onDrag=(action "handleDrag") label="3" title="Marker #3"}}
{{/g-map}}
```
### Custom Marker Images
You can assign custom images to your markers by pointing the `icon` attribute to an image file (jpg, png, svg, etc.)
```handlebars
{{g-map-marker context lat=lat lng=lng icon="/assets/images/driver-icon.svg" }}
```
### Complex Marker Icons
You can also create a [complex marker icon](https://developers.google.com/maps/documentation/javascript/markers#complex_icons) by defining an icon object and passing it to the `icon` attribute
```javascript
myIcon: {
url: "/assets/images/driver-icon.svg",
size: new google.maps.Size(30,30),
scaledSize: new google.maps.Size(20,20),
anchor: new google.maps.Point(15, 15),
origin: new google.maps.Point(0, 0),
labelOrigin: new google.maps.Point(30, 15),
}
```
```handlebars
{{g-map-marker context lat=lat lng=lng icon=myIcon }}
```
## Map with Info Windows
These Info Windows will be open right after component is rendered
and will be closed forever after user closes them. You can specify optional `onOpen` action to trigger anything you need to when the Info Window opens. The infowindow is passed as the only argument to the `onOpen` action. You can specify optional `onClose` action to tear down anything you need when Info Window
has been closed by user.
Available options (see details [in docs](https://developers.google.com/maps/documentation/javascript/3.exp/reference#InfoWindowOptions)):
- disableAutoPan,
- maxWidth,
- pixelOffset
```handlebars
{{#g-map lat=37.7833 lng=-122.4167 zoom=12 as |context|}}
{{#g-map-infowindow context lat=37.7733 lng=-122.4067}}
<h1>Info Window with Block</h1>
<p>Text with {{bound}} variables</p>
<button {{action "do"}}>Do</button>
{{/g-map-infowindow}}
{{g-map-infowindow context lat=37.7733 lng=-122.4067
title="Blockless form" message="Plain text."}}
{{g-map-infowindow context lat=37.7733 lng=-122.4067
title="With action set"
onOpen="myOnOpenAction"
onClose="myOnCloseAction"}}
{{g-map-infowindow context lat=37.7733 lng=-122.4067
title="With closure action set"
onOpen=(action "myOnOpenAction")
onClose=(action "myOnCloseAction")}}
{{/g-map}}
```
## Map fits to show all initial Markers
`markersFitMode` attribute overrides `lat`, `lng`, `zoom` settings.
`markersFitMode` value can be one of:
* 'init' - which will make the map fit the markers on creation.
* 'live' - which will keep the map keep fitting the markers as they are added,
removed or moved.
```handlebars
{{#g-map markersFitMode='live' as |context|}}
{{g-map-marker context lat=37.7933 lng=-122.4167}}
{{g-map-marker context lat=37.7833 lng=-122.4267}}
{{g-map-marker context lat=37.7733 lng=-122.4067}}
{{/g-map}}
```
## Map with Markers and bound Info Windows
Markers can have bound Info Windows activated on click.
To properly bind Info Window with Marker you should call `g-map-marker`
in block form and set context of Info Window to the one provided by Marker.
You can optionally setup custom `openOn`/`closeOn` events for each Info Window,
available options are: `click`, `dblclick`, `rightclick`, `mouseover`, `mouseout`.
By default `openOn` is set to `click` and `closeOn` is set to `null`. When `openOn`
and `closeOn` are the same, Info Window visibility is being toggled by this event.
```handlebars
{{#g-map lat=37.7833 lng=-122.4167 zoom=12 as |context|}}
{{#g-map-marker context lat=37.7833 lng=-122.4267 as |markerContext|}}
{{#g-map-infowindow markerContext openOn="mouseover" closeOn="mouseout"}}
<h2>Bound Info Window</h2>
{{/g-map-infowindow}}
{{/g-map-marker}}
{{#g-map-marker context lat=37.7833 lng=-122.4267 as |markerContext|}}
{{g-map-infowindow markerContext openOn="click" closeOn="click" title="Blockless form 1"}}
{{/g-map-marker}}
{{#g-map-marker context lat=37.7833 lng=-122.4267 as |markerContext|}}
{{g-map-infowindow markerContext openOn="dblclick" title="Blockless form 2"}}
{{/g-map-marker}}
{{/g-map}}
```
## Grouped Markers with Info Windows
Additionally you can specify parameter `group` which ensures that only
one Info Window is open at each moment for Markers of each group.
```handlebars
{{#g-map lat=37.7833 lng=-122.4167 zoom=12 as |context|}}
{{#g-map-marker context group="cats" lat=37.7833 lng=-122.4167 as |markerContext|}}
{{#g-map-infowindow markerContext}}
<h2>Cat #1</h2>
{{/g-map-infowindow}}
{{/g-map-marker}}
{{#g-map-marker context group="cats" lat=37.7433 lng=-122.4467 as |markerContext|}}
{{#g-map-infowindow markerContext}}
<h2>Cat #2</h2>
{{/g-map-infowindow}}
{{/g-map-marker}}
{{#g-map-marker context group="dogs" lat=37.7533 lng=-122.4167 as |markerContext|}}
{{#g-map-infowindow markerContext}}
<h2>Dog #1</h2>
{{/g-map-infowindow}}
{{/g-map-marker}}
{{#g-map-marker context group="dogs" lat=37.7733 lng=-122.4467 as |markerContext|}}
{{#g-map-infowindow markerContext}}
<h2>Dog #2</h2>
{{/g-map-infowindow}}
{{/g-map-marker}}
{{/g-map}}
```
## Marker bound to address query
Proxy `g-map-address-marker` component takes address string as parameter
and translates it to lat/lng/viewport under the hood.
The viewport is used internally to fit the map and can be passed as optional parameter.
Optional `onLocationChange` action hook will send you back coordinates
of the latest address search result and the raw array of
[google.maps.places.PlaceResult](https://developers.google.com/maps/documentation/javascript/reference#PlaceResult) objects provided by `places` library.
Other optional parameters are the same as for `g-map-marker`.
Requires `places` library to be specified in `environment.js`.
```javascript
ENV['g-map'] = {
libraries: ['places']
}
```
```javascript
actions: {
onLocationChangeHandler(lat, lng, results) {
const { viewport } = results[0].geometry;
Ember.Logger.log(`lat: ${lat}, lng: ${lng}`);
Ember.Logger.log(`viewport: ${viewport}`);
Ember.Logger.debug(results);
}
}
```
```handlebars
{{#g-map lat=37.7833 lng=-122.4167 zoom=12 as |context|}}
{{g-map-address-marker context address="San Francisco, Russian Hill"}}
{{#g-map-address-marker context address="Delft, The Netherlands" as |markerContext|}}
{{#g-map-infowindow markerContext}}
Works in block form too.
{{/g-map-infowindow}}
{{/g-map-address-marker}}
{{g-map-address-marker context address=searchedAddress
onLocationChange=(action "onLocationChangeHandler")}}
{{g-map-address-marker context address=anotherSearchedAddress
onLocationChange="onLocationChangeHandler"}}
{{/g-map}}
```
## Map with route between 2 locations
Using Google Maps [Directions](https://developers.google.com/maps/documentation/javascript/directions) service.
You can optionally set travel mode with `travelMode` attr:
- `walking`
- `bicycling`
- `transit`
- `driving` (default)
You can optionally set following custom polyline options as attributes:
- `strokeColor`
- `strokeWeight`
- `strokeOpacity`
- `zIndex`
```handlebars
{{#g-map lat=37.7833 lng=-122.4167 zoom=12 as |context|}}
{{g-map-route context
travelMode='driving' strokeColor='red'
originLat=37.7933 originLng=-122.4167
destinationLat=37.7733 destinationLng=-122.4167}}
{{g-map-route context
travelMode='bicycling' strokeColor='blue' zIndex=10
originLat=37.7933 originLng=-122.4167
destinationLat=37.7733 destinationLng=-122.4167}}
{{/g-map}}
```
## Route bound to address queries
Proxy `g-map-address-route` component takes 2 address strings as parameters
and translates them to lat/lng pairs under the hood.
Optional `onLocationChange` action hook will send you back coordinates
of the latest address search result and the raw array of
[google.maps.places.PlaceResult](https://developers.google.com/maps/documentation/javascript/reference#PlaceResult) objects provided by `places` library.
Other optional parameters are the same as for `g-map-route`.
Requires `places` library to be specified in `environment.js`.
```javascript
ENV['g-map'] = {
libraries: ['places']
}
```
```javascript
actions: {
onLocationChangeHandler(lat, lng, results) {
Ember.Logger.log(`lat: ${lat}, lng: ${lng}`);
Ember.Logger.debug(results);
}
}
```
```handlebars
{{#g-map lat=37.7833 lng=-122.4167 zoom=12 as |context|}}
{{g-map-address-route context
originAddress="Los Angeles, California"
destinationAddress="San Francisco, California"}}
{{g-map-address-route context
originAddress=searchedAddress
destinationAddress=anotherSearchedAddress
onLocationChange=(action "onLocationChangeHandler")}}
{{g-map-address-route context
originAddress=searchedAddress
destinationAddress=anotherSearchedAddress
onLocationChange="onLocationChangeAction"}}
{{/g-map}}
```
## Route with waypoints
You can add optional waypoints to both `{{g-map-route}}` and `{{g-map-address-route}}`.
Waypoints could be added using
`{{g-map-route-waypoint}}` or `{{g-map-route-address-waypoint}}` components.
```handlebars
{{#g-map lat=37.7833 lng=-122.4167 zoom=12 as |context|}}
{{#g-map-address-route context
originAddress="Los Angeles, California"
destinationAddress="San Francisco, California"
as |routeContext|}}
{{g-map-route-address-waypoint routeContext address="New York City, New York"}}
{{g-map-route-waypoint routeContext lat=37.7933 lng=-122.4167}}
{{g-map-route-address-waypoint routeContext address="Dallas, Texas"}}
{{/g-map-address-route}}
{{/g-map}}
```
## Map with Polylines
You can optionally set following custom polyline options as attributes:
- `strokeColor`
- `strokeWeight`
- `strokeOpacity`
- `zIndex`
- `clickable`
- `draggable`
- `geodesic`
- `icons`
- `visible`
- `path`
```handlebars
{{#g-map lat=37.7833 lng=-122.4167 zoom=12 as |context|}}
{{#g-map-polyline context
strokeColor="green" strokeWeight="10" strokeOpacity="0.3"
geodesic=true draggable=true onDrag=(action "onPolylineDrag") as |coordinateContext|}}
{{g-map-polyline-coordinate coordinateContext lat=37.7833 lng=-122.4667}}
{{g-map-polyline-coordinate coordinateContext lat=37.7933 lng=-122.4567}}
{{g-map-polyline-coordinate coordinateContext lat=37.7933 lng=-122.4667}}
{{/g-map-polyline}}
{{g-map-polyline context path=decodedPolyline}}
{{/g-map}}
```
For both the `onClick` and `onDrag` actions, the arguments are `event` and `polyline`:
```javascript
actions: {
onPolylineDrag(event, polyline) {
const bounds = new window.google.maps.LatLngBounds();
polyline.getPath().forEach((e) => bounds.extend(e));
polyline.map.fitBounds(bounds);
}
}
```
## Demo
http://asennikov.github.io/ember-g-map/
# Planned Features
- Polygons
- Google Maps events
- Better DEMO app
## Running
* `ember server`
* Visit your app at http://localhost:4200.
## Running Tests
* `ember test`
* `ember test --server`
## Building
* `ember build`
For more information on using ember-cli, visit [http://www.ember-cli.com/](http://www.ember-cli.com/).
## Legal
[Licensed under the MIT license](http://www.opensource.org/licenses/mit-license.php)