I'm trying to remove an array of GeoJson layers from Google Maps using the turf.js library for smoothing of the poly-lines.
I can create the layer fine and add them to the map, but when I try and remove the layers I get the following error code:
Uncaught TypeError: a.getId is not a function
To add the layers I do this, looping through my GeoJson file...
else if(Type==="LineString" && Pype==="isobar") {
//DO ISOBARS STUFF=================================
//GET LNG/LAT======================================
CorrLEN = dataID1.features[i].geometry.coordinates.length;
var Corrds =[];
var Corrs =[];
var LNGLAT ={};
var CORRS = new Object();
var x=0;
for (x=0;x<CorrLEN;x++){
var a = x-1;
LNGLAT = (dataID1.features[i].geometry.coordinates[x]);
Corrds.push(LNGLAT);
}
//=================================================================
//GET COLOUR INFO===================================================
var STCL = dataID1.features[i].properties.strokeColor;
var STOP = dataID1.features[i].properties.strokeOpacity;
var STSW = dataID1.features[i].properties.strokeWeight;
//=================================================================
LL = turf.linestring(Corrds);
curved = turf.bezier(LL,20000, 0.35);
curved.properties = {weight:STSW,color:STCL};
map.data.setStyle(function(feature) {
return {strokeWeight:feature.getProperty('weight'),
strokeColor: feature.getProperty('color')
};
});
IsoBars.push(curved);
I then use the following functions to add or remove the layers
//SHOW ISOBARS (works fine)
function ShowIsoBars() {
for (var i = 0; i < IsoBars.length; i++) {
map.data.addGeoJson(IsoBars[i]);
}}
//HIDE ISOBARS (Gets the error) Uncaught TypeError: a.getId is not a function
function HideIsoBars() {
for (var i = 0; i < IsoBars.length; i++) {
map.data.remove(IsoBars[i]);
}}
Many thanks in advance,
I found a solution by taking the new smoothed coordinates and then using them in a new google.maps.Polyline like so
var Path =[];
var x=0;
for (x=0;x<CorrLEN;x++){
Path.push(new google.maps.LatLng(curved.geometry.coordinates[x][1],curved.geometry.coordinates[x][0]));
}
var IsoBar = new google.maps.Polyline({
path: Path,
geodesic: true,
strokeColor: STCL,
strokeOpacity: STOP,
strokeWeight: STSW
});
IsoBars.push(IsoBar);
And then I can use the the following functions to show or hide the layers
function ShowIsoBars() {
for (var i = 0; i < IsoBars.length; i++) {
IsoBars[i].setMap(map);
}}
function HideIsoBars() {
for (var i = 0; i < IsoBars.length; i++) {
IsoBars[i].setMap(null);
}}
I found rather than removing all objects from the layer. It was easier to destroy and recreate the layer, which circumvents the error:
//Remove layer from map if it exists
if (mapLayer != null) {
mapLayer.setMap(null);
}
//create new layer
mapLayer = new window.google.maps.Data({ map: googleMap });
Related
I have 2 tables one with markers another with marker icons. The icons are stored in the database as blob, where markers and icons are mapped by the ID's. The issue i am having is mapping the icons by id and markers type to the correct.
for example:
I'm trying to implement something like the following https://developers.google.com/maps/documentation/javascript/custom-markers
what i have done so far is the following
converting the overlay results(which i get via ajax and push to overlayRes object)
var binary = new Array();
for (i = 0; i < overlayRes.length; i++) {
var iconData = overlayRes[i].OverlayData.replace(/[^A-Fa-f0-9]/g, "");
for(var i=0; i< iconData.length / 2; i++){
var h = iconData.substr(i * 2, 2);
binary[i] = parseInt(h, 16);
}
}
byteArray = new Uint8Array(binary);
img = window.URL.createObjectURL(new Blob([byteArray], { type: 'application/octet-stream' }));
var icons = {
K: {
icon: img
},
L: {
icon: img
},
};
//markers
for (var i = 0; i < features.length; i++) {
var marker = new google.maps.Marker({
position: features[i].position,
icon: icons[features[i].type].icon, // need to get different markers per marker type
map: map
});
TIA
I wish to determine if a given point(latitude and longitude) is found within a drawn polygon on a Bing map or not. The polygon is drawn by the user.
This is what I already have
<script type='text/javascript'>
var map, drawingManager;
function GetMap() {
map = new Microsoft.Maps.Map('#myMap', {});
//Load the DrawingTools module
Microsoft.Maps.loadModule('Microsoft.Maps.DrawingTools', function () {
//Create an instance of the DrawingTools class and bind it to the map.
var tools = new Microsoft.Maps.DrawingTools(map);
//Show the drawing toolbar and enable editing on the map.
tools.showDrawingManager(function (manager) {
//Store a reference to the drawing manager as it will be useful later.
drawingManager = manager;
//Create a shortcut to the DrawingBarAction to minimize code.
var da = Microsoft.Maps.DrawingTools.DrawingBarAction;
//Limit which tools appear in the drawing toolbar.
manager.setOptions({
drawingBarActions: da.polyline | da.polygon | da.erase,
fillColor: 'rgba(255, 0, 0, 0.5)'
});
});
});
}
function IsPointInPolygon() {
var shapes = drawingManager.getPrimitives();
if (shapes && shapes.length > 0) {
for (i = 0; i < shapes.length; i++) {
var points = shapes[i].getLocations();
//Get all locations from DB
$.ajax({
url: 'http://localhost:53851/Locations/ReturnLocationsList',
type: 'POST',
dataType: 'json',
success: function (response) {
//do something with data
//alert(JSON.stringify(response.data));
arrayLocations = response.data;
//alert(arrayLocations.length);
var columns = ['IdLocation', 'Name', 'Latitude', 'Longitude'];
//Convert gotten locations to Maps.Locations in order to ease calculations
var allLocations = [];
alert("are you here ?");
for (i = 0; i < arrayLocations.length; i++) {
var coordinates = new Microsoft.Maps.Location(arrayLocations[i].Latitude, arrayLocations[i].Longitude);
allLocations.push(coordinates);
}
alert(allLocations[0]);
//Add pushpin to each location coming from DB
var pinLocation = new Microsoft.Maps.Pushpin(origin, {
color: 'blue'
});
for (i = 0; i < allLocations.length; i++) {
map.entities.push(pinLocation);
if (pointInPolygon(points, allLocations[i].Latitude, allLocations[i].Longitude)) {
alert("Point is inside polygon");
}
else {
alert("Point is not found in polygon");
}
}
function pointInPolygon(points, lat, lng) {
// ray-casting algorithm based on
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
var inside = false;
for (var i = 0, j = points.length - 1; i < points.length; j = i++) {
var intersect =
points[i].latitude > lat != points[j].latitude > lat &&
lng <
((points[j].longitude - points[i].longitude) *
(lat - points[i].latitude)) /
(points[j].latitude - points[i].latitude) +
points[i].longitude;
if (intersect) inside = !inside;
}
return inside;
}
},
error: function (error) {
//log or alert the error
alert("There's an error !");
//alert(error);
}
});
}
//return locations;
} else {
alert("No shapes in the drawing manager.");
}
}
</script>
<script type='text/javascript' src='https://www.bing.com/api/maps/mapcontrol?callback=GetMap&key=[Bing Map key]' async defer></script>
<div class="row">
<div class="col-lg-12">
<div id="myMap" style="position:relative;width:950px;height:500px;"></div>
<input type="button" class="btn btn-primary" value="Get Shapes" onclick="IsPointInPolygon()" />
</div>
</div>
The arrayLocations are locations actually coming from the database and within these locations are at least one found in the drawn polygon area, but I definitely get the "Point not found in polygon" message, for all the locations.
I even tried adding pushpins to each of the locations coming from the database, but the pushpins won't display on the map.
I'm completely lost. Please for any help!
It appears you adapted the Polygon Search algorithm from official documentation, right? If so, their implementation is appears to be buggy and is not working as expected.
Instead i would propose to utilize the following one to determine whether the point is actually inside the polygon:
function pointInPolygon(points, lat, lng) {
// ray-casting algorithm based on
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
var inside = false;
for (var i = 0, j = points.length - 1; i < points.length; j = i++) {
var intersect =
points[i].latitude > lat != points[j].latitude > lat &&
lng <
((points[j].longitude - points[i].longitude) *
(lat - points[i].latitude)) /
(points[j].latitude - points[i].latitude) +
points[i].longitude;
if (intersect) inside = !inside;
}
return inside;
}
Demo
var map, drawingManager, point;
function GetMap() {
map = new Microsoft.Maps.Map("#myMap", {});
point = map.getCenter();
var pin = new Microsoft.Maps.Pushpin(point, {
title: "Center point"
});
map.entities.push(pin);
//Load the DrawingTools module
Microsoft.Maps.loadModule("Microsoft.Maps.DrawingTools", function() {
//Create an instance of the DrawingTools class and bind it to the map.
var tools = new Microsoft.Maps.DrawingTools(map);
//Show the drawing toolbar and enable editing on the map.
tools.showDrawingManager(function(manager) {
//Store a reference to the drawing manager as it will be useful later.
drawingManager = manager;
//Create a shortcut to the DrawingBarAction to minimize code.
var da = Microsoft.Maps.DrawingTools.DrawingBarAction;
//Limit which tools appear in the drawing toolbar.
manager.setOptions({
drawingBarActions: da.polyline | da.polygon | da.erase,
fillColor: "rgba(255, 0, 0, 0.5)"
});
});
});
}
function getShapes() {
var shapes = drawingManager.getPrimitives();
if (shapes && shapes.length > 0) {
for (i = 0; i < shapes.length; i++) {
var points = shapes[i].getLocations();
if (pointInPolygon(points, point.latitude, point.longitude)) {
alert("Point is inside polygon");
} else {
alert("Point is not found in polygon");
}
}
//return locations;
} else {
alert("No shapes in the drawing manager.");
}
}
function pointInPolygon(points, lat, lng) {
// ray-casting algorithm based on
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
var inside = false;
for (var i = 0, j = points.length - 1; i < points.length; j = i++) {
var intersect =
points[i].latitude > lat != points[j].latitude > lat &&
lng <
((points[j].longitude - points[i].longitude) *
(lat - points[i].latitude)) /
(points[j].latitude - points[i].latitude) +
points[i].longitude;
if (intersect) inside = !inside;
}
return inside;
}
<div id="myMap" style="position:relative;width:640px;height:320px;"></div>
<input type="button" class="btn btn-primary" value="Get Shapes" onclick="getShapes()" />
<script
type="text/javascript"
src="https://www.bing.com/api/maps/mapcontrol?key=Ap12Gwv9esg5iXgfAh5Ehlbf36MZ-O8051Sl66Zm6glGwq7PSaaKgGPpcOUEGICy&callback=GetMap"
async
defer
></script>
I want to display multiple polylines from an XML file:
<lines>
<line>
<linePoint lat="47.608940" lng="-122.340141"/>
<linePoint lat="47.613590" lng="-122.344391"/>
<linePoint lat="47.624561" lng="-122.356445"/>
</line>
<line>
<linePoint lat="47.616600" lng="-122.344491"/>
<linePoint lat="47.627661" lng="-122.356545"/>
</line>
</lines>
I believe that the script should iterate twice - the outer loop going through line elements and the inner loop going through linePoint elements within each line.
But it seems that my script dumps all 5 linePoint into a single polyline instead of creating 2 polylines.
downloadUrl("createXML.php", function(data) {
var xml = data.responseXML;
var line = xml.documentElement.getElementsByTagName("line");
// Read each line
for (var a = 0; a < line.length; a++) {
var linePoint = xml.documentElement.getElementsByTagName("linePoint");
var path = [];
// Read markers on each line
for (var i = 0; i < linePoint.length; i++) {
var lat = parseFloat(linePoint[i].getAttribute("lat"));
var lng = parseFloat(linePoint[i].getAttribute("lng"));
var point = new google.maps.LatLng(lat,lng);
path.push(point);
}
var polyline = new google.maps.Polyline({
path: path
});
polyline.setMap(map);
}
});
Can someone please point out what I'm overlooking?
Yes, that is because you just extract all <linePoint>'s in one chunk by getElementsByTagName("linePoint") (elements in plural). Iterate over <line>'s and for each <line> iterate over its <linePoint>'s :
function showPolyLines() {
var parser = new DOMParser();
var xml = parser.parseFromString(responseXML, "application/xml");
var line = xml.querySelectorAll("line");
for (var l = 0; l < line.length; l++) {
var path = [],
linePoints = line[l].querySelectorAll('linePoint');
for (var p = 0; p < linePoints.length; p++) {
var linePoint = linePoints[p],
lat = parseFloat(linePoint.getAttribute("lat")),
lng = parseFloat(linePoint.getAttribute("lng")),
point = new google.maps.LatLng(lat, lng);
path.push(point);
}
var polyline = new google.maps.Polyline({
path: path,
//just to be sure the lines actually is shown on the map :)
strokeColor: '#FF0000',
strokeOpacity: 1.0,
strokeWeight: 2
});
polyline.setMap(map);
}
}
I am using a DOMParser to substitute xml.documentElement because I dont have a real responseXML in my fiddle test, but they are practically the same.
demo -> http://jsfiddle.net/9sqastj1/
http://rca2.com/mapping/thispageblinks.htm
http://rca2.com/mapping/doesnotremove.htm
The second example really doesn't do anything without continuously updated xml data.
I'm converting (finally!) my map applications from Google v2 to v3. In v2, the application read in xml data every 5 seconds, cleared markers, then new markers were created and placed on the map. The ability to clear the map overlay using map.clearOverlays() no longer exists in v3. The suggested solution is to keep track of the old markers, then remove them. Clearing the markers in a loop prior to creating new markers is easy to do, and works. Except for the fact that the markers blink when replaced more often than not. This is very distracting, and highly undesirable since this did not happen in v2.
I decided that I should compare the new marker data to the old marker data. If the location and icon color stayed the same, both old and new markers are basically ignored. For the sake of clarity, the icon color signifies a status of the vehicle represented by the icon. In this case the application is to track ambulance activity, so green would be available, blue would be en-route, etc.
The code handles the checking of the new and old markers fine, but for some reason, it will never remove the old marker when a marker (unit) moves. I saw suggestions about setMap() being asynchronous. I also saw suggestions about the arrays not being google.maps.Marker objects. I believe that my code handles each of these issues correctly, however the old markers are still never removed.
I've also made sure that my marker arrays are global variables. I am also using the variable side_bar_html to display information about which markers were supposed to be removed, and which markers were supposed to be added. The added markers are being added just fine. I just don't know where to turn next. Any help you could offer would be greatly appreciated.
function getMarkers() {
// create a new connection to get our xml data
var Connect = new XMLHttpRequest();
// send the get request
Connect.open("GET", xml_file, false);
Connect.setRequestHeader("Content-Type", "text/xml");
Connect.send(null);
// Place the response in an XML document.
var xmlDoc = Connect.responseXML;
// obtain the array of markers and loop through it
var marker_data = xmlDoc.documentElement.getElementsByTagName("marker");
// hide the info window, otherwise it still stays open where a potentially removed marker used to be
infowindow.close();
// reset the side_bar and clear the arrays
side_bar_html = "";
markerInfo = [];
newMarkers = [];
remMarkers = [];
addMarkers = [];
// obtain the attributes of each marker
for (var i = 0; i < marker_data.length; i++) {
var latData = marker_data[i].getAttribute("lat");
var lngData = marker_data[i].getAttribute("lng");
var minfo = marker_data[i].getAttribute("html");
var name = marker_data[i].getAttribute("label");
var icontype = marker_data[i].getAttribute("icontype");
var unitNum = marker_data[i].getAttribute("unitNum");
var llIcon = latData + lngData + icontype;
zIndexNum = zIndexNum + 1;
// create the new marker data needed
var myLatLng = new google.maps.LatLng(parseFloat(latData), parseFloat(lngData));
var marker = {
position: myLatLng,
icon: gicons[icontype],
title: "",
unitIcon: unitNum,
unitLLIData: llIcon,
zIndex: zIndexNum
};
// add a line to the side_bar html
// side_bar_html += '<a href="javascript:myclick(' + i + ')">' + name + '<\/a><br />';
// add an event listeners on the marker
addInfoWindow(marker, minfo);
// save the current data for later comparison
markerInfo.push(minfo);
newMarkers.push(marker);
}
// now loop thru the old marker data and compare to the new, to see if we need to remove any old markers
var refreshIt = true;
var removeIt = true;
var currNumber = "";
var currLLIcon = "";
var lastNumber = "";
var lastLLIcon = "";
for (var i = 0; i < newMarkers.length; i++) {
currNumber = newMarkers[i].unitIcon;
currLLIcon = newMarkers[i].unitLLIData;
for (var j = 0; j < oldMarkers.length; j++) {
refreshIt = true;
lastNumber = oldMarkers[j].unitIcon;
lastLLIcon = oldMarkers[j].unitLLIData;
if (lastNumber == currNumber) {
if (currLLIcon == lastLLIcon) {
refreshIt = false;
} else {
refreshIt = true;
remMarkers.push(oldMarkers[j]);
}
break;
}
}
// if we need to refresh a marker, add it to our new array here
if (refreshIt == true) {
addMarkers.push(newMarkers[i]);
}
}
// then loop thru and see if any units are no longer on the map
for (var j = 0; j < oldMarkers.length; j++) {
removeIt = true;
lastNumber = oldMarkers[j].unitIcon;
for (var i = 0; i < newMarkers.length; i++) {
currNumber = newMarkers[i].unitIcon;
if (lastNumber == currNumber) {
removeIt = false;
break;
}
}
// if we need to refresh a marker, add it to our new array here
if (removeIt == true) {
remMarkers.push(oldMarkers[j]);
}
}
// now loop thru the old markers and remove them
for (var i = 0; i < remMarkers.length; i++) {
var marker = new google.maps.Marker(remMarkers[i]);
marker.setMap(null);
side_bar_html += 'removing ' + remMarkers[i].unitIcon + '<br />';
}
// then loop thru the new markers and add them
for (var i = 0; i < addMarkers.length; i++) {
var marker = new google.maps.Marker(addMarkers[i]);
marker.setMap(map);
side_bar_html += 'adding ' + addMarkers[i].unitIcon + '<br />';
}
// and last save the old markers array into oldMarkers
oldMarkers = [];
for (var i = 0; i < newMarkers.length; i++) {
oldMarkers.push(newMarkers[i]);
}
// put the assembled side_bar_html contents into the side_bar div, then sleep
document.getElementById("side_bar").innerHTML = side_bar_html;
setTimeout('getMarkers()', 5000);
}
For context purposes, here is the code that does clear the old markers, but many (not all) or the markers blink when refreshed, even if they don't in fact move loaction.
function getMarkers() {
// create a new connection to get our xml data
var Connect = new XMLHttpRequest();
// send the get request
Connect.open("GET", xml_file, false);
Connect.setRequestHeader("Content-Type", "text/xml");
Connect.send(null);
// Place the response in an XML document.
var xmlDoc = Connect.responseXML;
// obtain the array of markers and loop through it
var marker_data = xmlDoc.documentElement.getElementsByTagName("marker");
// hide the info window, otherwise it still stays open where the removed marker used to be
infowindow.close();
// now remove the old markers
for (var i = 0; i < oldMarkers.length; i++) {
oldMarkers[i].setMap(null);
}
oldMarkers.length = 0;
// reset the side_bar and clear the arrays
side_bar_html = "";
markerInfo = [];
newMarkers = [];
// obtain the attributes of each marker
for (var i = 0; i < marker_data.length; i++) {
var latData = marker_data[i].getAttribute("lat");
var lngData = marker_data[i].getAttribute("lng");
var minfo = marker_data[i].getAttribute("html");
var name = marker_data[i].getAttribute("label");
var icontype = marker_data[i].getAttribute("icontype");
var unitNum = marker_data[i].getAttribute("unitNum");
zIndexNum = zIndexNum + 1;
// create the new marker data needed
var myLatLng = new google.maps.LatLng(parseFloat(latData), parseFloat(lngData));
var marker = new google.maps.Marker({
position: myLatLng,
icon: gicons[icontype],
title: "",
unitIcon: unitNum,
zIndex: zIndexNum
});
// add a line to the side_bar html
side_bar_html += '<a href="javascript:myclick(' + i + ')">' + name + '<\/a><br />';
// add an event listeners on the marker
addInfoWindow(marker, minfo);
// save the current data for later comparison
markerInfo.push(minfo);
newMarkers.push(marker);
oldMarkers.push(marker);
}
// now add the new markers
for (var i = 0; i < newMarkers.length; i++) {
newMarkers[i].setMap(map);
}
// put the assembled side_bar_html contents into the side_bar div, then sleep
document.getElementById("side_bar").innerHTML = side_bar_html;
setTimeout('getMarkers()', 5000);
}
Finally figured out the solution. The process was reading in new xml data which was compared to the saved xml data, to determine if a marker needed to be moved or displayed in a different color on the map.
When I created a new marker object, I did not set the map: property, because I needed to compare the lat/lon/color of the new object to the old before I determined whether a marker needed to be moved. The problem was the map: property not being set. I save the marker data without the map: property set into the new marker array, then copied the new marker array into old marker array to do the next comparison. I should have copied the old marker object into the new marker array! The old marker object HAD the map: property set, and that allowed the Google mapping code to know which marker I wanted to remove.
Sorry for the stupid mistake, but I'm pretty new to Javascript.
Rich
I have an MVCArray to store my polyline path in, but I need to clear the MVCArray when the user changes their selection. Relevant code is below.
routePoints = new google.maps.MVCArray();
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
markersArray = eval("(" + xmlhttp.responseText + ")");
removeLines();
for (var i = 0; i < markersArray.length; i++) {
var address = new google.maps.LatLng(markersArray[i][0], markersArray[i][1]);
routePoints.insertAt(routePoints.length, address);
}
routePath = new google.maps.Polyline({
path: routePoints,
strokeOpacity: 1.0,
strokeWeight: 2,
map: map,
});
}
}
The removeLines() function is below. I have tried many different versions of this function (while loop, routePoints.pop(), setting routePoints.length to 0), but nothing has cleared the MVCArray. The polylines are being displayed correctly by the way, but once a user changes their selection I need the previous polylines to be removed from the map. Thanks in advance.
function removeLines() {
if (routePoints) {
for (var i=0; i < routePoints.length; i++) {
routePoints.removeAt(i);
}
}
}
to delete all mvcarray elements:
routePoints.clear();
So routePoints is just an array of LatLng objects, not individual polylines. I think you probably need a separate array for the polylines, which you can then loop over to remove them all.
If you want to remove visible polylines, you can just call the setMap() function, passing it null.
routePoints = new google.maps.MVCArray();
var polylines = []; // new array for the polylines, needs to be a global variable
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
markersArray = eval("(" + xmlhttp.responseText + ")");
removeLines();
for (var i = 0; i < markersArray.length; i++) {
var address = new google.maps.LatLng(markersArray[i][0], markersArray[i][1]);
routePoints.insertAt(routePoints.length, address);
}
routePath = new google.maps.Polyline({
path: routePoints,
strokeOpacity: 1.0,
strokeWeight: 2,
map: map,
});
// add the polyline to the array
polylines.push(routePath);
}
}
function removeLines() {
for (var i=0; i < polylines.length; i++) {
polylines[i].setMap(null);
}
// you probably then want to empty out your array as well
polylines = [];
// not sure you'll require this at this point, but if you want to also clear out your array of coordinates...
routePoints.clear();
}