How to use a react component for showing Google Maps InfoWindow - reactjs

i have my code as follows, i am not using any external libraries inside my react app
import React, { Component } from "react";
import MarkerInfo from "./MarkerInfo";
import { render } from "react-dom";
class Map extends Component {
componentDidMount() {
this.renderMap();
}
renderMarkerInfo = () => {
return (
<div id="markerinfo">
<h1>THis is info marker</h1>
</div>
);
};
renderMap = () => {
loadScript(
"https://maps.googleapis.com/maps/api/js?key=KEY&callback=initMap"
);
window.initMap = this.initMap;
};
initMap = () => {
var uluru = { lat: -25.363, lng: 131.044 };
var map = new window.google.maps.Map(document.getElementById("map"), {
zoom: 4,
center: uluru
});
var contentString =
'<div id="content">' +
'<div id="siteNotice">' +
"</div>" +
'<h1 id="firstHeading" class="firstHeading">Uluru</h1>' +
'<div id="bodyContent">' +
"<p><b>Uluru</b>, also referred to as <b>Ayers Rock</b>, is a large " +
"sandstone rock formation in the southern part of the " +
"Northern Territory, central Australia. It lies 335 km (208 mi) " +
"south west of the nearest large town, Alice Springs; 450 km " +
"(280 mi) by road. Kata Tjuta and Uluru are the two major " +
"features of the Uluru - Kata Tjuta National Park. Uluru is " +
"sacred to the Pitjantjatjara and Yankunytjatjara, the " +
"Aboriginal people of the area. It has many springs, waterholes, " +
"rock caves and ancient paintings. Uluru is listed as a World " +
"Heritage Site.</p>" +
'<p>Attribution: Uluru, <a href="https://en.wikipedia.org/w/index.php?title=Uluru&oldid=297882194">' +
"https://en.wikipedia.org/w/index.php?title=Uluru</a> " +
"(last visited June 22, 2009).</p>" +
"</div>" +
"</div>";
var infowindow = new window.google.maps.InfoWindow({
content: contentString
});
var marker = new window.google.maps.Marker({
position: uluru,
map: map,
title: "Uluru (Ayers Rock)"
});
marker.addListener("click", function() {
infowindow.open(map, marker);
});
};
render() {
return (
<div id="map">
<MarkerInfo />
</div>
);
}
}
function loadScript(url) {
var index = window.document.getElementsByTagName("script")[0];
var script = window.document.createElement("script");
script.src = url;
script.async = true;
script.defer = true;
index.parentElement.insertBefore(script, index);
}
export default Map;
current I am showing the info window with the hardcoded text, I want to show it using a react component, how can I be able to do that?
i wrote another component, whenever the marker i want to show the react component dynamically
Thanks in Advance

One option to consider would be:
1) to create an instance of InfoWindow without setting content property at this stage:
const infowindow = new window.google.maps.InfoWindow({
content: ""
});
2) and set or update content dynamically via InfoWindow.setContent function once a marker is clicked:
marker.addListener("click", () => {
const content = ReactDOMServer.renderToString(InfoWindowContent);
infowindow.setContent(content);
infowindow.open(map, marker);
});
where InfoWindowContent is represented as a React element and ReactDOMServer.renderToString function is used to render it into HTML
string since InfoWindow.setContent accepts content value as a string:
const InfoWindowContent = (
<div id="bodyContent">
<p>
<b>Uluru</b>, also referred to as <b>Ayers Rock</b>, is a large sandstone
rock formation in the southern part of the Northern Territory, central
Australia. It lies 335 km (208 mi) south west of the nearest
large town, Alice Springs; 450 km (280 mi) by road. Kata Tjuta
and Uluru are the two major features of the Uluru - Kata Tjuta National
Park. Uluru is sacred to the Pitjantjatjara and Yankunytjatjara, the
Aboriginal people of the area. It has many springs, waterholes, rock caves
and ancient paintings. Uluru is listed as a World Heritage Site.
</p>
<p>
Attribution: Uluru,
<a href="https://en.wikipedia.org/w/index.php?title=Uluru&oldid=297882194">
https://en.wikipedia.org/w/index.php?title=Uluru
</a>
(last visited June 22, 2009).
</p>
</div>
);
Here is a demo

Related

Combining react-leaflet and leaflet-pixi-overlay

I am trying to display a complex map with many moving markers, with different icons etc... I have a pure react / react-leaflet solution, but it start to struggle with ~1k markers moving every second.
It looks like leaflet-pixi-overlay could be a way of really speeding things up. But I am just starting with the whole chain (react/javascript/maps/leaflet/etc..) and have problems when connecting all this.
Right now I am just trying to display a polygon in my overlay, and nothing is rendered. It turns out that the translation of lat/long to x/y is failing for that polygon's points. Pixi's latLngToLayerPoint function returns 'infinity' for x and y.
This seems to come from the fact that the zoom is not defined for the layer in question (it is 'infinity' also).
Even if I call latLngToLayerPoint with the zoom setting from the map, things fail too (x/y values are not infinite any more, but they are way out there).
This is my code:
import React, { useEffect, useRef } from 'react';
import { Map, TileLayer } from 'react-leaflet'
import "leaflet/dist/leaflet.css"
import * as PIXI from 'pixi.js'
import 'leaflet-pixi-overlay' // Must be called before the 'leaflet' import
import L from 'leaflet';
let polyLatLngs = [[50.630, 13.047], [50.645, 13.070], [50.625, 13.090], [50.608, 13.070], [50.630, 13.047]]
let pixiContainer = new PIXI.Container()
let prevZoom
let firstDraw = true;
let projectedPolygon;
var shape = new PIXI.Graphics();
pixiContainer.addChild(shape);
let myOverlay = L.pixiOverlay(function (utils) {
let map = utils.getMap()
let zoom = map.getZoom()
console.log('map zoom=' + zoom + ', center=' + map.getCenter())
console.log(' bounds=' + JSON.stringify(map.getBounds()))
console.log(' size=' + map.getSize() + ', panes=' + JSON.stringify(map.getPanes()))
if (map) {
var container = utils.getContainer();
var renderer = utils.getRenderer();
var project = utils.latLngToLayerPoint;
var scale = utils.getScale();
if (firstDraw) {
projectedPolygon = polyLatLngs.map((coords, index) => {
console.log('i=' + index + ', coords=' + coords + ', proj=' + project(coords))
return project(coords)
// return project(coords, zoom) // : this fails too
})
}
if (firstDraw || prevZoom !== zoom) {
shape.clear();
shape.lineStyle(3 / scale, 0x3388ff, 1);
shape.beginFill(0x3388ff, 0.2);
projectedPolygon.forEach(function (coords, index) {
if (index === 0) shape.moveTo(coords.x, coords.y);
else shape.lineTo(coords.x, coords.y);
});
shape.endFill();
}
firstDraw = false;
prevZoom = zoom;
renderer.render(container);
}
}, pixiContainer)
function PxMap(props) {
const mapRef = useRef(null);
useEffect(() => {
if (mapRef.current !== null) {
let map = mapRef.current.leafletElement;
console.log('useEffect: add overlay ')
console.log(JSON.stringify(map.getPane('overlayPane').childElementCount))
myOverlay.addTo(map);
console.log(JSON.stringify(map.getPane('overlayPane').childElementCount))
}
}, [mapRef]);
return (
<div style={{ flexgrow: 1, height: '100%' }}>
<Map
preferCanvas={true}
ref={mapRef}
style={{ height: '100%' }}
center={[50.63, 13.047]}
zoom={12}
>
<TileLayer
attribution='&copy OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?"
/>
</Map>
</div>
)
}
export default PxMap
I think that things are connected correctly between React and leaflet, the map displays ok, I can see the overlay being added etc...
BUT there is a connection missing somewhere, to give more context / information to PIXI.
Any ideas? Thanks!
Finally found the problem, drilling down into the leaflet-pixi-overlay lib.
The solution is to define the minZoom and maxZoom in the Map element:
<Map
preferCanvas={true}
ref={mapRef}
style={{ height: '100%' }}
center={[50.63, 13.047]}
zoom={12}
minZoom={ 9} // Add these options...
maxZoom={ 16} //
Internally, L.PixiOverlay.js relies on these two values to define:
// return the layer projection zoom level
projectionZoom: function (map) {return (map.getMaxZoom() + map.getMinZoom()) / 2;},
Which in turn is used to define the default zoom setting?
this._initialZoom = this.options.projectionZoom(map);
....
zoom = (zoom === undefined) ? _layer._initialZoom : zoom;
var projectedPoint = map.project(L.latLng(latLng), zoom);
Not sure why this is done this way, but setting these options solves the problem.

web component after page load is getting destroyed

I created a custom element(web component) and using webpack will render without any issues but as I include on the working page(which is a wordpress) on render will show up and at the end of the request to hole rendered element is getting destroyed. I do not get any error in console.
the component looks as it follows
import moment from "moment";
import 'moment/min/moment-with-locales'
moment.locale('de');
export class ToursEvents extends HTMLElement {
constructor() {
super();
//this.attachShadow({mode: 'closed'});
}
connectedCallback() {
this.html = this.innerHTML;
}
get data() {
return this._data;
}
set data(tours) {
let times = tours[0]
this._data = tours[0];
this.vendors = tours[1];
let div = document.createElement("div");
div.innerHTML = `
${times.reduce((acc, item) => `${acc}
<div class="bk_day tours-list__slot">
<div class="bk_date tours-list__date">${moment(item.day).format("dddd")}, ${moment(item.day).format("DD.MM.YYYY")}</div>
<ul class="tours-list__vendors">${ this.makeList(item.times) }</ul>
</div>`
, ``)}`;
this.innerHTML = div.innerHTML
//this.shadowRoot.appendChild(div);
}
makeList(times) {
let list = '';
times.map( (time) => {
const eventId = time.event_id;
const vendor = this.vendors[eventId];
let percentageFree = 0, mark = "", availability ="", workload = typeof(WORKLOAD) !== 'undefined' ? WORKLOAD : 0.8;
let tips = '';
list += '<li data-date="' + time.date + '" data-event-id="' + eventId + '" class="' + mark + '">';
list += '<div class="tours-list__time">' + moment(time.date).format('HH.mm') + ' - ' + moment(time.date).format('HH.mm') +'</div>';
if(vendor.title.includes("Discount")) {
tips += '<div><span class="discount">Spar-tipp!</span></div>';
}
list += '<div class="tours-list__title">' + tips + vendor.title + '</div>';
if(time.available_slots != 0) {
list += '<div class=""><button class=""><span class="bk_info_text">Infos/Tickets</span> <span class="icon-down"></span></button></div>'
} else {
list += '<div class="bk_info"><span>Booked</span></div>'
}
list += '</li>';
});
return list
}
showDetails() {
}
}
customElements.define('tours-events', ToursEvents);
How should I debug this issue?
If you run customElements.define('tours-events', class{}); in the console
and you get undefined you know (WordPress?) redirected you to another page.
If you get a DOM exception the Element IS defined
If your Element is not in the DOM (if that is what you mean with 'destroyed')
you have to step through the console-debugger to find the reason when/why it was removed.
Put a debugger; statement in your element's Constructor and take it from there.

Using for loop render some Html elements in React render function

I am trying to render some html using for loop. Every thing work fine but the html prints like a string inside that UL element I dont know what I did wrong pls help me with this. I am new to this React Js thing.
My Script
const Pagination = React.createClass({
getInitialState: function () {
return {
"page": {
"size": 100,
"limit": 30,
"offset": 0,
"number": 1
}
};
},
render: function () {
var html = [];
var i = 0;
var className = '';
var noOfPages = 0;
var number = 1;
var page = this.state.page;
if (page) {
noOfPages = parseInt((page.size / page.limit), 10);
for (i; i < noOfPages; i++) {
className = (className === number) ? 'selected' : '';
html.push('<li key=' + {i} + ' className=""><button className="' + {className} + '">' + {i} + '</button></li>');
}
}
return (
<div className="pagination-sec-wrapper">
<form className="pagination-inner-sec-wrapper" id="pagination-form">
<ul className="">
{html}
</ul>
</form>
</div>
);
}
});
That's because you are pushing string values into your HTML array.
html.push('<span key=' + {i} + ' className=""><button className="' + {className} + '">' + {i} + '</button></span>');
You need to push React components instead.
html.push(<span key={i} className="">
<button className={className}>{i}</button>
</span>);
It's important to remember that even though JSX looks like HTML strings, it's really just syntactic sugar for regular Javascript function calls.
The above JSX is just the same as the following JS.
html.push(React.createElement("span", { key: i, className: "" },
React.createElement("button", { className: className }, i)));

How to get state and city using placeid in Google Map Api in Angularjs

How to get state and city using place_id. I want to get state and city using place_id. t
Please see the following link Google_map, I want to get state and city of following place_id "place_id" : "ChIJLfyY2E4UrjsRVq4AjI7zgRY",
Google Place Details response contains address_components[] field which represents an array of separate address components used to compose a given address, you could extract city and state from this property.
According to Address Component Types:
administrative_area_level_1 - indicates a first-order civil entity below the country level. Within the United States, these
administrative levels are states. Not all nations exhibit these
administrative levels.
locality - indicates an incorporated city or town political entity.
Example
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 10
});
var infowindow = new google.maps.InfoWindow();
var service = new google.maps.places.PlacesService(map);
service.getDetails({
placeId: 'ChIJLfyY2E4UrjsRVq4AjI7zgRY'
}, function (place, status) {
if (status === google.maps.places.PlacesServiceStatus.OK) {
map.setCenter(place.geometry.location);
/*var marker = new google.maps.Marker({
map: map,
position: place.geometry.location
});*/
showPlaceDetails(map, place, infowindow);
}
});
}
function showPlaceDetails(map, place, infowindow) {
//parse address details
var info = '';
place.address_components.forEach(function (item) {
if (item.types.indexOf("administrative_area_level_1") > -1) {
info += '<div>State: ' + item.long_name + '</div>';
}
if (item.types.indexOf("locality") > -1) {
info += '<div>City: ' + item.long_name + '</div>';
}
});
infowindow.setContent(info);
infowindow.setPosition(place.geometry.location);
infowindow.open(map);
}
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
<div id="map"></div>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places&callback=initMap" async defer></script>

angular-google-maps : Is it possible to acess addMarker function?

There is a add Maker function in the Source Code.
How can I access it?
Also how do I change the icon and add infoBox to the marker?
this.addMarker = function (lat, lng, icon, infoWindowContent, label, url, thumbnail)
Javascript is a flexible language. You can wirte your code as :
var marker = new google.maps.Marker({ position: latLng, clickable: true, icon: markerJSON[i].icon, myExtraEntity1: markerJSON[i].oldLatLng, myExtraEntity2: markerJSON[i].headshipID});
marker.myExtraEntity3 = markerJSON[i].id;
marker.map=mymap;
var content= "Tool: " + markerJSON[i].toolName+ " <br><br>Gang: " + markerJSON[i].gangName + "<br><br>Gang Cheff: " +
markerJSON[i].cheff+ "<br><br><a href='javascript:drawPath(" + marker.id + ")'>[1 Day Path]</a><a href='javascript:cleanPath(" + marker.id + ")'>[Clean Path]</a>"
var boxText = document.createElement("div");
boxText.className = "infoBox";
boxText.innerHTML = content;
marker.info = new google.maps.InfoWindow({
content: boxText
});
addInfoWindow(marker, marker.info.content);
markers.push(marker);

Resources