Jump to content

Module: Leaflet Map


Mats

Recommended Posts

7 hours ago, kaz said:

Fatal error: Uncaught TypeError: round(): Argument #1 ($num) must be of type int|float, string given in site/modules/FieldtypeLeafletMapMarker/InputfieldLeafletMapMarker.module:193

Hey @kaz, in

/site/modules/FieldtypeLeafletMapMarker/InputfieldLeafletMapMarker.module

try changing line 193 f.

        if(	((string) round($lat, $precision)) != ((string) round($this->defaultLat, $precision)) ||
            ((string) round($lng, $precision)) != ((string) round($this->defaultLng, $precision))) {

to

        if(	((string) round(floatval($lat), $precision)) != ((string) round(floatval($this->defaultLat), $precision)) ||
            ((string) round(floatval($lng), $precision)) != ((string) round(floatval($this->defaultLng), $precision))) {

that's hotfixing the issue over here. Don't know about the rest of the module, but I haven't gotten other errors so far.

  • Like 1
Link to comment
Share on other sites

  • 1 month later...

I am using this module and am generally happy with it. Would be good if someone would maintain it. 

One issue I have; maps sometimes don't show up. I guess the javascript doesn't kick in somewhere and then you get a empty blank block.

What can I do to make sure the javascript kicks in? Or something has to happen in the right order? Has anyone else seen this issue and fixed it?

Probably not even 100% related to the module; it may just be something dumb in my templates. 

Link to comment
Share on other sites

  • 1 month later...

The only thing you really need here is the inputfield that handles all the address to lat/long work and that works perfectly fine.

You shouldn't hide it in a tab or collapse its fieldset per default, as that backfires a bit and the map doesn't initialize somehow.

On the frontend it's easy to build the necessary parts by hand which you probably do anyway - or at least I do/did in the past. To handle all the necessary files and make it work with cookie banners.

As an alternative for the backend there is still the Google Maps version available to get the lat/long data.

Link to comment
Share on other sites

Thanks for the response @wbmnfktr. I've had this Leaflet module in my sites for years, but it has some problems. I was just wondering if there were better alternatives for 2023. Didn't Google Maps go fully commercial at some point, with unworkable limitations?

Quote

The only thing you really need here is the inputfield that handles all the address to lat/long work and that works perfectly fine.

What inputfield would that be? I think I use an inputfield StreetAddress that doesn't integrate with LeafletMapMarker at all. 

LeafletMapMarker has its own Address, Latitude, Longitude, Zoom fields, and then it also has a search field on the map. Entering an Address never works; the module forces you to use the search field on the map and that only finds a few weird irrelevant "landmarks" and in module's Address field weird addresses are added, sometimes adding words in Russian characters. 

Manually adding lat/long is usually the only way to get the marker in the right location. I have to use some other tool to find the correct lat/long.

Is there a way to get better integration? Just add a street address somewhere, generate a correct lat/long, not have the MapMarker module make up all kinds of stuff. 

Also sometimes the map does not "kick in" in the front end; I just get an empty space. Probably some javascript not loading or loading too late. And probably just my template mess, but I haven't been able to troubleshoot/fix it yet. 

Link to comment
Share on other sites

1 minute ago, modifiedcontent said:

if there were better alternatives for 2023

The one that comes to mind is Mapbox. I don't know if here Maps are still a thing or even available for websites.
Maybe there will be something in 2023 by Meta, Microsoft, AWS and TomTom.

 

46 minutes ago, modifiedcontent said:

What inputfield would that be?

The one that comes with the module. It works perfectly fine without issues for me. Ok, sometimes there aren't any results for addresses but thats an OSM issue and their lack of data. It's weird that your experience is so much worse than mine.

I'd look for alternatives in your case as well. That's not fun when there are so many issues.

50 minutes ago, modifiedcontent said:

Is there a way to get better integration? Just add a street address somewhere, generate a correct lat/long, not have the MapMarker module make up all kinds of stuff. 

Probably. Geocoding addresses is needed by quite a lot. There should be a solution somewhere.
Google Maps API with its free credits each month should do the trick just fine. Or are there hundreds of thousands requests each month you have to handle?

Link to comment
Share on other sites

We are working to fix exactly these issues. But it is slower than I imagined) Hope to get all this fixed some time soon, as we do need it.

Quote

LeafletMapMarker has its own Address, Latitude, Longitude, Zoom fields, and then it also has a search field on the map. Entering an Address never works; the module forces you to use the search field on the map and that only finds a few weird irrelevant "landmarks" and in module's Address field weird addresses are added, sometimes adding words in Russian characters. 

The Address field use here is different comparing to FieldtypeMapMarker. It is for storing the object address returned by geocoder, not for storing address data you enter. That's why I think it is better to have another field to store the actual address, and Leaflet Map to only set and store a point on the map. Maybe we could find a way to connect them via js, but now it is impossible. By the way, storing address  in a a separate field is better for ML environment anyway.

  • Like 4
  • Thanks 1
Link to comment
Share on other sites

@Ivan Gretskygreat news. I contributed to the module many years ago with leaflet providers and marker cluster integration. It definitely needs some attention and love. Upgrading assets etc.

I think that leaflet.js in general is still a viable solution for open source maps in general. Mapbox have changed their subscription model few years ago that is why I still prefer Leaflet over Mapbox.

As for geocoding addresses this is still an issue with the open source provider that sits behind InputfieldLeafletMapMarker (Nominatim). They have improved a lot over time. But still failing on more exotic addresses where the Google Maps geocoder is doing a better job. There's quite a few open source geocoding services out there, but most of them use data from OSM's Nominatim. So you can't expect better results than you get with Nominatim.  If looking for closed source geocoding APIs, one that might be worth looking into is https://positionstack.com/ . They have a free tier and seem to have a huge address pool. And I'd rather trust my data with an Austrian Company then sending it to Google. Just sayin... It could be used a s a fallback in case Nominatim returns garbage or nothing.

23 hours ago, Ivan Gretsky said:

That's why I think it is better to have another field to store the actual address, and Leaflet Map to only set and store a point on the map. Maybe we could find a way to connect them via js, but now it is impossible.

It is not. At least with v3.0.3 of InputfieldLeafletMapMarker. You can make seperate inputfields that hold address data work together with the InputfieldLeafletMapMarker. I once wrote a module for a specific use case where I have 3 inputfields, address, postcode, city. The module loads some JS that first hides the default InputfieldLeafletMapMarker inputs, adds a button which takes the values from those fields, geocodes them through Nominatim, adjusts the marker on the map in the InputfieldLeafletMapMarker and fills the (now hidden) fields with the lat lng and name. Although I have done this about 4 years ago or so, it is still working. Here's the module code for reference in case anyone wants to go a similar route. Not a very clean and portable integration but it is doing the job and is here mainly to serve as an example how you could tackle this scenario.

EDIT: short screencast to show UI

addr2map.gif.7aa193d11ad3d51787811193509c0550.gif

AddressToMap.module.php (just loads the necessary JS)

<?php

use ProcessWire\HookEvent;


class AddressToMap extends WireData implements Module {

	/**
	 * getModuleInfo is a module required by all modules to tell ProcessWire about them
	 *
	 * @return array
	 *
	 */
	public static function getModuleInfo() {

		return array(

			// The module'ss title, typically a little more descriptive than the class name
			'title' => 'AddressToMap', 

			// version number 
			'version' => 001, 

			// summary is brief description of what this module is
			'summary' => 'Geocode an Address and put a Pin on the Leaflet Map',
			
			// singular=true: indicates that only one instance of the module is allowed.
			// This is usually what you want for modules that attach hooks. 
			'singular' => true, 

			// autoload=true: indicates the module should be started with ProcessWire.
			// This is necessary for any modules that attach runtime hooks, otherwise those
			// hooks won't get attached unless some other code calls the module on it's own.
			// Note that autoload modules are almost always also 'singular' (seen above).
			'autoload' => "template=admin", 
		
			// Optional font-awesome icon name, minus the 'fa-' part
			'icon' => 'map', 
			);
	}

	public function init() {

        $this->wire->addHookAfter('ProcessPageEdit::loadPage', $this, 'loadAssets');
        
	}
    
	public function loadAssets(Hookevent $event) {
        
        $id = $event->arguments(0);
        $page = $this->pages->get($id);
        if($page->template == 'member') {
            $this->config->scripts->add($this->config->urls->siteModules . $this->className . "/{$this->className}.js");
        }
    }
}

AddressToMap.js

var AddressToMap = {



    init: function () {
        // $(window).on('map:init', function (e) {
        //     map = e.originalEvent.detail.map;
        //     console.log(map);
        // });

        var coder = window.L.Control.Geocoder.nominatim();
        // console.log(AddressToMap.geocoder);
        var address = $('p.InputfieldLeafletMapMarkerAddress').css({ 'display': 'none' });
        var setAddress = $('<p></p>').addClass('InputfieldLeafletMapMarkerSetAddress');
        var button = $($.parseHTML("<button class='btn btn-primary btn-block' id='setAddress'><i class='fa fa-arrow-down fa-fw'></i>" + ProcessWire.config.strings.addresstomap + "<i class='fa fa-arrow-down fa-fw'></i></button>"));
        setAddress.append(button);
        setAddress.insertAfter(address);
        var inputfieldName = $('.Inputfield.InputfieldLeafletMapMarker').attr('id').replace('wrap_', '');
        button.on('click', function (event) {
            event.preventDefault();
            var combAddress = $('#Inputfield_address').val() + ', ' + $('#Inputfield_postcode').val() + ', ' + $('#Inputfield_city').val();
            coder.geocode(combAddress, function (results) {
                if(results[0] !== undefined) {
                    var map = window.leafletmap;
                    map.eachLayer(function(layer){
                        if(layer.options.draggable === true) {
                            var latlng = L.latLng(results[0].center.lat, results[0].center.lng);
                            layer.setLatLng(latlng);
                            $('#_' + inputfieldName + '_lat').val(results[0].center.lat);
                            $('#_' + inputfieldName + '_lng').val(results[0].center.lng);
                            $('input#' + inputfieldName).val(results[0].name);
                            map.fitBounds(results[0].bbox);
                        }
                    });
                } else {
                    alert('Could not geocode this address');
                }
            });

        });

    }
}

$(document).ready(function () {
    AddressToMap.init();
}); 

 

  • Like 2
Link to comment
Share on other sites

@Ivan Gretskywhat do you think about extending the InputfieldLeafletMapMarker with some address inputs and implementing a clean JS approach roughly following my example from above along with a clean UI? I'd be willing to contribute to this effort.

EDIT: Oh and there is a custom fieldtype I once made that we could borrow some code from https://github.com/gebeer/FieldtypeAddressGeonames

  • Like 1
Link to comment
Share on other sites

  • 3 weeks later...
  • 1 month later...

@digitex@torf Just in case you (or anyone else) are still trying to work around this issue:

I just had the NaN JavaScript error on one of my sites using LeafletMapMarker that didn't exist a few months ago. In trying to identify the error since there were no PHP errors discovered (though it wasn't in debug mode), I noticed I had, in that time, upgraded the version of PHP from 8.0 to 8.1. On a whim I reverted back to 8.0. This fixed the rendering of the map. Something is apparently not working on the PHP side which is interfering with it passing the parameters to the module's JS initialization constructor.

This might not be a proper solution, but maybe a potential workaround (depending on your requirements) until or unless a more formal update to this module, or a successor can be offered.

Thankfully (?) there are quite a few people who seem to have used this module, so the need to get it fixed somehow sooner or later will be increased.

EDIT: There's a pull request in the module's GitHub repository that might fix this (untested).

  • Like 3
Link to comment
Share on other sites

  • 3 weeks later...
On 2/14/2023 at 5:55 PM, BrendonKoz said:

EDIT: There's a pull request in the module's GitHub repository that might fix this (untested).

I manually updated the plugin with your pull request. It works for me under PHP 8.1 (stopped working with JavaScript-Errors after upgrading PHP. Would be nice if it could be merged into the official repo!

Link to comment
Share on other sites

7 hours ago, gerritvanaaken said:

I manually updated the plugin with your pull request. It works for me under PHP 8.1 (stopped working with JavaScript-Errors after upgrading PHP. Would be nice if it could be merged into the official repo!

Hi, @gerritvanaaken. Thanks for checking it out. I've merged and added a bit to it. Made a little housekeeping also - renamed a few branches. You can download and test the dev branch. Please report back if you do so I feel more confident merging it into master.

Link to comment
Share on other sites

Good day, everyone!

I am happy (and a bit scared) to announce the release of a long awaited new maintenance version for this module. @Mats blessed me to take control over the module. In fact, the repo is moved not to my github account, but rather to an org called Friends of ProcessWire in which there are some brilliant devs already, and maybe more will join. But that is a story for another post I am planning to write soon (a little intrigue)))

As for now please test the new 3.0.4 version. It has some code merged from @ukyo (big thanks to him!) and a few lines by myself. I hope that this release does fix a few issues and hopefully not introduce new ones. But I can't be sure here, so changed the stability tag to Beta.

Here is the changelog:

  1. Now the module uses https://nominatim.openstreetmap.org for all geocoding. Before it still used Google geocoding API in places.
  2. Fixed the issue with the map display in admin when the field is in the repeater or in the collapsed fieldset. There is still a problem with ajax tabs.
  3. Fixed ProcessWire namespace declaration.
  4. Fixed markup in README.txt.
  5. Executable bit is removed from all files in the repo.
  6. Git branches are renamed to be more familiar. The latest released code is now in the master branch again instead of PW3. The dev is used for current dev. Previously used branches are renamed and kept for now, though will be probably deleted in the future.
  7. Updated the module page in the modules directory.
  • Like 3
  • Thanks 3
Link to comment
Share on other sites

  • 1 month later...

I would add some fixed routes drawn with GPX files on the maps. There is this plugin for Leaflet: https://github.com/mpetazzoni/leaflet-gpx. But my problem is that at least the example points to much newer Leaflet version that this module is using, v 1.7.1. What is the reason, that this module is still using v 0.7.3 of Leaflet.js and how difficult would it be to upgrade it to 1.7 or even 1.9?

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...