A Quick Leaflet Tutorial

I thought as I have Leaflet working well I would share some code to get people started if you want to use Leaflet in Wappler. Hopefully it will be integrated at some point, but it’s not too complicated to code. I did a quick db so don’t judge me if I don’t have field types/indexes set up properly :smiley:

First the tables. I have two for this example. One for the markers and one for the map icons (I’m using https://mapmarker.io/editor to create the icons - a fantastic free resource). You’ll, need to set up the database tables in your database and create the server connects - get_icons and get_markers.

There are no API keys needed for this as it’s using Open Street Maps. To use other map tiles and for more options, see the documentation at https://leafletjs.com/

MARKERS

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for tbl_markers
-- ----------------------------
DROP TABLE IF EXISTS `tbl_markers`;
CREATE TABLE `tbl_markers`  (
  `marker_id` int(11) NOT NULL AUTO_INCREMENT,
  `icon_id` int(11) NOT NULL,
  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  `lat` decimal(10, 4) NOT NULL,
  `lng` decimal(10, 4) NOT NULL,
  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
  PRIMARY KEY (`marker_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of tbl_markers
-- ----------------------------
INSERT INTO `tbl_markers` VALUES (1, 1, 'Test 1', 42.3691, 42.3691, 'Test One Description');
INSERT INTO `tbl_markers` VALUES (2, 2, 'Test 2', 50.8503, 50.8503, 'Test Two Description');
INSERT INTO `tbl_markers` VALUES (3, 3, 'Test 3 ', 50.8369, 50.8369, 'Test Three Description');
INSERT INTO `tbl_markers` VALUES (4, 2, 'Test 4', 49.4076, 49.4076, 'Test Four (same icon as 2');

SET FOREIGN_KEY_CHECKS = 1;

ICONS

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
    -- ----------------------------
    -- Table structure for tbl_icons
    -- ----------------------------
    DROP TABLE IF EXISTS `tbl_icons`;
    CREATE TABLE `tbl_icons`  (
      `icon_id` int(11) NOT NULL AUTO_INCREMENT,
      `icon_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
      PRIMARY KEY (`icon_id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;

    -- ----------------------------
    -- Records of tbl_icons
    -- ----------------------------
    INSERT INTO `tbl_icons` VALUES (1, 'https://cdn.mapmarker.io/api/v1/pin?size=120&background=%23373737&icon=fa-star&color=%23C45100&voffset=0&hoffset=1&');
    INSERT INTO `tbl_icons` VALUES (2, 'https://cdn.mapmarker.io/api/v1/pin?size=120&background=%23FCC400&icon=fa-star&color=%23C45100&voffset=0&hoffset=1&');
    INSERT INTO `tbl_icons` VALUES (3, 'https://cdn.mapmarker.io/api/v1/fa?size=120&icon=fa-star&color=%23C45100&');
    INSERT INTO `tbl_icons` VALUES (4, 'https://cdn.mapmarker.io/api/v1/fa/stack?size=120&icon=fa-star&color=%23194D33&on=fa-circle&oncolor=%23FCDC00&hoffset=1&voffset=0&iconsize=35&');

    SET FOREIGN_KEY_CHECKS = 1;

THE HEADERS
I can’t seem to paste the whole code all at once so here is the head section

<head>
<base href="/">
<script src="dmxAppConnect/dmxAppConnect.js"></script>
<meta charset="UTF-8">
<title>Leaflet Example</title>
<link rel="stylesheet" href="fontawesome4/css/font-awesome.min.css" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="bootstrap/4/united/bootstrap.min.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="" />
<!-- Make sure you put this AFTER Leaflet's CSS -->
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha384-ZvpUoO/+PpLXR1lu4jmpXWu80pZlYUAfxl5NsBMWOEPSjUn/6Z/hRTt8+pR6L4N2" crossorigin="anonymous"></script>
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>

THE CODE

<body is="dmx-app" id="leaflet">

    <dmx-serverconnect id="sc_icons" url="dmxConnect/api/Leaflet/get_icons.php"></dmx-serverconnect>

    <dmx-serverconnect id="sc_markers" url="dmxConnect/api/Leaflet/get_markers.php" onsuccess="setMapMarkers();"></dmx-serverconnect>

    <div id="mapid" style="height:800px;"></div> <!--Your DIV must have a height!!-->

    <script>

        //LEAFLET CODE

        

        //Main Map initialization   

        var map = L.map('mapid', {

              fullscreenControl: true,

              tap:false,

              touchZoom: true,

            fullscreenControlOptions: {

                position: 'topleft'

        },

            center: [41.6510,0.878195],

            zoom: 5});

    

            L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoiaGV6bWFubiIsImEiOiJjajhvOXN3OWEwMThvMndudGZoYzF0aTR0In0.oI4Z-bC2IM63PxoSNwwD2g', {

            attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',

            maxZoom: 18,

            id: 'mapbox/streets-v11',           

            }).addTo(map);

            

        //Make the Marker Icons from tbl_icons

        function makeIcons(){

            var icons = dmx.parse('sc_icons.data.query');

            if (Array.isArray(icons)){

                icons.forEach(function(icon){

                    var thisURL = icon.icon_url;

                    window['icon'+icon.icon_id] = L.icon({iconUrl: thisURL, iconAnchor: [16, 32], popupAnchor: [-16, -32]});                

                });

            }else{              

            }

        }

    

        markersLayer = new L.FeatureGroup(); //Create the Markers Layer

        //Create the map markers and pop up cards and add to main map

        //**MAKE SURE YOU ARE CALLING THIS IN YOUR SERVER CONNECT onsuccess() FOR THE MARKERS**//

        function setMapMarkers() {

            markersLayer.clearLayers();

            bounds = L.latLngBounds();

            //creates custom icons from tbl_icons, see above

            makeIcons(); 

            //get our markers from tbl_markers. If you filter the server connect this will automatically be filtered as well. Nifty!

            var markers = dmx.parse('sc_markers.data.query'); 

            //loop through all the markers from the database.  

            if (Array.isArray(markers)) {

                markers.forEach(function(marker) {

                    if(marker.lat && marker.lng && marker.lat != 0){

                        var title = encodeURI(marker.title);

                        //This is what is going in the pop-up.  It's very flexible, you can put cards/modals etc in here with whatever.  This is just a simple example.

                        var template ='<div class="card"><div clas="card-header">' + marker.title + '</div><div class="card-body"><p class="card-text">' + marker.description + '</p></div></div>';

                        //Get the right icon

                        var thisIcon = window['icon'+marker.icon_id];

                        //Put it all together

                        var x = L.marker([marker.lat, marker.lng],{icon: thisIcon, title: marker.title, draggable: true}).bindPopup(template);

                        //Add it to the markers lager

                        x.addTo(markersLayer);

                        //Get the bounds for this marker

                        var lat_lng = [marker.lat, marker.lng];

                        //Extend the bounds to include this marker

                        bounds.extend(lat_lng);

                    }

                });

                

                //add all the markers to the map

                markersLayer.addTo(map);

                //fit the map to our markers

                if(bounds.isValid()){

                    map.fitBounds(bounds);

                }

        

        }

        }

        //Keeps track of which popup is open

        var currentPopup; 

        map.on("popupopen", function(evt){currentPopup = evt.popup});

    </script>

    <script src="bootstrap/4/js/popper.min.js"></script>

    <script src="bootstrap/4/js/bootstrap.min.js"></script>

</body>

Hope that helps someone! Feel free to ask questions. :slight_smile:

6 Likes

Thank you.

1 Like

This is fantastic! Thank you I will definitely try it out.

1 Like

Let me know if it works for you!!

@Heather_Mann hello there. Do you happen to get it work with polyline? I’ve set var = latlng to dmx.parse which outputs result as : [[4.183333,103.444444],[4.183333,103.566667],[3.750000,103.566667],[3.750000,103.326111]] as per required, confirmed on console log but the polyline still doesn’t work with error leaflet.js:5 Uncaught TypeError: Cannot read property '0' of null.

Hey. I don’t work with polylines but I had a good crack at it and am getting the same as you. I can copy and past the console.log of the the latlng created by the dmx.parse ([[49.0000,17.0000],[49.0000,14.0000]]) into a static variable and it works fine, but creating it dynamically I get the error.

Post back here if you figure it out please. I’d love to know the answer! Good Luck!

I think even though the output is in array format but it still being detected as string by the script. I’m not sure the solution I just did is the correct way but I finally get it working using eval(string).

Cool. Worked like a charm on my test.

Here’s my code if anyone in future needs it. I worked this up quickly, so if there’s a better way please feel free to correct me!

Make sure you run this in the onSuccess of the server connect.

function addPolyline(){
var latlngs = ‘’;
var polys = dmx.parse(‘sc_polyline.data.query’);

polys.forEach(function(poly) {
    latlngs += ('[' + poly.lat + ',' + poly.lng + '],');
});

latlngs = eval('[' + latlngs.slice(0, -1) + ']');

var polyline = L.polyline(latlngs, {color: ‘red’}).addTo(mymap);
mymap.fitBounds(polyline.getBounds());

}

1 Like

@Heather_Mann - I just wanted to say thanks so much for posting this code, it’s solved a massive problem for me!

1 Like

You’re very welcome! Glad it was useful.