How can I pull a URL stored inside a Mapbox dataset and add it to a 'click' function on a popup? - mapbox

I have a function code that pulls data from the "description" field and displays it inside a popup on mouseenter, but can someone help me figure out how to pull in the URL stored inside "linkurl" and use it to open that URL when the icon is clicked? The popup displays properly over an icon, but I can't figure out how to bring the URL in as a link on click. Here's the code I'm working with:
map.on('load', function() {
// Create a popup, but don't add it to the map yet.
var popup = new mapboxgl.Popup({
closeButton: false,
closeOnClick: false
});
// POINTS OF INTEREST
function showPopup(e) {
// Updates the cursor to a hand (interactivity)
map.getCanvas().style.cursor = 'pointer';
// Show the popup at the coordinates with some data
popup
.setLngLat(e.features[0].geometry.coordinates)
.setHTML(checkEmpty(e.features[0].properties.description))
.addTo(map);
}
function hidePopup() {
map.getCanvas().style.cursor = '';
popup.remove();
}
function checkEmpty(info) {
return (info) ? info : "No data";
}
// CHANGE: Add layer names that need to be interactive
map.on('mouseenter', 'points-of-interest-2019', showPopup);
map.on('mouseleave', 'points-of-interest-2019', hidePopup);
});

To add a link within the Popup itself, you can use Popup#setHTML in conjunction with the <a> tag define a hyperlink. For example:
// Show the popup at the coordinates with some data
var properties = e.features[0].properties;
popup
.setLngLat(e.features[0].geometry.coordinates)
.setHTML(
'<a href=\'' + properties.linkurl + '\'>'
+ checkEmpty(properties.description)
+ '</a>')
.addTo(map);
Since creating a Popup with the GL JS API automatically creates a DOM element as outlined in the source code here, there is currently not a way to make the entire Popup clickable to navigate to a particular link. You could instead use Popup#setHTML along with some minimal CSS to create a link which wraps the entire content added to the Popup, so that clicking the content of the Popup will open the link.
Alternatively, if you are using Marker instances and would like clicking on the marker itself to open a link, you could utilize the options.element parameter to specify a DOM element wrapped in a link to use as a marker. For example, consider a slight modification to this example:
var el = document.createElement('a');
el.href = 'https://www.mapbox.com/'
el.className = 'marker';
el.style.backgroundImage =
'url(https://placekitten.com/g/' +
marker.properties.iconSize.join('/') +
'/)';
el.style.width = marker.properties.iconSize[0] + 'px';
el.style.height = marker.properties.iconSize[1] + 'px';
// add marker to map
new mapboxgl.Marker(el)
.setLngLat(marker.geometry.coordinates)
.addTo(map);

Related

Mapbox GL JS - Add new marker and remove previous marker

My function is supposed to display a marker over an existing icon (US Cities) when clicked/selected. The marker is an image file. Then when the user clicks on another icon, the previous marker should disappear.
It seems to work fine at first. The first marker is created when the icon is clicked. When the second icon is clicked, the marker is created and the original marker disappears. When a third icon is clicked, the marker does not appear. The console says "marker is not defined".
Here is my code:
map.on('click', 'usa_cities', function(highlightMarker) {
var markerCoordinates = highlightMarker.features[0].geometry.coordinates.slice();
var markerElement = document.createElement('div');
markerElement.id = 'marker';
// create the marker
new mapboxgl.Marker(markerElement)
.setLngLat(markerCoordinates)
.addTo(map);
map.on('click', 'usa_cities', function() {
marker.remove()
});
}),
Thank you
You don't need to create a new marker each time the user clicks. You can simply call marker.setLngLat(markerCoordinates).

How to add popup or bind popup to a point/marker in Leaflet FlowMap without breaking the 'flow' display?

I am using the following leaflet plugin:
https://github.com/jwasilgeo/Leaflet.Canvas-Flowmap-Layer
I am having issues adding a popup to the map when a user clicks on a point.
L.marker([pts[p].lat, pts[p].lng], {
icon: new L.DivIcon({
html: '<div>Test</div>'
})
}).addTo(map).bindPopup('A pretty CSS3 popup.<br> Easily customizable.')
.openPopup();
The popup shows, but I am unable to get the actual flowmap lines to show up. Is there anyway to allow for a popup and to allow for the lines to show up underneath it?
You can use the fact that the CanvasFlowmapLayer extends L.GeoJSON
You just need to overload the method creating the marker and add your popup there ...
var oneToManyFlowmapLayer = L.canvasFlowmapLayer(geoJsonFeatureCollection, {
pointToLayer: function(geoJsonPoint, latlng) {
var marker = L.circleMarker(latlng);
return marker.bindPopup('' + latlng)
},
// et caetera
Check it out here: https://yafred.github.io/Leaflet.Canvas-Flowmap-Layer/docs/main/

Leaflet map completely grey programmatically opening a popup tofa marker

I declare a leaflet map with
<div id="map" class="map-div"></div>
end initialize it with
var map = L.map('map').setView([51.178882, -1.826215],16);
$scope.map = map;
// OSM Mapnik
var osmUrl = "<a href='http://www.openstreetmap.org'>Open StreetMap</a>";
L.tileLayer(
'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© ' + osmUrl,
maxZoom: 18,
}).addTo(map);
I grab some data from my server, and and markers to the map, in a loop, by calling this function (it's AngularJS, but I doubt that that plays a role):
$scope.AddMarkerToMap = function(companyData, index, array)
{
var companyName = companyData.company_name;
var latitude = companyData.latitude;
var longitude = companyData.longitude;
var cssClassname = 'comapny_has_no_present_workers';
if (companyData['currentWorkers'] > 0)
cssClassname = 'comapny_has_present_workers';
var pubLatLng = L.latLng(latitude,longitude);
// see https://leafletjs.com/reference-1.4.0.html#marker
var marker = L.marker(pubLatLng,
{
// this is the tooltip hover stuff
title: companyData['currentWorkers'] + ' current matches ' + companyData['previousWorkers'] + ' previous matches',
// see https://leafletjs.com/reference-1.4.0.html#icon
// this is a permanent label.
icon: new L.DivIcon({
className: cssClassname,
////html: '<img class="my-div-image" src="http://png-3.vector.me/files/images/4/0/402272/aiga_air_transportation_bg_thumb"/>'+
//// '<span class="my-div-span">RAF Banff Airfield</span>'
html: '<span>' + companyName + '</span>'
})
}).addTo($scope.map);
// see https://leafletjs.com/reference-1.4.0.html#popup
marker.bindPopup("<b>Hello world!</b><br>I am a popup.").openPopup();
}; // AddMarkerToMap()
And the entire map is suddenly grey - with no problems reported in the developer console.
If I comment out the line
marker.bindPopup("<b>Hello world!</b><br>I am a popup.").openPopup();
then everything displays as expected.
The code seems correct, as per the Leaflet documentation.
[Updtae] I just checked and if I only marker.bindPopup("<b>Hello world!</b><br>I am a popup."), the the map displays and I can click on the marker to display the popup. But when I try to programmatically open it with .openPopup(); the map is all grey.
[Update++] the map and its markers display just fine, with any one of
marker.bindPopup("<b>Hello world!</b><br>I am a popup.");
$scope.map.fitBounds(bounds, {padding: [50, 50]});
but with both, the map is grey :-(
What am I doing wrongly?
I think the issue comes from trying to change the map view (possibly through openPopup with autoPan, which is on by default) too often, typically in a loop without giving any delay for the map to actually set the view between each call.
IIRC, this is already identified as a limitation in Leaflet, but I could not find the exact thread in the issue tracker unfortunately.
Normally, a very simple fix is simply to remove the map view changes within your loop, and keep only the very last one.
In your case, if you have the default behaviour of only 1 Popup being opened at a time, then that would definitely be a valid solution: just open the popup of your last Marker.
If you did configure your map to keep several Popups open simultaneously, and you do want to open all of them through your loop, then make sure to disable autoPan (at least during your loop).

Cant open popup programmatically

I have a map on which im loading the markers with geoJSON.
When the map loads i run a function buildVisibleSys which is responsible to build a list of currently visible systems on the map.
That function looks like this:
buildVisibleSys = function() {
var bounds, visibleSys;
visibleSys = [];
bounds = map.getBounds();
return systemLocations.eachLayer(function(marker) {
var link;
link = onScreenEl.appendChild(document.createElement('a'));
link.href = '#';
link.id = "marker" + marker._leaflet_id;
link.innerHTML = marker.options.title;
link.onclick = function() {
marker.openPopup();
map.panTo(marker.getLatLng());
};
});
};
map.on('load', buildVisibleSys);
In this function, for each layer im getting some data and building a html block with the names of each marker. Each of those names, associated to the link var, have a onclick event attached that will center the map on the correspondent marker. This all works except for the marker.openPopup() call i also have on that onclick event.
Any idea of what am I missing here?
I've also made a demo of the code available here:
http://jsfiddle.net/lmartins/z8wBW/
UPDATE:
Even more confusing to me is that with mouseover the same method works without a problem, that is, in the function above the following code do open the popup:
link.onmouseover = function(ev) {
marker.openPopup();
marker._icon.classList.add('is-active');
};
Change your link handler to
link.onclick = function(e) {
marker.openPopup();
map.panTo(marker.getLatLng());
e.stopPropagation();
e.preventDefault();
};
The click of the link to open the popup is bubbling down to the map and closing the popup right after it's opened.

How to show different popups on click and on mouseover?

The SelectFeature method in Control class provides a way of adding and removing popups on the Vector layer by listening to events featureselected and featureunselected respectively. Below shows a sample code that I obtained from an example in the openlayers website:
// create the layer with listeners to create and destroy popups
var vector = new OpenLayers.Layer.Vector("Points",{
eventListeners:{
'featureselected':function(evt){
var feature = evt.feature;
var popup = new OpenLayers.Popup.FramedCloud("popup",
OpenLayers.LonLat.fromString(feature.geometry.toShortString()),
null,
"<div style='font-size:.8em'>Feature: " + feature.id +"<br>Foo: </div>",
null,
true
);
feature.popup = popup;
map.addPopup(popup);
},
'featureunselected':function(evt){
var feature = evt.feature;
map.removePopup(feature.popup);
feature.popup.destroy();
feature.popup = null;
}
}
});
vector.addFeatures(features);
// create the select feature control
var selector = new OpenLayers.Control.SelectFeature(vector,{
hover:true, # this line
autoActivate:true
});
The code above will allow a popup to be shown upon mouseover on the Geometry object (icon or marker on the map). If the line hover:true is removed, the popup will be shown only upon a mouse click on the Geometry object.
What I want, is to be able to display one type of popup (example, an image plus a title) upon mouseover and another type (example, detailed description) upon a mouse click. I am not sure how this could be done. Some help would be much appreciated. Thanks.
Also, there another way, it's rather hack than correct usage of API, but seems to work. You can overwrite over and out callbacks.
var selectControl = new OpenLayers.Control.SelectFeature(vectorLayer, {
callbacks: {
over: function(feat) {
console.log('Show popup type 1');
},
out: function(feat) {
console.log('Hide popup type 1');
}
},
eventListeners: {
featurehighlighted: function(feat) {
console.log('Show popup type 2');
},
featureunhighlighted: function(feat) {
console.log('Hide popup type 2');
}
}
});
Here's working example: http://jsfiddle.net/eW8DV/1/
Take a look on select control's source to understand details.