A question was posted yesterday on the Leaflet forum about doing geofencing with LeafletJS, so I posted this demo in response: http://exploringspatial.com/#demo/9.
My demo scenario is that there is a user who likes to share her runs with friends on social media but doesn’t want everybody to see exactly where she lives, so she creates a privacy geofence around her house. The starting and ending sections of her run polyline are hidden once they enter the geofenced area. If the middle section of the run passes through the geofenced area it remains visible.
Here is a shout out to Roadrunners of Kansas City. The geofence boundary in this demo is around Sport+Spine, home-base to many of the Roadrunner runs. Thanks, Coach Amy!
For my example, I turned once again to the Leaflet-pip library, as I did for Demo7 and Demo 8. I use it a couple of different ways in this demo. First, I use it to locate runs for this demo whose start point falls within the demo’s privacy geofenced area. Second, when the user displays a run (by clicking the numbered buttons on the bottom of the page) I use Leaflet-pip again to test which points at the beginning and end of the run fall within the privacy geofence.
In the real world, you would always do the privacy filtering server-side, using something like GeoTools or spatial database queries, so that only the public sections of the polyline are exposed in the GeoJSON. I did this demo on the browser-side because my site is an Amazon S3-hosted static website, and also because the forum question was about doing geofencing with Leaflet.
The code for this demo can all be found in RightSideView.js. The render method does the following things:
- Creates the L.featureGroup, geoFence, and adds a L.polygon defining the geofence boundaries.
- Displays the geofence on the map.
- Loads the running log GeoJSON file from Demo 5.
- Uses leafletPip.pointInLayer to find runs that start in the geofenced area, and then adds a paging div to the bottom of the page to open each matching run.
- Loads the first run.
The interesting part of the code is in the onActivityFetched function. The “hidden” parts of the polyline are shown in gray on the map, so I needed to define three polylines: the hidden start, the visible middle, and the hidden end.
I loop through the polyline coordinates and add the points to the “fencedStart” array until I hit a point falling outside the geofenced area. After that, all points are added to a “middle” array.
Next, I loop backward over the points collected in the middle array looking for the points at the end of the run to be hidden.
Finally, now that I have the points to hide at the start and the end of the run, I just need to find the points in between to draw on the map in red.
Go to the demo and click on a few of the runs to see how it works. Doing this demo I learned that “Leaflet.PIP” (point-in-polygon), only works on polygons (go figure). I started out trying to use a L.circle for the geofenced area. That didn’t work.
The other shortcoming of this demo is that sometimes the first point outside the privacy geofence is some distance away, causing the visible line to stop short. That could easily be fixed with point projection along the bearing of the line between the two points that span the geofence boundary.
Happy Geofencing.