Google map gray box in a hidden div in react js - google-maps

I tried the solution here Google maps in hidden div but it didn't work. Think it might be an issue with react. The map loads fine when not placed in the hidden div.
When state.hideScore turns false in the parent container, the map shows up but as a gray box. any help?
Parent container
<div hidden={this.state.hideScore}>
<ScoreExplanation score={this.state.score} />
<br />
<ResultList data={this.state.scoreArray} />
<ResultMap />
</div>
Component
import React, { Component, PropTypes } from 'react';
var $ = require ('jquery');
var map;
var ResultMap = React.createClass({
componentDidMount: function() {
// ** Instantiating the Map ** //
map = new google.maps.Map(document.getElementById('map'), {
center: new google.maps.LatLng(-34.397, 150.644),
zoom: 14
});
google.maps.event.trigger(map, 'resize');
map.setZoom( map.getZoom() );
},
render: function() {
return (
<div style={{overflow:'visible',height:'300px',width:'300px'}} id="map"></div>
);
}
});
export default ResultMap;

Instead of initializing the map in componentDidMount, you should instead initialize it when the parent re-renders after calling setState to change this.state.hideScore. What's happening right now is, your map is getting loaded into the ResultMap component before its parent is visible. You should instead wait until the parent component is visible, then instantiate the ResultMap.
Example:
Parent component render method
// I prefer using CSS classes to hide/display components.
// Initialize hideScore to 'hidden' and see CSS.
render () {
return (
<div className={this.state.hideScore}>
<ScoreExplanation score={this.state.score} />
<br />
<ResultList data={this.state.scoreArray} />
<div id='result-container'></div>
</div>
)
}
Parent component click handler method (Can be whatever method).
handleClick = () => {
this.setState({
hideScore: 'shown' // See CSS.
});
ReactDOM.render(
<ResultMap />,
document.getElementById('result-container')
);
}
CSS
.shown {
display: block; // Or whatever is your preference.
}
.hidden {
display: none;
}

Related

How to made html map responsive without jquery plugins in React JS

My project is with a react and I don't want to use jquery plugins, tell me is there any possibility
Your post is not very descriptive, but you can always use an event listener to adjust your map like
state = {
windowHeight: undefined,
windowWidth: undefined
}
handleResize = () => this.setState({
windowHeight: window.innerHeight,
windowWidth: window.innerWidth
});
componentDidMount() {
this.handleResize();
window.addEventListener('resize', this.handleResize)
}
componentWillUnmount() {
window.removeEventListener('resize', this.handleResize)
}
Then just use the height and width from state to style your map, make sure to remove it when the page unmounts.

PrimeFaces GMap Inside div Element Does Not Show Up

I have a GMap inside a div with display:none;.
Inside the div is a PrimeFaces map component.
After clicking on a button, the content of the div element should appear, but only a blank page is showing.
<div class="form-group" id="mapContainer" style="display:none;">
<p:gmap id="gmap" center="51.30993291552862,9.448113441467285" zoom="15" type="terrain" style="width:100%;height:700px;" widgetVar="gmap" navigationControl="false" />
</div>
But outside the div element, the map is built and showing correctly.
How can I solve this problem?
As mentioned in one of comments, google map object is not initialized if mapContainer div is hidden (display: none) during page load...
so you will need to "manually" initialize google map object after you make mapContainer div visible.
Here is fully working code (based on your posted code) that will do what you need:
Add this JavaScript to your page
<script>
function resizeElement(elementId,width,height){
console.log("Resizing element " + elementId + " W/H="+ width + "/" + height);
var element = document.getElementById(elementId);
element.style.width=width+"px";
element.style.height=height+"px"
}
function resizePfGmapInsideWrapperElement(wrapperElementId){
var wrapperElement=document.getElementById(wrapperElementId);
var width=wrapperElement.clientWidth-40;
var height=wrapperElement.clientHeight-60;
resizeElement("gmap",width,height);
}
function resizePfGmapInsideDiv(){
var gmap = PF('gmap').getMap();
console.log(gmap);
resizePfGmapInsideWrapperElement("mapContainer");
}
function toggleDivVisibility() {
var div = document.getElementById("mapContainer");
if(div.style.display === "block"){
div.style.display = "none";
}else{
div.style.display = "block";
div.style.width="600px";
div.style.height="400px";
initializeGmap();
resizePfGmapInsideDiv();
}
}
function initializeGmap() {
var myOptions = {
zoom: 15,
center: new google.maps.LatLng(51.30993291552862, 9.448113441467285),
mapTypeId: google.maps.MapTypeId.TERRAIN
}
new google.maps.Map(document.getElementById("gmap"),myOptions);
}
</script>
and, just for testing purposes, add a button that will toggle mapContainer div visibility
<p:commandButton value="Show/hide map" onclick="toggleDivVisibility();"/>
The crucial JS method is self-explanatory initializeGmap() executed in the moment when you make div visible: it will create "a new map inside of the given HTML container, which is typically a DIV element." as stated in documentation referenced above.

Vue && mapbox- rendering component in <script> tag

I want to add HTML popup to Mapbox in Vue project.
This is my MapComponent.Vue
<template>
<div>
<div id='map'></div>
</div>
</template>
<script>
import mapboxgl from 'mapbox-gl'
import StarRating from 'vue-star-rating'
export default {
....
methods: {
...
createMap: function () {
mapboxgl.accessToken = 'pk.eyJ1IjoiYWxleC1wZXRyb3YiLCJhIjoiY2o3dGluZTl2NGh1bjMzbnVqYjA1dnc5cCJ9.6is8d4d-BwwVlT0rPcuU1Q'
this.map = new mapboxgl.Map({
container: 'map',
style: {
...
},
center: [-114.3393270, 48.4210780],
minZoom: 5,
maxZoom: 15,
zoom: 5
})
// disable map rotation using right click + drag
this.map.dragRotate.disable()
// disable map rotation using touch rotation gesture
this.map.touchZoomRotate.disableRotation()
this.$store.state.trails.forEach((trail) => this.addMarker(trail))
},
addMarker: function (trail) {
// create a HTML element for each feature
var el = document.createElement('div')
el.className = 'marker'
// var content = this.popupContent(trail)
// create the popup
var popup = new mapboxgl.Popup()
.setHTML(<StarRating />)
// make a marker for each feature and add to the map
new mapboxgl.Marker(el)
.setLngLat(trail.elements[14].data.point.split(','))
.setPopup(popup)
.addTo(this.map)
}
...
},
components: {
StarRating
}
}
</script>
I got this error.
ReferenceError: h is not defined
at VueComponent.addMarker (MapComponent.vue?70f3:101)
at VueComponent.boundFn [as addMarker] (vue.esm.js?65d7:179)
at eval (MapComponent.vue?70f3:92)
at Array.forEach (<anonymous>)
at VueComponent.createMap (MapComponent.vue?70f3:92)
at VueComponent.boundFn [as createMap] (vue.esm.js?65d7:180)
at eval (MapComponent.vue?70f3:54)
at <anonymous>
An error has occurred in this code.
// create the popup
var popup = new mapboxgl.Popup()
.setHTML(<StarRating />)
I am trying to search for this error but I didn't get any answer yet.
Is there anyone who has experience with this error?
How can I get rendered HTML code of StarRating Component in Script?
Thanks.

Google Places autocomplete not working (in Bootstrap modal)

I'm trying to include a google places autocomplete input box in my React app.
I've followed the guide here to place an <input> text field, and initializing the search box like so:
export default class MySearch extends class Component {
...
componentDidMount() {
var defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(-33.8902, 151.1759),
new google.maps.LatLng(-33.8474, 151.2631));
var input = document.getElementById('searchTextField');
var searchBox = new google.maps.places.SearchBox(input, {
bounds: defaultBounds
});
}
render() {
return (
...
<input id="searchTextField"
type="text"
className="form-control"
placeholder="Search for a location"
/>
);
}
}
But I don't see any suggestions dropping down from the text field.
I inspected the networks tab, to see whether API requests are being hit as I type, and I, not only see requests, but responses from the API, with matching locations, based on my search term, as I type through.
I have no idea why the received suggestions are not being displayed in a dropdown suggestions list below my input box.
Thanks in advance :)
Update
PS: I've placed the text box inside a bootstrap modal. When I place exactly the same text box, outside the bootstrap modal, it works like a breeze.
Any idea why the text box isn't showing suggestions while inside the modal?
It is a styling issue, as the modal's z-index > dropdown's (.pac-container's) z-index. Fixed it with the following CSS snippet:
.pac-container {
background-color: #FFF;
z-index: 2001;
position: fixed;
display: inline-block;
float: left;
}
.modal{
z-index: 2000;
}
.modal-backdrop{
z-index: 1000;
}​
DOM reference (findDOMNode)
You should not select a dom element with id in react component. Use ref (reference) instead. Learn more about findDOMNode here https://facebook.github.io/react/docs/react-dom.html#finddomnode
import { findDOMNode } from 'react-dom';
export default class MySearch extends class Component {
componentDidMount() {
var defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(-33.8902, 151.1759),
new google.maps.LatLng(-33.8474, 151.2631));
var input = findDOMNode(this.refs['searchTextField']);
var searchBox = new google.maps.places.SearchBox(input, {
bounds: defaultBounds
});
}
render() {
return (
<input ref="searchTextField"
type="text"
className="form-control"
placeholder="Search for a location"
/>
);
}
}

Google Map gets rendered with an offset when put in a lightbox

I'm using Ember.js to implement a lightbox containing a Google Map. The problem is that when the map is in the lightbox it renders shifted up and to the left of where I expected it to be. The left over space on the bottom and right is just a blank area where you cannot drag the map. When I render the same map view in the main page, there is no problem. I also noticed that if I open the developer tools (in Chrome and Firefox), the map becomes correct. I have no idea why that is.
Here's the JSFiddle: http://jsfiddle.net/hekevintran/qt5k4/9/.
Screenshot (the bottom map is in the lightbox):
HTML:
<script src="http://maps.googleapis.com/maps/api/js?libraries=places&sensor=false"></script>
<script type="text/x-handlebars" data-template-name="buttons">
<button {{action "openBox" }}>Open Box</button>
<button {{action "closeBox" }}>Close Box</button>
{{view App.MapView}}
</script>
<script type="text/x-handlebars" data-template-name="lightbox">
<div style="
background-color: lightgray;
border: 2px solid #000000;">
{{view App.MapView}}
</div>
</script>
JavaScript:
App = Ember.Application.create({});
App.MapView = Ember.View.extend({
installMap: function () {
var mapOptions = {
// San Francisco
center: new google.maps.LatLng(37.773429,-122.424774),
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
new google.maps.Map(this.$()[0], mapOptions);
},
didInsertElement: function () {
this.$().css(
{'height': '350px',
'width': '350px'}
);
this.installMap();
}
});
Lightbox = Ember.Object.extend({
isVisible: false,
open: function () {
this.set('isVisible', true);
},
close: function () {
this.set('isVisible', false);
},
view: function () {
var controller = this;
return Ember.View.extend({
templateName: 'lightbox',
controller: controller,
isVisibleBinding: 'controller.isVisible'
})
}.property()
});
lightbox = Lightbox.create();
Ember.View.create({
templateName: 'buttons',
controller: Ember.Object.create({
openBox: function () {
lightbox.open();
},
closeBox: function () {
lightbox.close();
}
})
}).append();
lightbox.get('view').create().append();
The problem is that you are creating the map in the lightbox when you first load your page. This happens when you call lightbox.get('view').create().append(); at the end of your JavaScript page.
But the lightbox is not visible yet, and that confuses the Maps API. You could probably work around the problem by triggering a resize event on the map after opening the lightbox, but it's better by far to avoid creating the map and the lightbox view until you need them.
That fixes the problem, and as a bonus your page loads faster because you avoid creating the second map at load time.
To do this, I replaced the last part of your code with:
var lightbox;
Ember.View.create({
templateName: 'buttons',
controller: Ember.Object.create({
openBox: function () {
if( ! lightbox ) {
lightbox = Lightbox.create();
lightbox.get('view').create().append();
}
lightbox.open();
},
closeBox: function () {
if( lightbox ) {
lightbox.close();
}
}
})
}).append();
As you can see, I moved the lightbox = Lightbox.create(); and lightbox.get('view').create().append(); calls inside openBox(), but only calling them the first time this function is called.
I also added a guard in closeBox() so it doesn't try to close the nonexistent lightbox if it hasn't been created yet.
Here is an updated fiddle with the working code.