Initializing Google Maps inside component but inside certain element - google-maps

I using this tutorial to use Google maps API https://markus.oberlehner.net/blog/using-the-google-maps-api-with-vue/ and it is working well. But it use this.$el to load the Google map instance inside the component and that makes take all screen, I want to load inside .map instead so I can have smaller map.
<template>
<div class="container-fluid">
init map
<div class="map">
</div>
</div>
</template>
<script>
import ProgressSpinner from '.././Preloader';
import { mapGetters } from 'vuex'
import gmapsInit from '../.././utils/gmaps';
export default {
name: 'Tracking',
data: () => ({
}),
async mounted() {
$('.container-fluid').bootstrapMaterialDesign();
try {
const google = await gmapsInit();
const geocoder = new google.maps.Geocoder();
const map = new google.maps.Map(this.$el);
geocoder.geocode({ address: 'Austria' }, (results, status) => {
if (status !== 'OK' || !results[0]) {
throw new Error(status);
}
map.setCenter(results[0].geometry.location);
map.fitBounds(results[0].geometry.viewport);
});
} catch (error) {
console.error('Error with calling Google maps API: ',error);
}
},
computed: {
...mapGetters([])
},
created(){
this.$store.dispatch ('allPoints')
.then(()=> console.log('points'))
.catch( () => console.log('no poiints ') )
},
methods: {
},
components: {
ProgressSpinner
}
}
</script>
<style scoped>
.map {
width: 150px;
}
</style>

The problem with style, so I should have added height to the .map element.

Related

Use map instance outside onLoad in react-google-maps

I am trying to use places library, It requires map instance to call the library but map instance is only available inside onLoad, I am trying to use the places library whenever the center change(inside onCenterChange).
import React, { useEffect, useState, useCallback } from 'react';
import { GoogleMap, useJsApiLoader } from '#react-google-maps/api';
import GoogleMapReact from 'google-map-react';
import List from './List'
export default function Nearby(){
const { isLoaded, loadError } = useJsApiLoader({
googleMapsApiKey: "My_Key"
})
const onLoad = useCallback(
function onLoad (map) {
var loc= new window.google.maps.LatLng(6.9270786, 79.861243);
var request = {
location: loc,
radius: '500',
type: ['hospital'],
};
function callback(results, status) {
if (status === window.google.maps.places.PlacesServiceStatus.OK) {
console.log(results)
}
}
let service = new window.google.maps.places.PlacesService(map);
service.nearbySearch(request,callback)
}
)
function onCenterChanged(){
//Need to use service.nearbySearch(request,callback) here
}
return(
<div className='map-container'>
<div className = 'google-map'>
<GoogleMap mapContainerStyle={{ height: '91vh', width: '75vw' }}
zoom={14}
onLoad={onLoad}
center= { currentPos}
onCenterChanged={onCenterChanged()}
>
</GoogleMap>
</div>
</div>
)
}

google is not defined when using vue2-google-maps

I am using Nuxt and vue2-google-maps but I do have the following error
module error: google is not defined
I read the official GitHub FAQ, so I used this.$gmapApiPromiseLazy().then().
But, I do have the aforementioned error.
getCurrentPositionandBathroom method is to get current position and search for convenience store around current position.
<template>
<v-app>
<v-btn class="blue white--text" #click="getCurrentPositionandBathroom"> search for bathroom! </v-btn>
<GmapMap
ref="mapRef"
:center="maplocation"
:zoom="15"
map-type-id="roadmap"
style="height: 300px; width: 900px"
>
<GmapMarker
v-for="m in markers"
:key="m.id"
:position="m.position"
:clickable="true"
:draggable="true"
:icon="m.icon"
#click="center = m.position"
/>
</GmapMap>
</v-app>
</template>
<script>
export default {
data() {
return {
maplocation: { lat: 35.6814366, lng: 139.767157 },
markers: [],
}
},
methods: {
getCurrentPositionandBathroom() {
if (process.client) {
if (!navigator.geolocation) {
alert('Japanese sentences')
return
}
navigator.geolocation.getCurrentPosition(this.success, this.error)
}
},
success(position) {
this.maplocation.lat = position.coords.latitude
this.maplocation.lng = position.coords.longitude
this.$gmapApiPromiseLazy().then(() => {
google.maps.event.addListenerOnce(
this.$refs.mapRef.$mapObject,
'idle',
function () {
this.getBathroom()
}.bind(this),
)
})
},
getBathroom() {
const map = this.$refs.mapRef.$mapObject
const placeService = new google.maps.places.PlacesService(map)
placeService.nearbySearch(
{
location: new google.maps.LatLng(this.maplocation.lat, this.maplocation.lng),
radius: 500,
type: ['convenience_store'],
},
function (results, status) {
if (status === google.maps.places.PlacesServiceStatus.OK) {
results.forEach((place) => {
const icon = {
url: place.icon,
scaledSize: new google.maps.Size(30, 30),
}
const marker = {
position: place.geometry.location,
icon,
title: place.name,
id: place.place_id,
}
this.markers.push(marker)
})
}
}.bind(this),
)
},
error(errorMessage) {
switch (errorMessage.code) {
case 1:
alert('Japanese sentences')
break
case 2:
alert('Japanese sentences')
break
case 3:
alert('Japanese sentences')
break
default:
alert('Japanese sentences')
break
}
},
},
}
</script>
What I should I do?
PS: I can see the Google Maps. In other words, Google Maps is displayed.
Alright, so there was quite a few configuration to do but I achieved to have a working map. Your this.getBathroom() method was not working for me, but this is related to the API or how you handle the logic I guess.
I basically followed the package README and it all went smooth at the end. Nothing special and google is available as explained in the following section:
If you need to gain access to the google object
Here is the final code of the .vue file
<template>
<div>
<button class="blue white--text" #click="getCurrentPositionandBathroom">
search for bathroom!
</button>
<GmapMap
ref="mapRef"
:center="maplocation"
:zoom="15"
map-type-id="roadmap"
style="height: 300px; width: 900px"
>
<GmapMarker
v-for="m in markers"
:key="m.id"
:position="m.position"
:clickable="true"
:draggable="true"
:icon="m.icon"
#click="center = m.position"
/>
</GmapMap>
</div>
</template>
<script>
import { gmapApi } from 'vue2-google-maps'
export default {
data() {
return {
maplocation: { lat: 35.6814366, lng: 139.767157 },
markers: [],
}
},
computed: {
google: gmapApi,
},
methods: {
getCurrentPositionandBathroom() {
if (process.client) {
if (!navigator.geolocation) {
alert('Japanese sentences')
return
}
navigator.geolocation.getCurrentPosition(this.success, this.error)
}
},
success(position) {
this.maplocation.lat = position.coords.latitude
this.maplocation.lng = position.coords.longitude
// this.$gmapApiPromiseLazy().then(() => { // not needed here anymore
this.google.maps.event.addListenerOnce(
this.$refs.mapRef.$mapObject,
'idle',
function () {
this.getBathroom()
}.bind(this)
)
// })
},
getBathroom() {
const map = this.$refs.mapRef.$mapObject
const placeService = new this.google.maps.places.PlacesService(map)
placeService.nearbySearch(
{
location: new this.google.maps.LatLng(
this.maplocation.lat,
this.maplocation.lng
),
radius: 500,
type: ['convenience_store'],
},
function (results, status) {
if (status === this.google.maps.places.PlacesServiceStatus.OK) {
results.forEach((place) => {
const icon = {
url: place.icon,
scaledSize: new this.google.maps.Size(30, 30),
}
const marker = {
position: place.geometry.location,
icon,
title: place.name,
id: place.place_id,
}
this.markers.push(marker)
})
}
}.bind(this)
)
},
error(errorMessage) {
switch (errorMessage.code) {
case 1:
alert('Japanese sentences')
break
case 2:
alert('Japanese sentences')
break
case 3:
alert('Japanese sentences')
break
default:
alert('Japanese sentences')
break
}
},
},
}
</script>
You can find the useful commit on my github repo here.
This is how it looks at the end, no errors so far.
PS: I didn't saw that you were using Vuetify, so I didn't bother bringing it back later on.

Async displaying markers with React-Google-Maps and Redux

I'm trying to render markers on a Google map from a React-Redux state but I'm getting the errors "Cannot read property 'map' of undefined" and "Cannot read property '_currentElement' of null"
Here's my component:
class Map extends Component {
constructor() {
super()
this.state = {}
}
componentDidMount() {
APIManager.get('/api/hike', null, (err, response) => {
if (err) {
return
}
this.props.hikesReceived(response.results)
})
}
componentDidUpdate() {
console.log('updated list of hikes ' + JSON.stringify(this.props.hikes))
}
render() {
const hikes = this.props.hikes.map((hike, i) => {
const hikeMarker = {
latlng: {
lat: hike.location.lat,
lng: hike.location.lng
}
}
return <Markey key={i} {...hikeMarker} />
})
return (
<GoogleMapLoader
containerElement = { this.props.mapContainer }
googleMapElement = {
<GoogleMap
defaultZoom={10}
defaultCenter={this.props.center}
options={{streetViewControl: false, mapTypeControl: false}}
onClick={this.addMarker.bind(this)} >
<Marker {...hikeMarker}/>
</GoogleMap>
} />
)
}
}
const stateToProps = (state) => {
return {
hikes: state.hike.list,
}
}
const dispatchToProps = (dispatch) => {
return {
hikesReceived: (hikes) => dispatch(actions.hikesReceived(hikes)),
}
}
export default connect(stateToProps, dispatchToProps)(Map)
I know it's an async problem because the console.log() happens twice. The first time it's empty and the second time it renders with the data. The markers also display with no error when I'm using dummy data.
How do I go about telling the map to wait to render, or re-render, once there is data in this.props?
Half of the problem was names changing in the database. The other half was solved with:
if (this.props.hikes == null || undefined) {return: false}

Integrating Multiple Custom Markers with Ionic 2 + 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'

how do you render GoogleMaps API to a route-specific HTML Div element?

I'm using React Meteor 1.3 and this google maps package.
https://github.com/dburles/meteor-google-maps-react-example.
I can successfully render the map to a single page App, however as soon as I add routing to the mix - things stop working. Specifically when I move the element from an index html template to a JSX component that renders to the page - it breaks. I'm at a bit of a loss here and as the problem is quite vague (in my mind at least) I can't find an answer on google.
What's happening here? Does anyone have an example of this package working with flowrouter?
My current working set up looks like this.
Map.jsx
import React from 'react';
import ReactDOM from 'react-dom';
MyTestMap = React.createClass({
mixins: [ReactMeteorData],
componentDidMount() {
GoogleMaps.load();
},
getMeteorData() {
return {
loaded: GoogleMaps.loaded(),
mapOptions: GoogleMaps.loaded() && this._mapOptions()
};
},
_mapOptions() {
return {
center: new google.maps.LatLng(-37.8136, 144.9631),
zoom: 8
};
},
render() {
if (this.data.loaded)
return <GoogleMap name="mymap" options={this.data.mapOptions} />;
return <div>Loading map...</div>;
}
});
GoogleMap = React.createClass({
propTypes: {
name: React.PropTypes.string.isRequired,
options: React.PropTypes.object.isRequired
},
componentDidMount() {
GoogleMaps.create({
name: this.props.name,
element: ReactDOM.findDOMNode(this),
options: this.props.options
});
GoogleMaps.ready(this.props.name, function(map) {
var marker = new google.maps.Marker({
position: map.options.center,
map: map.instance
});
});
},
componentWillUnmount() {
if (GoogleMaps.maps[this.props.name]) {
google.maps.event.clearInstanceListeners(GoogleMaps.maps[this.props.name].instance);
delete GoogleMaps.maps[this.props.name];
}
},
render() {
return (
<div id="mapId" className="map-container"></div>
)
}
});
if (Meteor.isClient) {
Meteor.startup(function() {
return ReactDOM.render(<MyTestMap />, document.getElementById('root'));
});
}
And then I render this to an Index.html file - however this means that the map is on every page.
<head>
<title>googlemaps-react</title>
</head>
<body>
<div id="root"></div>
</body>
Thanks