React Google Maps API - containsLocation "b.get is not a function" - javascript

I am creating a marker where the map is clicked and I want to know if this marker is inside or outside the polygon. I use the containsLocation function for this, but I keep getting the following error "TypeError: b.get is not a function". Thank you in advance for your answers.
function App() {
const refPoly = useRef(null);
const [position, setPosition] = useState(null);
const center = {
lat: 25.774,
lng: -80.19,
};
const containerStyle = {
position: "absolute",
width: "70%",
height: "70%",
};
const bermudaTriangle = [
{ lat: 25.774, lng: -80.19 },
{ lat: 18.466, lng: -66.118 },
{ lat: 32.321, lng: -64.757 },
];
const google = window.google;
const onHandleClickMap = (event) => {
setPosition({ lat: event.latLng.lat(), lng: event.latLng.lng() });
console.log(
google.maps.geometry.poly.containsLocation(event.latLng, bermudaTriangle)
);
};
return (
<div className="App">
<LoadScript
googleMapsApiKey={GOOGLE_MAPS_API_KEY}
id="script-loader"
libraries={["geometry"]}
>
<GoogleMap
mapContainerStyle={containerStyle}
center={center}
zoom={18}
onClick={onHandleClickMap}
>
<Polygon
ref={refPoly}
paths={bermudaTriangle}
strokeColor="#0000FF"
strokeOpacity={0.8}
strokeWeight={2}
fillColor="#0000FF"
fillOpacity={0.35}
/>
{position && <Marker position={position} />}
</GoogleMap>
</LoadScript>
</div>
);
}

I had the same issue; I solved it like this:
Instead of:
const bermudaTriangle = [
{ lat: 25.774, lng: -80.19 },
{ lat: 18.466, lng: -66.118 },
{ lat: 32.321, lng: -64.757 },
];
...I wrote the bermudaTriangle like this:
const bermudaTriangle = new window.google.maps.Polygon({
paths: polygons[0].paths,
});
console.log(window.google.maps.geometry.poly.containsLocation(
{ lat: event.latLng.lat(), lng: event.latLng.lng() },
bermudaTriangle)
);

Related

How to display more data on Marker PopUP in leaflet ReactJS

Have two arrays coords and popUPs
Use Leaflet and display on data from the first array.
I Want to know how to display on data from first and the second array ?
On the console.log I see the data from the second array, but I don't know how to input in the other map function.
Code:
import React from "react";
import { Map as LeafletMap, TileLayer, Marker, Popup } from "react-leaflet";
import L from "leaflet";
const customMarker = new L.Icon({
iconUrl: "https://unpkg.com/browse/leaflet#1.5.1/dist/images/marker-shadow.png",
iconSize: [25, 41],
iconAnchor: [10, 41],
popupAnchor: [2, -40]
});
class Map extends React.Component {
constructor(props) {
super(props);
this.state = {
coords: [
{ lat: 41.19197, lng: 25.33719 },
{ lat: 41.26352, lng: 25.1471 },
{ lat: 41.26365, lng: 25.24215 },
{ lat: 41.26369, lng: 25.33719 },
],
popUPs: [
{ station: 1010, city: 'Ново село' },
{ station: 1020, city: 'Видин' },
{ station: 1030, city: 'Грамада' },
{ station: 1040, city: 'Белоградчик' },
],
zoom: 7
};
}
render() {
const { coords, zoom, popUPs } = this.state;
return (
<LeafletMap
center={[42.733883, 25.48583]}
zoom={zoom}
style={{ height: "100vh" }}
>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.osm.org/{z}/{x}/{y}.png"
/>
{this.state.popUPs.map(({ station, city }, index) => (
console.log(station, city)
))}
{coords.map(({ lat, lng }, index) => (
<Marker position={[lat, lng]} icon={customMarker} key={index}>
<Popup>
{index + 1} is for popup with lat: {lat} and lon {lng}
</Popup>
</Marker>
))}
</LeafletMap>
);
}
}
export default Map;
If we take into account that you coords array items correspond to each item on popups array then you can merge the items of both arrays like this :
const { coords, popUPs, zoom } = this.state;
const mergedArrays = coords.map((coord, i) => ({
...coord,
station: popUPs[i].station,
city: popUPs[i].city
}));
and then iterate over new array mergedArrays instead of coords which will have all items you want to display:
{mergedArrays.map(({ lat, lng, station, city }, index) => (
<Marker position={[lat, lng]} icon={customMarker} key={index}>
<Popup>
{index + 1} is for popup with lat <b>{lat}</b> and lon{" "}
<b>{lng}</b> with station <b>{station}</b> at city <b>{city}</b>
</Popup>
</Marker>
))}
Demo

How to check my location is in the polygon or in the particular area in react native using react-native-maps?

I am rendering location via server and polygon as well.
When the user is out of polygon it will throw some message.
<MapView
style={styles.map}
toolbarEnabled={true}
region={{
latitude:this.state.lat,
longitude: this.state.long,
latitudeDelta: 0.015,
longitudeDelta: 0.0121,
}}
rotateEnabled={true}
provider={this.props.provider}
onPress={e => this.onPress(e)}
{...mapOptions}
animateToCoordinate={[this.state.initialPosition, 500]}
>
{this.state.polygons.map(polygon => (
<Polygon
key={polygon.id}
coordinates={polygon.coordinates}
holes={polygon.holes}
strokeColor="#F00"
fillColor="rgba(255,0,0,0.5)"
strokeWidth={2}
/>
))}
{this.state.editing && (
<Polygon
key={this.state.editing.id}
coordinates={this.state.editing.coordinates}
holes={this.state.editing.holes}
strokeColor="#000"
fillColor="rgba(255,0,0,0.5)"
strokeWidth={2}
/>
)}
<Marker coordinate={{
latitude:this.state.lat,
longitude: this.state.long}} >
</Marker>
</MapView>
I am using:
react-native :0.47.1
react-native-maps : 0.20.1
use https://github.com/surialabs/react-native-geo-fencing library for check
point in polygon
componentDidMount() {
const polygon = [
{ lat: 3.1336599385978805, lng: 101.31866455078125 },
{ lat: 3.3091633559540123, lng: 101.66198730468757 },
{ lat: 3.091150714460597, lng: 101.92977905273438 },
{ lat: 3.1336599385978805, lng: 101.31866455078125 } // last point has to be same as first point
];
let point = {
lat: 2.951269758090068,
lng: 101.964111328125
};
GeoFencing.containsLocation(point, polygon)
.then(() => console.log('point is within polygon'))
.catch(() => console.log('point is NOT within polygon'))
}
pass your polygon data to polygon array and marker in point..
it will show you ..point in polygon or not
In case you have trouble with the onPress for Polygon or MapView
const MapScreen = (props)=>{
const [selectedLocation, setSelectedLocation] = useState();
const [isSelectedLocationinZone, setIsSelectedLocationInZone] = useState(false);
const mapRegion = {
latitude: 37.78,
longitude:-122.43,
latitudeDelta: 0.0922,
longitudeDelta:0.0421,
};
const coordinates = [
{ name: 'Burger', latitude: 37.8025259, longitude: -122.4351431 },
{ name: 'Pizza', latitude: 37.7946386, longitude: -122.421646 },
{ name: 'Soup', latitude: 37.7665248, longitude: -122.4165628 },
{ name: 'Sushi', latitude: 37.7834153, longitude: -122.4527787 },
{ name: 'Curry', latitude: 37.7948105, longitude: -122.4596065 },
]
const selectedLocationHandler = event =>{
try {setSelectedLocation({
lat: event.nativeEvent.coordinate.latitude,
lng: event.nativeEvent.coordinate.longitude,
})}catch(err){
console.log(err)
}
}
const areaCorrectaHandler = ()=>{
setIsSelectedLocationInZone(true);
console.log(selectedLocation)
}
console.log(selectedLocation)
let markerLocation;
if(selectedLocation){
markerLocation={
latitude: selectedLocation.lat,
longitude: selectedLocation.lng
}
}
const saveLocationHandler = useCallback(()=>{
if(!selectedLocation){
Alert.alert(
"Seleccione una ubicación",
"No podemos continuar sin punto de entrega",
[{ text: "Ok" }])
return;
}
if(!isSelectedLocationinZone){
Alert.alert(
"No se encuentra al alcance",
"Todavia no repartimos en tu zona",
[{ text: "Ok" }])
return;
}
props.navigation.navigate('Checkout', {pickedLocation: selectedLocation});
},[selectedLocation])
useEffect(()=>{
props.navigation.setParams({saveLocation: saveLocationHandler});
}, [saveLocationHandler])
return <MapView style={styles.map}region={mapRegion} onPress={selectedLocationHandler}>
<Polygon coordinates = {coordinates} onPress = {areaCorrectaHandler}/>
{markerLocation && <Marker title= 'Ubicacion' coordinate = {markerLocation}/>}
</MapView>
}

Make a user editable polygon on Google maps using ionic 3

i am getting only normal polygon line when my marker is placed on map.
#ionic/cli-utils : 1.19.2
ionic (Ionic CLI) : 3.20.0
global packages:
cordova (Cordova CLI) : 8.0.0
local packages:
#ionic/app-scripts : 3.1.8
Cordova Platforms : android 7.0.0
Ionic Framework : ionic-angular 3.9.2
System:
Android SDK Tools : 26.1.1
Node : v8.10.0
npm : 5.6.0
OS : Windows 10
Environment Variables:
ANDROID_HOME : C:\Users\w2s-pc\AppData\Local\Android\Sdk
Misc:
backend : pro
Code:
import { NavController } from 'ionic-angular';
import{LatLng,GoogleMaps,GoogleMap,GoogleMapsEvent,GoogleMapOptions,
CameraPosition,MarkerOptions,Polyline,Polygon,PolygonOptions,
Spherical,Marker} from '#ionic- native/google-maps';
import { Component } from "#angular/core/";
import { Geolocation } from '#ionic-native/geolocation';
#Component({
selector: 'home',
templateUrl: 'home.html'
})
export class HomePage {
map: GoogleMap;
me: any;
locations = []
constructor() { }
ionViewDidLoad() {
this.loadMap();
}
loadMap() {
let mapOptions: GoogleMapOptions = {
// camera: {
// target: {
// lat: this.me._x,
// lng: this.me._y
// },
// zoom: 18,
// tilt: 30,
// },
MyLocation:true,
MyLocationButton:true,
disableDefaultUI: true,
mapType: "MAP_TYPE_HYBRID",
};
let map= this.map = GoogleMaps.create('map_canvas', mapOptions);
// var div = document.getElementById("map_canvas");
// var map = new GoogleMaps()
// Wait the MAP_READY before using any methods.
this.map.on(GoogleMapsEvent.MAP_READY)
.subscribe(() => {
console.log('Map is ready!');
this.map.setMyLocationEnabled(true)
this.map.setMyLocationButtonEnabled(true)
this.map.on(GoogleMapsEvent.MAP_CLICK).subscribe((location: any) => {
console.log(location);
this.locations.push(new LatLng(location[0].lat, location[0].lng));
console.log(location);
let PolyLineInfo;
this.map.addPolygon({
'points' : this.locations ,
'strokeColor' : '# AA00FF' ,
'fillColor' : '# 00FFAA' ,
'strokeWidth' : 4 ,
'editable' :true,
}).then((info: Polyline) => {
// info.setPoints
PolyLineInfo = info;
}
);
this.map.addMarker({
animation: 'DROP',
draggable: true,
position: {
lat: location[0].lat,
lng: location[0].lng,
},
customInfo: this.locations.length - 1
})
.then(marker => {
marker.on(GoogleMapsEvent.MARKER_DRAG_END)
.subscribe((marker) => {
let index = marker[1].get("customInfo");
this.locations[index] = new LatLng(marker[0].lat, marker[0].lng);
PolyLineInfo.remove();
console.log(this.locations[0]);
console.log(this.locations[1]);
console.log(this.locations[2]);
let dis = Spherical.computeSignedArea(this.locations);
console.log(dis);
let km = Spherical.computeLength(this.locations);
console.log(km);
this.map.addPolygon({
'points' : this.locations ,
'strokeColor' : '# AA00FF' ,
'fillColor' : '#FF0000' ,
'strokeWidth' : 4 ,
'editable' :true,
}).then((info: Polyline) => {
PolyLineInfo = info;
}
);
});
})
});
});
}
}
i need to do like this using ionic version 3 on Google Map
https://github.com/mapsplugin/cordova-plugin-googlemaps-doc/blob/master/v2.0.0/class/Polygon/getPoints/README.md
var GORYOKAKU_POINTS = [
{lat: 41.79883, lng: 140.75675},
{lat: 41.799240000000005, lng: 140.75875000000002},
{lat: 41.797650000000004, lng: 140.75905},
{lat: 41.79637, lng: 140.76018000000002},
{lat: 41.79567, lng: 140.75845},
{lat: 41.794470000000004, lng: 140.75714000000002},
{lat: 41.795010000000005, lng: 140.75611},
{lat: 41.79477000000001, lng: 140.75484},
{lat: 41.79576, lng: 140.75475},
{lat: 41.796150000000004, lng: 140.75364000000002},
{lat: 41.79744, lng: 140.75454000000002},
{lat: 41.79909000000001, lng: 140.75465}//,
//{lat: 41.79883, lng: 140.75673}
];
var mapDiv = document.getElementById("map_canvas");
// Create a map with specified camera bounds
var map = plugin.google.maps.Map.getMap(mapDiv, {
camera: {
target: GORYOKAKU_POINTS
}
});
map.addEventListener(plugin.google.maps.event.MAP_READY, function() {
addEditablePolygon(map, GORYOKAKU_POINTS, function(polygon) {
// To do something...
});
});
function addEditablePolygon(map, points, callback) {
// Add a polygon
map.addPolygon({
'points': points,
'strokeColor' : '#AA00FF',
'fillColor' : '#00FFAA',
'width': 10
}, function(polygon) {
// polygon.getPoints() returns an instance of the BaseArrayClass.
var mvcArray = polygon.getPoints();
// Add draggable markers
mvcArray.map(function(latLng, cb) {
map.addMarker({
position: latLng,
draggable: true
}, cb);
}, function(markers) {
// If a marker is dragged, set the position of it to the points of the Polygon.
markers.forEach(function(marker, idx) {
marker.on(plugin.google.maps.event.MARKER_DRAG, function(position) {
mvcArray.setAt(idx, position);
});
});
callback(polygon);
});
});
}

Ways to handle more than 23 waypoints Google Maps

I followed the below reference posted by mikep to handle more than 23 waypoints with premier license, it does handle more than 23 waypoints however it's not considering the optimal route with 28 waypoints. Please find the snippet of code below. Please let me know, if I missed anything.
Reference: Exceed 23 waypoint per request limit on Google Directions API (Business/Work level)
<!DOCTYPE html>
<html>
<head>
<title>Distance Matrix service</title>
<style>
#right-panel {
font-family: 'Roboto','sans-serif';
line-height: 30px;
padding-left: 10px;
}
#right-panel select, #right-panel input {
font-size: 15px;
}
#right-panel select {
width: 100%;
}
#right-panel i {
font-size: 12px;
}
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
width: 50%;
}
#right-panel {
float: right;
width: 48%;
padding-left: 2%;
}
#output {
font-size: 11px;
}
</style>
</head>
<body>
<div id="right-panel">
<div id="inputs">
<pre>
var origin1 = {lat: 55.930, lng: -3.118};
var origin2 = 'Greenwich, England';
var destinationA = 'Stockholm, Sweden';
var destinationB = {lat: 50.087, lng: 14.421};
</pre>
</div>
<div>
<strong>Results</strong>
</div>
<div id="output"></div>
</div>
<div id="map"></div>
<script>
function initMap() {
var service = new google.maps.DirectionsService;
var map = new google.maps.Map(document.getElementById('map'));
// list of points
// list of points
var stations = [
{lat: 42.304403, lng: -89.04231900000002, name: 'Station 1'},
{lat: 42.236168, lng: -88.54327699999999, name: 'Station 2'},
{lat: 42.234782, lng: -88.53974299999999, name: 'Station 3'},
{lat: 42.151208, lng: -88.47053599999998, name: 'Station 4'},
{lat: 42.159458, lng: -88.44529899999998, name: 'Station 5'},
{lat: 42.157442, lng: -88.45886899999999, name: 'Station 6'},
{lat: 42.187703, lng: -88.36313100000001, name: 'Station 7'},
{lat: 42.188238, lng: -88.34060099999999, name: 'Station 8'},
{lat: 42.185022, lng: -88.309731, name: 'Station 9'},
{lat: 42.17901, lng: -88.32207499999998, name: 'Station 10'},
{lat: 42.165468, lng: -88.322519, name: 'Station 11'},
{lat: 41.91145, lng: -88.30584899999997, name: 'Station 12'},
{lat: 41.903634, lng: -88.3133890000000, name: 'Station 13'},
{lat: 41.67167, lng: -88.548182, name: 'Station 14'},
{lat: 41.564786, lng: -88.600822, name: 'Station 15'},
{lat: 41.561587, lng: -88.60028599999998, name: 'Station 16'},
{lat: 41.560347, lng: -88.597355, name: 'Station 17'},
{lat: 41.582568, lng: -88.90418599999998, name: 'Station 18'},
{lat: 41.5849, lng: -88.90929499999999, name: 'Station 19'},
{lat: 41.584279, lng: -88.91100, name: 'Station 20'},
{lat: 41.794906, lng: -88.93928299999999, name: 'Station 21'},
{lat: 41.796471, lng: -88.94241299999999, name: 'Station 22'},
{lat: 41.849191, lng: -89.0242670000000, name: 'Station 23'},
{lat: 41.846972, lng: -89.020418, name: 'Station 24'},
{lat: 41.875845, lng: -88.45214199999998, name: 'Station 25'},
{lat: 42.030196, lng: -88.271702, name: 'Station 26'},
{lat: 42.304403, lng: -89.04231900000002, name: 'Station 27'},
// ... as many other stations as you need
];
// Zoom and center map automatically by stations (each station will be in visible map area)
var lngs = stations.map(function(station) { return station.lng; });
var lats = stations.map(function(station) { return station.lat; });
map.fitBounds({
west: Math.min.apply(null, lngs),
east: Math.max.apply(null, lngs),
north: Math.min.apply(null, lats),
south: Math.max.apply(null, lats),
});
// Show stations on the map as markers
for (var i = 0; i < stations.length; i++) {
new google.maps.Marker({
position: stations[i],
map: map,
title: stations[i].name
});
}
// Divide route to several parts because max stations limit is 25 (23 waypoints + 1 origin + 1 destination)
for (var i = 0, parts = [], max = 25 - 1; i < stations.length; i = i + max)
parts.push(stations.slice(i, i + max + 1));
// Service callback to process service results
var service_callback = function(response, status) {
if (status != 'OK') {
console.log('Directions request failed due to ' + status);
return;
}
var renderer = new google.maps.DirectionsRenderer;
renderer.setMap(map);
renderer.setOptions({ suppressMarkers: true, preserveViewport: true });
renderer.setDirections(response);
};
// Send requests to service to get route (for stations count <= 25 only one request will be sent)
for (var i = 0; i < parts.length; i++) {
// Waypoints does not include first station (origin) and last station (destination)
var waypoints = [];
for (var j = 1; j < parts[i].length - 1; j++)
waypoints.push({location: parts[i][j], stopover: false});
// Service options
var service_options = {
origin: parts[i][0],
destination: parts[i][parts[i].length - 1],
waypoints: waypoints,
optimizeWaypoints: true,
travelMode: 'DRIVING'
};
// Send request
service.route(service_options, service_callback);
}
}
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyABPfm9lb39EOvsKMyrdnwdTJSN8IjqVy0&callback=initMap">
</script>
</body>
</html>
Global minima is not possible in that case using Google's API. We have to have an approximation -
Iteratively, cluster 20-25 points together and generate route based on that; Select one master point from the 20-25 points from each cluster - it can be 1st point/one in the middle by comparing averages etc,.
Generate another calcRoute using cluster's master points. Based on this, try to generate a broad route between clusters and route between clusters.

JavaScript - leaflet, adding a bunch of markers

Let's say I have a bunch of markers (over 100) I want to add from this:
module.exports = [
{ value: 'Varrock', lng: 22.5, lat: -15.52249812756166, popular: 1 },
{ value: 'Lumbridge', lng: 25.9661865234375, lat: -43.644025847699496, popular: 1 },
{ value: 'Monastery', lng: -4.0924072265625, lat: -5.714379819235291 },
{ value: 'Edgeville', lng: 2.4884033203125, lat: -6.0094592380595495, popular: 1 },
{ value: 'Varrock Palace', lng: 22.412109375, lat: -6.882800241767556 },
{ value: 'Digsite', lng: 46.043701171875, lat: -17.266727823520508 },
{ value: 'River Salve', lng: 54.931640625, lat: -14.083301314706778 },
{ value: 'Morytania', lng: 64.610595703125, lat: -13.501814172428656 },
{ value: 'Mort Myre Swamp', lng: 59.820556640625, lat: -22.740723091194727 }
];
It uses browserify to get it. So, I do this:
var locations = require('./locations');
What would be the best way to add all of those into LayerGroup()? I mean, because doing var fairy = L.layerGroup([One, Two, Three...]); by hand would get tiresome.
So how would I go about adding all of those markers into a new layer (so I can toggle them on/off)
How about adding an empty L.LayerGroup, looping over your array and adding them to that layer?
var locations = [];
var layer = L.layerGroup().addTo(map);
locations.forEach(function (location) {
L.marker([location.lat, location.lng])
.bindPopup(location.value)
.addTo(layer);
});
Working example on Plunker: http://plnkr.co/edit/Q0DGqs?p=preview

Categories