publiclab / Leaflet.DistortableImage

A Leaflet extension to distort or "rubber sheet" images
https://publiclab.github.io/Leaflet.DistortableImage/examples/
BSD 2-Clause "Simplified" License
270 stars 283 forks source link

Adding custom tool/function to the toolbar #733

Open MerionLial opened 4 years ago

MerionLial commented 4 years ago

First off: I'm not sure if opening issues here is the best way of asking question along the line of "How do I do X?" If there's a discord, IRC, forum, subreddit or whatnot you'd rather have me use, please let me know.

Now for the actual question:

Scope: Leaflet project of middling complexity. Using the following other plugins and libraries: /lib/jquery-3.5.1.min.js /lib/arrive.min.js /leaflet/leaflet.js /leaflet/leaflet.toolbar.min.js /leaflet/leaflet.draw.js /leaflet/easy-button.js (will be removed soon) /leaflet/leaflet-search.js /leaflet/leaflet.measure.js (adapted) /leaflet/leaflet.responsive.popup.js /leaflet/leaflet.distortableimage.js (just the file from the dist folder of the .zip, not using npm or anything) /suneditor.min.js /jquery.emojiarea.min.js (adapted) /jquery.emojiarea.symbol-mapping.js

Description: I want to add a button to the toolbar that executes a function of my own making. Basically defining my on Action. What the new Action should do is: return the corners array for me to further work with, then remove the image from the map, add a regular imageOverlay and open a popup on it.

I have seen this: https://github.com/publiclab/Leaflet.DistortableImage/issues/194 where @jywarren uses img._addTool(NewTool) and extends EditOverlayAction. But when I try to replicate this, I get Uncaught ReferenceError: EditOverlayAction is not defined and I can't seem to find EditOverlayAction in any of the files in the Leaflet.DistortableImage-main.zip

Did something change since this was posted over a year ago? Or am I doing something wrong? What would be the proper way to add a custom Action?

sashadev-sky commented 4 years ago

@MerionLial have been to get some documentation on this in a wiki if you want to help out! You can find an example of how a custom action here:

https://github.com/publiclab/mapknitter/blob/301e7e4a606610d7492f63ae6f8b12000e5b4146/app/assets/javascripts/mapknitter/Map.js#L739-L766

and it getting added to the toolbar here: https://github.com/publiclab/mapknitter/blob/301e7e4a606610d7492f63ae6f8b12000e5b4146/app/assets/javascripts/mapknitter/Map.js#L174-L188

Lmk if that helps!

MerionLial commented 4 years ago

Thank you! I'll look into it and see what I can do with it. Once I understood what is happening and know how to adapt it to non-mapknitter maps, I'll happily write up something for the wiki.

I might have some question concerning those two functions before that, so be warned ;-)

sashadev-sky commented 4 years ago

@MerionLial sounds good thanks!

MerionLial commented 4 years ago

I had a look and to be honest, I did not understand everything that is going on.

But okay, let's try and break this down. The whole affair seems to be a 3 step process:

  1. Have a function you want to execute. This code could be included in step 2, but I think it's cleaner to have it as a seperate function:

    function theActualFunctionToExecute(){
        console.log("works");
    }
  2. Defining the action In your example, you are defining the action as part of some larger function. I don't, so I just create a new function for it. It looks like this:

    newAction = L.EditAction.extend({
            initialize: function (map, overlay, options) {
                options = options || {};
                options.toolbarIcon = {
                html: '<i class="fas fa-check"></i>',
                tooltip: My new Action'
                };

                L.EditAction.prototype.initialize.call(this, map, overlay, options);
            },

            addHooks: function () {
                var ov = this._overlay;
                if (ov.editing._mode !== 'lock') {
                      theActualFunctionToExecute();
                }
            }
        });

I can't say I really understand what the initialize: part does and if I have to adapt that or have to hand over anything. I obviously have a map object and the options are defined right within that initialize block, but is overlaysomething I need to declare? It does work, but I'm curious.

  1. Adding the Action to the toolbar I assume in the larger function I mentioned above, you created the action as a function of your mapknitter object. As I want to use it standalone and also don't intend to replace an existing action, I ended up with:
    // adding the new action the popup toolbar
    L.DomEvent.on(img._image, 'load', function() {
        img.editing.addTool(newAction);
      });

If you think this code is clean and understandable enough, I will add it to the wiki, explaining the things I did understand ;-)

jywarren commented 3 years ago

Hi, just chiming in late here, but:

I can't say I really understand what the initialize: part does

That section "sets up" the HTML UI for the menu to begin using your new tool; it specifies the name and the icon. It is run by the library and the values for map, overlay, options are passed in for you to use. addHooks connects up the events for the UI.

Once the toolbar UI is defined, 3) is as you said actually adding the tool to the toolbar.

Thank you, that would be tremendous to see in the wiki if you're still interested!