diff --git a/assets/maps/contao-leaflet.js b/assets/maps/contao-leaflet.js
index 7dea8b5..652a519 100644
--- a/assets/maps/contao-leaflet.js
+++ b/assets/maps/contao-leaflet.js
@@ -1 +1 @@
-L.Contao=L.Class.extend({includes:L.Mixin.Events,attribution:' | netzmacht creative',maps:{},icons:{},initialize:function(){L.Icon.Default.imagePath="assets/leaflet/libs/leaflet/images",this.setGeoJsonListeners(L.GeoJSON)},addMap:function(t,e){return e.map.attributionControl.setPrefix(e.map.attributionControl.options.prefix+this.attribution),this.maps[t]=e,this.fire("map:added",{id:t,map:e}),this},getMap:function(t){return"undefined"==typeof this.maps[t]?null:this.maps[t]},addIcon:function(t,e){return this.icons[t]=e,this.fire("icon:added",{id:t,icon:e}),this},loadIcons:function(t){for(var e=0;ei&&(n[n.length]=[e,t].join("=")),document.location.pathname+n.join("&")}}),L.contao=new L.Contao,L.Map.include({_dynamicBounds:null,calculateFeatureBounds:function(t,e){if(t){if(!this.options.adjustBounds&&!e)return;this._scanForBounds(t)}else this.eachLayer(this._scanForBounds,this);this._dynamicBounds&&this.fitBounds(this._dynamicBounds)},_scanForBounds:function(t){var e;t.feature&&t.feature.properties&&t.feature.properties.affectBounds?t.getBounds?(e=t.getBounds(),e.isValid()&&(this._dynamicBounds?this._dynamicBounds.extend(e):this._dynamicBounds=L.latLngBounds(e.getSouthWest(),e.getNorthEast()))):t.getLatLng&&(e=t.getLatLng(),this._dynamicBounds?this._dynamicBounds.extend(e):this._dynamicBounds=L.latLngBounds(e,e)):t.eachLayer&&t.eachLayer(this._scanForBounds,this)}});
\ No newline at end of file
+L.Contao=L.Class.extend({includes:L.Mixin.Events,attribution:' | netzmacht creative',maps:{},icons:{},initialize:function(){L.Icon.Default.imagePath="assets/leaflet/libs/leaflet/images",this.setGeoJsonListeners(L.GeoJSON)},addMap:function(t,e){return e.map.attributionControl.setPrefix(e.map.attributionControl.options.prefix+this.attribution),this.maps[t]=e,this.fire("map:added",{id:t,map:e}),this},getMap:function(t){return"undefined"==typeof this.maps[t]?null:this.maps[t]},addIcon:function(t,e){return this.icons[t]=e,this.fire("icon:added",{id:t,icon:e}),this},loadIcons:function(t){for(var e=0;ei&&(n[n.length]=[e,t].join("=")),document.location.pathname+n.join("&")}}),L.contao=new L.Contao,L.Map.include({_dynamicBounds:null,calculateFeatureBounds:function(t,e){if(t){if(!this.options.adjustBounds&&!e)return;this._scanForBounds(t)}else this.eachLayer(this._scanForBounds,this);this._dynamicBounds&&this.fitBounds(this._dynamicBounds)},_scanForBounds:function(t){var e;t.feature&&t.feature.properties&&t.feature.properties.affectBounds?t.getBounds?(e=t.getBounds(),e.isValid()&&(this._dynamicBounds?this._dynamicBounds.extend(e):this._dynamicBounds=L.latLngBounds(e.getSouthWest(),e.getNorthEast()))):t.getLatLng&&(e=t.getLatLng(),this._dynamicBounds?this._dynamicBounds.extend(e):this._dynamicBounds=L.latLngBounds(e,e)):t.eachLayer&&t.eachLayer(this._scanForBounds,this)}});
\ No newline at end of file
diff --git a/assets/maps/src/Contao.js b/assets/maps/src/Contao.js
index c7c9253..3fc588f 100644
--- a/assets/maps/src/Contao.js
+++ b/assets/maps/src/Contao.js
@@ -119,8 +119,8 @@ L.Contao = L.Class.extend({
* @param map Pass a map object so that the data loading events are passed to the map.
*/
load: function (hash, type, options, customLayer, map) {
- var url = this.createRequestUrl(hash);
- var layer = omnivore[type](url, options, customLayer);
+ var url = this.createRequestUrl(hash),
+ layer = omnivore[type](url, options, customLayer);
if (map) {
// Required because Control.Loading tries to get _leafet_id which is created here.
diff --git a/module/assets/img/cluster.png b/module/assets/img/cluster.png
new file mode 100644
index 0000000..832a1da
Binary files /dev/null and b/module/assets/img/cluster.png differ
diff --git a/module/assets/img/cluster_1.png b/module/assets/img/cluster_1.png
new file mode 100644
index 0000000..9bcea90
Binary files /dev/null and b/module/assets/img/cluster_1.png differ
diff --git a/module/config/config.php b/module/config/config.php
index 71ff8e6..a4380af 100644
--- a/module/config/config.php
+++ b/module/config/config.php
@@ -92,6 +92,7 @@ $GLOBALS['LEAFLET_MAPPERS'][] = 'Netzmacht\Contao\Leaflet\Mapper\Layer\MarkersLa
$GLOBALS['LEAFLET_MAPPERS'][] = 'Netzmacht\Contao\Leaflet\Mapper\Layer\GroupLayerMapper';
$GLOBALS['LEAFLET_MAPPERS'][] = 'Netzmacht\Contao\Leaflet\Mapper\Layer\VectorsLayerMapper';
$GLOBALS['LEAFLET_MAPPERS'][] = 'Netzmacht\Contao\Leaflet\Mapper\Layer\ReferenceLayerMapper';
+$GLOBALS['LEAFLET_MAPPERS'][] = 'Netzmacht\Contao\Leaflet\Mapper\Layer\MarkerClusterLayerMapper';
// Control mappers.
$GLOBALS['LEAFLET_MAPPERS'][] = 'Netzmacht\Contao\Leaflet\Mapper\Control\ZoomControlMapper';
@@ -209,6 +210,11 @@ $GLOBALS['LEAFLET_LAYERS'] = array
return $label;
}
+ ),
+ 'markercluster' => array
+ (
+ 'children' => true,
+ 'icon' => 'system/modules/leaflet/assets/img/cluster.png',
)
);
diff --git a/module/dca/tl_leaflet_layer.php b/module/dca/tl_leaflet_layer.php
index f1cd297..f2f90a5 100644
--- a/module/dca/tl_leaflet_layer.php
+++ b/module/dca/tl_leaflet_layer.php
@@ -144,7 +144,6 @@ $GLOBALS['TL_DCA']['tl_leaflet_layer'] = array
'active' => array('active'),
),
'markers extends default' => array(
- '+title' => array('markerCluster'),
'+expert' => array('pointToLayer'),
'+active' => array('deferred')
),
@@ -157,7 +156,24 @@ $GLOBALS['TL_DCA']['tl_leaflet_layer'] = array
),
'reference extends default' => array(
'+title' => array('reference', 'standalone')
- )
+ ),
+ 'markercluster extends default' => array(
+ 'config' => array(
+ 'showCoverageOnHover',
+ 'zoomToBoundsOnClick',
+ 'removeOutsideVisibleBounds',
+ 'animateAddingMarkers',
+ 'spiderfyOnMaxZoom',
+ 'disableClusteringAtZoom',
+ 'maxClusterRadius',
+ 'singleMarkerMode',
+ ),
+ '+expert' => array(
+ 'polygonOptions',
+ 'iconCreateFunction',
+ 'disableDefaultStyle'
+ ),
+ ),
),
'metasubselectpalettes' => array(
@@ -169,6 +185,11 @@ $GLOBALS['TL_DCA']['tl_leaflet_layer'] = array
'HERE' => array('tile_provider_key', 'tile_provider_code'),
),
),
+
+ 'metasubpalettes' => array(
+ 'spiderfyOnMaxZoom' => array('spiderfyDistanceMultiplier')
+ ),
+
'fields' => array
(
'id' => array
@@ -278,22 +299,6 @@ $GLOBALS['TL_DCA']['tl_leaflet_layer'] = array
'eval' => array('mandatory' => true, 'maxlength' => 255, 'tl_class' => 'w50'),
'sql' => "varchar(255) NOT NULL default ''"
),
- 'markerCluster' => array
- (
- 'label' => &$GLOBALS['TL_LANG']['tl_leaflet_layer']['markerCluster'],
- 'exclude' => true,
- 'inputType' => 'select',
- 'options_callback' => array('Netzmacht\Contao\Leaflet\Dca\Layer', 'getMarkerClusterLayers'),
- 'reference' => &$GLOBALS['TL_LANG']['leaflet_layer'],
- 'eval' => array(
- 'mandatory' => false,
- 'maxlength' => 255,
- 'tl_class' => 'w50',
- 'chosen' => true,
- 'includeBlankOption' => true
- ),
- 'sql' => "varchar(255) NOT NULL default ''"
- ),
'deferred' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_leaflet_layer']['deferred'],
@@ -370,5 +375,130 @@ $GLOBALS['TL_DCA']['tl_leaflet_layer'] = array
),
'sql' => "mediumtext NULL"
),
+ 'showCoverageOnHover' => array
+ (
+ 'label' => &$GLOBALS['TL_LANG']['tl_leaflet_layer']['showCoverageOnHover'],
+ 'exclude' => true,
+ 'inputType' => 'checkbox',
+ 'default' => true,
+ 'eval' => array('tl_class' => 'w50', 'submitOnChange' => false, 'isBoolean' => true),
+ 'sql' => "char(1) NOT NULL default '1'"
+ ),
+ 'zoomToBoundsOnClick' => array
+ (
+ 'label' => &$GLOBALS['TL_LANG']['tl_leaflet_layer']['zoomToBoundsOnClick'],
+ 'exclude' => true,
+ 'inputType' => 'checkbox',
+ 'default' => true,
+ 'eval' => array('tl_class' => 'w50', 'submitOnChange' => false, 'isBoolean' => true),
+ 'sql' => "char(1) NOT NULL default '1'"
+ ),
+ 'spiderfyOnMaxZoom' => array
+ (
+ 'label' => &$GLOBALS['TL_LANG']['tl_leaflet_layer']['spiderfyOnMaxZoom'],
+ 'exclude' => true,
+ 'inputType' => 'checkbox',
+ 'default' => true,
+ 'eval' => array('tl_class' => 'w50 m12', 'submitOnChange' => true, 'isBoolean' => true),
+ 'sql' => "char(1) NOT NULL default '1'"
+ ),
+ 'removeOutsideVisibleBounds' => array
+ (
+ 'label' => &$GLOBALS['TL_LANG']['tl_leaflet_layer']['removeOutsideVisibleBounds'],
+ 'exclude' => true,
+ 'inputType' => 'checkbox',
+ 'default' => true,
+ 'eval' => array('tl_class' => 'w50', 'submitOnChange' => false, 'isBoolean' => true),
+ 'sql' => "char(1) NOT NULL default '1'"
+ ),
+ 'animateAddingMarkers' => array
+ (
+ 'label' => &$GLOBALS['TL_LANG']['tl_leaflet_layer']['animateAddingMarkers'],
+ 'exclude' => true,
+ 'inputType' => 'checkbox',
+ 'default' => false,
+ 'eval' => array('tl_class' => 'w50', 'submitOnChange' => false, 'isBoolean' => true),
+ 'sql' => "char(1) NOT NULL default ''"
+ ),
+ 'disableClusteringAtZoom' => array
+ (
+ 'label' => &$GLOBALS['TL_LANG']['tl_leaflet_layer']['disableClusteringAtZoom'],
+ 'exclude' => true,
+ 'inputType' => 'select',
+ 'options_callback' => array('Netzmacht\Contao\Leaflet\Dca\Leaflet', 'getZoomLevels'),
+ 'default' => '',
+ 'eval' => array(
+ 'maxlength' => 4,
+ 'rgxp' => 'digit',
+ 'tl_class' => 'w50',
+ 'includeBlankOption' => true,
+ 'nullIfEmpty' => true
+ ),
+ 'sql' => "int(4) NULL"
+ ),
+ 'maxClusterRadius' => array
+ (
+ 'label' => &$GLOBALS['TL_LANG']['tl_leaflet_layer']['maxClusterRadius'],
+ 'exclude' => true,
+ 'inputType' => 'text',
+ 'default' => null,
+ 'eval' => array('maxlength' => 5, 'rgxp' => 'digit', 'tl_class' => 'w50', 'nullIfEmpty' => true),
+ 'sql' => "int(5) NULL"
+ ),
+ 'singleMarkerMode' => array
+ (
+ 'label' => &$GLOBALS['TL_LANG']['tl_leaflet_layer']['singleMarkerMode'],
+ 'exclude' => true,
+ 'inputType' => 'checkbox',
+ 'default' => false,
+ 'eval' => array('tl_class' => 'w50 m12', 'submitOnChange' => false, 'isBoolean' => true),
+ 'sql' => "char(1) NOT NULL default ''"
+ ),
+ 'polygonOptions' => array
+ (
+ 'label' => &$GLOBALS['TL_LANG']['tl_leaflet_layer']['polygonOptions'],
+ 'exclude' => true,
+ 'inputType' => 'textarea',
+ 'eval' => array(
+ 'preserveTags' => true,
+ 'decodeEntities' => true,
+ 'allowHtml' => true,
+ 'rte' => 'ace|json',
+ 'tl_class' => 'clr'
+ ),
+ 'sql' => "mediumtext NULL"
+ ),
+ 'spiderfyDistanceMultiplier' => array
+ (
+ 'label' => &$GLOBALS['TL_LANG']['tl_leaflet_layer']['spiderfyDistanceMultiplier'],
+ 'exclude' => true,
+ 'inputType' => 'text',
+ 'default' => null,
+ 'eval' => array('maxlength' => 5, 'rgxp' => 'digit', 'tl_class' => 'w50', 'nullIfEmpty' => true),
+ 'sql' => "int(5) NULL"
+ ),
+ 'iconCreateFunction' => array
+ (
+ 'label' => &$GLOBALS['TL_LANG']['tl_leaflet_layer']['iconCreateFunction'],
+ 'exclude' => true,
+ 'inputType' => 'textarea',
+ 'eval' => array(
+ 'preserveTags' => true,
+ 'decodeEntities' => true,
+ 'allowHtml' => true,
+ 'rte' => 'ace|javascript',
+ 'tl_class' => 'clr'
+ ),
+ 'sql' => "mediumtext NULL"
+ ),
+ 'disableDefaultStyle' => array
+ (
+ 'label' => &$GLOBALS['TL_LANG']['tl_leaflet_layer']['disableDefaultStyle'],
+ 'exclude' => true,
+ 'inputType' => 'checkbox',
+ 'default' => false,
+ 'eval' => array('tl_class' => 'w50', 'submitOnChange' => false, 'isBoolean' => true),
+ 'sql' => "char(1) NOT NULL default ''"
+ ),
)
);
diff --git a/module/languages/en/tl_leaflet_layer.php b/module/languages/en/tl_leaflet_layer.php
index 60b3a11..fe5cf52 100644
--- a/module/languages/en/tl_leaflet_layer.php
+++ b/module/languages/en/tl_leaflet_layer.php
@@ -26,32 +26,56 @@ $GLOBALS['TL_LANG']['tl_leaflet_layer']['show'][1] = 'Show layer ID %s details
$GLOBALS['TL_LANG']['tl_leaflet_layer']['cut'][0] = 'Move layer';
$GLOBALS['TL_LANG']['tl_leaflet_layer']['cut'][1] = 'Move layer ID %s';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['title'][0] = 'Title';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['title'][1] = 'Title of the layer.';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['alias'][0] = 'Alias';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['alias'][1] = 'Alias of the layer.';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['type'][0] = 'Type';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['type'][1] = 'Choose the layer type.';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['tile_provider'][0] = 'Tile provider';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['tile_provider'][1] = 'Choose the layer type.';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['tile_provider_variant'][0] = 'Tile variant';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['tile_provider_variant'][1] = 'Tile variant style.';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['active'][0] = 'Activate layer';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['active'][1] = 'Activate layer on the map.';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['reference'][0] = 'Reference';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['reference'][1] = 'Choose the reference layer. Otherwise the same javscript object is used.';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['standalone'][0] = 'Standalone';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['standalone'][1] = 'Integrate reference as a copy of the referenced layer.';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['markerCluster'][0] = 'Marker cluster';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['markerCluster'][1] = 'Choose a marker cluster layer so that markers get clustered.';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['deferred'][0] = 'Deferred loading';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['deferred'][1] = 'Load data of the layer deferred using ajax.';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['groupType'][0] = 'Group type';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['groupType'][1] = 'Choose a layer group type.';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['onEachFeature'][0] = 'onEachFeature expression';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['onEachFeature'][1] = 'Use a custom onEachFeature expression. Can be a anonymous function or method reference. If defined the extension does not handle popup adding for you.';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['pointToLayer'][0] = 'pointToLayer expression';
-$GLOBALS['TL_LANG']['tl_leaflet_layer']['pointToLayer'][1] = 'Use a custom pointToLayer expression. Can be a anonymous function or method reference. If defined the extension does not handle popup or icon adding for you.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['title'][0] = 'Title';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['title'][1] = 'Title of the layer.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['alias'][0] = 'Alias';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['alias'][1] = 'Alias of the layer.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['type'][0] = 'Type';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['type'][1] = 'Choose the layer type.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['tile_provider'][0] = 'Tile provider';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['tile_provider'][1] = 'Choose the layer type.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['tile_provider_variant'][0] = 'Tile variant';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['tile_provider_variant'][1] = 'Tile variant style.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['active'][0] = 'Activate layer';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['active'][1] = 'Activate layer on the map.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['reference'][0] = 'Reference';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['reference'][1] = 'Choose the reference layer. Otherwise the same javscript object is used.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['standalone'][0] = 'Standalone';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['standalone'][1] = 'Integrate reference as a copy of the referenced layer.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['markerCluster'][0] = 'Marker cluster';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['markerCluster'][1] = 'Choose a marker cluster layer so that markers get clustered.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['deferred'][0] = 'Deferred loading';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['deferred'][1] = 'Load data of the layer deferred using ajax.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['groupType'][0] = 'Group type';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['groupType'][1] = 'Choose a layer group type.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['onEachFeature'][0] = 'onEachFeature expression';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['onEachFeature'][1] = 'Use a custom onEachFeature expression. Can be a anonymous function or method reference. If defined the extension does not handle popup adding for you.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['pointToLayer'][0] = 'pointToLayer expression';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['pointToLayer'][1] = 'Use a custom pointToLayer expression. Can be a anonymous function or method reference. If defined the extension does not handle popup or icon adding for you.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['showCoverageOnHover'][0] = 'Show coverage on hover';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['showCoverageOnHover'][1] = 'When you mouse over a cluster it shows the bounds of its markers.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['zoomToBoundsOnClick'][0] = 'Zoom to bounds on click';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['zoomToBoundsOnClick'][1] = 'When you click a cluster we zoom to its bounds.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['spiderfyOnMaxZoom'][0] = 'Spiderfy on max zoom';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['spiderfyOnMaxZoom'][1] = 'When you click a cluster at the bottom zoom level we spiderfy it so you can see all of its markers.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['removeOutsideVisibleBounds'][0] = 'Remove when outside of visible bounds';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['removeOutsideVisibleBounds'][1] = 'Clusters and markers too far from the viewport are removed from the map for performance.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['animateAddingMarkers'][0] = 'Animate adding markers';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['animateAddingMarkers'][1] = 'If set to true then adding individual markers to the MarkerClusterGroup after it has been added to the map will add the marker and animate it in to the cluster.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['disableClusteringAtZoom'][0] = 'Disable clustering at zoom level';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['disableClusteringAtZoom'][1] = 'If set, at this zoom level and below markers will not be clustered. This defaults to disabled. ';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['maxClusterRadius'][0] = 'Max cluster radius';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['maxClusterRadius'][1] = 'The maximum radius that a cluster will cover from the central marker (in pixels).';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['polygonOptions'][0] = 'Polygon options';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['polygonOptions'][1] = 'Options to pass when creating the L.Polygon(points, options) to show the bounds of a cluster.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['singleMarkerMode'][0] = 'Show cluster instead of marker';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['singleMarkerMode'][1] = 'If set to true, overrides the icon for all added markers to make them appear as a 1 size cluster.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['spiderfyDistanceMultiplier'][0] = 'Spiderfy distance multiplier';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['spiderfyDistanceMultiplier'][1] = 'Increase from 1 to increase the distance away from the center that spiderfied markers are placed. Use if you are using big marker icons.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['iconCreateFunction'][0] = 'Create cluster icon function';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['iconCreateFunction'][1] = 'Function used to create the cluster icon.';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['disableDefaultStyle'][0] = 'Disable default style';
+$GLOBALS['TL_LANG']['tl_leaflet_layer']['disableDefaultStyle'][1] = 'Do not load default marker cluster stylesheets.';
$GLOBALS['TL_LANG']['tl_leaflet_layer']['groupTypes']['layer'][0] = 'Layer group';
$GLOBALS['TL_LANG']['tl_leaflet_layer']['groupTypes']['layer'][1] = 'Basic layer group.
See http://leafletjs.com/reference.html#layergroup';
diff --git a/src/Netzmacht/Contao/Leaflet/Mapper/Layer/MarkerClusterLayerMapper.php b/src/Netzmacht/Contao/Leaflet/Mapper/Layer/MarkerClusterLayerMapper.php
new file mode 100644
index 0000000..480a529
--- /dev/null
+++ b/src/Netzmacht/Contao/Leaflet/Mapper/Layer/MarkerClusterLayerMapper.php
@@ -0,0 +1,113 @@
+
+ * @copyright 2015 netzmacht creative David Molineus
+ * @license LGPL 3.0
+ * @filesource
+ *
+ */
+
+namespace Netzmacht\Contao\Leaflet\Mapper\Layer;
+
+use Netzmacht\Contao\Leaflet\Mapper\DefinitionMapper;
+use Netzmacht\Contao\Leaflet\Model\LayerModel;
+use Netzmacht\JavascriptBuilder\Type\AnonymousFunction;
+use Netzmacht\JavascriptBuilder\Type\Expression;
+use Netzmacht\LeafletPHP\Definition;
+use Netzmacht\LeafletPHP\Definition\HasEvents;
+use Netzmacht\LeafletPHP\Definition\Layer;
+use Netzmacht\LeafletPHP\Definition\Type\LatLngBounds;
+use Netzmacht\LeafletPHP\Plugins\MarkerCluster\MarkerClusterGroup;
+use Netzmacht\LeafletPHP\Plugins\Omnivore\OmnivoreLayer;
+
+/**
+ * Class MarkerClusterLayerMapper maps the layer database model to the marker cluster definition.
+ *
+ * @package Netzmacht\Contao\Leaflet\Mapper\Layer
+ */
+class MarkerClusterLayerMapper extends AbstractLayerMapper
+{
+ /**
+ * Class of the definition being created.
+ *
+ * @var string
+ */
+ protected static $definitionClass = 'Netzmacht\LeafletPHP\Plugins\MarkerCluster\MarkerClusterGroup';
+
+ /**
+ * Layer type.
+ *
+ * @var string
+ */
+ protected static $type = 'markercluster';
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function initialize()
+ {
+ parent::initialize();
+
+ $this
+ ->addOptions('showCoverageOnHover', 'zoomToBoundsOnClick', 'spiderfyOnMaxZoom')
+ ->addOption('removeOutsideVisibleBounds')
+ ->addConditionalOption('maxClusterRadius')
+ ->addConditionalOption('singleMarkerMode')
+ ->addConditionalOption('animateAddingMarkers')
+ ->addConditionalOption('disableClusteringAtZoom')
+ ->addConditionalOption('spiderfyDistanceMultiplier');
+ }
+
+ /**
+ * {@inheritdoc}
+ * @SuppressWarnings(PHPMD.Superglobals)
+ */
+ protected function build(
+ Definition $definition,
+ \Model $model,
+ DefinitionMapper $mapper,
+ LatLngBounds $bounds = null,
+ Definition $parent = null
+ ) {
+ parent::build($definition, $model, $mapper, $bounds, $parent);
+
+ /** @var MarkerClusterGroup $definition */
+
+ if ($model->iconCreateFunction) {
+ $definition->setIconCreateFunction(new Expression($model->iconCreateFunction));
+ }
+
+ if ($model->polygonOptions) {
+ $definition->setPolygonOptions((array) json_decode($model->polygonOptions, true));
+ }
+
+ if (!$model->disableDefaultStyle) {
+ $GLOBALS['TL_CSS'][] = 'assets/leaflet/libs/leaflet-markercluster/MarkerCluster.Default.css||static';
+ }
+
+ $collection = LayerModel::findBy(
+ array('pid=?', 'active=1'),
+ array($model->id),
+ array('order' => 'sorting')
+ );
+
+ if ($collection) {
+ foreach ($collection as $layerModel) {
+ $layer = $mapper->handle($layerModel);
+
+ if ($layer instanceof Layer) {
+ $definition->addLayer($layer);
+
+ if ($layer instanceof OmnivoreLayer) {
+ $callback = new AnonymousFunction();
+ $callback->addLine('layers.' . $definition->getId() . '.addLayers(this.getLayers())');
+
+ $layer->on('ready', $callback);
+ }
+ }
+ }
+ }
+ }
+}