Cybermano Posted June 29, 2023 Share Posted June 29, 2023 (edited) Hi to everybody and special thanks to @Mats for sharing this big porting, to @gebeer @netcarver @dab for the hard implementations and to @Ivan Gretsky to keep it alive again, but also to all the contributors and maintainers of this awesome module. I'm testing it and it works really fine and easy. I would try to add an extra class to the markers and I followed this linked tip to Leaflet.AwesomeMarker properties for the main page with all the markers: $options = array( 'useMarkerSettings' => true, 'markerFormatter' => function($page, $marker_options) { $marker_options['icon'] = $page->icon; // Override the default icon for this marker. $marker_options['markerColor'] = $page->color; // Override the default color for this marker. // Adding extra classes to this marker ?? $marker_options['extraClasses'] = 'music-stage'; // Or dynamically from an option field: $page->stage_kind->value return $marker_options; }, ... ); But as you can see from the screenshot below, no classes are added to the icon (there is a blank space instead between the classes into <i></i> tag; actually it's always present, with or without the 'extraClasses' index into $marker_options). Am I missing something? P.S. The JS correctly loads the object properties: mleafletmap1.addMarkerIcon(L.AwesomeMarkers.icon({prefix: 'fa', icon: 'music', markerColor: 'red', iconColor: 'white', extraClasses: 'music-stage'}) Basically it would be nice to add extra classes to the whole marker (not only to the icon) to manipulate it with js (eg. filtering by type/class on a triggered event such as a button click or select change, or hiding from page if an event date is passed, like for exibitions/music lives and so on). Does anybody have any suggestions to do this? Thanks in advance. Edited July 25, 2023 by Cybermano typo fixed Link to comment Share on other sites More sharing options...
Cybermano Posted July 11, 2023 Share Posted July 11, 2023 Hi, is there anybody that knows how to easly disable "scrollWheelZoom" on admin page editing? Or is there a "module/field" settings development plan for map options in admin? (an overrideble setting in the field options could be great). I find a little annoying the zooming in/out of the map on page scroll. At the moment I put manually a js line of code in InputfieldLeafletMapMarker.js after line 24 // line 24 var map = L.map(mapElement).setView([lat, lng], options.zoom); // new line map.scrollWheelZoom.disable(); But I'm not so happy to modify original modules... (on updates the modifications could be lose). The second approach that I have succesfully tested is to load a js file in admin, but it needs to completely initialize a new map, only with the add of an option in the declaration of the map init: var map = L.map('_Inputfield_fm_mappa_map', {center: [lat, lng], zoom: parseInt($('#_Inputfield_fm_mappa_zoom').val()), scrollWheelZoom: 0,} ); Spoiler Complete code $(document).ready(function(){ if ($('form#ProcessPageEdit').hasClass('YOUR_PW_TEMPLETE_NAME_TO_EDIT')) { var mapId = '_Inputfield_YOUR_FIELD_MAP_map'; var lat = $('#_Inputfield_YOUR_FIELD_MAP_lat').val(); var lng = $('#_Inputfield_YOUR_FIELD_MAP_lng').val(); var zoom = parseInt($('#_Inputfield_YOUR_FIELD_MAP_zoom').val()); var options = { zoom: 9, draggable: true, center: null, scrollWheelZoom: 0, } // var map = $('#_Inputfield_YOUR_FIELD_MAP_map'); var map = L.map('_Inputfield_YOUR_FIELD_MAP_map', {center: [lat, lng], zoom: zoom, scrollWheelZoom: 0,} ); var coder = L.Control.Geocoder.nominatim(), geocoder = L.Control.geocoder({ geocoder: geocoder, placeholder: '' }).addTo(map); var marker = L.marker( [lat,lng], {draggable: options.draggable} ).addTo(map); // tiles provider according to module settings (not mandatory), like OpenStreetMap.Mapnik L.tileLayer.provider('YOUR_SELECTED_TILES_PROVIDER').addTo(map); var $map = $('#' + mapId); //var $latlng = $map.siblings(".InputfieldLeafletMapMarkerLatLng").find("input[type=text]"); var $lat = $map.siblings(".InputfieldLeafletMapMarkerLat").find("input[type=text]"); var $lng = $map.siblings(".InputfieldLeafletMapMarkerLng").find("input[type=text]"); var $addr = $map.siblings(".InputfieldLeafletMapMarkerAddress").find("input[type=text]"); var $raw = $map.siblings(".InputfieldLeafletMapMarkerAddress").find("input[name$=_raw]"); var $zoom = $map.siblings(".InputfieldLeafletMapMarkerZoom").find("input[type=number]"); $( ".InputfieldLeafletMapMarkerAddress" ).on( "click", function() { $(".leaflet-control-geocoder.leaflet-control").toggleClass("leaflet-control-geocoder-expanded"); setTimeout(function() { $('input.undefined').focus() }, 300); }); $lat.val(marker.getLatLng().lat); $lng.val(marker.getLatLng().lng); $zoom.val(map.getZoom()); $zoom.change(function(event) { map.setZoom($zoom.val()); map.setView(marker.getLatLng()); }); $lat.change(function(event) { marker.setLatLng([$lat.val(),$lng.val()]); map.setView(marker.getLatLng(), 9); coder.reverse(marker.getLatLng(), map.options.crs.scale(map.getZoom()), function(results) { var r = results[0]; if (r) { $addr.val(r.name); $raw.val(JSON.stringify(r.properties)); } }) }); $lng.change(function(event) { marker.setLatLng([$lat.val(),$lng.val()]); map.setView(marker.getLatLng(), 9); coder.reverse(marker.getLatLng(), map.options.crs.scale(map.getZoom()), function(results) { var r = results[0]; if (r) { $addr.val(r.name); $raw.val(JSON.stringify(r.properties)); } }) }); geocoder.markGeocode = function(result) { marker.setLatLng(result.center); map.fitBounds(result.bbox); $lat.val(result.center.lat); $lng.val(result.center.lng); $addr.val(result.name); $raw.val(JSON.stringify(result.properties)); }; marker.on('dragend', function(event) { var result = marker.getLatLng(); $lat.val(result.lat).trigger('change.custom'); $lng.val(result.lng).trigger('change.custom'); //reverse geocoding displays in the adress field coder.reverse(marker.getLatLng(), map.options.crs.scale(map.getZoom()), function(results) { var r = results[0]; if (r) { $addr.val(r.name); $raw.val(JSON.stringify(r.properties)); } }) }); map.on('zoomend', function(event){ $zoom.val(map.getZoom()); }); // get the tab element where this map is integrated var $map = $('#' + mapId); // Get closed wrappers around the map. var $inputFields = $map.parents('.Inputfield.InputfieldStateCollapsed'); // Refresh the map when any of the wrappers open. $inputFields.on('opened',function(){ window.setTimeout(function(){ map.invalidateSize(); }, 200); }); function initializeLeafletMap() { $(".InputfieldLeafletMapMarkerMap").each(function(item) { var $t = $(this); if (!$t.children().length) { InputfieldLeafletMapMarker.init($t.attr('id'), $t.attr('data-lat'), $t.attr('data-lng'), $t.attr('data-zoom'), $t.attr('data-type'), $t.attr('data-provider')); } }); } $(document).ready(function() { initializeLeafletMap(); $(document).on('reloaded', '.InputfieldLeafletMapMarker', initializeLeafletMap); }); } }); Any suggestions? Link to comment Share on other sites More sharing options...
Ivan Gretsky Posted July 12, 2023 Share Posted July 12, 2023 23 hours ago, Cybermano said: Hi, is there anybody that knows how to easly disable "scrollWheelZoom" on admin page editing? Or is there a "module/field" settings development plan for map options in admin? (an overrideble setting in the field options could be great). I find a little annoying the zooming in/out of the map on page scroll. At the moment I put manually a js line of code in InputfieldLeafletMapMarker.js after line 24 // line 24 var map = L.map(mapElement).setView([lat, lng], options.zoom); // new line map.scrollWheelZoom.disable(); But I'm not so happy to modify original modules... (on updates the modifications could be lose). The second approach that I have succesfully tested is to load a js file in admin, but it needs to completely initialize a new map, only with the add of an option in the declaration of the map init: var map = L.map('_Inputfield_fm_mappa_map', {center: [lat, lng], zoom: parseInt($('#_Inputfield_fm_mappa_zoom').val()), scrollWheelZoom: 0,} ); Reveal hidden contents Complete code $(document).ready(function(){ if ($('form#ProcessPageEdit').hasClass('YOUR_PW_TEMPLETE_NAME_TO_EDIT')) { var mapId = '_Inputfield_YOUR_FIELD_MAP_map'; var lat = $('#_Inputfield_YOUR_FIELD_MAP_lat').val(); var lng = $('#_Inputfield_YOUR_FIELD_MAP_lng').val(); var zoom = parseInt($('#_Inputfield_YOUR_FIELD_MAP_zoom').val()); var options = { zoom: 9, draggable: true, center: null, scrollWheelZoom: 0, } // var map = $('#_Inputfield_YOUR_FIELD_MAP_map'); var map = L.map('_Inputfield_YOUR_FIELD_MAP_map', {center: [lat, lng], zoom: zoom, scrollWheelZoom: 0,} ); var coder = L.Control.Geocoder.nominatim(), geocoder = L.Control.geocoder({ geocoder: geocoder, placeholder: '' }).addTo(map); var marker = L.marker( [lat,lng], {draggable: options.draggable} ).addTo(map); // tiles provider according to module settings (not mandatory), like OpenStreetMap.Mapnik L.tileLayer.provider('YOUR_SELECTED_TILES_PROVIDER').addTo(map); var $map = $('#' + mapId); //var $latlng = $map.siblings(".InputfieldLeafletMapMarkerLatLng").find("input[type=text]"); var $lat = $map.siblings(".InputfieldLeafletMapMarkerLat").find("input[type=text]"); var $lng = $map.siblings(".InputfieldLeafletMapMarkerLng").find("input[type=text]"); var $addr = $map.siblings(".InputfieldLeafletMapMarkerAddress").find("input[type=text]"); var $raw = $map.siblings(".InputfieldLeafletMapMarkerAddress").find("input[name$=_raw]"); var $zoom = $map.siblings(".InputfieldLeafletMapMarkerZoom").find("input[type=number]"); $( ".InputfieldLeafletMapMarkerAddress" ).on( "click", function() { $(".leaflet-control-geocoder.leaflet-control").toggleClass("leaflet-control-geocoder-expanded"); setTimeout(function() { $('input.undefined').focus() }, 300); }); $lat.val(marker.getLatLng().lat); $lng.val(marker.getLatLng().lng); $zoom.val(map.getZoom()); $zoom.change(function(event) { map.setZoom($zoom.val()); map.setView(marker.getLatLng()); }); $lat.change(function(event) { marker.setLatLng([$lat.val(),$lng.val()]); map.setView(marker.getLatLng(), 9); coder.reverse(marker.getLatLng(), map.options.crs.scale(map.getZoom()), function(results) { var r = results[0]; if (r) { $addr.val(r.name); $raw.val(JSON.stringify(r.properties)); } }) }); $lng.change(function(event) { marker.setLatLng([$lat.val(),$lng.val()]); map.setView(marker.getLatLng(), 9); coder.reverse(marker.getLatLng(), map.options.crs.scale(map.getZoom()), function(results) { var r = results[0]; if (r) { $addr.val(r.name); $raw.val(JSON.stringify(r.properties)); } }) }); geocoder.markGeocode = function(result) { marker.setLatLng(result.center); map.fitBounds(result.bbox); $lat.val(result.center.lat); $lng.val(result.center.lng); $addr.val(result.name); $raw.val(JSON.stringify(result.properties)); }; marker.on('dragend', function(event) { var result = marker.getLatLng(); $lat.val(result.lat).trigger('change.custom'); $lng.val(result.lng).trigger('change.custom'); //reverse geocoding displays in the adress field coder.reverse(marker.getLatLng(), map.options.crs.scale(map.getZoom()), function(results) { var r = results[0]; if (r) { $addr.val(r.name); $raw.val(JSON.stringify(r.properties)); } }) }); map.on('zoomend', function(event){ $zoom.val(map.getZoom()); }); // get the tab element where this map is integrated var $map = $('#' + mapId); // Get closed wrappers around the map. var $inputFields = $map.parents('.Inputfield.InputfieldStateCollapsed'); // Refresh the map when any of the wrappers open. $inputFields.on('opened',function(){ window.setTimeout(function(){ map.invalidateSize(); }, 200); }); function initializeLeafletMap() { $(".InputfieldLeafletMapMarkerMap").each(function(item) { var $t = $(this); if (!$t.children().length) { InputfieldLeafletMapMarker.init($t.attr('id'), $t.attr('data-lat'), $t.attr('data-lng'), $t.attr('data-zoom'), $t.attr('data-type'), $t.attr('data-provider')); } }); } $(document).ready(function() { initializeLeafletMap(); $(document).on('reloaded', '.InputfieldLeafletMapMarker', initializeLeafletMap); }); } }); Any suggestions? Let me encourage you to create a PR) I promise to work with it. 2 Link to comment Share on other sites More sharing options...
Cybermano Posted July 12, 2023 Share Posted July 12, 2023 10 hours ago, Ivan Gretsky said: Let me encourage you to create a PR) I promise to work with it. Hi @Ivan Gretsky, thanks for your reply. I hope to create it asap. I will update you. 2 Link to comment Share on other sites More sharing options...
Mike-it Posted July 15, 2023 Share Posted July 15, 2023 (edited) OHHH, SORRY! I've replyed from my co-worker account: I'm Cybermano. --- Hi @Ivan Gretsky, as promised I made a PR on GitHub: hope it's ok. Basically I added a new InputfieldCheckbox in the InputfieldLeafletMapMarker.module fields configuration. Then I setted it in the constructor and also assigned to a variable into the ___render(): if the checkbox is checked, this variable will inoculate an html class ("scrollwheel-disabled") into the div.InputfieldLeafletMapMarkerMap. At the end, into the InputfieldLeafletMapMarker.js, if the div has this class assigned, map.scrollWheelZoom.disable() will do the work. Sorry, I didn't found a cleaner way ?: hope this could be helpful or of inspiration.? I attach the two file here, too. InputfieldLeafletMapMarker.js InputfieldLeafletMapMarker.module Edited July 15, 2023 by Mike-it Typos fixed 2 Link to comment Share on other sites More sharing options...
snck Posted July 26, 2023 Share Posted July 26, 2023 I had a problem with PHP 8.1.8 an saving pages containing the field. I got this error: Quote Fatal Error: Uncaught TypeError: round(): Argument #1 ($num) must be of type int|float, string given in site/modules/FieldtypeMapMarker/InputfieldLeafletMapMarker.module:193 I changed lines 193 and 194 to make sure all values that get rounded are floats: if( ((string) round(floatval($lat), $precision)) != ((string) round(floatval($this->defaultLat), $precision)) || ((string) round(floatval($lng), $precision)) != ((string) round(floatval($this->defaultLng), $precision))) { Maybe this could be included in a future version? Cheers, Flo 2 Link to comment Share on other sites More sharing options...
Cybermano Posted August 2, 2023 Share Posted August 2, 2023 Hi there, I'm testing a static call with JS to set a new view of the map (I need it on event change without refreshing the page), as found on Github and Stackoverflow: // frontend var mymap = L.map($('#mleafletmap1')).setView([45.53, 10.21], 2); // backend var mymap = L.map($('#_Inputfield_fm_mappa_map')).setView([45.53, 10.21], 2); This produces a TypeError: t.className is undefined. Spoiler Uncaught TypeError: t.className is undefined _getClass https://unpkg.com/leaflet@0.7.7/dist/leaflet.js:6 hasClass https://unpkg.com/leaflet@0.7.7/dist/leaflet.js:6 addClass https://unpkg.com/leaflet@0.7.7/dist/leaflet.js:6 _initLayout https://unpkg.com/leaflet@0.7.7/dist/leaflet.js:6 initialize https://unpkg.com/leaflet@0.7.7/dist/leaflet.js:6 e https://unpkg.com/leaflet@0.7.7/dist/leaflet.js:6 map https://unpkg.com/leaflet@0.7.7/dist/leaflet.js:6 <anonymous> debugger eval code:1 debugger eval code:6:11444 I looking for a solution, but didn't found it (...and I'm not a skilled js coder). Does anybody have an idea? Link to comment Share on other sites More sharing options...
Cybermano Posted August 3, 2023 Share Posted August 3, 2023 I would advice all you that the geocoder API is no longer accessible in the format of the current module. I have an error geocoding address and the return message from nominatim.openstreetmap is: Using the URL /search/ and /reverse/ (with slashes) is no longer supported. Change url from /search/?q=Berlin in /search?q=Berlin Also complete addresses are changed, see below: File not found: API no longer accessible via this URL Using the URL /search/ and /reverse/ (with slashes) is no longer supported. Please use URLs as given in the documentation. Examples how to change the URL: You use: https://nominatim.openstreetmap.org/search/?q=Berlin Change to: https://nominatim.openstreetmap.org/search?q=Berlin You use: https://nominatim.openstreetmap.org/search/US/Texas/Huston Change to: https://nominatim.openstreetmap.org/search?q=Huston, Texas, US See github issue #3134 for more details. See github issue #3134 for more details. Maybe editing ControlGeocoder.js fixes partially the problem? :343 L.Control.Geocoder.jsonp(this.options.serviceUrl + 'search/', L.extend({ change in L.Control.Geocoder.jsonp(this.options.serviceUrl + 'search', L.extend({ :370 L.Control.Geocoder.jsonp(this.options.serviceUrl + 'reverse/', L.extend({ change in L.Control.Geocoder.jsonp(this.options.serviceUrl + 'reverse', L.extend({ I have tested with simple addresses (italian street, number and city) ad it works fine again, both search and reverse. Posted a commit on Github:https://github.com/FriendsOfProcessWire/FieldtypeLeafletMapMarker/commit/63254dffea9bd504eb45b124d64fd5832e38f013 4 4 Link to comment Share on other sites More sharing options...
torf Posted Friday at 08:49 AM Share Posted Friday at 08:49 AM Hi, does anybody know how to use the module with a repeater? I need to have multiple mappoints in one map at my frontend, and due to the nature of the site I cannot put them in pages. So I thought of using a repeater for those points (as it is not possible to add multiple markers to one map). In the backend it works fine, but I cannot figure out how to collect those points and display them in one map. <?php $map = $modules->get('MarkupLeafletMap'); echo $map->getLeafletMapHeaderLines(); $mappoints = []; foreach ($page->map_repeater as $point) { array_push($mappoints, $point->map); //or array_push($mappoints, [$point->map]); //or array_push($mappoints, $point->map->LeafletMapMarker); array_push($mappoints, [$point->map->lat, $point->map->lng]); } echo $map->render($page, $mappoints, array('height' => '270px')); ?> All I tried gave me different mistakes. Does anybody know the correct syntax? Link to comment Share on other sites More sharing options...
Cybermano Posted Friday at 03:29 PM Share Posted Friday at 03:29 PM (edited) Hi @torf Never used Leaflet Map with repeaters, but in past I had to collect lot of points into a single map. I simply used a PageArray with wire('pages')-find('template=MY_TEMPLATE, and so on...') and then I passed the PageArray to the $map->render($MY_PAGE_ARRAY, 'MY_MAP_FIELD', $options); it works. So I suggest to collect your points in a PageArray with proper selectors. Don't forget that your repeater has a template, and if useful you can get the parents of them. Let me know if this solution can fit your needs. Edited Friday at 03:32 PM by Cybermano Link to comment Share on other sites More sharing options...
torf Posted Friday at 05:22 PM Share Posted Friday at 05:22 PM Thanks @Cybermano I already did it with page arrays and it works great, but this time I'd prefer a repeater. Using page arrays would make the backend to complicated. Link to comment Share on other sites More sharing options...
Cybermano Posted Friday at 08:38 PM Share Posted Friday at 08:38 PM 2 hours ago, torf said: Thanks @Cybermano I already did it with page arrays and it works great, but this time I'd prefer a repeater. Using page arrays would make the backend to complicated. Hi @torf, maybe I didn't get it at all or maybe I didn't explain well my idea. So I'll try again... 😉 Surely I could be wrong, but for me a PageArray is not only for admin side, but all the pw pages collected into a php variable created with pw selectors in a script file. For shortness I have created 2 pages with two repeaters each (repeater name is "multipoints"), with a title and a leaflet map field (named 'fm_mappa') into. This is the simply code for testing. Please note that I didn't get the repeater with a foreach statement, but with a pw search with a selector for all the templates with name equals to "repeater_NAMEOFTHEREPEATER", as pw builds. Obviously into your selector you can build your search to the desired points, e.g with sorting or something other. echo $pagesWithMultipointsRepeater = wire('pages')->find('template=repeater_multipoints'); if (count($pagesWithMultipointsRepeater)){ $map = $modules->get('MarkupLeafletMap'); $options = array( 'height' => 800, 'markerColour' => 'red', ); echo '<div class="g-mb-25">'; echo $map->render($pagesWithMultipointsRepeater,'fm_mappa',$options); echo '</div>'; } The numbers before the map are the repeater ids (note the "echo" on the first line of the code). And these are the admin pages: I hope that's clearer. 1 Link to comment Share on other sites More sharing options...
Cybermano Posted Friday at 08:54 PM Share Posted Friday at 08:54 PM Or maybe this edited code of your first post works? $map = $modules->get('MarkupLeafletMap'); echo $map->getLeafletMapHeaderLines(); $mappoints = new PageArray(); foreach ($page->map_repeater as $point) { $mappoints->add($point) // the repater is a page } echo $map->render($mappoints, 'your_map_field_name', array('height' => '270px')); ?> Link to comment Share on other sites More sharing options...
torf Posted yesterday at 07:29 AM Share Posted yesterday at 07:29 AM Thanks a lot @Cybermano That worked flawless. 1 Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now