Raruto / leaflet-elevation

Leaflet plugin that allows to add elevation profiles using d3js
GNU General Public License v3.0
254 stars 82 forks source link

EventListener on close-button #231

Closed mttucl closed 1 year ago

mttucl commented 1 year ago

Hi, I'm trying to load data with an external link that will toggle (expand) Elevation plot and then add EventListener to the close button to clear data when Elevation plot is collapsed. The EventListener doesn't fire the first time when clicking on the close button. The plot will collapse and will fire next time when toggling Elevation button.

Here is an example in JSFiddle. The example doesn't behave like in my case as it takes few clicks to collapse the plot in JSFiddle. In my case, first click will collapse the plot but won't fire EventListener and the second click will expand the plot and will fire EventListener . My case is similar to making detached: true in JSFiddle.

The relevant code in the example is from Line 53. If you comment Line 55, it works fine when the plot is collapsed on eledata_loaded.

mttucl commented 1 year ago

Just noticed that if you click on the close button and then click anywhere else before clicking again on the close button, it will not collapse the plot. You have to click twice on the close button to collapse the plot. Not sure if this is an issue with JSFiddle or something else.

Raruto commented 1 year ago

Hi @mttucl,

I don't quite understand what the final goal is, but since you're already referencing some internal stuffs (eg. _expand, _button) within your code, you can just try monkey patching the following function to add your event listener exactly where you want (without going crazy with add orders and the various stop propagations).

L.Control.Elevation.include({

  // override here default function behavior (just edit as you fit)
  _initButton: function(container) {
    const _ = L.Control.Elevation.Utils;

    L.DomEvent
      .disableClickPropagation(container)
      .disableScrollPropagation(container);

      this.options.collapsed ? this._collapse() : this._expand();

      if (this.options.autohide) {
         _.on(container, 'mouseover', this._expand,   this);
         _.on(container, 'mouseout',  this._collapse, this);
         this._map.on('click', this._collapse, this);
      }

      if (this.options.closeBtn) {
        let link = this._button = _.create('a', "elevation-toggle-icon", { href: '#', title: L._('Elevation'), }, container);
        _.on(link, 'click', L.DomEvent.stop);
        _.on(link, 'click', this._toggle, this);
        _.on(link, 'focus', this._toggle, this);
       fetch(this.__btnIcon).then(r => r.ok && r.text().then(img => link.innerHTML = img));
     }
  },

});

// and then proceed as usual
const elevation = L.control.elevation({...})

To better understand how to proceed, try searching among old issues and pull requests (it's a strategy I often recommend), below you can see similar example:

https://github.com/Raruto/leaflet-elevation/blob/868179234d8e9b8f7beaea57d0e34d8bd79a2622/examples/leaflet-elevation_dynamic-runner.html#L47-L85

👋 Raruto

mttucl commented 1 year ago

Hi @Raruto,

Thanks for the suggestions. I was actually looking at the runner example for a different reason but didn't know I could do it this way and I'm still learning. With this patching, I can do it like below

L.Control.Elevation.include({

  // override here default function behavior (just edit as you fit)
  _initButton: function(container) {
    const _ = L.Control.Elevation.Utils;

    L.DomEvent
      .disableClickPropagation(container)
      .disableScrollPropagation(container);

    this.options.collapsed ? this._collapse() : this._expand();

    if (this.options.autohide) {
      _.on(container, 'mouseover', this._expand,   this);
      _.on(container, 'mouseout',  this._collapse, this);
      this._map.on('click', this._collapse, this);
    }

    if (this.options.closeBtn) {
      let link = this._button = _.create('a', "elevation-toggle-icon", { href: '#', title: L._('Elevation'), }, container);
      _.on(link, 'click', L.DomEvent.stop);
      _.on(link, 'click', this._toggle, this);
      _.on(link, 'focus', this._toggle && this.clear, this); // ADDED: `&& this.clear`
      fetch(this.__btnIcon).then(r => r.ok && r.text().then(img => link.innerHTML = img));
      this.on('eledata_loaded', this._expand, this);         // ADDED: `this._expand`
    }
  },            
});

To give an example of my use case, I have a table with a list of paths with links to load elevation data from strings. When I click the link, I want to show the plot and when I close the plot, it should clear the data. The closest example is the toggable-charts

Awesome work and I appreciate your continuous support.

Raruto commented 1 year ago

To give an example of my use case, I have a table with a list of paths with links to load elevation data from strings. When I click the link, I want to show the plot and when I close the plot, it should clear the data. The closest example is the toggable-charts

If you manage to produce something useful for others too, feel free to submit a new file to add among other examples.

👋 Raruto