@ionic-native / google-maps
�Cordova GoogleMaps plugin project
��Masashi Katsumata
Ionic framework
@ionic-native/google-maps
・UI components
・View management
・TypeScript -> JS
...etc
Your code run on this browser view
Bridge between native system and your code!
@ionic-native/google-maps
Let’s see the demo!
<button ion-button>
(HTML)
Google Map!
(native view)
The Map
is touchable
The side menu is
touchable!!
The Map
is not touchable!
Google Map View is under the browser!!�(and this is not a HTML element)
This is native Google Maps view, which is not
a HTML element.
touch layer�(native)
Is this on map or browser?
Pass
the touch event to the map or browser
Hello world
Create a project
API key
Create a project
API key
Enable billing
API key
You need to register your payment way.��But don’t worry, you probably won’t charge.
Because Google Maps Android API and Google Maps SDK for iOS are free.
(Except geocoding, StreetView)
Are Google Maps APIs free to use?
Thus, this plugin is also free!
Enable Google Maps APIs
API key
Enable Google Maps APIs
API key
This is your API key
Restrict your key when you release your app
Create a project
API key
Create project
$> ionic start myApp sidemenu --type=angular
? Integrate your new app with Cordova to target native iOS and Android? YES�
$> npm install @ionic-native/core�
$> npm install @ionic-native/google-maps�
Install cordova-plugin-googlemaps
API key
Create project
$> ionic cordova plugin add cordova-plugin-googlemaps
Edit `config.xml`
<?xml version='1.0' encoding='utf-8'?>
<widget ...>
<preference � name="GOOGLE_MAPS_ANDROID_API_KEY" value="(api key)" />
<preference
name="GOOGLE_MAPS_IOS_API_KEY" value="(api key)" />
</widget>
API key
Create project
src/app/home/home.page.html
<ion-content padding>
<h3>Ionic GoogleMaps Starter</h3>
<div id="map_canvas">
<button ion-button (click)="onButtonClick($event)">Start demo</button>
</div>�
</ion-content>
Add a div (map div)
API key
Create project
HTML & CSS
src/pages/home/home.scss
#map_canvas {
height: 90%;
}
100 x 100 pixels are minimum requirement dimension.
API key
Create project
HTML & CSS
Background styles become be transparent
by the maps plugin mandatory!
You can set the background color through
Environment.setBackgroundColor()
src/app/home/home.page.ts
import { Component, OnInit } from '@angular/core';
import { Platform } from '@ionic/angular';
import { GoogleMaps, GoogleMap } from '@ionic-native/google-maps/ngx';
export class HomePage implements OnInit {
map: GoogleMap;
constructor(private platform:Platform) {}
async ngOnInit() {� // you need to wait `platform.ready()`� await this.platform.ready();
await this.loadMap();
}
API key
Create project
HTML & CSS
Coding
Important!!!
If you forget that …
ionViewDidLoad() is executed�(DOM elements are ready)
platform.ready() is executed later�(the native plugins are ready to use)
Then you get this error message���
src/app/home/home.page.ts
loadMap() {� // If you want to run your app� // on browser, insert this line.� Environment.setEnv({� 'API_KEY_FOR_BROWSER_RELEASE': '',� 'API_KEY_FOR_BROWSER_DEBUG':''� });
// Create a map� // after the view is ready� // and the native platform is ready.� this.map = GoogleMaps.create('map_canvas');
}
API key
Create project
HTML & CSS
Coding
Run it!!
$> ionic cordova run android
$> ionic cordova run browser -l
API key
Create project
HTML & CSS
Coding
Run it!
Marker
@ionic-native/google-maps
Add a marker
this.map.addMarker({
title: '@ionic-native/google-maps',
icon: 'blue',
animation: 'DROP',
position: {
lat: 43.0741904,
lng: -89.3809802
}
}).then((marker: Marker) => {
marker.showInfoWindow();
});
Add a marker
from v4.8.2 -
let marker: Marker = this.map.addMarkerSync({
title: '@ionic-native/google-maps',
icon: 'blue',
animation: 'DROP',
position: {
lat: 43.0741904,
lng: -89.3809802
}
});
marker.showInfoWindow();
icon property
this.map.addMarkerSync({
title: '@ionic-native/google-maps',
icon: 'blue',
animation: 'DROP',
position: {
lat: 43.0741904,
lng: -89.3809802
}
});
color name : blue, red, green, yellow ....
(157 color names are defined in this plugin)
rgb(), rgba() , hsl(), hsla(), #RGB, #RGBA :
./assets/icon.png (jpg, gif, and png) :
http(s)://yourserver/icon.png :
cdvfile:// …. /icon.png :
data:image/png;base64,iVBORw0KGgo...CC :
:
icon property
let POINTS: BaseArrayClass<any> = new BaseArrayClass<any>([
{
position: {lat:41.79883, lng:140.75675},
iconData: "./assets/imgs/Number-1-icon.png"
},
{
position: {lat:41.799240000000005, lng:140.75875000000002},
iconData: "http://icons.iconarchive.com/.../24/Number-2-icon.png"
},
{
position: {lat:41.797650000000004, lng:140.75905},
iconData: {
url: "http://icons.iconarchive.com/.../48/Number-3-icon.png",
size: { width: 24, height: 24}
}
},
{
position: {lat:41.79637, lng:140.76018000000002},
title: "4",
iconData: "blue"
},
{
position: {lat:41.79567, lng:140.75845},
title: "5",
iconData: "data:image/png;base64,iVBORw...CC"
}
]);
Marker events
Add event listener
Listen the event only one time
Listen the event multiple times
marker.addEventListenerOnce(GoogleMapsEvent.MARKER_CLICK).then();
// Alias method
marker.one(GoogleMapsEvent.MARKER_CLICK).then();
marker.addEventListener(GoogleMapsEvent.MARKER_CLICK).subscribe();
// Alias method
marker.on(GoogleMapsEvent.MARKER_CLICK).subscribe();
Remove event listener
Listen the event only one time
// Remove particular event listener
marker.off(GoogleMapsEvent.MARKER_CLICK, this.onMarkerClick);
// Remove all event listeners for the MARKER_CLICK event
marker.off(GoogleMapsEvent.MARKER_CLICK);
// Remove all event listeners of all events
marker.off();
Example
this.map.addMarker({
position: {
lat: 43.0741804,
lng: -89.381
},
title: "A",
disableAutoPan: true
}).then(this.onMarkerAdded);
this.map.addMarker({
position: {
lat: 43.0741804,
lng: -89.382
},
title: "B",
disableAutoPan: true
}).then(this.onMarkerAdded);
onMarkerAdded(marker: Marker) {
marker.one(GoogleMapsEvent.MARKER_CLICK).then(() => {
alert("Marker" + marker.getTitle() + " is clicked");
});
}
Polyline
@ionic-native/google-maps
Polyline
let AIR_PORTS = [� HND_AIR_PORT, HNL_AIR_PORT, SFO_AIR_PORT�];��this.map.addPolyline({� points: AIR_PORTS,� color: '#AA00FF',� width: 10,� geodesic: true,� clickable: true // clickable = false in default�}).then((polyline: Polyline) => {� polyline.on(GoogleMapsEvent.POLYLINE_CLICK).subscribe((params: any) => {� let position: LatLng = <LatLng>params[0];� this.map.addMarker({� position: position,� title: position.toUrlValue(),� disableAutoPan: true� }).then((marker: Marker) => {� marker.showInfoWindow();� });� });�});
Click event with LatLng
(Because this plugin calculates own way)
Polyline
let AIR_PORTS = [� HND_AIR_PORT, HNL_AIR_PORT, SFO_AIR_PORT�];��let polyline: Polyline = this.map.addPolylineSync({� points: AIR_PORTS,� color: '#AA00FF',� width: 10,� geodesic: true,� clickable: true // clickable = false in default�})
polyline.on(GoogleMapsEvent.POLYLINE_CLICK).subscribe((params: any) => {� let position: LatLng = <LatLng>params[0];� let marker: Marker = this.map.addMarkerSync({� position: position,� title: position.toUrlValue(),� disableAutoPan: true� });� marker.showInfoWindow();�});
from v4.8.2 -
Polygon
@ionic-native/google-maps
Polygon
let GORYOKAKU_POINTS: ILatLng[] = [� {lat: 41.79883, lng: 140.75675},� {lat: 41.799240000000005, lng: 140.75875000000002},� {lat: 41.797650000000004, lng: 140.75905},� …� {lat: 41.79909000000001, lng: 140.75465}�];��this.map.addPolygon({� 'points':GORYOKAKU_POINTS,� 'strokeColor' : '#AA00FF', � 'fillColor' : '#00FFAA',� 'strokeWidth': 10�}.then((polygon: Polygon) => {
...
});
Just pass ILatLng[]
Polygon
let GORYOKAKU_POINTS: ILatLng[] = [� {lat: 41.79883, lng: 140.75675},� {lat: 41.799240000000005, lng: 140.75875000000002},� {lat: 41.797650000000004, lng: 140.75905},� …� {lat: 41.79909000000001, lng: 140.75465}�];��let polygon: Polygon = this.map.addPolygonSync({� 'points':GORYOKAKU_POINTS,� 'strokeColor' : '#AA00FF', � 'fillColor' : '#00FFAA',� 'strokeWidth': 10�});
from v4.8.2 -
Circle
@ionic-native/google-maps
Circle
let center: ILatLng = {"lat": 32, "lng": -97};�let radius = 300; // radius (meter)��this.map.addCircle({� 'center': center,� 'radius': radius,� 'strokeColor' : '#AA00FF',� 'strokeWidth': 5,� 'fillColor' : '#00880055'�}).then((circle: Circle) => {
marker.on('position_changed').subscribe((params: any) => {� let newValue: ILatLng = <ILatLng>params[1];
let newRadius: number = Spherical.computeDistanceBetween(� center, newValue);
circle.setRadius(newRadius);� });�});
Circle
let center: ILatLng = {"lat": 32, "lng": -97};�let radius = 300; // radius (meter)��let circle: Circle = this.map.addCircleSync({� 'center': center,� 'radius': radius,� 'strokeColor' : '#AA00FF',� 'strokeWidth': 5,� 'fillColor' : '#00880055'�});
marker.on('position_changed').subscribe((params: any) => {� let newValue: ILatLng = <ILatLng>params[1];
let newRadius: number = Spherical.computeDistanceBetween(� center, newValue);
circle.setRadius(newRadius);�});�
from v4.8.2 -
GroundOverlay
@ionic-native/google-maps
GroundOverlay
this.map.one(GoogleMapsEvent.MAP_READY).then(() => {� return this.map.addGroundOverlay({� 'url': 'assets/imgs/newark_nj_1922.jpg',� 'bounds': bounds,� 'opacity': 0.5,� 'clickable': true // default = false� });�}).then((groundOverlay: GroundOverlay) => {�� // Catch the GROUND_OVERLAY_CLICK event� groundOverlay.on(GoogleMapsEvent.GROUND_OVERLAY_CLICK).subscribe(() => {� groundOverlay.setImage('assets/imgs/newark_nj_1922_2.jpg');� });��});
GroundOverlay
let groundOverlay: GroundOverlay = this.map.addGroundOverlaySync({� 'url': 'assets/imgs/newark_nj_1922.jpg',� 'bounds': bounds,� 'opacity': 0.5,� 'clickable': true // default = false� });�});��// Catch the GROUND_OVERLAY_CLICK event�groundOverlay.on(GoogleMapsEvent.GROUND_OVERLAY_CLICK).subscribe(() => {� groundOverlay.setImage('assets/imgs/newark_nj_1922_2.jpg');�});��
from v4.8.2 -
TileOverlay
@ionic-native/google-maps
TileOverlay
this.map.addTileOverlay({� getTile: (x: number, y: number, zoom: number) => {� return "http://tile.stamen.com/watercolor/" +� zoom + "/" + x + "/" + y + ".jpg";� },�� // draw the debug information on tiles� debug: false,�� opacity: 1.0�});
You can generate various URL
TileOverlay
let tileOverlay: TileOverlay = this.map.addTileOverlaySync({� getTile: (x: number, y: number, zoom: number) => {� return "http://tile.stamen.com/watercolor/" +� zoom + "/" + x + "/" + y + ".jpg";� },�� // draw the debug information on tiles� debug: false,�� opacity: 1.0�});
from v4.8.2 -
HtmlInfoWindow
@ionic-native/google-maps
HtmlInfoWindow(1)
let htmlInfoWindow = new HtmlInfoWindow();�let frame: HTMLElement = document.createElement('div');�frame.innerHTML = [� '<h3>Hearst Castle</h3>',� '<img src="assets/imgs/hearst_castle.jpg">'�].join("");�frame.getElementsByTagName("img")[0].addEventListener("click", () => {� htmlInfoWindow.setBackgroundColor('red');�});�htmlInfoWindow.setContent(frame, {width: "280px", height: "330px"});��this.map.addMarker({� position: {lat: 35.685208, lng: -121.168225},� draggable: true,� disableAutoPan: true�}).then((marker: Marker) => {� marker.on(GoogleMapsEvent.MARKER_CLICK).subscribe(() => {� htmlInfoWindow.open(marker);� });�});
HtmlInfoWindow(2)
onMarkerClick(params: any[]) {� // Get a marker instance from the passed parameters� let marker: Marker = params.pop();�� // Create a component� const compFactory = this.resolver.resolveComponentFactory(CustomTag);� let compRef: ComponentRef<CustomTag> = compFactory.create(this.injector);� compRef.instance.myTitle = marker.get('myTitle');� this.appRef.attachView(compRef.hostView);�� let div = document.createElement('div');� div.appendChild(compRef.location.nativeElement);�� // Dynamic rendering� this._ngZone.run(() => {� this.htmInfoWindow.setContent(div);� this.htmInfoWindow.open(marker);� });�}
Marker cluster
@ionic-native/google-maps
MarkerCluster
this.map.addMarkerCluster({
markers: data,
icons: [
{
min: 3, max: 9,
url: "./assets/markercluster/small.png",
label: { color: "white" }
},
{
min: 10,
url: "./assets/markercluster/large.png",
label: { color: "white" }
}
]
}).then((markerCluster: MarkerCluster) => {
markerCluster.on(GoogleMapsEvent.MARKER_CLICK).subscribe((params) => {
let marker: Marker = params[1];
marker.setTitle(marker.get("name"));
marker.setSnippet(marker.get("address"));
marker.showInfoWindow();
});
});
MarkerCluster
from v4.8.2 -
let markerCluster: MarkerCluster = this.map.addMarkerClusterSync({
markers: data,
icons: [
{
min: 3, max: 9,
url: "./assets/markercluster/small.png",
label: { color: "white" }
},
{
min: 10,
url: "./assets/markercluster/large.png",
label: { color: "white" }
}
]
});
markerCluster.on(GoogleMapsEvent.MARKER_CLICK).subscribe((params) => {
let marker: Marker = params[1];
marker.setTitle(marker.get("name"));
marker.setSnippet(marker.get("address"));
marker.showInfoWindow();
});
Geocoding
@ionic-native/google-maps
Geocoding
Geocoding for one address
// Address -> latitude,longitude
Geocoder.geocode({
"address": this.search_address
})
.then((results: GeocoderResult[]) => {
console.log(results);
return this.map1.addMarker({
'position': results[0].position,
'title': JSON.stringify(results[0].position)
})
})
.then(...)
Batch geocoding
Pass locations as array
Get a mvc array first,
then `finish` event is notified.
Just 1.9 sec!
Geocoder.geocode({
// US Capital cities
"address": [
"Montgomery, AL, USA", "Juneau, AK, USA", ...� "Madison, WI, USA", "Cheyenne, Wyoming, USA"
]
})
.then((mvcArray: BaseArrayClass<GeocoderResult[]>) => {
});
BaseClass
@ionic-native/google-maps
All classes extend Base class
BaseClass
BaseArrayClass
Marker
Circle
Polyline
Polygon
GroundOverlay
TileOverlay
MarkerCluster
Map
BaseClass
set() and get()
"Hello_changed" event occurs
obj.set(key, value, noNotify?)
obj.get(key)
let myObj: BaseClass = new BaseClass();
myObj.set("hello", "world");
console.log(myObj.get("hello"));
(key)_changed event
let myObj: BaseClass = new BaseClass();�
myObj.on("hello_changed").subscribe((params) => {
console.log(params);
});�
myObj.set("hello", "world");
myObj.set("hello", "world2");
hello_changed
hello_changed
Status change event
marker.setPosition(...);
marker.setTitle("....");
position_changed
title_changed
Own property
this.map.addMarker({
position: { lat: 43.0741704, lng: -89.3809802},
count: 0
})
.then((marker: Marker) => {
marker.on(GoogleMapsEvent.MARKER_CLICK).subscribe(() => {
marker.set("count", marker.get("count") + 1);
});�
marker.on("count_changed").subscribe((params: []) => {
let oldValue = params[0];
let newValue = params[1];
let key = params[2];
marker.setTitle("'" + key + "' is changed from '" +� oldValue + "' to '" + newValue + "'");
});�
});
Own property
from v4.8.2 -
let marker: Marker = this.map.addMarkerSync({
position: { lat: 43.0741704, lng: -89.3809802},
count: 0
});
marker.on(GoogleMapsEvent.MARKER_CLICK).subscribe(() => {
marker.set("count", marker.get("count") + 1);
});�
marker.on("count_changed").subscribe((params: []) => {
let oldValue = params[0];
let newValue = params[1];
let key = params[2];
marker.setTitle("'" + key + "' is changed from '" +� oldValue + "' to '" + newValue + "'");
});
noNotify option
let myObj: BaseClass = new BaseClass();
�myObj.on("hello_changed").subscribe((params) => {
console.log(params);
});�
myObj.set("hello", "world", true);
hello_changed
DO NOT
OCCUR
bindTo()
let objA: BaseClass = new BaseClass();
let objB: BaseClass = new BaseClass();�
objA.bindTo("hello", objB, "world");�
objA.set("hello", "こんにちは");
objB.get("world");
objA
objB
hello
world
"こんにちは"
"こんにちは"
sourceObj.bindTo(targetKey, dest, destKey?, noNotify?)
bindTo()
this.map.addMarker({
position: {lat: 43.0741704, lng: -89.3809802},
draggable: true
})
.then((marker: Marker) => {
this.map.addCircle({
center: marker.getPosition(),
radius: 10,
fillColor: "rgba(0, 0, 255, 0.5)",
strokeColor: "rgba(0, 0, 255, 0.75)",
strokeWidth: 1
}).then((circle: Circle) => {
marker.bindTo("position", circle, "center");
});
});
bindTo()
from v4.8.2 -
let marker: Marker = this.map.addMarkerSync({
position: {lat: 43.0741704, lng: -89.3809802},
draggable: true
});
let circle: Circle = this.map.addCircleSync({
center: marker.getPosition(),
radius: 10,
fillColor: "rgba(0, 0, 255, 0.5)",
strokeColor: "rgba(0, 0, 255, 0.75)",
strokeWidth: 1
});
marker.bindTo("position", circle, "center");
trigger()
obj.trigger(eventName, args?...)
createMarkers() {
let bounds = this.map.getVisibleRegion();
let sw = bounds.southwest, ne = bounds.northeast;
let diffY = (ne.lat - sw.lat), diffX = (ne.lng - sw.lng);
for (let i = 0; i < 10; i++) {
this.map.addMarker({
'position': {
'lat': sw.lat + diffY * Math.random(),
'lng': sw.lng + diffX * Math.random()
}
}).then((marker:Marker) => {
this.map.on('animate').subscribe((params: []) => {
let animation: string = params[0];
marker.setAnimation(animation);
});
});
}
}
onButtonClick() {
let btnTxt: string = event.srcElement.innerText;
this.map.trigger("animate", btnTxt);
}
Deep understanding
Internal command queue
Cordova executes all methods in asynchronously!
this.map.addMarker({
…
})
exec("Map", "loadPlugin", "Marker");
map.addMarker()
(native code)
.then((marker:Marker) => {
});
What would be occurred like this code?
this.map.clear();
for (let i = 0; i < positions.length; i++) {
this.map.addMarker({
position: positions[i]
}).then((marker: Marker) => {
this.markers.push(marker);
});
}
map.clear() is slow...
this.map.clear();
for (let i = 0; i < positions.length; i++) {
this.map.addMarker({
position: positions[i]
}).then((marker: Marker) => {
this.markers.push(marker);
});
}
Correct way:
this.map.clear().then(() => {
….
});
Don’t worry, this plugin handles correctly!
this.map.clear();
for (let i = 0; i < positions.length; i++) {
this.map.addMarker({
position: positions[i]
}).then((marker: Marker) => {
this.markers.push(marker);
});
}
Because this plugin has own command queue!
map.clear()
addMarker()
addMarker()
addMarker()
addMarker()
addMarker()
addMarker()
addMarker()
addMarker()
addMarker()
addMarker()
Execute method in synchronous
(Stop all other methods)
addMarker()
addMarker()
addMarker()
addMarker()
addMarker()
addMarker()
addMarker()
addMarker()
addMarker()
addMarker()
Execute 10 methods in parallel at a once
Limit 10 is problem sometimes...
Sorry, there is no solution currently.
synchronous methods
@ionic-native/google-maps� version 4.8.2
Breaking changes are introduced
Add new methods:
this.map.addMarker({
position: {lat: …, lng: …},� title: "Hello world"
}).then((marker:Marker) => {
marker.showInfoWindow();
});
from v4.8.2 -
Used be ...
let marker:Marker = this.map.addMarkerSync({
position: {lat: …, lng: …},� title: "Hello world"
});�
marker.showInfoWindow();
You can still use this syntax code
MAP_READY event
this.map = GoogleMaps.create('map_canvas');�this.map.one(GoogleMapsEvent.MAP_READY).then(() => {� this.map.addMarker({
position: {lat: …, lng: …},� title: "Hello world"
});�});
from v4.8.2 -
Used be ...
this.map = GoogleMaps.create('map_canvas');��let marker:Marker = this.map.addMarkerSync({
position: {lat: …, lng: …},� title: "Hello world"
});�
However, if you use map.getVisibleRegion()...
this.map = GoogleMaps.create('map_canvas');�
let visibleRegion: VisibleRegion = this.map.getVisibleRegion();
console.log(visibleRegion); // == null
You still have to need to wait MAP_READY event for this case!
StreetView panorama
class StreetViewPage {� let panorama: StreetViewPanorama;
ionViewDidLoad() {
this.loadPanorama();
}�� loadPanorama() {
// Create a map after the view is loaded.
// (platform is already ready in app.component.ts)
this.panorama = GoogleMaps.createPanorama('pano_canvas', {
camera: {
target: {lat: 42.345573, lng: -71.098326}
}
});
}
}
BaseArrayClass
@ionic-native/google-maps
BaseArrayClass
forEach()
baseArray.forEach(fn)
0
1
2
3
4
forEach()
let baseArray: BaseArrayClass<ILatLng> = new BaseArrayClass(positions);��baseArray.forEach((position: ILatLng, idx: number) => {�
this.map.addMarker({
position: position
}).then((marker: Marker) => {
this.markers.push(marker);
});�
});
baseArray.forEach(fn)
forEachAsync()
0
1
2
3
4
baseArray.forEachAsync(fn).then()
Async task
(i.e. setTimeout())
forEachAsync()
let baseArray: BaseArrayClass<ILatLng> = new BaseArrayClass(positions);��baseArray.forEachAsync((position: ILatLng, next:() => void) => {�
this.map.addMarker({
position: position
}).then((marker: Marker) => {
this.markers.push(marker);
next();
});�
}.then(() => {
console.log('finish!');
});
baseArray.forEachAsync(fn).then()
map()
0
1
2
3
4
a
b
c
d
e
a
b
c
d
e
baseArray.map(fn)
map()
let baseArray: BaseArrayClass<Marker> = new BaseArrayClass(this.markers);��let titles: [] = baseArray.map((marker: Marker, idx: number) => {�
return marker.getTitle();�
});
baseArray.map(fn)
mapAsync()
0
1
2
3
4
a
b
c
d
e
a
b
c
d
e
Async task
(i.e. setTimeout())
baseArray.mapAsync(fn).then()
mapAsync()
let baseArray: BaseArrayClass<ILatLng> = new BaseArrayClass(positions);��baseArray.mapAsync((position: ILatLng, next: (result: any) => void) => {�
this.map.addMarker({
position: position
}).then(next);�
}).then(markers: Marker[]) => {
console.log('finish!');
});
baseArray.mapAsync(fn).then()
filter()
0
1
2
3
4
true
false
true
false
true
a
c
e
baseArray.filter(fn)
filter()
let baseArray: BaseArrayClass<Marker> = new BaseArrayClass(this.markers);��let matchedMarkers: [] = baseArray.filter((marker: Marker, idx: number) => {�
return marker.get('category') === 'restaurant';�
});
baseArray.filter(fn)
filterAsync()
0
1
2
3
4
true
false
true
false
true
a
c
e
Async task
(i.e. setTimeout())
baseArray.filterAsync(fn).then()
filterAsync()
let baseArray: BaseArrayClass<Marker> = new BaseArrayClass(this.markers);��baseArray.filter((marker: Marker, next: (result: boolean) => void) => {�
// i.e. Get data from remote database
http_request� .get('https://yourserver/getData/', {id: marker.get('dbId')})� .then((locationData: object) => {
// detect later
next(location.category === 'restaurant');� });�
}).then(matchedMarkers: Marker[]) => {
console.log('finish');
});
baseArray.filterAsync(fn).then()
Asynchronous process
push(), pop()
let baseArray: BaseArrayClass = new BaseArrayClass();����baseArray.push('a');��baseArray.push('b');��baseArray.push('c');
�baseArray.pop();
baseArray.pop();�
baseArray.pop();
insert_at event
remove_at event
BaseArrayClass example
let points: ILatLng[] = [
{lat: 33.91636924837674, lng: -118.39605331420898},
{lat: 33.90205144970967, lng: -118.39639663696288},
{lat: 33.90190897196702, lng: -118.37905883789062},
{lat: 33.89471353635718, lng: -118.3787155151367}
];
this.map = this.googleMaps.create('map_canvas', {
camera: {
target: points
}
});
this.map.one(GoogleMapsEvent.MAP_READY).then(() => {
return this.map.addPolyline({
points: points
});
})
//continue to next page...
BaseArrayClass example
.then((polyline: Polyline) => {
let baseArray: BaseArrayClass<ILatLng> = polyline.getPoints();
baseArray.mapAsync((point: ILatLng, next: Function) => {
this.map.addMarker({
position: point,
draggable: true
}).then(next);
}, (markers: Marker[]) => {
markers.forEach((marker: Marker, idx: number) => {
marker.on('position_changed').subscribe((params: []) => {
baseArray.setAt(idx, params[1]);
});
});
// trigger the position_changed event for the first calculation.
markers[0].trigger('position_changed', null, markers[0].getPosition());
});
baseArray.on('set_at', () => {
this._ngZone.run(() => {
let distanceMeter: number = Spherical.computeLength(baseArray);
this.distance = (distanceMeter * 0.000621371192).toFixed(2) + " miles";
});
});
});
polyline.getPoints() returns BaseArrayClass
Calculate the distance
when any markers are dragged
BaseArrayClass example
KML Overlay
@ionic-native/google-maps
KML overlay
this.loading = this.loadingCtrl.create({
content: 'Please wait...'
});
this.loading.present();
this.map.addKmlOverlay({
url: "assets/kmloverlay/polygon.kml"
}).then((kmlOverlay: KmlOverlay) => {
this.loading.dismiss();
console.log(kmlOverlay);
this.map.moveCamera(kmlOverlay.getDefaultViewport());
// You can get additional information
kmlOverlay.on(GoogleMapsEvent.KML_CLICK).subscribe((params: any) => {
let overlay: Polygon = params[0]; // depends on overlay
let latLng: ILatLng = params[1];
console.log(overlay, latLng);
});
});
Fits camera
to view kml overall
LocationService
@ionic-native/google-maps
LocationService
let option: MyLocationOptions = {
// true: use GPS as much as possible (use battery usage alot)
//
// false: use network location or lastKnownLocation
// (save battery usage)
enableHighAccuracy: true
};
LocationService.getMyLocation(option).then((location: MyLocation) => {
this.map = GoogleMaps.create({
'camera': location.latLng,
'zoom': 16
});
...
}).catch((error: any) => {
// Can not get location, permission refused, and so on...
console.log(error);
});
Good example projects
How to use this plugin in real project
Main page + detail page
Special thanks for battika
Use two maps in two pages
There is a map and “Open Second Page” button in home.html.
If you tap on the button, open a detail page using
this.navCtrl.push(SecondPage,{},{animate:false});
In this case, ionic keeps the first page but css visibility = hidden.
The maps plugin can detect this particular case, and detach the main page map automatically.
Then create another map for detail page.
After closing the second page, there is no more div element for the second map. So the maps plugin destroys the second map automatically.
Then the maps plugin attaches the map view to browser automatically, when the main page becomes visibility = visible.
Plugin repository�https://github.com/mapsplugin/cordova-plugin-googlemaps
�
Official documents�https://github.com/ionic-team/ionic-native-google-maps/blob/master/documents/README.md
�Code repository�https://github.com/mapsplugin/ionic-googlemaps-quickdemo
Google Developers Expert of
Google Maps API��Masashi Katsumata
Cordova GoogleMaps plugin author
&