Dynamic google map icons - javascript

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

Related

Filter data from database in Leaflet [duplicate]

I want to filter my markers by name, using map.addLayer(nameOfTheMarker) and map.remvoeLayer(nameOfTheLayer) with a checkbox like this:
$('#markertoggle').change(function () {
if (!this.checked)
// ^
map.addLayer(nameOfTheMarker);
else
map.remvoeLayer(nameOfTheLayer;
});
I found a jsfiddle with an example of a filter, but I don't know how to apply it to my code:
var locations = [
['AB11 5HW','17','A',57.147701,-2.085442 ] ,
['AB11 8DG','3','B',57.129372,-2.090916 ]
];
var markersA = [];
var markersB = [];
//Loop through the initial array and add to two different arrays based on the specified variable
for(var i=0; i < locations.length; i++) {
switch (locations[i][2]) {
case 'A' :
markersA.push(L.marker([locations[i][3], locations[i][4]]));
break;
case 'B' :
markersB.push(L.marker([locations[i][3], locations[i][4]]));
break;
default :
break;
}
}
//add the groups of markers to layerGroups
var groupA = L.layerGroup(markersA);
var groupB = L.layerGroup(markersB);
//background tile set
var tileLayer = {'Gray' : L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png')
};
var map = L.map('map', {
center: new L.LatLng(57.0, -2),
zoom: 9,
layers: [tileLayer['Gray'], groupA, groupB] //change this to determine which ones start loaded on screen
});
//Control on the Top Left that handles the switching between A and B
var overlayMaps = {
"A": groupA,
"B": groupB
};
L.control.layers(tileLayer, overlayMaps, {position:'topleft'}).addTo(map);
http://jsfiddle.net/RogerHN/31v2afte/2/
The function that I use to pull the markers:
function showMarkersByName(name) {
for (var i = 0; i < markers.resources.length; i++) {
var resName = markers.resources[i].name;
if (resName == name) {
var resIcon = icons.resources[i].icon;
var resSize = icons.resources[i].size;
var resPname = icons.resources[i].pname;
var customIcon = L.icon({
iconUrl: resIcon,
iconSize: resSize, // size of the icon
iconAnchor: [resSize[0]/2, resSize[1]/2], // point of the icon which will correspond to marker's location
popupAnchor: [2, -resSize[1]/2] // point from which the popup should open relative to the iconAnchor
});
for (var j = 0; j < markers.resources[i].coords.length; j++) {
var x = markers.resources[i].coords[j].x;
var y = markers.resources[i].coords[j].y;
marker = L.marker([y, x], {icon: customIcon});
marker.addTo(map).bindPopup(resPname);
$(marker._icon).addClass(name)
}
}
}
My markers structure its very similar with the one in the example, I just don't know where in my function I need to insert the filter to filter the markers by name, adding then to a layer to later toggle them use the checkbox above.
My full code here: http://plnkr.co/edit/UwAelIuUYz4OkoOG7zFn?p=preview
Using the example above and the code iH8 mentioned I was able to create a checkbox to toggle markers filtering them by its name:
function initLayerGroups() {
for (var i = 0; i < markers.resources.length; i++) {
switch (markers.resources[i].name) {
case 'GreenMarker':
for (var j = 0; j < markers.resources[i].coords.length; j++) {
var x = markers.resources[i].coords[j].x;
var y = markers.resources[i].coords[j].y;
marker = L.marker([y, x], {
icon: getIcon(i)
}).bindPopup(getPopupContent(i));
markersGreen.push(marker);
}
break;
case 'BlueMarker':
for (var j = 0; j < markers.resources[i].coords.length; j++) {
var x = markers.resources[i].coords[j].x;
var y = markers.resources[i].coords[j].y;
marker = L.marker([y, x], {
icon: getIcon(i)
}).bindPopup(getPopupContent(i));
markersBlue.push(marker);
}
break;
case 'RedMarker':
for (var j = 0; j < markers.resources[i].coords.length; j++) {
var x = markers.resources[i].coords[j].x;
var y = markers.resources[i].coords[j].y;
marker = L.marker([y, x], {
icon: getIcon(i)
}).bindPopup(getPopupContent(i));
markersRed.push(marker);
}
break;
default:
break;
}
}
groupGreen = L.layerGroup(markersGreen);
groupBlue = L.layerGroup(markersBlue);
groupRed = L.layerGroup(markersRed);
}
The checkbox:
<input type="checkbox" id="greenmarkertoggle"/>
<label for="greenmarkertoggle">Green Marker</label>
And the javascript code to show or hide the layer:
$('#greenmarkertoggle').change(function() {
if (this.checked)
map.addLayer(groupGreen);
else
map.removeLayer(groupGreen);
});
And here's the full working example using the code above:
http://plnkr.co/edit/GuIVhtFdtMDbmZdME1bV?p=preview
Thanks to iH8 and the example above I was able to create that function and filter the markers by its name.

using leaflet styled layer control and clusters

I'm creating a map that uses this styled layer control plug in
and the marker clusters plug in.
I've gotten both plug ins to work on their own with my data, but can't figure out how to get them to work together.
I have downloaded and included the marker cluster layer support files and attempted to implement them but it didn't change anything.
Basically there will be a category for each day of the week, and then within each day filters to show food or drink information, so I need this kind of layer control. I'm also open to suggestions for how to create my own layer control that is like this (grouping layers and then allowing you to filter within those groups)
var base = L.tileLayer('https://api.mapbox.com/styles/v1/agrosh/cj6p9fuxu2di72ss05n5nhycx/tiles/256/{z}/{x}/{y}?access_token=pk.eyJ1IjoiYWdyb3NoIiwiYSI6ImNpeWFscjNkZzAwN3AycW55aXB6eWtjZnoifQ.ZudIxK3hMrxAX8O4BXhiEg', {
});
var zoomLevel = 13;
var setLat = 35.593464;
var setLong = -82.551934;
var map = L.map('map', {
center: [setLat, setLong],
zoom: zoomLevel
});
map.addLayer(base);
var mondayFood = [
{
"name":"name",
"details":"ex",
"address":"",
"website":"",
"lat":35.591140,
"lng":-82.552111,
"yelp":"",
"google":"",
"img":"img"
}];
var mondayDrink = [
{
"name":"name",
"details":"ex",
"address":"",
"website":"",
"lat":35.594446,
"lng":-82.555602,
"yelp":"",
"google":"",
"img":"img"
}];
var markerClusters = L.markerClusterGroup.layerSupport().addTo(map);
// monday
for ( var i = 0; i < mondayFood.length; ++i )
{
var monFood = mondayFood[i].img;
var mF = L.marker( [mondayFood[i].lat, mondayFood[i].lng], {icon: myIcon} )
.bindPopup( monFood );
markerClusters.addLayer( mF );
}
for ( var i = 0; i < mondayDrink.length; ++i )
{
var monDrink = mondayDrink[i].img;
var mD = L.marker( [mondayDrink[i].lat, mondayDrink[i].lng], {icon: myIcon} )
.bindPopup( monDrink );
markerClusters.addLayer( mD );
}
var overlays = [
{
groupName : "Monday",
expanded : true,
layers : {
"Food" : mondayFood
"Drink" : mondayDrink,
}];
}
var options = {
container_width : "300px",
group_maxHeight : "80px",
//container_maxHeight : "350px",
exclusive : false,
collapsed : true,
position: 'topright'
};
var control = L.Control.styledLayerControl(overlays, options);
map.addControl(control);
The Layers Control can handle Leaflet layers, not plain JavaScript data object.
In your case, you would probably not even directly use your mD and mF layers, since they are used only temporarily within your loops.
Instead, the classic way is to use Leaflet Layer Groups to gather your drink markers and food markers. MCG.layersupport is designed to be able to handle these Layer Groups.
var markerClusters = L.markerClusterGroup.layerSupport().addTo(map);
var groupFood = L.layerGroup().addTo(markerClusters);
var groupDrink = L.layerGroup().addTo(markerClusters);
for (var i = 0; i < mondayFood.length; ++i) {
var mF = L.marker([mondayFood[i].lat, mondayFood[i].lng]);
//markerClusters.addLayer(mF);
mF.addTo(groupFood);
}
for (var i = 0; i < mondayDrink.length; ++i) {
var mD = L.marker([mondayDrink[i].lat, mondayDrink[i].lng]);
//markerClusters.addLayer(mD);
mD.addTo(groupDrink);
}
var overlays = [{
groupName: "Monday",
expanded: true,
layers: {
//"Food": mondayFood,
//"Drink": mondayDrink
"Food": groupFood,
"Drink": groupDrink
}
}];
var control = L.Control.styledLayerControl(overlays);
map.addControl(control);
Live demo: http://plnkr.co/edit/ufoKZ0BJbjXILPV3iLpj?p=preview

Removing GeoJson Layers from Google Maps

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 });

Google map not getting centered

The google map i am using does not get centered about the mean point i have calculated.
The code for the initialization is given. The map appears to be zoomed out a lot and its center far off from the center i have calculated. The mean appears in the extreme top left of the map. What is the problem here?
I am displaying the map in Bootstrap modal.
function initializeMap()
{
var xMean = 0.0;
var yMean = 0.0;
for(var i=0;i<points.length;i++)
{
xMean += parseFloat(points[i][0]);
yMean += parseFloat(points[i][1]);
}
xMean /= parseFloat(points.length);
yMean /= parseFloat(points.length);
var myMean = new google.maps.LatLng(xMean, yMean);
var mapOptions = {
zoom:17,
center:myMean
}
map = new google.maps.Map(document.getElementById('map'), mapOptions);
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i<points.length;i++) {
path.push(new google.maps.LatLng(points[i][0],points[i][1]));
bounds.extend(path[i]);
};
map.fitBounds(bounds);
//Displaying the markers
var marker;
for (var i = 0; i < path.length; i++) {
marker = new google.maps.Marker({
position: path[i],
map: map
});
}
//Displaying the path
for (var i = 0; i<path.length-1; i++) {
var start = path[i];
var end = path[i+1];
requestDirections(start,end);
}
}
by using:
map.fitBounds(bounds);
map.setCenter(bounds.getCenter());
you seem to overwrite myMean coordinates

Google Maps v3 using markers that move about the map

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

Categories

Resources