- Heroku: http://freedraw.herokuapp.com/
- Bower:
bower install leaflet.freedraw
;
Use Leaflet.draw for drawing pre-defined polygons and linear shapes – Leaflet.FreeDraw
's selling point is that it allows you to freely draw a polygon like Zoopla. Hulls are also supported to normalise polygons when users draw an insane polygon – currently Leaflet.FreeDraw
supports Brian Barnett's Graham Scan module and my adaptation of the concave hull algorithm.
L.FreeDraw
has been tested in IE9+
Note: For drawing polylines instead, try L.Pather
.
L.FreeDraw
follows the same convention as other modules, and therefore you should invoke the addLayer
on your map instance – passing in an instance of L.FreeDraw
.
// Create Leaflet.js instance and then add FreeDraw on top.
var map = L.map('map').setView([51.505, -0.09], 14);
map.addLayer(new L.FreeDraw());
Upon instantiation of L.FreeDraw
you can immediately define the mode – with the default being L.FreeDraw.MODES.VIEW
– please see modes for more information.
// Allow the user to only create and edit polygons.
map.addLayer(new L.FreeDraw({
mode: L.FreeDraw.MODES.CREATE | L.FreeDraw.MODES.EDIT
}));
Worth noting is that Leaflet.js often ships with new
able equivalents – such as L.map
for new L.Map
— see why here — L.FreeDraw
follows the same convention and provides a convenient L.freeDraw
method for instantiating L.FreeDraw
for you whilst passing through the options.
Furthermore by invoking the cancelAction
method you can cancel the current action – such as drawing a polygon – this method is especially useful for allowing the user to cancel their action by pressing the escape key.
Once the user has created, deleted, or edited a polygon, you'll likely wish to load in markers based on the polygons visible – with L.FreeDraw
the event markers
is emitted with an array of L.LatLng
objects in the first argument as eventData.latLngs
:
freeDraw.on('markers', function getMarkers(eventData) {
var latLngs = eventData.latLngs;
// ...
});
Once you have your markers it's entirely up to you to add them to your Leaflet.js map using the marker methods.
FreeDraw has quite a few options – all of which can be seen by taking a look at the L.FreeDraw.Options
object. However, there are certain options that you are likely to use more than others.
// Prevent the rendering of the polygon via a convex/concave hull.
freeDraw.options.setHullAlgorithm(false);
// Utilise Brian Barnett's convex hull.
freeDraw.options.setHullAlgorithm('brian3kb/graham_scan_js');
// ...Or my adaptation of the concave hull.
freeDraw.options.setHullAlgorithm('Wildhoney/ConcaveHull');
For the hull algorithm implementations, take a look at the following paper on convex hulls and concave hulls.
All of the polygons drawn with L.FreeDraw
can be modified using the options and standard CSS.
Once the user has drawn their free-hand drawing, it is converted into a polygon by Leaflet.js – you can define how smooth the rendered polygon is by using the setSmoothFactor
method – by default the smoothFactor
is 5.
When a user is modifying a polygon the markers
event is emitted each and every time – which may be overkill, especially if your requests are somewhat time consuming. In this case L.FreeDraw
allows you to defer the fetching of markers for when the edit mode has been exited with freeDraw.options.setBoundariesAfterEdit(true)
.
By invoking the freeDraw.allowPolygonMerging(true)
method, L.FreeDraw
will attempt to join up any polygons that intersect.
After drawing a polygon the L.FreeDraw.MODES.CREATE
mode will automatically be exited – but this can be suppressed by specifying freeDraw.options.exitModeAfterCreate(false)
in which case the create mode will be persisted until the user explicitly exits it.
FreeDraw by default uses the L.FreeDraw.MODES.VIEW
mode which prevents the user from creating, editing, or deleting any polygons. When instantiating L.FreeDraw
you may override the default mode – in the following case a user may only delete polygons:
var freeDraw = new L.FreeDraw({
mode: L.FreeDraw.MODES.DELETE
});
In specifying the mode you are using bitwise operators with the mapping being as follows:
L.FreeDraw.MODES = {
VIEW: 1,
CREATE: 2,
EDIT: 4,
DELETE: 8,
APPEND: 16,
EDIT_APPEND: 4 | 16,
ALL: 1 | 2 | 4 | 8 | 16
}
Therefore you're able to combine the bitwise operators to specify multiple modes. For example, if you would like to allow the user to create and delete, then you would specify the options as L.FreeDraw.MODES.CREATE | L.FreeDraw.MODES.DELETE
. By allowing a user to perform every action you would have to concatenate all of the modes via the pipe (|
) character – therefore L.FreeDraw
provides the convenient L.FreeDraw.MODES.ALL
property which does that for you.
Using the L.FreeDraw.MODES.ALL
property you could easily enable all the modes except edit with the following: L.FreeDraw.MODES.ALL ^ L.FreeDraw.MODES.EDIT
.
All modes allow the user to zoom and drag except when you have the L.FreeDraw.MODES.CREATE
enabled – even when used in conjunction with other modes.
It's quite likely that you'll want to change the mode as the user interacts with your application – for this you have the setMode
method which accepts an aforementioned bitwise operator for determining what actions the user is able to perform.
// Change the mode to allow the user to only edit and delete polygons.
var freeDraw = new L.FreeDraw();
freeDraw.setMode(L.FreeDraw.MODES.EDIT | L.FreeDraw.MODES.DELETE);
L.FreeDraw
also ships with the freeDraw.unsetMode
for unsetting a mode based on the current mode.
You may also listen to updates of the mode using the freeDraw.on('mode')
event.
Using the L.FreeDraw.MODES.APPEND
mode you can allow users to create new edges on the polygon. If both the L.FreeDraw.MODES.APPEND
and L.FreeDraw.MODES.DELETE
modes are active at the same time then some logic is applied to decide whether the user wishes to delete or create a new edge. However if L.FreeDraw.MODES.APPEND
is active and L.FreeDraw.MODES.DELETE
is not then any click on the polygon will create a new edge – and vice-versa for the inverse.
If you would like to control the edge size in which a new polygon will be created when both aforementioned modes are active, you can do so using the setMaximumDistanceForElbow
method where the default is currently set to 10.
Even when the L.FreeDraw.MODES.APPEND
mode is active exclusively, you still may not wish for any click to add a new elbow, and therefore by enabling the addElbowOnlyWithinDistance
mode a click on the polygon will stay pay attention to the setMaximumDistanceForElbow
value.
Depending on the mode you can apply different CSS styles – for example when the user is not in edit mode you probably wish to hide the edges – by default all edges would be hidden, and only enabled when the mode-edit
class has been applied to the map
node:
section.map.mode-edit div.polygon-elbow {
opacity: 1;
pointer-events: all;
}
Each mode maps to a different class which is conditionally applied to the map
based on whether that mode is active:
mode-view
maps toL.FreeDraw.MODES.VIEW
;mode-create
maps toL.FreeDraw.MODES.CREATE
;mode-edit
maps toL.FreeDraw.MODES.EDIT
;mode-delete
maps toL.FreeDraw.MODES.DELETE
;mode-append
maps toL.FreeDraw.MODES.APPEND
;
Another example would be changing the cursor
type when the user is in polygon creation mode:
section.map.mode-create {
cursor: crosshair;
}
You may change the class name of the polygon edges with the setIconClassName
method, and the SVG class name with setSVGClassName
.
When you're drawing a polygon on the map, the path that is being drawn is invisible – this is caused by a handful of missing styles that you need to apply to the svg.tracer
node:
svg.tracer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
It's worth noting that the above style properties may well be changed to suit your circumstances, but this is a good starting point.