Integrating Multiple Custom Markers with Ionic 2 + Google Maps - google-maps

I've searched the web for hours now and can't seem to find the problem to my seemingly, pretty simple issue.
Simply put, the icon property of google.maps.Marker doesn't seem to do anything when I ionic serve the app, despite everything else working out fine.
In other words, what does Ionic 2 use with the Google Maps Javascript API that allows it to define the icon images for custom markers?
I'll provide all my relevant code here but I have a feeling that it might not be very helpful for a question like this.
With what I know about Ionic 2, I've been able to integrate Google Maps, it's online/offline states, and some default markers into a page on my app.
BTW, my test image files are located in the same folder as google-maps.ts (just doing this for now as I figure out what's happening).
All the code for initializing google maps and creating the addMarker functions are located in this one file (This huge piece of code is placed here just in case, skip the code below to the next snippet to see the most relevant section of it):
src/providers/google-maps.ts
import { Injectable } from '#angular/core';
import { Connectivity } from './connectivity';
import { Geolocation } from 'ionic-native';
/*
Generated class for the GoogleMaps provider.
See https://angular.io/docs/ts/latest/guide/dependency-injection.html
for more info on providers and Angular 2 DI.
*/
declare var google;
#Injectable()
export class GoogleMaps {
mapElement: any;
pleaseConnect: any;
map: any;
mapInitialised: boolean = false;
mapLoaded: any;
mapLoadedObserver: any;
markers: any = [];
apiKey: string;
styles: any;
constructor(public connectivityService: Connectivity) {
}
init(mapElement: any, pleaseConnect: any): Promise<any> {
this.mapElement = mapElement;
this.pleaseConnect = pleaseConnect;
return this.loadGoogleMaps();
}
loadGoogleMaps(): Promise<any> {
return new Promise((resolve) => {
if(typeof google == "undefined" || typeof google.maps == "undefined") {
console.log("Google maps Javascript needs to be loaded");
this.disableMap();
if(this.connectivityService.isOnline()) {
window['mapInit'] = () => {
this.initMap().then(() => {
resolve(true);
});
this.enableMap();
}
let script = document.createElement("script");
script.id = "googleMaps";
if(this.apiKey) {
script.src = 'http://maps.google.com/maps/api/js?key=' + this.apiKey
+ '&callback=mapInit';
} else {
script.src = 'http://maps.google.com/maps/api/js?callback=mapInit';
}
document.body.appendChild(script);
}
}
else {
if(this.connectivityService.isOnline()) {
this.initMap();
this.enableMap();
} else {
this.disableMap();
}
}
this.addConnectivityListeners();
})
}
initMap(): Promise<any> {
this.mapInitialised = true;
return new Promise((resolve) => {
Geolocation.getCurrentPosition().then((position) => {
let latLng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
let mapOptions = {
center: latLng,
zoom: 15,
//mapTypeId: google.maps.MapTypeId.ROADMAP, -Doesn't seem necessary anymore
styles: [
{
"featureType": "poi.business",
"stylers": [
{
"visibility": "off"
}
]
},
{
"featureType": "road",
"elementType": "labels.icon",
"stylers": [
{
"visibility": "off"
}
]
},
{
"featureType": "transit",
"stylers": [
{
"visibility": "off"
}
]
}
]
}
this.map = new google.maps.Map(this.mapElement, mapOptions);
resolve(true);
});
});
}
disableMap(): void {
if(this.pleaseConnect) {
this.pleaseConnect.style.display = "block";
}
}
enableMap(): void {
if(this.pleaseConnect) {
this.pleaseConnect.style.display = "none";
}
}
addConnectivityListeners(): void {
document.addEventListener('online', () => {
console.log("online");
setTimeout(() => {
if(typeof google == "undefined" || typeof google.maps == "undefined") {
this.loadGoogleMaps();
}
else {
if(!this.mapInitialised) {
this.initMap();
}
this.enableMap();
}
},2000);
}, false);
}
//Setting up custom Google Maps markers
//iconBase: any = 'https://maps.google.com/mapfiles/kml/shapes/'; -Probably not necessary
icons: any = {
partner: {
icon: 'partner.png'
},
boughtFrom: {
icon: 'boughtFrom.png'
}
}
addMarker(lat: number, lng: number, feature: any): void {
let latLng = new google.maps.LatLng(lat, lng);
let marker = new google.maps.Marker({
map: this.map,
animation: google.maps.Animation.DROP,
position: latLng,
icon: this.icons[feature].icon
});
this.markers.push(marker);
}
}
The part that isn't working for me is the "icon" assignment in that last "addMarker()" function:
addMarker(lat: number, lng: number, feature: any): void {
let latLng = new google.maps.LatLng(lat, lng);
let marker = new google.maps.Marker({
map: this.map,
animation: google.maps.Animation.DROP,
position: latLng,
icon: this.icons[feature].icon //Doesn't do anything
});
this.markers.push(marker);
}
Currently I'm attempting to also call different types of markers for different locations, but even if I simply replace it with partners.png or { url: 'partners.img' }, it still doesn't recognize anything.
In case this matters, these are also the two test markers I'm using that appear in default style on the map:
src/assets/data/locations.json
{
"locations": [
{
"latitude": 40.79567309999999,
"longitude": -73.97358559999998,
"type": "partner"
},
{
"latitude": 40.8107211,
"longitude": -73.95413259999998,
"type": "boughtFrom"
}
]
}
I'll also include the map page that integrates all this info:
src/pages/home.ts
import { Component, ElementRef, ViewChild } from '#angular/core';
import { Locations } from '../../providers/locations';
import { GoogleMaps } from '../../providers/google-maps';
import { NavController, Platform } from 'ionic-angular';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
#ViewChild('map') mapElement: ElementRef;
#ViewChild('pleaseConnect') pleaseConnect: ElementRef;
constructor(public navCtrl: NavController, public maps: GoogleMaps,
public Platform: Platform, public locations: Locations) {
}
ionViewDidLoad() {
this.Platform.ready().then(() => {
let mapLoaded = this.maps.init(this.mapElement.nativeElement, this.pleaseConnect.nativeElement);
let locationsLoaded = this.locations.load();
Promise.all([
mapLoaded,
locationsLoaded
]).then((result) => {
let locations = result[1];
for(let location of locations) {
this.maps.addMarker(location.latitude, location.longitude, location.type);
}
})
});
}
}
Thank you for your time!
Any and all help is appreciated.

In other words, what does Ionic 2 use with the Google Maps Javascript API that allows it to define the icon images for custom markers?
Nothing. Ionic has no responsibility for this whatsoever.
BTW, my test image files are located in the same folder as google-maps.ts (just doing this for now as I figure out what's happening).
This is the issue. The build process takes typescript files from a place and compiles them in to a single file. In to build www/build/main.js.
These images are not there with the main.js
Move your images to assets folder and give the proper path.
For example:
icon: 'assets/icon1.png'

Related

HTTP google maps Polyline

I have a Ionic App using google maps . I am trying to get latitude and longitude from data json api for flight route then inject that data arrays to Google Maps polyline . Fetch data json api working fine without problem , but when l put objects inside Google Maps l get error
ERROR Error: Uncaught (in promise): TypeError: Cannot use 'in' operator to search for 'getPosition' in 40.11882
TypeError: Cannot use 'in' operator to search for 'getPosition' in 40.11882
at getLatLng (Common.js:544)
at Array.map (<anonymous>)
at Object.convertToPositionArray (Common.js:575)
at Map.addPolyline (Map.js:1231)
at vendor.js:76340
my code
export class HomePage{
map: GoogleMap;
latitude: any;
longitude: any;
dates=[]
constructor(
public toastCtrl: ToastController,
private platform: Platform,
private http: HTTP
) { }
ngOnInit() {
// Since ngOnInit() is executed before `deviceready` event,
// you have to wait the event.
this.platform.ready();
this.getmarker();
this.loadMap();
}
async getmarker(){
this.http.get('/v1/flightjson?flightId=201',{},{})
.then( data=>{
// this.latitude = JSON.parse(data.data).result.response.data.flight.track.latitude
// this.longitude = JSON.parse(data.data).result.response.data.flight.track
for(let datas of JSON.parse(data.data).result.response.data.flight['track']) {
this.longitude = datas.longitude
this.latitude = datas.latitude
console.log(this.longitude, this.latitude)
}
})
}
loadMap() {
let AIR_PORTS = [
this.longitude = datas.longitude
this.latitude = datas.latitude
];
console.log(AIR_PORTS)
this.map = GoogleMaps.create('map_canvas');
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();
});
}
}
console log for AIR_PORTS
my data json url
original code
export class PolylinePage implements OnInit {
map: GoogleMap;
constructor(private platform: Platform) { }
async ngOnInit() {
// Since ngOnInit() is executed before `deviceready` event,
// you have to wait the event.
await this.platform.ready();
await this.loadMap();
}
loadMap() {
let HND_AIR_PORT = {lat: 35.548852, lng: 139.784086};
let SFO_AIR_PORT = {lat: 37.615223, lng: -122.389979};
let HNL_AIR_PORT = {lat: 21.324513, lng: -157.925074};
let AIR_PORTS = [
HND_AIR_PORT,
HNL_AIR_PORT,
SFO_AIR_PORT
];
this.map = GoogleMaps.create('map_canvas', {
camera: {
target: AIR_PORTS
}
});
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();
});
}
}
i think the way you are reading data and passing data to the GoogleMap is incorrect, Please try the following
export class HomePage{
map: GoogleMap;
points: {lng: number, lat: number}[] = [];
constructor(
public toastCtrl: ToastController,
private platform: Platform,
private http: HTTP
) { }
ngOnInit() {
this.platform.ready();
this.getmarker();
this.loadMap();
}
async getmarker(){
this.http.get('/v1/flightjson?flightId=201',{},{})
.then( data=>{
for(let datas of JSON.parse(data.data).result.response.data.flight['track']) {
this.points.push({lng: datas.longitude, lat: datas.latitude});
}
})
}
loadMap() {
let AIR_PORTS = this.points;
console.log(AIR_PORTS)
this.map = GoogleMaps.create('map_canvas');
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();
});
}
}
you can find a working example here which i tried with your data - Example Demo.
And code from here Example Code

Google API to detect location closest to the user from a list of locations

I have a phone app developed in Ionic which supposedly only supports a few stores. What I want to do is to use Cordova Geolocation to fetch the user's current location, and use it to find a store in our support list closest to their location. What would be the best Google API to use for this, Google Maps or Google Places? Also what would be the easiest way for me to achieve this?
Other than finding the store I don't need to use any other map functionality.
Place Search Requests (https://developers.google.com/places/web-service/search#PlaceSearchRequests)
A Nearby Search query
https://maps.googleapis.com/maps/api/place/nearbysearch/json?parameters
Required parameters in above query
key : Your applications API key.
location : The latitude/longitude around which to retrieve place information.
radius : Defines the distance (in meters) within which to return place results
rankby : distance
type : Restricts the results to places matching the specified type. list of supported types (https://developers.google.com/places/web-service/supported_types)
Example
https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=-33.8670522,151.1957362&radius=1500&type=store&key=YOUR_API_KEY
IONIC IMPLIMENTATION
Install the Cordova and Ionic Native plugins
`$ ionic cordova plugin add cordova-plugin-geolocation --variable GEOLOCATION_USAGE_DESCRIPTION="To locate you"`
`$ npm install --save #ionic-native/geolocation`
HTML
<ion-header>
<ion-navbar>
<ion-title>
Google Maps NearBy Search
</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<div #map id="map"></div>
</ion-content>
js
import { Component, ElementRef, ViewChild } from '#angular/core';
import { NavController, Platform } from 'ionic-angular';
import { Geolocation } from '#ionic-native/geolocation';
import { googlemaps } from 'googlemaps';
declare var google;
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
#ViewChild('map') mapElement: ElementRef;
map: any;
latLng: any;
options: any;
infowindow: any;
constructor(private ngZone: NgZone, private geolocation: Geolocation) {}
constructor(
public navCtrl: NavController,
public navParams: NavParams,
public geolocation: Geolocation) {}
ionViewDidLoad() {
this.initMap();
}
initMap() {
this.geolocation.getCurrentPosition().then((resp) => {
this.latLng = new google.maps.LatLng(resp.coords.latitude, resp.coords.longitude);
this.options = {
center: this.latLng,
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
this.map = new google.maps.Map(this.mapElement.nativeElement, this.options);
let service = new google.maps.places.PlacesService(this.map);
service.nearbySearch({
location: this.latLng,
radius: 1000,
type: ['store']
}, (results, status) => {
if (status === google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
this.createMarker(results[i]);
}
}
});
}).catch((error) => {
console.log('Error getting location', error);
});
}
createMarker(place) {
var placeLoc = place.geometry.location;
var marker = new google.maps.Marker({
map: map,
position: placeLoc
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(place.name);
infowindow.open(map, this);
});
}
}

Ionic Google Maps - MapType not assignable

Weird observation with the Ionic/Cordova Google Maps. I want to bring up the map with hybrid maps.
if(!this.map){
// const myMapType: MapType = 'HYBRID';
const mapOptions: GoogleMapOptions = {
// controls: {
// compass: false,
// myLocation: true,
// myLocationButton: false,
// mapToolbar: false,
// },
// mapType: myMapType
};
this.map = GoogleMaps.create('map_canvas', mapOptions);
this.map.setMapTypeId(GoogleMapsMapTypeId.HYBRID);
}
Fails running with Argument of type 'string' not assignable to parameter of type 'MapType'. When I disable that line, the app starts. However, a second edit to enable setMapTypeId with ionic livereload loads the map in hybrid. I do not get it. Am I not preloading something that's set in the initial load and then prevails in the simulator memory so that the second time the error is not triggered?
Running simulator with
ionic cordova run ios --consolelogs --target "iPhone-8"
Should work.
import { GoogleMaps, GoogleMap, GoogleMapsMapTypeId} from '#ionic-native/google-maps';
#IonicPage()
#Component({
selector: 'page-set-map-type-id',
templateUrl: 'set-map-type-id.html',
})
export class ExamplePage {
map: GoogleMap;
constructor() {}
ionViewDidLoad() {
this.loadMap();
}
loadMap() {
this.map = GoogleMaps.create('map_canvas', {
mapType: GoogleMapsMapTypeId.HYBRID
});
}
}

Mapbox missing Gl JS css

My map is not loading and no error is being displayed in the console.
please help.
this is the error screenshot as shown in the browser
there is no build error while compiling the code neither any error is thrown but the ma form mabox is not loading and is written as - Missing mapbox Gl JS CSS
the following is the code snippet for the same
// code for map.component.ts
import { Component, OnInit } from '#angular/core';
import * as mapboxgl from 'mapbox-gl';
import { MapService } from '../map.service';
import { GeoJson, FeatureCollection } from '../map';
#Component({
selector: 'app-map-box',
templateUrl: './map-box.component.html',
styleUrls: ['./map-box.component.css']
})
export class MapBoxComponent implements OnInit{
/// default settings
map: mapboxgl.Map;
style = 'mapbox://styles/kanavmalik10/cjfbjx6fp70fl2snuphc7zjw2';
lat = 37.75;
lng = -122.41;
message = 'Hello World!';
// data
source: any;
markers: any;
constructor(private mapService: MapService) {
}
ngOnInit() {
this.markers = this.mapService.getMarkers()
this.initializeMap()
}
private initializeMap() {
/// locate the user
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(position => {
this.lat = position.coords.latitude;
this.lng = position.coords.longitude;
this.map.flyTo({
center: [this.lng, this.lat]
})
});
}
this.buildMap()
}
buildMap() {
this.map = new mapboxgl.Map({
container: 'map',
style: this.style,
zoom: 13,
center: [this.lng, this.lat]
});
/// Add map controls
this.map.addControl(new mapboxgl.NavigationControl());
//// Add Marker on Click
this.map.on('click', (event) => {
const coordinates = [event.lngLat.lng, event.lngLat.lat]
const newMarker = new GeoJson(coordinates, { message: this.message })
this.mapService.createMarker(newMarker)
})
/// Add realtime firebase data on map load
this.map.on('load', (event) => {
/// register source
this.map.addSource('firebase', {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: []
}
});
/// get source
this.source = this.map.getSource('firebase')
/// subscribe to realtime database and set data source
this.markers.subscribe(markers => {
let data = new FeatureCollection(markers)
this.source.setData(data)
})
/// create map layers with realtime data
this.map.addLayer({
id: 'firebase',
source: 'firebase',
type: 'symbol',
layout: {
'text-field': '{message}',
'text-size': 24,
'text-transform': 'uppercase',
'icon-image': 'rocket-15',
'text-offset': [0, 1.5]
},
paint: {
'text-color': '#f16624',
'text-halo-color': '#fff',
'text-halo-width': 2
}
})
})
}
/// Helpers
removeMarker(marker) {
this.mapService.removeMarker(marker.$key)
}
flyTo(data: GeoJson) {
this.map.flyTo({
center: data.geometry.coordinates
})
}
}
<input type="text" [(ngModel)]="message" placeholder="your message...">
<h1>Markers</h1>
<div *ngFor="let marker of markers | async">
<button (click)="flyTo(marker)">{{ marker.properties.message }}</button>
<button (click)="removeMarker(marker)">Delete</button>
</div>
<div class="map" id="map"></div>
You seed to include the GL JS CSS stylesheet. See the quickstart at https://docs.mapbox.com/mapbox-gl-js/overview/#quickstart
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.45.0/mapbox-gl.css' rel='stylesheet' />

Ionic2 google maps image layer

I am building an Ionic2 app where I am using google maps as an orientation map and I need to put an image layer on top of the map. I am trying to put building layout image over the building complex in Google maps.
I found this solution for javascript here, which is exactly what I need: Google maps js API
I am quite new to Ionic2 and Anglular2 and having no luck figuring it out so far.
Any advice appreciated
My code :
import { Component, ViewChild, ElementRef } from '#angular/core';
import { NavController } from 'ionic-angular';
import { Geolocation } from '#ionic-native/geolocation';
declare var google;
#Component({
selector: 'map',
templateUrl: 'map.html'
})
export class MapPage {
#ViewChild('map') mapElement: ElementRef;
map: any;
lat : any ;
lng : any ;
constructor(public navCtrl: NavController, public geolocation: Geolocation) {
this.getGeoLocation();
}
initializeMap() {
var minZoomLevel = 17;
let mapOptions =
{
zoom: minZoomLevel,
center: new google.maps.LatLng(lat, lng),
mapTypeId: google.maps.MapTypeId.ROADMAP,
}
this.map = new google.maps.Map(this.mapElement.nativeElement, mapOptions);
}
getGeoLocation(){
this.geolocation.getCurrentPosition().then((position) => {
this.lat = position.coords.latitude;
this.lng = position.coords.longitude;
this.initializeMap();
}, (err) => {
console.log(err);
});
}
Well, apparently it was easier than I thought. You just define image boundaries and create an instance of an overlay and then add it to the map like this...
var oldBuilding = {
north: 53.27959,
west: -9.01287,
south: 53.278038,
east: -9.00876
};
this.oldBuildingOverLay = new google.maps.GroundOverlay('../assets/Map.png', oldBuilding);
this.oldBuildingOverLay.setMap(this.map);
Declare oldBuildingOverlay: any; and you're up and running.