SlideShare a Scribd company logo
@ionic-native / google-maps
Cordova GoogleMaps plugin project
Masashi Katsumata
Ionic framework
@ionic-native/google-maps
● Embed native Google Maps view in your app
● One code for both Android and iOS
● Easy to use
● Faster than Google Maps Javascript API v3
● Free to use. Apache License v2
・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 is under the browser!!
touch layer
(native)
Is this on map
or browser?
Pass
the touch event to
the map or browser
Hello world
Google Maps API key
https://console.developers.google.com/projectselector/apis/library
API key
Enable Google Maps APIs
Enable Both APIs
API key
Create credential
Start from here!
API key
Generate an API key
This is the API key
Restrict your key
when you
release your app
API key
Create a project & install plugins
$> ionic start myApp sidemenu
$> npm install @ionic-native/google-maps @ionic-native/core
$> ionic cordova plugin add cordova-plugin-googlemaps
--variable API_KEY_FOR_ANDROID=”.....”
--variable API_KEY_FOR_IOS=”.....”
Please use the
latest version
anytime!
API key Create project
app/src/app.module.ts
Add this line
Add this line
API key Create project
import { BrowserModule } from '@angular/platform-browser';
...
import { GoogleMaps } from "@ionic-native/google-maps";
@NgModule({
....
providers: [
StatusBar,
SplashScreen,
GoogleMaps,
{provide: ErrorHandler, useClass: IonicErrorHandler}
]
})
export class AppModule {}
src/pages/home/home.html
Add a div (map div)
API key Create project HTML & CSS
<ion-content padding>
<h3>Ionic GoogleMaps Starter</h3>
<div id="map_canvas">
<button ion-button (click)="onButtonClick($event)">Start demo</button>
</div>
</ion-content>
src/pages/home/home.scss
page-home {
#map_canvas {
height: 90%;
}
}
Background styles become be transparent
by the maps plugin mandatory!
You can set the background color through
Environment.setBackgroundColor()
API key Create project HTML & CSS
src/app/app.components.ts
API key Create project HTML & CSS Coding
export class MyApp {
@ViewChild(Nav) nav: Nav;
rootPage: any;
constructor(public platform: Platform, public statusBar: StatusBar, public splashScreen: SplashScreen) {
this.initializeApp();
}
initializeApp() {
this.platform.ready().then(() => {
this.rootPage = HomePage;
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
this.statusBar.styleDefault();
this.splashScreen.hide();
});
}
Set the first page
after the platform.read() is called
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/pages/home/home.ts
API key Create project HTML & CSS Coding
import { GoogleMaps, GoogleMap, GoogleMapsEvent } from '@ionic-native/google-maps';
export class HomePage {
map: GoogleMap;
constructor( public navCtrl: NavController, private googleMaps: GoogleMaps ) { }
ionViewDidLoad() {
this.loadMap();
}
src/pages/home/home.ts
loadMap() {
// Create a map after the view is ready and the native platform is ready.
this.map = this.googleMaps.create('map_canvas');
// Wait the maps plugin is ready until the MAP_READY event
this.map.one(GoogleMapsEvent.MAP_READY).then(() => {
console.log('map is ready to use.');
});
}
API key Create project HTML & CSS Coding
Run it!!
$> ionic cordova run android
API key Create project HTML & CSS Coding Run it!
Marker
@ionic-native/google-maps
Add a marker
this.map.addMarker({
title: 'Ionic',
icon: 'blue',
animation: 'DROP',
position: {
lat: 43.0741904,
lng: -89.3809802
}
}).then((marker: Marker) => {
marker.showInfoWindow();
});
icon property
this.map.addMarker({
title: 'Ionic',
icon: 'blue',
animation: 'DROP',
position: {
lat: 43.0741904,
lng: -89.3809802
}
}).then((marker: Marker) => {
marker.showInfoWindow();
});
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
● MARKER_CLICK
● MARKER_DRAG_START
● MARKER_DRAG
● MARKER_DRAG_END
● INFO_CLICK
● INFO_LONG_CLICK
● INFO_OPEN
● INFO_CLOSE
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)
Polygon
@ionic-native/google-maps
Polygon
Just pass ILatLng[]
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) => {
...
});
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 =
this.spherical.computeDistanceBetween(center, newValue);
circle.setRadius(newRadius);
});
});
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');
});
});
TileOverlay
@ionic-native/google-maps
TileOverlay
You can generate various URL
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
});
HtmlInfoWindow
@ionic-native/google-maps
HtmlInfoWindow
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);
});
});
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();
});
});
Geocoding
@ionic-native/google-maps
Geocoding
Geocoding for one address
// Address -> latitude,longitude
this.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!
this.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()
● get()
● bindTo()
● trigger()
● on() / addEventListener()
● one() / addEventListenerOnce()
● off()
● empty()
● destroy()
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 + "'");
});
});
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");
});
});
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
All methods are executed in asynchronously!
this.map.addMarker({
…
})
exec("Map", "loadPlugin",
"Marker");
map.addMarker()
(native code)
.then((marker:Marker) =>
{
});
adding Marker after map.clear()
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...
Correct way:
this.map.clear().then(() => {
….
});
this.map.clear();
for (let i = 0; i < positions.length; i++) {
this.map.addMarker({
position: positions[i]
}).then((marker: Marker) => {
this.markers.push(marker);
});
}
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
● googleMaps.create()
● map.setCameraZoom()
● map.panBy()
● map.clear()
● map.setCameraTilt()
● map.setCameraBearing()
● map.moveCameraZoomIn()
● map.moveCameraZoomOut()
● map.animateCameraZoomIn()
● map.animateCameraZoomOut()
● map.animateCamera()
● map.moveCamera()
● map.setMyLocationEnabled()
● map.getMyLocation()
● map.remove()
● map.setDiv()
BaseArrayClass
@ionic-native/google-maps
BaseArrayClass
● insertAt()
● getArray()
● getAt()
● setAt()
● removeAt()
● getLength()
● reverse()
● sort()
● indexOf()
● empty()
● push()
● pop()
● map()
● mapAsync()
● forEach()
● forEachAsync()
● filter()
● filterAsync()
forEach() baseArray.forEach(fn)
0 1 2 3 4
forEach() baseArray.forEach(fn)
let baseArray: BaseArrayClass<ILatLng> = new BaseArrayClass(positions);
baseArray.forEach((position: ILatLng, idx: number) => {
this.map.addMarker({
position: positions[i]
}).then((marker: Marker) => {
this.markers.push(marker);
});
});
forEachAsync()
0 1 2 3 4
baseArray.forEachAsync(fn).then()
Async task
(i.e. setTimeout())
forEachAsync() baseArray.forEachAsync(fn).then()
let baseArray: BaseArrayClass<ILatLng> = new BaseArrayClass(positions);
baseArray.forEachAsync((position: ILatLng, next:() => void) => {
this.map.addMarker({
position: positions[i]
}).then((marker: Marker) => {
this.markers.push(marker);
next();
});
}.then(() => {
console.log('finish!');
});
0 1 2 3 4
a b c d e
a b c d e
map() baseArray.map(fn)
let baseArray: BaseArrayClass<Marker> = new BaseArrayClass(this.markers);
let titles: [] = baseArray.map((position: ILatLng, idx: number) => {
return this.markers[idx].getTitle();
});
map() baseArray.map(fn)
0 1 2 3 4
a b c d e
a b c d e
Async task
(i.e. setTimeout())
mapAsync() baseArray.mapAsync(fn).then()
let baseArray: BaseArrayClass<ILatLng> = new BaseArrayClass(positions);
baseArray.mapAsync((position: ILatLng, next: (result: any) => void) => {
this.map.addMarker({
position: positions[i]
}).then(next);
}).then(markers: Marker[]) => {
console.log('finish!');
});
mapAsync() baseArray.mapAsync(fn).then()
0 1 2 3 4
true false true false true
a c e
filter() baseArray.filter(fn)
filter() baseArray.filter(fn)
let baseArray: BaseArrayClass<Marker> = new BaseArrayClass(this.markers);
let matchedMarkers: [] = baseArray.filter((marker: Marker, idx: number) => {
return marker.get('category') === 'restaurant';
});
0 1 2 3 4
true false true false true
a c e
Async task
(i.e. setTimeout())
filterAsync() baseArray.filterAsync(fn).then()
filterAsync() baseArray.filterAsync(fn).then()
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');
});
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 = this.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
Plugin repository
https://github.com/mapsplugin/
cordova-plugin-googlemaps
Official documents
https://github.com/mapsplugin/cord
ova-plugin-googlemaps-doc
Code repository
https://github.com/mapsplugin/ionic-
googlemaps-quickdemo
Google Developers Expert of
Google Maps API
Masashi Katsumata
Cordova GoogleMaps plugin
author
&

More Related Content

Similar to @Ionic native/google-maps

Android Development w/ ArcGIS Server - Esri Dev Meetup - Charlotte, NC
Android Development w/ ArcGIS Server - Esri Dev Meetup - Charlotte, NCAndroid Development w/ ArcGIS Server - Esri Dev Meetup - Charlotte, NC
Android Development w/ ArcGIS Server - Esri Dev Meetup - Charlotte, NCJim Tochterman
 
mobl
moblmobl
mobl
zefhemel
 
The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]
Nilhcem
 
Google Maps API 101
Google Maps API 101Google Maps API 101
Google Maps API 101
Sebastian Roming
 
GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspec...
GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspec...GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspec...
GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspec...
mharkus
 
Android L08 - Google Maps and Utilities
Android L08 - Google Maps and UtilitiesAndroid L08 - Google Maps and Utilities
Android L08 - Google Maps and Utilities
Mohammad Shaker
 
GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...
GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...
GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...
Bruno Salvatore Belluccia
 
Mobile App Development: Primi passi con NativeScript e Angular 2
Mobile App Development: Primi passi con NativeScript e Angular 2Mobile App Development: Primi passi con NativeScript e Angular 2
Mobile App Development: Primi passi con NativeScript e Angular 2
Filippo Matteo Riggio
 
Android MapView and MapActivity
Android MapView and MapActivityAndroid MapView and MapActivity
Android MapView and MapActivityAhsanul Karim
 
Developing AIR for Android with Flash Professional
Developing AIR for Android with Flash ProfessionalDeveloping AIR for Android with Flash Professional
Developing AIR for Android with Flash Professional
Chris Griffith
 
Android 3
Android 3Android 3
Android 3
Robert Cooper
 
The Glass Class - Tutorial 4 - GDK-Live Cards
The Glass Class - Tutorial 4 - GDK-Live CardsThe Glass Class - Tutorial 4 - GDK-Live Cards
The Glass Class - Tutorial 4 - GDK-Live Cards
Gun Lee
 
Google Maps JS API
Google Maps JS APIGoogle Maps JS API
Google Maps JS API
Alberto Simões
 
Android classes in mumbai
Android classes in mumbaiAndroid classes in mumbai
Android classes in mumbai
Vibrant Technologies & Computers
 
A tech writer, a map, and an app
A tech writer, a map, and an appA tech writer, a map, and an app
A tech writer, a map, and an app
Sarah Maddox
 
21 android2 updated
21 android2 updated21 android2 updated
21 android2 updated
GhanaGTUG
 
The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]
Nilhcem
 
22Flutter.pdf
22Flutter.pdf22Flutter.pdf
22Flutter.pdf
dbaman
 
Google Developer Day 2010 Japan: Android や iPhone で活用する Maps API のモバイル端末向け新機能...
Google Developer Day 2010 Japan: Android や iPhone で活用する Maps API のモバイル端末向け新機能...Google Developer Day 2010 Japan: Android や iPhone で活用する Maps API のモバイル端末向け新機能...
Google Developer Day 2010 Japan: Android や iPhone で活用する Maps API のモバイル端末向け新機能...
Google Developer Relations Team
 
Java Applet and Graphics
Java Applet and GraphicsJava Applet and Graphics
Java Applet and Graphics
OXUS 20
 

Similar to @Ionic native/google-maps (20)

Android Development w/ ArcGIS Server - Esri Dev Meetup - Charlotte, NC
Android Development w/ ArcGIS Server - Esri Dev Meetup - Charlotte, NCAndroid Development w/ ArcGIS Server - Esri Dev Meetup - Charlotte, NC
Android Development w/ ArcGIS Server - Esri Dev Meetup - Charlotte, NC
 
mobl
moblmobl
mobl
 
The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]
 
Google Maps API 101
Google Maps API 101Google Maps API 101
Google Maps API 101
 
GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspec...
GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspec...GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspec...
GDG GeorgeTown Devfest 2014 Presentation: Android Wear: A Developer's Perspec...
 
Android L08 - Google Maps and Utilities
Android L08 - Google Maps and UtilitiesAndroid L08 - Google Maps and Utilities
Android L08 - Google Maps and Utilities
 
GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...
GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...
GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...
 
Mobile App Development: Primi passi con NativeScript e Angular 2
Mobile App Development: Primi passi con NativeScript e Angular 2Mobile App Development: Primi passi con NativeScript e Angular 2
Mobile App Development: Primi passi con NativeScript e Angular 2
 
Android MapView and MapActivity
Android MapView and MapActivityAndroid MapView and MapActivity
Android MapView and MapActivity
 
Developing AIR for Android with Flash Professional
Developing AIR for Android with Flash ProfessionalDeveloping AIR for Android with Flash Professional
Developing AIR for Android with Flash Professional
 
Android 3
Android 3Android 3
Android 3
 
The Glass Class - Tutorial 4 - GDK-Live Cards
The Glass Class - Tutorial 4 - GDK-Live CardsThe Glass Class - Tutorial 4 - GDK-Live Cards
The Glass Class - Tutorial 4 - GDK-Live Cards
 
Google Maps JS API
Google Maps JS APIGoogle Maps JS API
Google Maps JS API
 
Android classes in mumbai
Android classes in mumbaiAndroid classes in mumbai
Android classes in mumbai
 
A tech writer, a map, and an app
A tech writer, a map, and an appA tech writer, a map, and an app
A tech writer, a map, and an app
 
21 android2 updated
21 android2 updated21 android2 updated
21 android2 updated
 
The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]
 
22Flutter.pdf
22Flutter.pdf22Flutter.pdf
22Flutter.pdf
 
Google Developer Day 2010 Japan: Android や iPhone で活用する Maps API のモバイル端末向け新機能...
Google Developer Day 2010 Japan: Android や iPhone で活用する Maps API のモバイル端末向け新機能...Google Developer Day 2010 Japan: Android や iPhone で活用する Maps API のモバイル端末向け新機能...
Google Developer Day 2010 Japan: Android や iPhone で活用する Maps API のモバイル端末向け新機能...
 
Java Applet and Graphics
Java Applet and GraphicsJava Applet and Graphics
Java Applet and Graphics
 

Recently uploaded

When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
Elena Simperl
 
Welocme to ViralQR, your best QR code generator.
Welocme to ViralQR, your best QR code generator.Welocme to ViralQR, your best QR code generator.
Welocme to ViralQR, your best QR code generator.
ViralQR
 
Free Complete Python - A step towards Data Science
Free Complete Python - A step towards Data ScienceFree Complete Python - A step towards Data Science
Free Complete Python - A step towards Data Science
RinaMondal9
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
91mobiles
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
Sri Ambati
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Jemma Hussein Allen
 
Quantum Computing: Current Landscape and the Future Role of APIs
Quantum Computing: Current Landscape and the Future Role of APIsQuantum Computing: Current Landscape and the Future Role of APIs
Quantum Computing: Current Landscape and the Future Role of APIs
Vlad Stirbu
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Paige Cruz
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Ramesh Iyer
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
Product School
 
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to ProductionGenerative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Aggregage
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
Safe Software
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Albert Hoitingh
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Product School
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
Dorra BARTAGUIZ
 

Recently uploaded (20)

When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
 
Welocme to ViralQR, your best QR code generator.
Welocme to ViralQR, your best QR code generator.Welocme to ViralQR, your best QR code generator.
Welocme to ViralQR, your best QR code generator.
 
Free Complete Python - A step towards Data Science
Free Complete Python - A step towards Data ScienceFree Complete Python - A step towards Data Science
Free Complete Python - A step towards Data Science
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
 
Quantum Computing: Current Landscape and the Future Role of APIs
Quantum Computing: Current Landscape and the Future Role of APIsQuantum Computing: Current Landscape and the Future Role of APIs
Quantum Computing: Current Landscape and the Future Role of APIs
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to ProductionGenerative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to Production
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
 

@Ionic native/google-maps

  • 1. @ionic-native / google-maps Cordova GoogleMaps plugin project Masashi Katsumata
  • 3. @ionic-native/google-maps ● Embed native Google Maps view in your app ● One code for both Android and iOS ● Easy to use ● Faster than Google Maps Javascript API v3 ● Free to use. Apache License v2
  • 4. ・UI components ・View management ・TypeScript -> JS ...etc Your code run on this browser view Bridge between native system and your code!
  • 7. The Map is touchable The side menu is touchable!! The Map is not touchable!
  • 8. Google Map is under the browser!!
  • 9. touch layer (native) Is this on map or browser? Pass the touch event to the map or browser
  • 11. Google Maps API key https://console.developers.google.com/projectselector/apis/library API key
  • 12. Enable Google Maps APIs Enable Both APIs API key
  • 14. Generate an API key This is the API key Restrict your key when you release your app API key
  • 15. Create a project & install plugins $> ionic start myApp sidemenu $> npm install @ionic-native/google-maps @ionic-native/core $> ionic cordova plugin add cordova-plugin-googlemaps --variable API_KEY_FOR_ANDROID=”.....” --variable API_KEY_FOR_IOS=”.....” Please use the latest version anytime! API key Create project
  • 16. app/src/app.module.ts Add this line Add this line API key Create project import { BrowserModule } from '@angular/platform-browser'; ... import { GoogleMaps } from "@ionic-native/google-maps"; @NgModule({ .... providers: [ StatusBar, SplashScreen, GoogleMaps, {provide: ErrorHandler, useClass: IonicErrorHandler} ] }) export class AppModule {}
  • 17. src/pages/home/home.html Add a div (map div) API key Create project HTML & CSS <ion-content padding> <h3>Ionic GoogleMaps Starter</h3> <div id="map_canvas"> <button ion-button (click)="onButtonClick($event)">Start demo</button> </div> </ion-content>
  • 18. src/pages/home/home.scss page-home { #map_canvas { height: 90%; } } Background styles become be transparent by the maps plugin mandatory! You can set the background color through Environment.setBackgroundColor() API key Create project HTML & CSS
  • 19. src/app/app.components.ts API key Create project HTML & CSS Coding export class MyApp { @ViewChild(Nav) nav: Nav; rootPage: any; constructor(public platform: Platform, public statusBar: StatusBar, public splashScreen: SplashScreen) { this.initializeApp(); } initializeApp() { this.platform.ready().then(() => { this.rootPage = HomePage; // Okay, so the platform is ready and our plugins are available. // Here you can do any higher level native things you might need. this.statusBar.styleDefault(); this.splashScreen.hide(); }); } Set the first page after the platform.read() is called
  • 20. 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
  • 21. src/pages/home/home.ts API key Create project HTML & CSS Coding import { GoogleMaps, GoogleMap, GoogleMapsEvent } from '@ionic-native/google-maps'; export class HomePage { map: GoogleMap; constructor( public navCtrl: NavController, private googleMaps: GoogleMaps ) { } ionViewDidLoad() { this.loadMap(); }
  • 22. src/pages/home/home.ts loadMap() { // Create a map after the view is ready and the native platform is ready. this.map = this.googleMaps.create('map_canvas'); // Wait the maps plugin is ready until the MAP_READY event this.map.one(GoogleMapsEvent.MAP_READY).then(() => { console.log('map is ready to use.'); }); } API key Create project HTML & CSS Coding
  • 23. Run it!! $> ionic cordova run android API key Create project HTML & CSS Coding Run it!
  • 25. Add a marker this.map.addMarker({ title: 'Ionic', icon: 'blue', animation: 'DROP', position: { lat: 43.0741904, lng: -89.3809802 } }).then((marker: Marker) => { marker.showInfoWindow(); });
  • 26. icon property this.map.addMarker({ title: 'Ionic', icon: 'blue', animation: 'DROP', position: { lat: 43.0741904, lng: -89.3809802 } }).then((marker: Marker) => { marker.showInfoWindow(); }); 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 : :
  • 27. 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" } ]);
  • 28. Marker events ● MARKER_CLICK ● MARKER_DRAG_START ● MARKER_DRAG ● MARKER_DRAG_END ● INFO_CLICK ● INFO_LONG_CLICK ● INFO_OPEN ● INFO_CLOSE
  • 29. 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();
  • 30. 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();
  • 31. 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"); }); }
  • 33. 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)
  • 35. Polygon Just pass ILatLng[] 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) => { ... });
  • 37. 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 = this.spherical.computeDistanceBetween(center, newValue); circle.setRadius(newRadius); }); });
  • 39. 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'); }); });
  • 41. TileOverlay You can generate various URL 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 });
  • 43. HtmlInfoWindow 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); }); });
  • 45. 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(); }); });
  • 47. Geocoding Geocoding for one address // Address -> latitude,longitude this.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(...)
  • 48. Batch geocoding Pass locations as array Get a mvc array first, then `finish` event is notified. Just 1.9 sec! this.geocoder.geocode({ // US Capital cities "address": [ "Montgomery, AL, USA", "Juneau, AK, USA", ... "Madison, WI, USA", "Cheyenne, Wyoming, USA" ] }) .then((mvcArray: BaseArrayClass<GeocoderResult[]>) => { });
  • 50. All classes extend Base class BaseClass BaseArrayClass Marker Circle Polyline Polygon GroundOverlay TileOverlay MarkerCluster Map
  • 51. BaseClass ● set() ● get() ● bindTo() ● trigger() ● on() / addEventListener() ● one() / addEventListenerOnce() ● off() ● empty() ● destroy()
  • 52. 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"));
  • 53. (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
  • 55. 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 + "'"); }); });
  • 56. 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
  • 57. 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?)
  • 58. 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"); }); });
  • 59. 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); }
  • 61. All methods are executed in asynchronously! this.map.addMarker({ … }) exec("Map", "loadPlugin", "Marker"); map.addMarker() (native code) .then((marker:Marker) => { });
  • 62. adding Marker after map.clear() this.map.clear(); for (let i = 0; i < positions.length; i++) { this.map.addMarker({ position: positions[i] }).then((marker: Marker) => { this.markers.push(marker); }); }
  • 63. map.clear() is slow... Correct way: this.map.clear().then(() => { …. }); this.map.clear(); for (let i = 0; i < positions.length; i++) { this.map.addMarker({ position: positions[i] }).then((marker: Marker) => { this.markers.push(marker); }); }
  • 64. 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
  • 65. Limit 10 is problem sometimes... Sorry, there is no solution currently.
  • 66. synchronous methods ● googleMaps.create() ● map.setCameraZoom() ● map.panBy() ● map.clear() ● map.setCameraTilt() ● map.setCameraBearing() ● map.moveCameraZoomIn() ● map.moveCameraZoomOut() ● map.animateCameraZoomIn() ● map.animateCameraZoomOut() ● map.animateCamera() ● map.moveCamera() ● map.setMyLocationEnabled() ● map.getMyLocation() ● map.remove() ● map.setDiv()
  • 68. BaseArrayClass ● insertAt() ● getArray() ● getAt() ● setAt() ● removeAt() ● getLength() ● reverse() ● sort() ● indexOf() ● empty() ● push() ● pop() ● map() ● mapAsync() ● forEach() ● forEachAsync() ● filter() ● filterAsync()
  • 70. forEach() baseArray.forEach(fn) let baseArray: BaseArrayClass<ILatLng> = new BaseArrayClass(positions); baseArray.forEach((position: ILatLng, idx: number) => { this.map.addMarker({ position: positions[i] }).then((marker: Marker) => { this.markers.push(marker); }); });
  • 71. forEachAsync() 0 1 2 3 4 baseArray.forEachAsync(fn).then() Async task (i.e. setTimeout())
  • 72. forEachAsync() baseArray.forEachAsync(fn).then() let baseArray: BaseArrayClass<ILatLng> = new BaseArrayClass(positions); baseArray.forEachAsync((position: ILatLng, next:() => void) => { this.map.addMarker({ position: positions[i] }).then((marker: Marker) => { this.markers.push(marker); next(); }); }.then(() => { console.log('finish!'); });
  • 73. 0 1 2 3 4 a b c d e a b c d e map() baseArray.map(fn)
  • 74. let baseArray: BaseArrayClass<Marker> = new BaseArrayClass(this.markers); let titles: [] = baseArray.map((position: ILatLng, idx: number) => { return this.markers[idx].getTitle(); }); map() baseArray.map(fn)
  • 75. 0 1 2 3 4 a b c d e a b c d e Async task (i.e. setTimeout()) mapAsync() baseArray.mapAsync(fn).then()
  • 76. let baseArray: BaseArrayClass<ILatLng> = new BaseArrayClass(positions); baseArray.mapAsync((position: ILatLng, next: (result: any) => void) => { this.map.addMarker({ position: positions[i] }).then(next); }).then(markers: Marker[]) => { console.log('finish!'); }); mapAsync() baseArray.mapAsync(fn).then()
  • 77. 0 1 2 3 4 true false true false true a c e filter() baseArray.filter(fn)
  • 78. filter() baseArray.filter(fn) let baseArray: BaseArrayClass<Marker> = new BaseArrayClass(this.markers); let matchedMarkers: [] = baseArray.filter((marker: Marker, idx: number) => { return marker.get('category') === 'restaurant'; });
  • 79. 0 1 2 3 4 true false true false true a c e Async task (i.e. setTimeout()) filterAsync() baseArray.filterAsync(fn).then()
  • 80. filterAsync() baseArray.filterAsync(fn).then() 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'); }); Asynchronous process
  • 81. 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
  • 82. 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...
  • 83. 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 = this.spherical.computeLength(baseArray); this.distance = (distanceMeter * 0.000621371192).toFixed(2) + " miles"; }); }); }); polyline.getPoints() returns BaseArrayClass Calculate the distance when any markers are dragged
  • 85. Plugin repository https://github.com/mapsplugin/ cordova-plugin-googlemaps Official documents https://github.com/mapsplugin/cord ova-plugin-googlemaps-doc Code repository https://github.com/mapsplugin/ionic- googlemaps-quickdemo Google Developers Expert of Google Maps API Masashi Katsumata Cordova GoogleMaps plugin author &