2

I'm trying to open a popup when clicking on a tooltip of a layer.

I try following code:

function add_layer_rescue_spot() {
    rescue_spot_layer = new L.GeoJSON.AJAX(rescue_spot_path, {
        style: label_style,
        pane: 'label',
        onEachFeature: on_each_rescue_spot_feature,
        pointToLayer: function(feature, latlon) {
            return point_to_label_layer(
                    '<i class="fa fa-plus-circle"></i>',
                    latlon, 'rescue_spot');
        },
    }).addTo(map);

    rescue_spot_layer.on('data:loaded', function() {
        rescue_spot_layer.getLayers().forEach(function(feature) {
            tooltip = feature.getTooltip().getElement();
            tooltip.addEventListener('click', function(e) {
                console.log('test');
                feature.openPopup();
            });
            tooltip.style.pointerEvents = 'auto';
        });
    });
}

function on_each_rescue_spot_feature(feature, layer) {
    rescue_spot_popup(feature, layer);
}

function point_to_label_layer(text, latlon, class_name) {
    var label = String(text);
    return new L.CircleMarker(latlon, {
        radius: 1,
    }).bindTooltip(label, {
        permanent: true,
        direction: 'center',
        className: class_name + '-label',
    }).openTooltip();
}

function rescue_spot_popup(feature, layer) {
    var properties = feature.properties;
    var max_height = parseInt($('#map').height() * 0.95);
    var popup_html = `
            <h5>Test</h5>
            <table class="popup-table">
                <tr>
                    <td class="attrib-name">foo</td>
                    <td class="attrib-value">foo</td>
                </tr>
                <tr>
                    <td class="attrib-name">bar</td>
                    <td class="attrib-value">bar</td>
                </tr>
            </table>`;
    layer.bindPopup(popup_html, {maxHeight: max_height});
}

So when I click on the tooltip, 'test' is logged and the map moves a bit like the popup would be opened. But the popup doesn't show up.

When I open the popup manually in the browser by typing:

rescue_spot_layer.getLayers()[0].openPopup()

the popup opens as expected.

Any ideas what I'm doing wrong?

  • Definitions of two functions are missing in your code (point_to_label_layer and rescue_spot_popup). That would help pinponting the reason for popup not showing up. – TomazicM Jul 25 at 7:54
  • rescue_spot_popup is a bit vital to this, to provide a complete answer – Chris Schaller Jul 25 at 8:40
0

There are a few optimisations here that might help.

  1. Consolidate your layer processing into the onEachFeature callback, there is no need to do this on data load as well.

  2. Consider making the layer clickable instead of the tooltip. I'm not sure why this works any differently, but it solves your issue in my code base. IMO this is more intuitive for the user anyway, clicking the tooltip will usually be close to the layer itself, so just let the user click your shape.

The following code will put the click event on the layer, effectively making the whole shape clickable.

function add_layer_rescue_spot() {
    rescue_spot_layer = new L.GeoJSON.AJAX(rescue_spot_path, {
        style: label_style,
        pane: 'label',
        onEachFeature: on_each_rescue_spot_feature,
        pointToLayer: function(feature, latlon) {
            return point_to_label_layer(
                    '<i class="fa fa-plus-circle"></i>',
                    latlon, 'rescue_spot');
        },
    }).addTo(map);
}

function on_each_rescue_spot_feature(feature, layer) {

    // NOTE: example of one of my tooltips, OP didn't detail theirs
    var tooltipContent = '<div class="map-paddock-tooltip">';
    tooltipContent += '<strong>Paddock: #' + feature.properties.Id + '</strong></br>';
    tooltipContent += '<strong>Name:</strong>' + feature.properties.Title + '</br>';
    tooltipContent += '<i>click for more info!</i></br>';
    tooltipContent += '</div>';

    var tooltip = L.tooltip({ className: 'll-tooltip' })
        .setContent(tooltipContent);

    layer.bindTooltip(tooltip);
    layer.on('click', function () {
        layer.openPopup();
    });

}

Further considerations

Consider a context menu, instead of a clickable tooltip, if you have multiple functions that you want to enable when the user right clicks on your layer. Context menus the user will intuitively understand how to work with.

In the following screenshot you will see a shape with a tooltip on the left, and a context menu on the right.
Layer with Tooltip and context menu
I inject disabled context menu items to display structured info about the shape with enabled menu items to call back to actions.
Look into aratcliffe/Leaflet.contextmenu on GitHub

  • Great documentation and support for GeoJSON too.
  • Thanks. My problem is still, that the layer consists of point geometries without marker. So the user has to click on the single pixel to open the popup. So my idea was to display a permanent tooltip. Maybe it's a better way to design an own marker. – nlaan Jul 25 at 9:57
  • Posting the additional code helps with that ;) Your issue really is about how to increase the clickable surface of the marker then. So why not make the markers with a larger radius or add search to your UI. There's even a leaflet plugin for that. Then you have another mechanism to search the points, rather than relying on the click directly. In this case I think a screenshot of what you have now would help attract a more suitable solution. – Chris Schaller Jul 25 at 23:03
0

There is no need to use onEachFeature function. Since we are dealing with points only, pointToLayer function is enough. There we can create point marker and bind popup and tooltip to it.

If option interactive: true is used when creating tooltip, it will accept mouse clicks. This mouse click will be propagated to marker and so popup will be automatically opened upon clicking on tooltip.

So code can be greatly simplified:

function add_layer_rescue_spot() {
  rescue_spot_layer = new L.GeoJSON.AJAX(rescue_spot_path, {
    style: label_style,
    pane: 'label',
    pointToLayer: function(feature, latlon) {
      return point_to_label_layer(
               '<i class="fa fa-plus-circle"></i>',
               feature, latlon, 'rescue_spot'
             );
    }
}).addTo(map);

function point_to_label_layer(text, feature, latlon, class_name) {
  var label = String(text);
  var properties = feature.properties;
  var max_height = parseInt($('#map').height() * 0.95);
  var popup_html = `
          <h5>Test</h5>
          <table class="popup-table">
              <tr>
                  <td class="attrib-name">foo</td>
                  <td class="attrib-value">foo</td>
              </tr>
              <tr>
                  <td class="attrib-name">bar</td>
                  <td class="attrib-value">bar</td>
              </tr>
          </table>`;
  myMarker = L.circleMarker(latlon, {radius: 1});
  myMarker.bindPopup(popup_html, {maxHeight: max_height});
  myMarker.bindTooltip(label, {
      interactive: true,
      permanent: true,
      direction: 'center',
      className: class_name + '-label',
  });
  return myMarker;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.