testing new leaflet map for the breweries page
authorAnthony Talarico <talarico@gaslightmedia.com>
Thu, 30 Aug 2018 19:37:04 +0000 (15:37 -0400)
committerAnthony Talarico <talarico@gaslightmedia.com>
Thu, 30 Aug 2018 19:37:04 +0000 (15:37 -0400)
glm-member-db/views/front/members/list.html
js/leaflet.geometryutil.js [new file with mode: 0644]
sections/brewery-map.php

index 75b9bd3..1e5cb86 100644 (file)
@@ -4,7 +4,7 @@
     {if $settings.list_map_show_opened || $view == 'map'}map-opened{else}map-closed{/if}
     {if $settings.list_show_search_filters_opened}filters-opened{else}filters-closed{/if}
 ">
-BAGAGA
+
 {if $view != 'no-map'}
             {if $settings.selected_map_interface == 1}
                 <!--  Leaflet Map -->
@@ -22,7 +22,7 @@ BAGAGA
             {/if}
 
 {/if}
-        {apply_filters('glm-member-db-front-members-list-pageTop', '')}
+{apply_filters('glm-member-db-front-members-list-pageTop', '')}
 <div class="glm-member-list-inner-wrapper">
     {if $settings.list_show_map}
             <div id="glm-member-list-map-toggle" class="button glm-button">Map</div>
@@ -526,14 +526,14 @@ BAGAGA
             var startLat = $('#glmLat').val();
             var startLon = $('#glmLng').val();
             var defZoom = Number({$settings.maps_default_zoom});
-                 
-      {if $settings.selected_map_interface == 1 && $view != 'no-map'}
+
+      {if $settings.selected_map_interface == 1 || $view != 'no-map'}
 
             /*
              *  Leaflet Map
              *  API reference: https://leafletjs.com/reference-1.3.2.html
              */
-            console.log('LEAF')
+
             function initMap() {
 
                 var leafletMap = L.map('LeafletMapContainer').setView([{$settings.maps_default_lat}, {$settings.maps_default_lon}], defZoom);
@@ -603,7 +603,7 @@ BAGAGA
 
       {/if}
 
-      {if $settings.selected_map_interface == 2 && $view != 'no-map'}
+      {if $settings.selected_map_interface == 2 || $view != 'no-map'}
  
                         /*
                          * Google Maps
@@ -739,12 +739,14 @@ BAGAGA
                     mapInitialized = true;
                 }
             });
-        {if $settings.list_map_show_opened}
-            // Start with map opened
-            initMap();
-            mapInitialized = true;
+        {if $view != 'no-map'}
+            {if $settings.list_map_show_opened }
+                // Start with map opened
+                initMap();
+                mapInitialized = true;
+            {/if}
+                initMap();
         {/if}
-            initMap();
 
             // Processes click-through counts for website links
             $('.glm-member-list-website-link').on('click', function() {
diff --git a/js/leaflet.geometryutil.js b/js/leaflet.geometryutil.js
new file mode 100644 (file)
index 0000000..b5cf112
--- /dev/null
@@ -0,0 +1,767 @@
+// Packaging/modules magic dance.
+(function (factory) {
+    var L;
+    if (typeof define === 'function' && define.amd) {
+        // AMD
+        define(['leaflet'], factory);
+    } else if (typeof module !== 'undefined') {
+        // Node/CommonJS
+        L = require('leaflet');
+        module.exports = factory(L);
+    } else {
+        // Browser globals
+        if (typeof window.L === 'undefined')
+            throw 'Leaflet must be loaded first';
+        factory(window.L);
+    }
+}(function (L) {
+"use strict";
+
+L.Polyline._flat = L.LineUtil.isFlat || L.Polyline._flat || function (latlngs) {
+    // true if it's a flat array of latlngs; false if nested
+    return !L.Util.isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined');
+};
+
+/**
+ * @fileOverview Leaflet Geometry utilities for distances and linear referencing.
+ * @name L.GeometryUtil
+ */
+
+L.GeometryUtil = L.extend(L.GeometryUtil || {}, {
+
+    /**
+        Shortcut function for planar distance between two {L.LatLng} at current zoom.
+
+        @tutorial distance-length
+
+        @param {L.Map} map Leaflet map to be used for this method
+        @param {L.LatLng} latlngA geographical point A
+        @param {L.LatLng} latlngB geographical point B
+        @returns {Number} planar distance
+     */
+    distance: function (map, latlngA, latlngB) {
+        return map.latLngToLayerPoint(latlngA).distanceTo(map.latLngToLayerPoint(latlngB));
+    },
+
+    /**
+        Shortcut function for planar distance between a {L.LatLng} and a segment (A-B).
+        @param {L.Map} map Leaflet map to be used for this method
+        @param {L.LatLng} latlng - The position to search
+        @param {L.LatLng} latlngA geographical point A of the segment
+        @param {L.LatLng} latlngB geographical point B of the segment
+        @returns {Number} planar distance
+    */
+    distanceSegment: function (map, latlng, latlngA, latlngB) {
+        var p = map.latLngToLayerPoint(latlng),
+           p1 = map.latLngToLayerPoint(latlngA),
+           p2 = map.latLngToLayerPoint(latlngB);
+        return L.LineUtil.pointToSegmentDistance(p, p1, p2);
+    },
+
+    /**
+        Shortcut function for converting distance to readable distance.
+        @param {Number} distance distance to be converted
+        @param {String} unit 'metric' or 'imperial'
+        @returns {String} in yard or miles
+    */
+    readableDistance: function (distance, unit) {
+        var isMetric = (unit !== 'imperial'),
+            distanceStr;
+        if (isMetric) {
+            // show metres when distance is < 1km, then show km
+            if (distance > 1000) {
+                distanceStr = (distance  / 1000).toFixed(2) + ' km';
+            }
+            else {
+                distanceStr = Math.ceil(distance) + ' m';
+            }
+        }
+        else {
+            distance *= 1.09361;
+            if (distance > 1760) {
+                distanceStr = (distance / 1760).toFixed(2) + ' miles';
+            }
+            else {
+                distanceStr = Math.ceil(distance) + ' yd';
+            }
+        }
+        return distanceStr;
+    },
+
+    /**
+        Returns true if the latlng belongs to segment A-B
+        @param {L.LatLng} latlng - The position to search
+        @param {L.LatLng} latlngA geographical point A of the segment
+        @param {L.LatLng} latlngB geographical point B of the segment
+        @param {?Number} [tolerance=0.2] tolerance to accept if latlng belongs really
+        @returns {boolean}
+     */
+    belongsSegment: function(latlng, latlngA, latlngB, tolerance) {
+        tolerance = tolerance === undefined ? 0.2 : tolerance;
+        var hypotenuse = latlngA.distanceTo(latlngB),
+            delta = latlngA.distanceTo(latlng) + latlng.distanceTo(latlngB) - hypotenuse;
+        return delta/hypotenuse < tolerance;
+    },
+
+    /**
+     * Returns total length of line
+     * @tutorial distance-length
+     *
+     * @param {L.Polyline|Array<L.Point>|Array<L.LatLng>} coords Set of coordinates
+     * @returns {Number} Total length (pixels for Point, meters for LatLng)
+     */
+    length: function (coords) {
+        var accumulated = L.GeometryUtil.accumulatedLengths(coords);
+        return accumulated.length > 0 ? accumulated[accumulated.length-1] : 0;
+    },
+
+    /**
+     * Returns a list of accumulated length along a line.
+     * @param {L.Polyline|Array<L.Point>|Array<L.LatLng>} coords Set of coordinates
+     * @returns {Array<Number>} Array of accumulated lengths (pixels for Point, meters for LatLng)
+     */
+    accumulatedLengths: function (coords) {
+        if (typeof coords.getLatLngs == 'function') {
+            coords = coords.getLatLngs();
+        }
+        if (coords.length === 0)
+            return [];
+        var total = 0,
+            lengths = [0];
+        for (var i = 0, n = coords.length - 1; i< n; i++) {
+            total += coords[i].distanceTo(coords[i+1]);
+            lengths.push(total);
+        }
+        return lengths;
+    },
+
+    /**
+        Returns the closest point of a {L.LatLng} on the segment (A-B)
+
+        @tutorial closest
+
+        @param {L.Map} map Leaflet map to be used for this method
+        @param {L.LatLng} latlng - The position to search
+        @param {L.LatLng} latlngA geographical point A of the segment
+        @param {L.LatLng} latlngB geographical point B of the segment
+        @returns {L.LatLng} Closest geographical point
+    */
+    closestOnSegment: function (map, latlng, latlngA, latlngB) {
+        var maxzoom = map.getMaxZoom();
+        if (maxzoom === Infinity)
+            maxzoom = map.getZoom();
+        var p = map.project(latlng, maxzoom),
+           p1 = map.project(latlngA, maxzoom),
+           p2 = map.project(latlngB, maxzoom),
+           closest = L.LineUtil.closestPointOnSegment(p, p1, p2);
+        return map.unproject(closest, maxzoom);
+    },
+
+    /**
+        Returns the closest latlng on layer.
+
+        Accept nested arrays
+
+        @tutorial closest
+
+        @param {L.Map} map Leaflet map to be used for this method
+        @param {Array<L.LatLng>|Array<Array<L.LatLng>>|L.PolyLine|L.Polygon} layer - Layer that contains the result
+        @param {L.LatLng} latlng - The position to search
+        @param {?boolean} [vertices=false] - Whether to restrict to path vertices.
+        @returns {L.LatLng} Closest geographical point or null if layer param is incorrect
+    */
+    closest: function (map, layer, latlng, vertices) {
+
+        var latlngs,
+            mindist = Infinity,
+            result = null,
+            i, n, distance, subResult;
+
+        if (layer instanceof Array) {
+            // if layer is Array<Array<T>>
+            if (layer[0] instanceof Array && typeof layer[0][0] !== 'number') {
+                // if we have nested arrays, we calc the closest for each array
+                // recursive
+                for (i = 0; i < layer.length; i++) {
+                    subResult = L.GeometryUtil.closest(map, layer[i], latlng, vertices);
+                    if (subResult.distance < mindist) {
+                        mindist = subResult.distance;
+                        result = subResult;
+                    }
+                }
+                return result;
+            } else if (layer[0] instanceof L.LatLng
+                        || typeof layer[0][0] === 'number'
+                        || typeof layer[0].lat === 'number') { // we could have a latlng as [x,y] with x & y numbers or {lat, lng}
+                layer = L.polyline(layer);
+            } else {
+                return result;
+            }
+        }
+
+        // if we don't have here a Polyline, that means layer is incorrect
+        // see https://github.com/makinacorpus/Leaflet.GeometryUtil/issues/23
+        if (! ( layer instanceof L.Polyline ) )
+            return result;
+
+        // deep copy of latlngs
+        latlngs = JSON.parse(JSON.stringify(layer.getLatLngs().slice(0)));
+
+        // add the last segment for L.Polygon
+        if (layer instanceof L.Polygon) {
+            // add the last segment for each child that is a nested array
+            var addLastSegment = function(latlngs) {
+                if (L.Polyline._flat(latlngs)) {
+                    latlngs.push(latlngs[0]);
+                } else {
+                    for (var i = 0; i < latlngs.length; i++) {
+                        addLastSegment(latlngs[i]);
+                    }
+                }
+            };
+            addLastSegment(latlngs);
+        }
+
+        // we have a multi polygon / multi polyline / polygon with holes
+        // use recursive to explore and return the good result
+        if ( ! L.Polyline._flat(latlngs) ) {
+            for (i = 0; i < latlngs.length; i++) {
+                // if we are at the lower level, and if we have a L.Polygon, we add the last segment
+                subResult = L.GeometryUtil.closest(map, latlngs[i], latlng, vertices);
+                if (subResult.distance < mindist) {
+                    mindist = subResult.distance;
+                    result = subResult;
+                }
+            }
+            return result;
+
+        } else {
+
+            // Lookup vertices
+            if (vertices) {
+                for(i = 0, n = latlngs.length; i < n; i++) {
+                    var ll = latlngs[i];
+                    distance = L.GeometryUtil.distance(map, latlng, ll);
+                    if (distance < mindist) {
+                        mindist = distance;
+                        result = ll;
+                        result.distance = distance;
+                    }
+                }
+                return result;
+            }
+
+            // Keep the closest point of all segments
+            for (i = 0, n = latlngs.length; i < n-1; i++) {
+                var latlngA = latlngs[i],
+                    latlngB = latlngs[i+1];
+                distance = L.GeometryUtil.distanceSegment(map, latlng, latlngA, latlngB);
+                if (distance <= mindist) {
+                    mindist = distance;
+                    result = L.GeometryUtil.closestOnSegment(map, latlng, latlngA, latlngB);
+                    result.distance = distance;
+                }
+            }
+            return result;
+        }
+
+    },
+
+    /**
+        Returns the closest layer to latlng among a list of layers.
+
+        @tutorial closest
+
+        @param {L.Map} map Leaflet map to be used for this method
+        @param {Array<L.ILayer>} layers Set of layers
+        @param {L.LatLng} latlng - The position to search
+        @returns {object} ``{layer, latlng, distance}`` or ``null`` if list is empty;
+    */
+    closestLayer: function (map, layers, latlng) {
+        var mindist = Infinity,
+            result = null,
+            ll = null,
+            distance = Infinity;
+
+        for (var i = 0, n = layers.length; i < n; i++) {
+            var layer = layers[i];
+            if (layer instanceof L.LayerGroup) {
+                // recursive
+                var subResult = L.GeometryUtil.closestLayer(map, layer.getLayers(), latlng);
+                if (subResult.distance < mindist) {
+                    mindist = subResult.distance;
+                    result = subResult;
+                }
+            } else {
+                // Single dimension, snap on points, else snap on closest
+                if (typeof layer.getLatLng == 'function') {
+                    ll = layer.getLatLng();
+                    distance = L.GeometryUtil.distance(map, latlng, ll);
+                }
+                else {
+                    ll = L.GeometryUtil.closest(map, layer, latlng);
+                    if (ll) distance = ll.distance;  // Can return null if layer has no points.
+                }
+                if (distance < mindist) {
+                    mindist = distance;
+                    result = {layer: layer, latlng: ll, distance: distance};
+                }
+            }
+        }
+        return result;
+    },
+
+    /**
+        Returns the n closest layers to latlng among a list of input layers.
+
+        @param {L.Map} map - Leaflet map to be used for this method
+        @param {Array<L.ILayer>} layers - Set of layers
+        @param {L.LatLng} latlng - The position to search
+        @param {?Number} [n=layers.length] - the expected number of output layers.
+        @returns {Array<object>} an array of objects ``{layer, latlng, distance}`` or ``null`` if the input is invalid (empty list or negative n)
+    */
+    nClosestLayers: function (map, layers, latlng, n) {
+        n = typeof n === 'number' ? n : layers.length;
+
+        if (n < 1 || layers.length < 1) {
+            return null;
+        }
+
+        var results = [];
+        var distance, ll;
+
+        for (var i = 0, m = layers.length; i < m; i++) {
+            var layer = layers[i];
+            if (layer instanceof L.LayerGroup) {
+                // recursive
+                var subResult = L.GeometryUtil.closestLayer(map, layer.getLayers(), latlng);
+                results.push(subResult);
+            } else {
+                // Single dimension, snap on points, else snap on closest
+                if (typeof layer.getLatLng == 'function') {
+                    ll = layer.getLatLng();
+                    distance = L.GeometryUtil.distance(map, latlng, ll);
+                }
+                else {
+                    ll = L.GeometryUtil.closest(map, layer, latlng);
+                    if (ll) distance = ll.distance;  // Can return null if layer has no points.
+                }
+                results.push({layer: layer, latlng: ll, distance: distance});
+            }
+        }
+
+        results.sort(function(a, b) {
+            return a.distance - b.distance;
+        });
+
+        if (results.length > n) {
+            return results.slice(0, n);
+        } else  {
+            return results;
+        }
+    },
+
+    /**
+     * Returns all layers within a radius of the given position, in an ascending order of distance.
+       @param {L.Map} map Leaflet map to be used for this method
+       @param {Array<ILayer>} layers - A list of layers.
+       @param {L.LatLng} latlng - The position to search
+       @param {?Number} [radius=Infinity] - Search radius in pixels
+       @return {object[]} an array of objects including layer within the radius, closest latlng, and distance
+     */
+    layersWithin: function(map, layers, latlng, radius) {
+      radius = typeof radius == 'number' ? radius : Infinity;
+
+      var results = [];
+      var ll = null;
+      var distance = 0;
+
+      for (var i = 0, n = layers.length; i < n; i++) {
+        var layer = layers[i];
+
+        if (typeof layer.getLatLng == 'function') {
+            ll = layer.getLatLng();
+            distance = L.GeometryUtil.distance(map, latlng, ll);
+        }
+        else {
+            ll = L.GeometryUtil.closest(map, layer, latlng);
+            if (ll) distance = ll.distance;  // Can return null if layer has no points.
+        }
+
+        if (ll && distance < radius) {
+            results.push({layer: layer, latlng: ll, distance: distance});
+        }
+      }
+
+      var sortedResults = results.sort(function(a, b) {
+          return a.distance - b.distance;
+      });
+
+      return sortedResults;
+    },
+
+    /**
+        Returns the closest position from specified {LatLng} among specified layers,
+        with a maximum tolerance in pixels, providing snapping behaviour.
+
+        @tutorial closest
+
+        @param {L.Map} map Leaflet map to be used for this method
+        @param {Array<ILayer>} layers - A list of layers to snap on.
+        @param {L.LatLng} latlng - The position to snap
+        @param {?Number} [tolerance=Infinity] - Maximum number of pixels.
+        @param {?boolean} [withVertices=true] - Snap to layers vertices or segment points (not only vertex)
+        @returns {object} with snapped {LatLng} and snapped {Layer} or null if tolerance exceeded.
+    */
+    closestLayerSnap: function (map, layers, latlng, tolerance, withVertices) {
+        tolerance = typeof tolerance == 'number' ? tolerance : Infinity;
+        withVertices = typeof withVertices == 'boolean' ? withVertices : true;
+
+        var result = L.GeometryUtil.closestLayer(map, layers, latlng);
+        if (!result || result.distance > tolerance)
+            return null;
+
+        // If snapped layer is linear, try to snap on vertices (extremities and middle points)
+        if (withVertices && typeof result.layer.getLatLngs == 'function') {
+            var closest = L.GeometryUtil.closest(map, result.layer, result.latlng, true);
+            if (closest.distance < tolerance) {
+                result.latlng = closest;
+                result.distance = L.GeometryUtil.distance(map, closest, latlng);
+            }
+        }
+        return result;
+    },
+
+    /**
+        Returns the Point located on a segment at the specified ratio of the segment length.
+        @param {L.Point} pA coordinates of point A
+        @param {L.Point} pB coordinates of point B
+        @param {Number} the length ratio, expressed as a decimal between 0 and 1, inclusive.
+        @returns {L.Point} the interpolated point.
+    */
+    interpolateOnPointSegment: function (pA, pB, ratio) {
+        return L.point(
+            (pA.x * (1 - ratio)) + (ratio * pB.x),
+            (pA.y * (1 - ratio)) + (ratio * pB.y)
+        );
+    },
+
+    /**
+        Returns the coordinate of the point located on a line at the specified ratio of the line length.
+        @param {L.Map} map Leaflet map to be used for this method
+        @param {Array<L.LatLng>|L.PolyLine} latlngs Set of geographical points
+        @param {Number} ratio the length ratio, expressed as a decimal between 0 and 1, inclusive
+        @returns {Object} an object with latLng ({LatLng}) and predecessor ({Number}), the index of the preceding vertex in the Polyline
+        (-1 if the interpolated point is the first vertex)
+    */
+    interpolateOnLine: function (map, latLngs, ratio) {
+        latLngs = (latLngs instanceof L.Polyline) ? latLngs.getLatLngs() : latLngs;
+        var n = latLngs.length;
+        if (n < 2) {
+            return null;
+        }
+
+        // ensure the ratio is between 0 and 1;
+        ratio = Math.max(Math.min(ratio, 1), 0);
+
+        if (ratio === 0) {
+            return {
+                latLng: latLngs[0] instanceof L.LatLng ? latLngs[0] : L.latLng(latLngs[0]),
+                predecessor: -1
+            };
+        }
+        if (ratio == 1) {
+            return {
+                latLng: latLngs[latLngs.length -1] instanceof L.LatLng ? latLngs[latLngs.length -1] : L.latLng(latLngs[latLngs.length -1]),
+                predecessor: latLngs.length - 2
+            };
+        }
+
+        // project the LatLngs as Points,
+        // and compute total planar length of the line at max precision
+        var maxzoom = map.getMaxZoom();
+        if (maxzoom === Infinity)
+            maxzoom = map.getZoom();
+        var pts = [];
+        var lineLength = 0;
+        for(var i = 0; i < n; i++) {
+            pts[i] = map.project(latLngs[i], maxzoom);
+            if(i > 0)
+              lineLength += pts[i-1].distanceTo(pts[i]);
+        }
+
+        var ratioDist = lineLength * ratio;
+
+               // follow the line segments [ab], adding lengths,
+        // until we find the segment where the points should lie on
+               var cumulativeDistanceToA = 0, cumulativeDistanceToB = 0;
+               for (var i = 0; cumulativeDistanceToB < ratioDist; i++) {
+                       var pointA = pts[i], pointB = pts[i+1];
+
+                       cumulativeDistanceToA = cumulativeDistanceToB;
+                       cumulativeDistanceToB += pointA.distanceTo(pointB);
+               }
+               
+               if (pointA == undefined && pointB == undefined) { // Happens when line has no length
+                       var pointA = pts[0], pointB = pts[1], i = 1;
+               }
+
+               // compute the ratio relative to the segment [ab]
+               var segmentRatio = ((cumulativeDistanceToB - cumulativeDistanceToA) !== 0) ? ((ratioDist - cumulativeDistanceToA) / (cumulativeDistanceToB - cumulativeDistanceToA)) : 0;
+               var interpolatedPoint = L.GeometryUtil.interpolateOnPointSegment(pointA, pointB, segmentRatio);
+               return {
+                       latLng: map.unproject(interpolatedPoint, maxzoom),
+                       predecessor: i-1
+               };
+    },
+
+    /**
+        Returns a float between 0 and 1 representing the location of the
+        closest point on polyline to the given latlng, as a fraction of total line length.
+        (opposite of L.GeometryUtil.interpolateOnLine())
+        @param {L.Map} map Leaflet map to be used for this method
+        @param {L.PolyLine} polyline Polyline on which the latlng will be search
+        @param {L.LatLng} latlng The position to search
+        @returns {Number} Float between 0 and 1
+    */
+    locateOnLine: function (map, polyline, latlng) {
+        var latlngs = polyline.getLatLngs();
+        if (latlng.equals(latlngs[0]))
+            return 0.0;
+        if (latlng.equals(latlngs[latlngs.length-1]))
+            return 1.0;
+
+        var point = L.GeometryUtil.closest(map, polyline, latlng, false),
+            lengths = L.GeometryUtil.accumulatedLengths(latlngs),
+            total_length = lengths[lengths.length-1],
+            portion = 0,
+            found = false;
+        for (var i=0, n = latlngs.length-1; i < n; i++) {
+            var l1 = latlngs[i],
+                l2 = latlngs[i+1];
+            portion = lengths[i];
+            if (L.GeometryUtil.belongsSegment(point, l1, l2)) {
+                portion += l1.distanceTo(point);
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            throw "Could not interpolate " + latlng.toString() + " within " + polyline.toString();
+        }
+        return portion / total_length;
+    },
+
+    /**
+        Returns a clone with reversed coordinates.
+        @param {L.PolyLine} polyline polyline to reverse
+        @returns {L.PolyLine} polyline reversed
+    */
+    reverse: function (polyline) {
+        return L.polyline(polyline.getLatLngs().slice(0).reverse());
+    },
+
+    /**
+        Returns a sub-part of the polyline, from start to end.
+        If start is superior to end, returns extraction from inverted line.
+        @param {L.Map} map Leaflet map to be used for this method
+        @param {L.PolyLine} polyline Polyline on which will be extracted the sub-part
+        @param {Number} start ratio, expressed as a decimal between 0 and 1, inclusive
+        @param {Number} end ratio, expressed as a decimal between 0 and 1, inclusive
+        @returns {Array<L.LatLng>} new polyline
+     */
+    extract: function (map, polyline, start, end) {
+        if (start > end) {
+            return L.GeometryUtil.extract(map, L.GeometryUtil.reverse(polyline), 1.0-start, 1.0-end);
+        }
+
+        // Bound start and end to [0-1]
+        start = Math.max(Math.min(start, 1), 0);
+        end = Math.max(Math.min(end, 1), 0);
+
+        var latlngs = polyline.getLatLngs(),
+            startpoint = L.GeometryUtil.interpolateOnLine(map, polyline, start),
+            endpoint = L.GeometryUtil.interpolateOnLine(map, polyline, end);
+        // Return single point if start == end
+        if (start == end) {
+            var point = L.GeometryUtil.interpolateOnLine(map, polyline, end);
+            return [point.latLng];
+        }
+        // Array.slice() works indexes at 0
+        if (startpoint.predecessor == -1)
+            startpoint.predecessor = 0;
+        if (endpoint.predecessor == -1)
+            endpoint.predecessor = 0;
+        var result = latlngs.slice(startpoint.predecessor+1, endpoint.predecessor+1);
+        result.unshift(startpoint.latLng);
+        result.push(endpoint.latLng);
+        return result;
+    },
+
+    /**
+        Returns true if first polyline ends where other second starts.
+        @param {L.PolyLine} polyline First polyline
+        @param {L.PolyLine} other Second polyline
+        @returns {bool}
+    */
+    isBefore: function (polyline, other) {
+        if (!other) return false;
+        var lla = polyline.getLatLngs(),
+            llb = other.getLatLngs();
+        return (lla[lla.length-1]).equals(llb[0]);
+    },
+
+    /**
+        Returns true if first polyline starts where second ends.
+        @param {L.PolyLine} polyline First polyline
+        @param {L.PolyLine} other Second polyline
+        @returns {bool}
+    */
+    isAfter: function (polyline, other) {
+        if (!other) return false;
+        var lla = polyline.getLatLngs(),
+            llb = other.getLatLngs();
+        return (lla[0]).equals(llb[llb.length-1]);
+    },
+
+    /**
+        Returns true if first polyline starts where second ends or start.
+        @param {L.PolyLine} polyline First polyline
+        @param {L.PolyLine} other Second polyline
+        @returns {bool}
+    */
+    startsAtExtremity: function (polyline, other) {
+        if (!other) return false;
+        var lla = polyline.getLatLngs(),
+            llb = other.getLatLngs(),
+            start = lla[0];
+        return start.equals(llb[0]) || start.equals(llb[llb.length-1]);
+    },
+
+    /**
+        Returns horizontal angle in degres between two points.
+        @param {L.Point} a Coordinates of point A
+        @param {L.Point} b Coordinates of point B
+        @returns {Number} horizontal angle
+     */
+    computeAngle: function(a, b) {
+        return (Math.atan2(b.y - a.y, b.x - a.x) * 180 / Math.PI);
+    },
+
+    /**
+       Returns slope (Ax+B) between two points.
+        @param {L.Point} a Coordinates of point A
+        @param {L.Point} b Coordinates of point B
+        @returns {Object} with ``a`` and ``b`` properties.
+     */
+    computeSlope: function(a, b) {
+        var s = (b.y - a.y) / (b.x - a.x),
+            o = a.y - (s * a.x);
+        return {'a': s, 'b': o};
+    },
+
+    /**
+       Returns LatLng of rotated point around specified LatLng center.
+        @param {L.LatLng} latlngPoint: point to rotate
+        @param {double} angleDeg: angle to rotate in degrees
+        @param {L.LatLng} latlngCenter: center of rotation
+        @returns {L.LatLng} rotated point
+     */
+    rotatePoint: function(map, latlngPoint, angleDeg, latlngCenter) {
+        var maxzoom = map.getMaxZoom();
+        if (maxzoom === Infinity)
+            maxzoom = map.getZoom();
+        var angleRad = angleDeg*Math.PI/180,
+            pPoint = map.project(latlngPoint, maxzoom),
+            pCenter = map.project(latlngCenter, maxzoom),
+            x2 = Math.cos(angleRad)*(pPoint.x-pCenter.x) - Math.sin(angleRad)*(pPoint.y-pCenter.y) + pCenter.x,
+            y2 = Math.sin(angleRad)*(pPoint.x-pCenter.x) + Math.cos(angleRad)*(pPoint.y-pCenter.y) + pCenter.y;
+        return map.unproject(new L.Point(x2,y2), maxzoom);
+    },
+
+    /**
+       Returns the bearing in degrees clockwise from north (0 degrees)
+       from the first L.LatLng to the second, at the first LatLng
+       @param {L.LatLng} latlng1: origin point of the bearing
+       @param {L.LatLng} latlng2: destination point of the bearing
+       @returns {float} degrees clockwise from north.
+    */
+    bearing: function(latlng1, latlng2) {
+        var rad = Math.PI / 180,
+            lat1 = latlng1.lat * rad,
+            lat2 = latlng2.lat * rad,
+            lon1 = latlng1.lng * rad,
+            lon2 = latlng2.lng * rad,
+            y = Math.sin(lon2 - lon1) * Math.cos(lat2),
+            x = Math.cos(lat1) * Math.sin(lat2) -
+                Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1);
+
+        var bearing = ((Math.atan2(y, x) * 180 / Math.PI) + 360) % 360;
+        return bearing >= 180 ? bearing-360 : bearing;
+    },
+
+    /**
+       Returns the point that is a distance and heading away from
+       the given origin point.
+       @param {L.LatLng} latlng: origin point
+       @param {float} heading: heading in degrees, clockwise from 0 degrees north.
+       @param {float} distance: distance in meters
+       @returns {L.latLng} the destination point.
+       Many thanks to Chris Veness at http://www.movable-type.co.uk/scripts/latlong.html
+       for a great reference and examples.
+    */
+    destination: function(latlng, heading, distance) {
+        heading = (heading + 360) % 360;
+        var rad = Math.PI / 180,
+            radInv = 180 / Math.PI,
+            R = 6378137, // approximation of Earth's radius
+            lon1 = latlng.lng * rad,
+            lat1 = latlng.lat * rad,
+            rheading = heading * rad,
+            sinLat1 = Math.sin(lat1),
+            cosLat1 = Math.cos(lat1),
+            cosDistR = Math.cos(distance / R),
+            sinDistR = Math.sin(distance / R),
+            lat2 = Math.asin(sinLat1 * cosDistR + cosLat1 *
+                sinDistR * Math.cos(rheading)),
+            lon2 = lon1 + Math.atan2(Math.sin(rheading) * sinDistR *
+                cosLat1, cosDistR - sinLat1 * Math.sin(lat2));
+        lon2 = lon2 * radInv;
+        lon2 = lon2 > 180 ? lon2 - 360 : lon2 < -180 ? lon2 + 360 : lon2;
+        return L.latLng([lat2 * radInv, lon2]);
+    },
+
+    /**
+       Returns the the angle of the given segment and the Equator in degrees,
+       clockwise from 0 degrees north.
+       @param {L.Map} map: Leaflet map to be used for this method
+       @param {L.LatLng} latlngA: geographical point A of the segment
+       @param {L.LatLng} latlngB: geographical point B of the segment
+       @returns {Float} the angle in degrees.
+    */
+    angle: function(map, latlngA, latlngB) {
+      var pointA = map.latLngToContainerPoint(latlngA),
+          pointB = map.latLngToContainerPoint(latlngB),
+          angleDeg = Math.atan2(pointB.y - pointA.y, pointB.x - pointA.x) * 180 / Math.PI + 90;
+      angleDeg += angleDeg < 0 ? 360 : 0;
+      return angleDeg;
+    },
+
+    /**
+       Returns a point snaps on the segment and heading away from the given origin point a distance.
+       @param {L.Map} map: Leaflet map to be used for this method
+       @param {L.LatLng} latlngA: geographical point A of the segment
+       @param {L.LatLng} latlngB: geographical point B of the segment
+       @param {float} distance: distance in meters
+       @returns {L.latLng} the destination point.
+    */
+    destinationOnSegment: function(map, latlngA, latlngB, distance) {
+      var angleDeg = L.GeometryUtil.angle(map, latlngA, latlngB),
+          latlng = L.GeometryUtil.destination(latlngA, angleDeg, distance);
+      return L.GeometryUtil.closestOnSegment(map, latlng, latlngA, latlngB);
+    },
+});
+
+return L.GeometryUtil;
+
+}));
index c56982e..21a0811 100644 (file)
 <script src="<?php echo $plugin_url; ?>/LeafletMarkerCluster/dist/leaflet.markercluster-src.js"></script>
 <link rel="stylesheet" href="<?php echo $plugin_url; ?>/Leaflet.loading/src/Control.Loading.css" />
 <script src="<?php echo $plugin_url; ?>/Leaflet.loading/src/Control.Loading.js"></script>
+<script src="<?php echo get_template_directory_uri(); ?>/js/leaflet.geometryutil.js"></script>
 <script>
     var leafletMap;
     function initMap() {
 
         // var distancePath = new google.maps.Polyline();
-        // function drawLine(point1, point2) {
-            
-        //     var coordinates = [point1,point2];
-
-        //     distancePath.setMap(null);
-
-        //     distancePath = new google.maps.Polyline({
-        //         path: coordinates,
-        //         geodesic: true,
-        //         strokeColor: '#91311D',
-        //         strokeOpacity: 1.0,
-        //         strokeWeight: 2
-        //     });
-
-        //     distancePath.setMap(map);
-        // }
+        
         // Styles a map in night mode.
         var url = '<?php echo $url ?>';
         leafletMap = L.map('brewery-map', {
         var leafletTileServer = 'https://maps.gaslightmedia.com/08172018-4c95c314f0934e680190f27ef99c6dcc/{z}/{x}/{y}.png';
         var leafletMinZoom = 3;
         var leafletMaxZoom = 19;
-        var clusterRadiusMax = 40;
-        var geocoder;
+
 
         // Loading features
-        var loadingControl = L.Control.loading({
-            separate: true,
-            delayIndicator: 500
-        });
-        leafletMap.addControl(loadingControl);
+        // var loadingControl = L.Control.loading({
+        //     separate: true,
+        //     delayIndicator: 500
+        // });
+        // leafletMap.addControl(loadingControl);
         
         // Init Map
         L.tileLayer(leafletTileServer, {
                 icon: 'final.png'
             },
         ];
+        var previous, distance, path, compare = [];
         brewers.forEach(function(brewer){
             let info = `<div class="marker-title">${brewer.brewery}</div><div>${brewer.address}</div><div>${brewer.contact}</div><div><a href="${brewer.website}">${brewer.website}</a></div>`;
 
             var breweryIcon = L.icon({
                 iconUrl: url+brewer.icon,
-                iconSize: [70, 95],
+                iconSize: [65, 95],
                 iconAnchor: [22, 94],
                 popupAnchor: [-3, -76],
                 shadowSize: [68, 95],
             )
             .addTo(leafletMap)
             .bindPopup(info)
-            .on('click', markerOnClick)
+            .on('click', function(e){
+                let lat = e.latlng.lat;
+                let lng = e.latlng.lng;
+                compare.push(L.latLng(e.latlng.lat, e.latlng.lng) );
+                if(compare.length >= 2){
+                    // console.log(L.GeometryUtil. distance(leafletMap,last(compare), compare[compare.length - 2] ))
+                    distance = `<div class="distance-marker"><span class="marker-label">Distance:</span> ${convertMetersToFeet(L.GeometryUtil.length([last(compare), compare[compare.length - 2]] ) ).toFixed(2)} Miles</div>`;
+                    this._popup.setContent(info + distance)
+                 
+                    drawLine(last(compare),compare[compare.length - 2]);
+                    
+                } else {
+                    distance = '';
+                }
+                })
         });
         function getMiles(i) {
-            return i*0.000621371192;
+            return i * 0.00018939;
         };
         function convertMetersToFeet(meters) {
             if (meters < (0)) {
                 return 'input cannot be less than zero'; 
             } else {
-                return getMiles((meters/0.3048));
+                if(getMiles((meters / 0.3048)) <= 0){
+                    return `< 1 mile`;
+                }else{
+                    return getMiles((meters / 0.3048));
+                }
+                
             }
         };
         last =  function(array, n) {
                 return array[array.length - 1];
             return array.slice(Math.max(array.length - n, 0));  
         };
-        function markerOnClick(e){
-            // console.log(e)
-            let lat = e.latlng.lat;
-            let lng = e.latlng.lng;
-            console.log(lat, lng);
-        };
+        let prev;
+        function drawLine(point1, point2) {
+            let distancePath;
+            let p1 = [point1.lat, point1.lng];
+            let p2 = [point2.lat, point2.lng];
+            let coordinates = [p1,p2];
+            if(prev){
+                leafletMap.removeLayer(prev);
+            }
+            
+            distancePath = L.polyline(coordinates, {
+                color: '#91311D',
+            });
+            distancePath.addTo(leafletMap);
+            prev = distancePath;
+        }
     }
     initMap();
 </script>