On the map, I have an added layer with polygons and one marker on another layer. When I click anywhere, the marker moves to that location and the polygon is selected. The marker has the ability to drag across the map, but just when I drag it, the polygon selection does not appear. How to do this?
var osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
});
var map = new L.Map('map', {
'center': [51, 17],
'zoom': 6,
'layers': [osm],
});
var selected;
var marker
marker = L.marker([51, 17], {
draggable: true
}).addTo(map);
var geoJsonLayer2
geoJsonLayer2 = L.geoJson( polygons ,{
style: {
fillColor: "#1ED100",
color: "orange",
fillOpacity: 0.0,
opacity: 0.0,
},
})
.on('click', function (e) {
// Check for selected
if (selected) {
// Reset selected to default style
e.target.resetStyle(selected)
}
// Assign new selected
selected = e.layer
// Bring selected to front
selected.bringToFront()
// Style selected
selected.setStyle({
'color': 'red',
'opacity': 1,
})
})
.addTo(map);
marker.on('dragend', function (e, feature) {
updateLatLng(marker.getLatLng().lat, marker.getLatLng().lng);
});
map.on('click', function (e) {
marker.setLatLng(e.latlng);
updateLatLng(marker.getLatLng().lat, marker.getLatLng().lng);
});
function updateLatLng(lat, lng, reverse) {
if (reverse) {
marker.setLatLng([lat, lng]);
map.panTo([lat, lng]);
} else {
document.getElementById('lat').value = marker.getLatLng().lat.toFixed(10);
document.getElementById('long').value = marker.getLatLng().lng.toFixed(10);
map.panTo([lat, lng]);
document.getElementById("lat").value = lat.toFixed(10);
document.getElementById("long").value = lng.toFixed(10);
}
}
view after clicking on the polygon
view after shifting the marker
Related
I am trying to alert user while drawing polygon over Google Maps with pre rendered Polygons using geoJson. Whenever polygon is drawn over existing Polygons, user should get alert. I got an example but it works for the polygons on the same layer (Fiddle Example). My Code is hosted here. Refer the image below that I need:
JS Code as below:
var drawingManager;
function initialize() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 12,
center: new google.maps.LatLng(28.631162, 77.213313),
mapTypeId: google.maps.MapTypeId.ROADMAP,
disableDefaultUI: true,
zoomControl: true
});
var polyOptions = {
fillColor: '#0099FF',
fillOpacity: 0.7,
strokeColor: '#AA2143',
strokeWeight: 2,
editable: true
};
// Creates a drawing manager attached to the map that allows the user to draw Polygons
map.data.loadGeoJson('near.json')
drawingManager = new google.maps.drawing.DrawingManager({
drawingControlOptions: {
drawingModes: [
google.maps.drawing.OverlayType.POLYGON
]
},
polygonOptions: polyOptions,
map: map
});
google.maps.event.addListener(drawingManager, 'overlaycomplete', function (e) {
alert("Polygon Completed. Here show message if overlapped");
});
}
HTML as below
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Create Boundary</title>
<style>
#map,
html,
body {
padding: 0;
margin: 0;
height: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://cdn.rawgit.com/bjornharrtell/jsts/gh-pages/1.1.2/jsts.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=API-KEY" async defer></script>
<script src="scripts/map.js"></script>
</div>
</body>
</html>
One option would be to parse the polygons from the GeoJSON to "normal" google.maps.Polygon objects, then preload those to your all_overlays array:
map.data.addListener('addfeature', function(e) {
if (e.feature.getGeometry().getType() == "Polygon") {
// simplifying assumption, depends on data
// just check first linear ring
var poly = new google.maps.Polygon({
path: e.feature.getGeometry().getAt(0).getArray(),
fillColor: '#0099FF',
fillOpacity: 0.7,
strokeColor: '#AA2143',
strokeWeight: 2,
map: map
});
all_overlays.push(poly);
}
});
proof of concept fiddle
code snippet:
var drawingManager;
var selectedShape;
var all_overlays = [];
var gmarkers = Array();
var polygons = Array();
function setSelection(shape) {
clearSelection();
selectedShape = shape;
shape.setEditable(true);
}
function clearSelection() {
if (selectedShape) {
selectedShape.setEditable(false);
selectedShape = null;
}
}
function initialize() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 10,
center: new google.maps.LatLng(33.619003, -83.867405),
mapTypeId: google.maps.MapTypeId.ROADMAP,
disableDefaultUI: true,
zoomControl: true
});
// zoom to show all the features
var bounds = new google.maps.LatLngBounds();
map.data.addListener('addfeature', function(e) {
processPoints(e.feature.getGeometry(), bounds.extend, bounds);
map.fitBounds(bounds);
if (e.feature.getGeometry().getType() == "Polygon") {
// simplifying assumption, depends on data
// just check first linear ring
var poly = new google.maps.Polygon({
path: e.feature.getGeometry().getAt(0).getArray(),
fillColor: '#0099FF',
fillOpacity: 0.7,
strokeColor: '#AA2143',
strokeWeight: 2,
map: map
});
all_overlays.push(poly);
}
});
map.data.loadGeoJson("https://raw.githubusercontent.com/datameet/Municipal_Spatial_Data/master/Delhi/Delhi_Wards.geojson");
map.data.setMap(null);
var polyOptions = {
fillColor: '#0099FF',
fillOpacity: 0.7,
strokeColor: '#AA2143',
strokeWeight: 2,
editable: true
};
// Creates a drawing manager attached to the map that allows the user to draw Polygons
drawingManager = new google.maps.drawing.DrawingManager({
drawingControlOptions: {
drawingModes: [
google.maps.drawing.OverlayType.POLYGON
]
},
polygonOptions: polyOptions,
map: map
});
google.maps.event.addListener(drawingManager, 'overlaycomplete', function(e) {
calcIntersection(e.overlay, all_overlays);
all_overlays.push(e.overlay);
});
}
function calcIntersection(newOverlay, allOverlays) {
//ensure the polygon contains enought vertices
if (newOverlay.getPath().getLength() < 3) {
alert("Not enought vertices. Draw a polygon that contains at least 3 vertices.");
return;
}
var geometryFactory = new jsts.geom.GeometryFactory();
var newPolygon = createJstsPolygon(geometryFactory, newOverlay);
//iterate existing polygons and find if a new polygon intersects any of them
var result = allOverlays.filter(function(currentOverlay) {
var curPolygon = createJstsPolygon(geometryFactory, currentOverlay);
var intersection = newPolygon.intersection(curPolygon);
return intersection.isEmpty() == false;
});
//if new polygon intersects any of exiting ones, draw it with green color
if (result.length > 0) {
newOverlay.setOptions({
strokeWeight: 2.0,
fillColor: 'green'
});
}
}
function createJstsPolygon(geometryFactory, overlay) {
var path = overlay.getPath();
var coordinates = path.getArray().map(function name(coord) {
return new jsts.geom.Coordinate(coord.lat(), coord.lng());
});
coordinates.push(coordinates[0]);
var shell = geometryFactory.createLinearRing(coordinates);
return geometryFactory.createPolygon(shell);
}
google.maps.event.addDomListener(window, 'load', initialize);
function processPoints(geometry, callback, thisArg) {
if (geometry instanceof google.maps.LatLng) {
callback.call(thisArg, geometry);
} else if (geometry instanceof google.maps.Data.Point) {
callback.call(thisArg, geometry.get());
} else {
geometry.getArray().forEach(function(g) {
processPoints(g, callback, thisArg);
});
}
}
#map,
html,
body {
padding: 0;
margin: 0;
height: 100%;
}
<script src="https://cdn.rawgit.com/bjornharrtell/jsts/gh-pages/1.1.2/jsts.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?libraries=drawing&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<div id="map"></div>
My map locator works but I am not sure how to reset the marker so that when the user geolocates it resets the position. Currently, my code looks like this:
//map locator
map.locate({setView: true, maxZoom: 16});
function onLocationFound(e) {
var radius = e.accuracy;
L.marker(e.latlng).addTo(map)
.bindPopup("Vous êtes ici").openPopup();
L.circle(e.latlng, radius).addTo(map);
}
map.on('locationfound', onLocationFound);
function onLocationError(e) {
alert(e.message);
}
map.on('locationerror', onLocationError);
// end of geolocator with marker
Overwrite the latlng and radius:
var marker = null;
var circle = null;
//map locator
map.locate({setView: true, maxZoom: 16});
function onLocationFound(e) {
var radius = e.accuracy;
if(!marker){
marker = L.marker(e.latlng).addTo(map);
circle = L.circle(e.latlng,radius).addTo(map);
}else{
marker.setLatLng(e.latlng);
circle.setLatLng(e.latlng);
circle.setRadius(radius);
}
marker.bindPopup("Vous êtes ici").openPopup();
}
In my rails application I have implemented a google maps using the polygon drawing tool. I have been able to add coordinates and save these to my database successfully.
The problem i'm having is when a user wants to edit and save any changes made to the polygon shape. How do i implement this function? My best guess is to use a conditional to see if the database has any saved coordinates, if so, load them in a listener?
HTML
<div style='width: 100%;'>
<%= hidden_field_tag(:map_coords, value = nil, html_options = {id: 'propertyCoordinates'}) %>
Javascript
function initMap() {
var map = new google.maps.Map(document.getElementById("map"), {
center: { lat: -40.6892, lng: 74.0445 },
zoom: 8,
mapTypeId: google.maps.MapTypeId.HYBRID,
});
var polyOptions = {
strokeWeight: 0,
fillOpacity: 0.45,
strokeColor: "#FF0000",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#FF0000",
fillOpacity: 0.35
};
// loads databased saved coordinates
var propertyCoords = [<%= #property.coordinates %>];
var points = [];
for (var i = 0; i < propertyCoords.length; i++) {
points.push({
lat: propertyCoords[i][0],
lng: propertyCoords[i][1]
});
}
var drawingManager = new google.maps.drawing.DrawingManager({
drawingMode: google.maps.drawing.OverlayType.POLYGON,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes: ["polygon"]
},
polylineOptions: {
editable: true,
draggable: true
},
rectangleOptions: polyOptions,
circleOptions: polyOptions,
polygonOptions: polyOptions,
map: map
});
if (typeof points !== 'undefined') {
// My guess is to use a conditional statement to check if the map has any coordinates saved?
} else {
google.maps.event.addListener(drawingManager, 'overlaycomplete', function (e) {
if (e.type !== google.maps.drawing.OverlayType.MARKER) {
// Switch back to non-drawing mode after drawing a shape.
drawingManager.setDrawingMode(null);
// Add an event listener that selects the newly-drawn shape when the user
// mouses down on it.
var newShape = e.overlay;
newShape.type = e.type;
google.maps.event.addListener(newShape, 'click', function (e) {
if (e.vertex !== undefined) {
if (newShape.type === google.maps.drawing.OverlayType.POLYGON) {
var path = newShape.getPaths().getAt(e.path);
path.removeAt(e.vertex);
if (path.length < 3) {
newShape.setMap(null);
}
}
}
setSelection(newShape);
});
}
var coords = e.overlay.getPath().getArray();
document.getElementById("propertyCoordinates").value = coords;
});
}
} // END function initMap()
If I understand correctly, what you're looking for is the polygon editing functionality. My stackblitz example goes something like this:
Draw a polygon if you already have user-saved coordinates. Then fit the map bounds to the poly's bounds. For this you'll probably need a getBounds polyfill.
Make the polygon editable so you can listen to its points' changes. Check the function enableCoordinatesChangedEvent.
Listen to the changes & extract the new polygon points. Look for function extractPolygonPoints.
Then proceed with your business logic.
FYI you'll need to put your own API key at the bottom of the stackblitz index.html. Look for YOUR_KEY.
I am using Google Maps API and I have implemented custom circle using this SO answer as reference which is working absolutely fine.
Here below is my screenshot what I have done so far.
As you can see above, I am showing my count with Map Icon.
Now I have used infobox as well so when I click on map icon, its opening something like this.
Now the problem which I am facing if I click on my count, its not opening the same infobox which is opening if I click on my icon.
I tried to use below code inside my for loop but its not working for me.
google.maps.event.addListener(ibLabel, 'click', (function (marker, i) {
return function () {
infowindow.setContent(locations[i][0]);
infowindow.open(map, marker);
}
})(marker, i));
Here is my full source code what I have done so far.
var locations = chartData;
map = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 4,
center: new google.maps.LatLng(-27.4756261, 129.3748879),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
map.setOptions({minZoom: 1, maxZoom: 15});
var marker, i;
var circle;
var latlng;
var myLatLng;
var closeInfoBox = document.getElementById("close-button");
var infowindow = new google.maps.InfoWindow({maxWidth: 350});
var oms = new OverlappingMarkerSpiderfier(map, {
//markersWontMove: true, // we promise not to move any markers, allowing optimizations
// markersWontHide: true, // we promise not to change visibility of any markers, allowing optimizations
// basicFormatEvents: true // allow the library to skip calculating advanced formatting information
});
for (i = 0; i < locations.length; i++) {
var user_id_array = '<?= $user_id_array; ?>';
var image_name = 'ouvar-pin-new.png';
var get_user_id = locations[i][4];
var fill_color_val = '#154ff6';
var latitude = locations[i][1];
var lontitude = locations[i][2];
myLatLng = google.maps.LatLng(latitude, lontitude);
var latlng = new google.maps.LatLng(latitude, lontitude);
if (user_id_array != '')
{
var data = JSON.parse(user_id_array);
image_name = data[get_user_id];
if(image_name != 'ouvar-pin-new-blue.png'){
fill_color_val = '#f24e82';
}
// alert(image_name);
}
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
map: map,
});
circle = new google.maps.Circle({
map: map,
radius: 200000, // 10 miles in metres
fillColor: fill_color_val,
strokeColor: '#FFFFFF',
strokeWeight: 5,
fillOpacity: 1,
});
circle.bindTo('center', marker, 'position');
var labelText = locations[i][5];
var myOptions = {
content: labelText,
boxStyle: {
border: "none",
textAlign: "center",
fontSize: "12pt",
width: "50px",
color:'white',
},
disableAutoPan: true,
pixelOffset: new google.maps.Size(-25,-5),
position: latlng,
closeBoxURL: "",
isHidden: false,
pane: "floatPane",
enableEventPropagation: true,
zIndex: null,
};
// marker.setVisible(false);
var ibLabel = new InfoBox(myOptions);
ibLabel.open(map);
google.maps.event.addListener(ibLabel, 'click', (function (marker, i) {
return function () {
infowindow.setContent(locations[i][0]);
infowindow.open(map, marker);
}
})(marker, i));
google.maps.event.addListener(marker, 'click', (function (marker, i) {
return function () {
infowindow.setContent(locations[i][0]);
infowindow.open(map, marker);
}
})(marker, i));
google.maps.event.addListener(map, 'click', function () {
infowindow.close();
marker.open = false;
});
oms.addMarker(marker);
//oms.addMarker(marker);
}
window.map = map; // for debugging/exploratory use in console
window.oms = oms;
google.maps.event.addListener(infowindow, 'domready', function () {
var iwOuter = $('.gm-style-iw');
var iwBackground = iwOuter.prev();
iwBackground.children(':nth-child(2)').css({'display': 'none'});
iwBackground.children(':nth-child(4)').css({'display': 'none'});
iwBackground.children(':nth-child(1)').attr('style', function (i, s) {
return s + 'left: 76px !important;'
});
iwBackground.children(':nth-child(3)').find('div').children().css({'box-shadow': 'rgba(72, 181, 233, 0.6) 0px 1px 6px', 'z-index': '1'});
var iwCloseBtn = iwOuter.next();
iwCloseBtn.css({opacity: '1', right: '38px', top: '3px', border: '7px solid #fff', 'border-radius': '13px', 'padding': '6px', ' box-shadow': '0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2)'});
if ($('.iw-content').height() < 140) {
$('.iw-bottom-gradient').css({display: 'none'});
}
iwCloseBtn.mouseout(function () {
$(this).css({opacity: '1'});
});
});
Can someone guide me how to enable click event for my custom circle as well.
If you want something to happen when someone clicks on the circle, you need to add a click listener to it. The code below will open the same infowindow on a click of the circle as the click listener on the marker (and reference it to the marker).
google.maps.event.addListener(circle, 'click', (function(marker, i) {
return function() {
infowindow.setContent(locations[i][0]);
infowindow.open(map, marker);
}
})(marker, i));
proof of concept fiddle
const citymap = {
chicago: {
name: "Chicago",
center: { lat: 41.878, lng: -87.629 },
population: 2714856,
},
newyork: {
name: "New York",
center: { lat: 40.714, lng: -74.005 },
population: 8405837,
},
losangeles: {
name: "Los Angeles",
center: { lat: 34.052, lng: -118.243 },
population: 3857799,
},
vancouver: {
name: "Vancouver",
center: { lat: 49.25, lng: -123.1 },
population: 603502,
},
};
function initMap() {
// Create the map.
const infowindow = new google.maps.InfoWindow({maxWidth: 350});
const map = new google.maps.Map(document.getElementById("map"), {
zoom: 4,
center: {
lat: 37.09,
lng: -95.712
},
mapTypeId: "terrain",
});
// Construct the circle for each value in citymap.
// Note: We scale the area of the circle based on the population.
for (const city in citymap) {
console.log("city:"+citymap[city].name);
// Add the circle for this city to the map.
const circle = new google.maps.Circle({
strokeColor: "#FF0000",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#FF0000",
fillOpacity: 0.35,
map,
center: citymap[city].center,
radius: Math.sqrt(citymap[city].population) * 100,
});
const marker = new google.maps.Marker({
position: citymap[city].center,
map: map,
});
google.maps.event.addListener(marker, 'click', (function(marker, city) {
return function() {
console.log("marker click:"+citymap[city].name);
infowindow.setContent(citymap[city].name);
infowindow.open(map, marker);
}
})(marker, city));
google.maps.event.addListener(circle, 'click', (function(marker, city) {
return function() {
console.log("circle click:"+citymap[city].name);
infowindow.setContent(citymap[city].name);
infowindow.open(map, marker);
}
})(marker, city));
}
}
window.initMap = initMap;
/*
* Always set the map height explicitly to define the size of the div element
* that contains the map.
*/
#map {
height: 100%;
}
/*
* Optional: Makes the sample page fill the window.
*/
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
<!DOCTYPE html>
<html>
<head>
<title>Circles</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
</head>
<body>
<div id="map"></div>
<script
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap"
defer
></script>
</body>
</html>
I am currently building out a small widget that allows someone to see a kml heat map of the united states population density then select an area on that map and drop a market on to that location. The user then enters a number and that creates a mile radius to show the user how much area they cover.
My problem is that I have 63 .kml files for just one state in the US. I know I can remove the xml <name> and <description> to prevent the name from popping up when clicked, but I can't see that being practical with that many .kml files.
Is there a programmatic solution or API solution to prevent just the kml layers from being clickable?
var citymap = {};
citymap['chicago'] = {
center: new google.maps.LatLng(41.878113, -87.629798),
value: 2714856
};
citymap['newyork'] = {
center: new google.maps.LatLng(40.714352, -74.005973),
value: 8405837
};
citymap['losangeles'] = {
center: new google.maps.LatLng(34.052234, -118.243684),
value: 3857799
};
citymap['vancouver'] = {
center: new google.maps.LatLng(49.25, -123.1),
value: 603502
};
var cityCircle;
function initialize() {
// Create the map.
var mapOptions = {
zoom: 8,
center: new google.maps.LatLng(34.7361, -92.3311),
mapTypeId: google.maps.MapTypeId.TERRAIN
};
var map = new google.maps.Map(document.getElementById('map-canvas'),
mapOptions);
// Construct the circle for each value in citymap.
// Note: We scale the area of the circle based on the population.
for (var city in citymap) {
var populationOptions = {
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35,
map: map,
center: citymap[city].center,
radius: Math.sqrt(citymap[city].value) * 100
};
// Add the circle for this city to the map.
cityCircle = new google.maps.Circle(populationOptions);
}
var ctaLayer = new google.maps.KmlLayer({
url: 'http://www.census.gov/main/kml/countysubs_z6/AR/05003.xml'
});
ctaLayer.setMap(map);
google.maps.event.addListener(map, 'click', function(e) {
placeMarker(e.latLng, map);
});
}
function placeMarker(position, map) {
var marker = new google.maps.Marker({
position: position,
map: map
});
map.panTo(position);
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map-canvas {
height: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp"></script>
<div id="map-canvas"></div>
Discretionary note: Google API does not work well with Stack Overflow's code snippet's widget.
set the KmlLayer clickable option to false
clickable boolean If true, the layer receives mouse events. Default value is true.
var citymap = {};
citymap['chicago'] = {
center: new google.maps.LatLng(41.878113, -87.629798),
value: 2714856
};
citymap['newyork'] = {
center: new google.maps.LatLng(40.714352, -74.005973),
value: 8405837
};
citymap['losangeles'] = {
center: new google.maps.LatLng(34.052234, -118.243684),
value: 3857799
};
citymap['vancouver'] = {
center: new google.maps.LatLng(49.25, -123.1),
value: 603502
};
var cityCircle;
function initialize() {
// Create the map.
var mapOptions = {
zoom: 8,
center: new google.maps.LatLng(34.7361, -92.3311),
mapTypeId: google.maps.MapTypeId.TERRAIN
};
var map = new google.maps.Map(document.getElementById('map-canvas'),
mapOptions);
// Construct the circle for each value in citymap.
// Note: We scale the area of the circle based on the population.
for (var city in citymap) {
var populationOptions = {
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35,
map: map,
center: citymap[city].center,
radius: Math.sqrt(citymap[city].value) * 100
};
// Add the circle for this city to the map.
cityCircle = new google.maps.Circle(populationOptions);
}
var ctaLayer = new google.maps.KmlLayer({
url: 'http://www.census.gov/main/kml/countysubs_z6/AR/05003.xml',
clickable: false
});
ctaLayer.setMap(map);
google.maps.event.addListener(map, 'click', function(e) {
placeMarker(e.latLng, map);
});
}
function placeMarker(position, map) {
var marker = new google.maps.Marker({
position: position,
map: map
});
map.panTo(position);
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map-canvas {
height: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js"></script>
<div id="map-canvas"></div>