Adding popup after Geocoding search result - popup

I've been figuring out how to add the popup after geocding search result.
Currently, i am using below documentation to try out. In the documentation, it only shows how to search using your own dataset and the marker will appear when the search is completed.
However, i would like to add the popup when the marker is clicked.
I've read up other documentation on Mapbox on "popup". However, i cannot seem to be able to implement in this code.
here is the documentation that i am currently trying for geocoding: https://docs.mapbox.com/mapbox-gl-js/example/forward-geocode-custom-data/

Welcome! I had this problem long ago. I had polygons where I needed a popup to appear onclick. My polygons were areas of the ocean where hazardous seas were (a warning for ships, etc). Here, I have a function that activates onclick. It then makes sure the popup appears in the correct order on the screen, and optionally will change the style of the mouse cursor.
I would explain more in detail but I think the code is self-explanatory for the most part. It is difficult to find good examples in documentation sometimes (although Mapbox is making great strides lately in the documentation side of things.)
Check the solution below and feel free to accept it if it works for you, otherwise I can help with questions as well if you need. I have commented it for you.
map.on('click', 'HazardousSeasWarning', function (e) {
var coordinates = e.features[0].geometry.coordinates[0][0].slice();
var description = e.features[0].properties.description;
// Ensure that if the map is zoomed out such that multiple
// copies of the feature are visible, the popup appears
// over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
new mapboxgl.Popup()
.setLngLat(coordinates)
.setHTML(description)
.addTo(map);
});
// Change the cursor to a pointer when the mouse is over the places layer.
map.on('mouseenter', 'HazardousSeasWarning', function () {
map.getCanvas().style.cursor = 'pointer';
});
// Change it back to a pointer when it leaves.
map.on('mouseleave', 'HazardousSeasWarning', function () {
map.getCanvas().style.cursor = '';
});

Related

How to edit only selected feature from geojson using leaflet geoman

I have a GeoJson having 40,000 features as MultiPolygon.Can anyone guide me that how can i select individual polygon from it and edit that selected one. Right now when I click edit in Leaflet-Geoman toolbar it selects all 40,000 features and make them editable that crash browser window.
if I understand right your question, you need to filter that objects by property.
Maybe you could send some screenshots or code examples?
You could try to do it like this:
let obj = []
if (condition) continue
for (obj in geoJson) {
obj.push(geoJson[obj])
}
console.log(“filtered objects”, obj)

Change dragging state for all markers

I'm using Leaflet.markercluster 1.0.1
I'm trying to add button on my map, so users can enter in 'edit mode'. On click on that button it should toggle dragging state for all markers. I don't really know how to implement that correctly, but I wrote that code
var drag = false;
$('#button').on('click', function () {
drag = !drag;
markers.eachLayer(function (marker) {
marker.options.draggable = drag;
if (marker.dragging) {
drag ? marker.dragging.enable() : marker.dragging.disable();
}
});
});
It works for some time, but then I get Exception on .enable()
Uncaught TypeError: Cannot read property 'classList' of null
Is anyone know any correct way to do that?
Thanks in advance!
It seems that the logic for the forEach method in MarkerClusterGroup iterates through markers not visible on the map after dragging a spiderified marker. Then the logic for enabling dragging fails, as the marker does not have an icon instance, because it has been removed from the map.
I've cleaned up the reproducible example a bit, and left a copy at https://playground-leaflet.rhcloud.com/qate/1/edit?html,output - I strongly suggest that you turn this into a good bug report in the Leaflet.MarkerCluster.
You may also check if each of the markers has a marker._map private property to check if they are on the map, and skip those which are not, but this may lead to other issues down the road.

Leaflet taphold to set markers

I want to set markers on a Leaflet map. To achieve this I tried jquery-mobile-events with minor success. This is how I integrated it:
$(map).off('taphold');
$(map).bind('taphold', function(e, options){
... do something ...
});
It works on the desktop but not on mobile. 'map' is a L.map object. An other problem which is associated with it is that I can not get options.startPosition and options.endPosition. I need this to create a distinction between a long tap for panning the map and one to place a marker. Does anyone know a solution to this?
There is actualle a really neat implementation in Leaflet for this:
map.on('contextmenu', function(e){
.. do something ...
});
The problem is that it is also triggerd by clicking rightclick on desktop.
Edit: You can prevent it by checking if (event.button == 2) {...}

Click-through markers and polylines in Leaflet

In Leaflet, is it possible to define a marker or polyline with {clickable:false}, so that a click is passed through to whatever lies beneath - be it the map or a clickable geometry object?
At the moment I solve this problem by making the marker/polyline clickable and passing the event onwards myself. But this leads to the mouse cursor always showing as the hand symbol. Ideally, the mouse cursor should look like the normal pointer or the hand, depending on whether what is beneath the marker/polyline is clickable.
This may not be the answer you are looking for, but you can use featureGroups to have all of your clickable polylines come to the front so that the actions are surfaced.
var lg_noclick = new L.FeatureGroup().addTo(map);
var lg_click = new L.FeatureGroup().addTo(map);
// Add lines
lg_click.bringToFront();
updated fiddle
Also if you can afford to know your lines before hand, correct ordering of when you add the lines it will work as well.
I know this is not ideal but it suited my situation just fine, so it might be good for you as well.
This hides the icon and brings it back after a second using mouseenter and mouseleave events:
$('.leaflet-marker-icon').mouseenter(function() {
$(this).hide();
});
$('.leaflet-marker-icon').mouseleave(function() {
$(this).delay(1000).show(0);
});

How do I center and show an infobox in bing maps?

My code does a .pantolatlong then a .showinfobox
The info box does not appear, unless I remove the pantolatlong. I guess it is stopping it. I tried adding it to the endpan event but that did not work.
What is the simplest way to pan to a pushpin and display the infobox for it?
I was using setcenter, but I discovered that sometimes setcenter pans, and this breaks it.
After some insane googling, I came up with the solution, and I'll share it here so that others can hopefully not have the grief I went through.
I created and power my bing map using pure javascript, no sdk or iframe solutions. In my code, I generate the javascript to add all of the pins I want to the map, and inject it using an asp.net label.
If you call the setCenter() method on your Bing Map, it is supposed to instantly set the map, surprise surprise, to the coordinates you specify. And it does... most of the time. Occasionally though, it decides to pan between points. If you do a SetCenter, followed by a ShowInfoBox, it will work great, unless it decides to pan.
The solution? Being great programmers we are, we dive into the sdk, and it reveals there are events we can hook into to deal with these. There is an onendpan event, which is triggered after a pan is completed. There is also an onchangeview event, which triggers when the map jumps.
So we hook into these events, and try to display the infobox for our pushpin shape... but nothing happens. Why not?
You have to give it a few milliseconds to catch its breath, for unknown reasons, when the event is called. Using a setTimeout with 10 milliseconds seems to be fine. Your box will appear great after this.
The next problem is, you only want it to appear when it pans via whatever you used to make it flick between your pushpins (in my case, a table with onclick methods). I create/destroy the event handlers on the fly, although there are other options such as using a global variable to track if the user is panning, or if the system is panning in response to a click.
Finally, you have the one bug that comes from this. If you click a place in your list, and it jumps/pans to that location, the infobox will display fine. If the user dismisses it though, then clicks again on the list item, the map does not move, and therefore no events are triggered.
My solution to this is to detect if the map moved or not, by recording its long/lat, and using another setTimeout method, detecting if they changed 100ms later. If they did not, display the infobox.
There are other things you need to keep track of, as there is no way I can see to pass parameters to the eventhandlers so I use global javascript variables for this - you have to know which pushpin shape you are displaying, and also keep track of the previous mapcoordinates before checking to see if they changed.
It took me a while to piece all this together, but it seems to work. Here is my code, some sections are removed:
// An array of our pins to allow panning to them
var myPushPins = [];
// Used by the eventhandler
var eventPinIndex;
var oldMapCenter;
// Zoom in and center on a pin, then show its information box
function ShowPushPin(pinIndex) {
eventPinIndex = pinIndex;
oldMapCenter = map.GetCenter();
map.AttachEvent("onendpan", EndPanHandler);
map.AttachEvent("onchangeview", ChangeViewHandler);
setTimeout("DetectNoMapChange();", 200);
map.SetZoomLevel(9);
map.SetCenter(myPushPins[pinIndex].GetPoints()[0]);
}
function EndPanHandler(e) {
map.DetachEvent("onendpan", EndPanHandler);
setTimeout("map.ShowInfoBox(myPushPins[eventPinIndex]);", 10);
}
function ChangeViewHandler(e) {
map.DetachEvent("onchangeview", ChangeViewHandler);
setTimeout("map.ShowInfoBox(myPushPins[eventPinIndex]);", 10);
}
function DetectNoMapChange(centerofmap) {
if (map.GetCenter().Latitude == oldMapCenter.Latitude && map.GetCenter().Longitude == oldMapCenter.Longitude) {
map.ShowInfoBox(myPushPins[eventPinIndex]);
}
}
Here is another way:
function addPushpin(lat,lon,pinNumber) {
var pinLocation = new Microsoft.Maps.Location(lat, lon);
var pin = new Microsoft.Maps.Pushpin(map.getCenter(), { text: pinNumber.toString() });
pinInfobox = new Microsoft.Maps.Infobox(pinLocation,
{ title: 'Details',
description: 'Latitude: ' + lat.toString() + ' Longitude: ' + lon.toString(),
offset: new Microsoft.Maps.Point(0, 15)
});
map.entities.push(pinInfobox);
map.entities.push(pin);
pin.setLocation(pinLocation);
map.setView({ center: pinLocation});
}