How do you get a mapbox's marker? - leaflet

I'm trying to add markers to a map using the
L.mapbox.featureLayer({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [ll[0], ll[1]]
},
properties: {
title: d[i].screen_name,
media: d[i].media_url,
id: d[i].source_id,
text: d[i].text,
userId: d[i].user_id,
'marker-color': '#000',
'marker-symbol': 'star-stroked'
}
}).addTo(map);
method but how do I from there access that marker? map.getLayerAt(0) or something?
It doesn't; display on the map for some reason..

Mocked this up quickly based on an example on the Mapbox site:
var map = L.mapbox.map('map', 'examples.map-zr0njcqy');
map.featureLayer.on('ready', function(e) {
var markers = [];
this.eachLayer(function(marker) { markers.push(marker); });
cycle(markers);
});
function cycle(markers) {
var i = 0;
function run() {
if (++i > markers.length - 1) i = 0;
var marker = markers[i];
console.log(marker.getLatLng());
}
run();
}
You can use the cycle() function to do stuff with each individual marker - if you look in the console you'll see that you can know access the marker's internal properties like latLng etc. I don't know what you want to do with each marker, so if you provide more information I'll be able to assist you more!

Related

adding layer on search for leaflet map changes polygon opacity

I have two leaflet maps which are loaded with geojson on the basis of a search button click. This shows some polygons with a style opacity 0.3 so you can see the street names under the polygons.
It works great except that any additional searches and loading of polygons starts to change the opacity of the polygon, making it more solid so you cant read the names of the streets under the polygon.
I try clearing the geojson layer before adding to the map, but the issue persists.
I have created a rough code pen of the issue here:
https://codepen.io/joomkit/pen/xxXgLPJ?editors=1111
Essentially just click the search button to load the layer no need to fill the listener runs a function and gets static data.
I have tried various methods to remove layer. A second click on the search is meant to clear the layer and load a new one. In the example it's just reloading the original data but the opacity is clearly demonstrated.
Main code is also below.
var geoMap2;
var lamap = new L.Map("map2", {
center: new L.LatLng(51.44094723464765, 0.048892332250943187),
// center: new L.LatLng(39.75621,-104.99404),
zoom: 14,
maxZoom: 18
});
var osm2 = L.tileLayer(
"https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",
{
attribution:
'© OpenStreetMap contributors © CARTO',
subdomains: "abcd",
maxZoom: 18
}
);
lamap.addLayer(osm2);
searchButton.addEventListener("click", function (e) {
let searchQuery = inputSearch.value;
// searchOpenFunding(searchQuery);
setLaMap(data);
});
function setLaMap(data) {
removeLayers();
let geojsonFeatureCollection2 = {
type: "FeatureCollection",
features: setFeatureCollection2(data)
};
geoMap2 = L.geoJSON(geojsonFeatureCollection2, {
style: polyStyleLAMap,
onEachFeature: function myonEachFeatureLaMap(feature, layer) {
layer.myTag = "myGeoJSON";
}
}).addTo(lamap);
lamap.setMaxBounds(lamap.fitBounds(geoMap2.getBounds()));
lamap.setZoom(13);
}
var removeLayers = function () {
lamap.eachLayer(function (layer) {
if (layer.myTag && layer.myTag === "myGeoJSON") {
lamap.removeLayer(layer);
console.log("rem layer from ");
}
});
};
function setFeatureCollection2(data) {
for (const [key, item] of Object.entries(data)) {
// setup lealfet geojson collection from data mapit api is incomplete pe ritem so we build it here
geoJsonFeatures2.push({
type: "Feature",
properties: {
craftentryId: item.id,
areaId: item.mapitAreaId,
lsoacode: item.lsoacode,
localauthority: item.localauthority,
openForFunding: item.openForFunding,
fundableRegion: item.fundableRegion,
title: item.title,
popupContent: ""
},
geometry: item.geojson
});
}
return geoJsonFeatures2;
}
function polyStyleLAMap(feature) {
return {
fillColor: getFillColorLaMap(feature.properties.openForFunding),
weight: 1,
opacity: 1,
color: getBorderColor(feature.properties.openForFunding),
dashArray: "0",
fillOpacity: 0.3
};
}
function getFillColorLaMap(d) {
return d === true ? "#FFFFFF" : d === false ? "#FED976" : "#FED976";
}
function getBorderColor(d) {
return d === true ? "#0e9c12" : d === false ? "#adabab" : "#cccccc";
}
Look here https://codepen.io
The code I modified is:
// 029A, 029C
function setLaMap(data) {
removeLayers();
let geojsonFeatureCollection2 = {
type: "FeatureCollection",
features: setFeatureCollection2(data),
};
console.log(geojsonFeatureCollection2);
const geoMap2 = L.geoJSON(geojsonFeatureCollection2, {
style: polyStyleLAMap,
onEachFeature: function (feature, layer) {
layer.myTag = "myGeoJSON";
},
});
map.addLayer(geoMap2);
map.setMaxBounds(map.fitBounds(geoMap2.getBounds()));
// map.setZoom(13);
}
function removeLayers() {
map.eachLayer((layer) => {
if (layer.myTag && layer.myTag === "myGeoJSON") {
console.log(layer);
map.removeLayer(layer);
}
});
}
You need to keep the geojson layer in a global variable and remove it before over writing with the new layer data.
var geoMap2;
function setLaMap(data){
if(geoMap2) { // if geoMap2 is set remove it
lamap.removeLayer(geoMap2)
}
const geojsonFeatureCollection2 = {
"type": "FeatureCollection",
"features": setFeatureCollection2(data)
}
geoMap2 = L.geoJSON(geojsonFeatureCollection2, {
style: polyStyleLAMap,
onEachFeature: myonEachFeatureLaMap
})
.........

How to add predefined places/markers to Leaflet Geocoder

I am using Leaflet Map with geocoder (ESRI) and Routing Machine.
I have added two markers, let's say my home and my work
var marker_work = L.marker([50.27, 19.03], { title: 'MyWork'}).addTo(map)
.bindPopup("work").openPopup();
var marker_home = L.marker([50.10, 18.4], { title: 'MyHome'}).addTo(map)
.bindPopup("home").openPopup();
Here is an example fiddle:
https://jsfiddle.net/21nmk8so/1/
How can I add this markers/point as a predefined places for ControlGeocoder?
I want to use them in search and use as a start point / end point for route calculation.
Another example for the same question: how to add custom-fake city with lat/lon and be able to search (find route) to/from that city.
I don't know if this is the best solution but it is working:
Create a custom Geocoder Class which overwrites the geocode function. There you can overwrite the result function and apply suggestions to the result.
L.CustomGeocoder = L.Control.Geocoder.Nominatim.extend({
suggestions: [],
setSuggestions(arr){
this.suggestions = arr;
},
createSuggestionFromMarker(marker){
this.suggestions.push({name: marker.options.title, center: marker.getLatLng()});
},
getResultsOfSuggestions(query){
var results = [];
this.suggestions.forEach((point)=>{
if(point.name.indexOf(query) > -1){
point.center = L.latLng(point.center);
point.bbox = point.center.toBounds(100);
results.push(point);
}
});
return results;
},
geocode(query, resultFnc, context) {
var that = this;
var callback = function(results){
var sugg = that.getResultsOfSuggestions(query);
resultFnc.call(this,sugg.concat(results));
}
L.Control.Geocoder.Nominatim.prototype.geocode.call(that,query, callback, context);
}
})
Then you have to use the new Geocoder Class:
var geocoder = new L.CustomGeocoder({});
var control = L.Routing.control({
waypoints: [],
router: new L.Routing.osrmv1({
language: 'en',
profile: 'car'
}),
geocoder: geocoder
}).addTo(map);
And finally you can add suggestions over markers and theier title option over createSuggestionFromMarker(marker) or setSuggestions(arr):
var suggestions = [
{
name: 'Test Car 1',
center: [50.27, 19.03]
},
{
name: 'Test Car 2',
center: [50.10, 18.4]
}
];
geocoder.setSuggestions(suggestions);
var marker_work = L.marker([50.27, 19.03], { title: 'MyWork'}).addTo(map);
var marker_home = L.marker([50.10, 18.4], { title: 'MyHome'}).addTo(map);
geocoder.createSuggestionFromMarker(marker_work);
geocoder.createSuggestionFromMarker(marker_home);
Update, use marker Ref instead of fix latlng
Change this two function, then the marker is referenced and it always searches from the current position of the marker:
createSuggestionFromMarker(marker){
this.suggestions.push({name: marker.options.title, marker: marker});
},
getResultsOfSuggestions(query){
var results = [];
this.suggestions.forEach((point)=>{
if(point.name.indexOf(query) > -1){
if(point.marker){
point.center = point.marker.getLatLng();
}
point.center = L.latLng(point.center);
point.bbox = point.center.toBounds(100);
results.push(point);
}
});
return results;
},
You can test this in the demo, when you drag the marker
https://jsfiddle.net/falkedesign/hu25jfd1/

make multiple markers draggable

I use an Array to create a couple of markers in my leaflet map for Photos with Geolocations which works fine:
for (var p of ArrayofData) {
var lat = p.lat;
var lon = p.lon;
var markerLocation = new L.LatLng(lat, lon);
var marker = new L.Marker(markerLocation,{
draggable: 'true',
id: p.Filename
});
mymap.addLayer(marker);
}
to enable users to change their photo location I need them to drag those markers around and then I can read the new location:
marker.on('dragend', function (e) {
// Get position of dropped marker
var latLng = e.target.getLatLng();
console.log ("id:"+e.target.options.id);
console.log ("NewLocation:"+latLng);
});
As all of my markers have the same constructor it seems as if this script only works with the last marker. All others are draggable but do not give back any feedback when released.
Does anybody know, how I can access all of them?
You can do that by adding those drag event handlers inside your for loop.
for (var p of data) {
var lat = p.lat;
var lon = p.lon;
var markerLocation = new L.LatLng(lat, lon);
var marker = new L.Marker(markerLocation,{
draggable: 'true',
id: p.Filename
});
map.addLayer(marker);
marker.on('dragend', function (e) {
// Get position of dropped marker
var latLng = e.target.getLatLng();
console.log ("id:"+e.target.options.id);
console.log ("NewLocation:"+latLng);
});
}
Also I highly recommend that you keep track of your markers by adding them to an array.
var markers = [];
for (var p of data) {
var lat = p.lat;
var lon = p.lon;
var markerLocation = new L.LatLng(lat, lon);
var marker = new L.Marker(markerLocation,{
draggable: 'true',
id: p.Filename
});
map.addLayer(marker);
marker.on('dragend', function (e) {
// Get position of dropped marker
var latLng = e.target.getLatLng();
console.log ("id:"+e.target.options.id);
console.log ("NewLocation:"+latLng);
});
markers.push(marker);
}
Demo

Add an info window to each marker when select place in list view

// inital Locations
var myLocations = [{
name: "Istanbul",
address: "214 S Highland Ave, Pittsburgh, PA",
latlng: {
lat: 41.008238,
lng: 28.978359
}
}, {
name: "Antalya",
address: "5469 Penn Ave Pittsburgh, PA 15206",
latlng: {
lat: 36.896891,
lng: 30.713323
}
}, {
name: "Ankara",
address: "236 Fifth Ave Pittsburgh, PA 15222",
latlng: {
lat: 39.933363,
lng: 32.859742
}
}, {
name: "Trabzon",
address: "5608 Walnut St Pittsburgh, PA 15232",
latlng: {
lat: 41.002697,
lng: 39.716763
}
}, {
name: "Bursa",
address: "5841 Penn Ave Pittsburgh, PA 15206",
latlng: {
lat: 40.188528,
lng:29.060964
}
},
];
//String to display in info window
//Declare Map variable and markers array
var map;
var infoWindow;
var marker;
//Create Instance of a map from the Google maps api
//Grab the reference to the "map" id to display map
//Set the map options object properties
function initMap() {
map = new google.maps.Map(document.getElementById("map"), {
center: {
lat: 38.963745,
lng: 35.243322
},
zoom: 5,
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControl: true,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
}
});
};
// tells the view model what to do when a change occurs
function mLocation(value) {
this.name = ko.observable(value.name);
this.address = ko.observable(value.address);
this.description = ko.observable(value.description);
this.latlng = ko.observable(value.lat);
};
//ViewModel
function ViewModel() {
var self = this;
self.markers = [];
//Copies the values of initialLocations and stores them in sortedLocations(); observableArray
self.sortedLocations = ko.observableArray(myLocations);
//Adds new markers at each location in the initialLocations Array
self.sortedLocations().forEach(function(location) {
marker = new google.maps.Marker({
position: location.latlng,
map: map,
title: location.name,
icon: 'img/marker.png',
animation: google.maps.Animation.DROP
});
location.marker = marker;
var content = '<div id="iw_container">' +
'<div class="iw_title">' + name + </div>';
//Pushes each marker into the markers array
this.markers.push(marker);
});
//Map info windows to each item in the markers array
self.markers.map(function(info) {
infoWindow = new google.maps.InfoWindow({
content: content
});
//Add click event to each marker to open info window
info.addListener('click', function() {
infoWindow.open(map, this),
info.setAnimation(google.maps.Animation.BOUNCE) //Markers will bounce when clicked
setTimeout(function() {
info.setAnimation(null)
}, 2000); //Change value to null after 2 seconds and stop markers from bouncing
});
});
//Click on item in list view
self.listViewClick = function(loc) {
if (loc.name) {
map.setZoom(15); //Zoom map view
map.panTo(loc.latlng); // Pan to correct marker when list view item is clicked
loc.marker.setAnimation(google.maps.Animation.BOUNCE); // Bounce marker when list view item is clicked
infoWindow.open(map, loc.marker); // Open info window on correct marker when list item is clicked
}
setTimeout(function() {
loc.marker.setAnimation(null); // End animation on marker after 2 seconds
}, 2000);
};
// Stores user input
self.query = ko.observable('');
//Filter through observableArray and filter results using knockouts utils.arrayFilter();
self.search = ko.computed(function() {
return ko.utils.arrayFilter(self.sortedLocations(), function(listResult) {
return listResult.name.toLowerCase().indexOf(self.query().toLowerCase()) >= 0;
});
});
};
$(document).ready(function() {
initMap();
ko.applyBindings(ViewModel());
});
I would like to ask about how to add an info window to a marker in Google Maps. The condition is, I have to create a program with multiple markers on a map. But how I can give a specified info window to each marker when select in each place in the view list?

Leaflet Markercluster - tooltip on hover issue

I'm a newbie of javascript, trying to build an interactive map online, where some events should be triggered by clicking on markers and some just by hovering them.
Managed to have the click part working, but, because of Markercluster plugin, I'm not sure where to use onEachFeature function for having the tooltip opened by hover a single marker.
Anyone please can tell me what I'm doing wrong?
var geoJsonFeature = {
type: 'FeatureCollection',
features:
[
{
type: 'Feature',
properties: {
title: 'Title',
page: 'some.html',
'marker-color': '#000000',
zoom: 7
},
geometry: {
type: 'Point',
coordinates: [12.583745,55.6750803]
}
},
...
};
// access to mapbox api
L.mapbox.accessToken ='...';
var map = L.mapbox.map('map', 'example1234').setView([34, -37], 3);
function getTitle(marker) {
return marker.feature.properties.title;
};
function getPage(marker) {
return marker.feature.properties.page;
};
var markerGroup = new L.MarkerClusterGroup({showCoverageOnHover:false});
var geoJsonLayer = L.geoJson(geoJsonFeature, {
onEachFeature: function (feature, layer) {
var popupContent = getTitle(marker);
layer.bindPopup(popupContent);
}
});
markerGroup.addLayer(geoJsonLayer);
map.addLayer(markerGroup);
markerGroup.on('click', function(ev) {
var marker = ev.layer;
marker.on('click', function(ev) {
if(map.getZoom() > marker.feature.properties.zoom) {
map.setView(ev.latlng, map.getZoom());
}
else {
map.setView(ev.latlng, marker.feature.properties.zoom);
}
});
});
});
geoJsonLayer.on('mouseover', function(e) {
e.layer.openPopup();
});
geoJsonLayer.on('mouseout', function(e) {
e.layer.closePopup();
});
You need to use the onEachFeature option to get the individual markers and bind handlers to the mouseover and mouseout events:
onEachFeature: function (feature, layer) {
layer.bindPopup(feature.properties.title);
layer.on("mouseover", function () {
layer.openPopup();
});
layer.on("mouseout", function () {
layer.closePopup();
});
}
Here's a working example on Plunker: http://plnkr.co/edit/hfjOWv3uCBFawDGqR3Ue?p=preview
Note: i'm not using ClusterMarker in this example but it should work just fine when using ClusterMarker