forked from Snck3rs/contao-leaflet-maps
Implement boundsMode fit.
This commit is contained in:
@@ -1 +1 @@
|
||||
L.Contao=L.Class.extend({includes:L.Mixin.Events,statics:{ATTRIBUTION:' | <a href="http://contao-leaflet.netzmacht.de/" title="Leaflet extension for Contao CMS">netzmacht <em>creative</em></a>'},maps:{},icons:{},initialize:function(){L.Icon.Default.imagePath="assets/leaflet/libs/leaflet/images",this.setGeoJsonListeners(L.GeoJSON)},addMap:function(t,e){return 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;e<t.length;e++){var o=L[t[e].type](t[e].options);this.addIcon(t[e].id,o)}},getIcon:function(t){return"undefined"==typeof this.icons[t]?null:this.icons[t]},load:function(t,e,o,n,i){var s=this.createRequestUrl(t),r=omnivore[e](s,o,n);return i&&(L.stamp(r),i.fire("dataloading",{layer:r}),r.on("ready",function(){i.calculateFeatureBounds(r),i.fire("dataload",{layer:r})}),r.on("error",function(){i.fire("dataload",{layer:r})})),r},pointToLayer:function(t,e){var o="marker",n=null;if(t.properties&&(t.properties.bounds=!0,t.properties.type&&(o=t.properties.type),t.properties.arguments&&(n=L[o].apply(L[o],t.properties.arguments),L.Util.setOptions(n,t.properties.options))),null===n&&(n=L[o](e,t.properties.options)),t.properties){if(t.properties.radius&&n.setRadius(t.properties.radius),t.properties.icon){var i=this.getIcon(t.properties.icon);i&&n.setIcon(i)}this.bindPopupFromFeature(n,t)}return this.fire("point:added",{marker:n,feature:t,latlng:e,type:o}),n},onEachFeature:function(t,e){t.properties&&(L.Util.setOptions(e,t.properties.options),this.bindPopupFromFeature(e,t),this.fire("feature:added",{feature:t,layer:e}))},bindPopupFromFeature:function(t,e){e.properties&&(e.properties.popup?t.bindPopup(e.properties.popup):e.properties.popupContent&&t.bindPopup(e.properties.popupContent))},setGeoJsonListeners:function(t){t&&t.prototype&&(t.prototype.options={pointToLayer:this.pointToLayer.bind(this),onEachFeature:this.onEachFeature.bind(this)})},createRequestUrl:function(t){t=encodeURIComponent(t);var e="leaflet",o=document.location.search.substr(1).split("&");if(""==o)return document.location.pathname+"?"+[e,t].join("=");for(var n,i=o.length;i--;)if(n=o[i].split("="),n[0]==e){n[1]=t,o[i]=n.join("=");break}return 0>i&&(o[o.length]=[e,t].join("=")),document.location.pathname+o.join("&")}}),L.Contao.Attribution={setPrefix:function(t){return-1===t.indexOf(L.Contao.ATTRIBUTION)&&(t+=L.Contao.ATTRIBUTION),this.options.prefix=t,this._update(),this}},L.Control.Attribution.addInitHook(function(){this.options.prefix+=L.Contao.ATTRIBUTION}),L.Control.Attribution.include(L.Contao.Attribution),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.ignoreForBounds?L.MarkerClusterGroup&&t instanceof L.MarkerClusterGroup&&t.options.affectBounds?(e=t.getBounds(),e.isValid()&&(this._dynamicBounds?this._dynamicBounds.extend(e):this._dynamicBounds=L.latLngBounds(e.getSouthWest(),e.getNorthEast()))):(!t.options||t.options&&t.options.affectBounds)&&t.eachLayer&&t.eachLayer(this._scanForBounds,this):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))}});
|
||||
L.Contao=L.Class.extend({includes:L.Mixin.Events,statics:{ATTRIBUTION:' | <a href="http://contao-leaflet.netzmacht.de/" title="Leaflet extension for Contao CMS">netzmacht <em>creative</em></a>'},maps:{},icons:{},initialize:function(){L.Icon.Default.imagePath="assets/leaflet/libs/leaflet/images",this.setGeoJsonListeners(L.GeoJSON)},addMap:function(t,e){return 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;e<t.length;e++){var o=L[t[e].type](t[e].options);this.addIcon(t[e].id,o)}},getIcon:function(t){return"undefined"==typeof this.icons[t]?null:this.icons[t]},load:function(t,e,o,n,i){var s=this.createRequestUrl(t,i),r=omnivore[e](s,o,n);return i&&(L.stamp(r),i.options.dynamicLoad&&"fit"==r.options.boundsMode&&(r.options.requestHash=t,i.on("moveend",r.refreshData,r),i.on("layerremove",function(t){t.layer===r&&i.off("moveend",r.updateBounds,r)})),i.fire("dataloading",{layer:r}),r.on("ready",function(){i.calculateFeatureBounds(r),i.fire("dataload",{layer:r})}),r.on("error",function(){i.fire("dataload",{layer:r})})),r},pointToLayer:function(t,e){var o="marker",n=null;if(t.properties&&(t.properties.bounds=!0,t.properties.type&&(o=t.properties.type),t.properties.arguments&&(n=L[o].apply(L[o],t.properties.arguments),L.Util.setOptions(n,t.properties.options))),null===n&&(n=L[o](e,t.properties.options)),t.properties){if(t.properties.radius&&n.setRadius(t.properties.radius),t.properties.icon){var i=this.getIcon(t.properties.icon);i&&n.setIcon(i)}this.bindPopupFromFeature(n,t)}return this.fire("point:added",{marker:n,feature:t,latlng:e,type:o}),n},onEachFeature:function(t,e){t.properties&&(L.Util.setOptions(e,t.properties.options),this.bindPopupFromFeature(e,t),this.fire("feature:added",{feature:t,layer:e}))},bindPopupFromFeature:function(t,e){e.properties&&(e.properties.popup?t.bindPopup(e.properties.popup):e.properties.popupContent&&t.bindPopup(e.properties.popupContent))},setGeoJsonListeners:function(t){t&&t.prototype&&(t.prototype.options={pointToLayer:this.pointToLayer.bind(this),onEachFeature:this.onEachFeature.bind(this)})},createRequestUrl:function(t,e){var o,n="leaflet",i=document.location.search.substr(1).split("&");if(t=encodeURIComponent(t),""==i)t=document.location.pathname+"?"+[n,t].join("=");else{for(var s,r=i.length;r--;)if(s=i[r].split("="),s[0]==n){s[1]=t,i[r]=s.join("=");break}0>r&&(i[i.length]=[n,t].join("=")),t=document.location.pathname+i.join("&")}return e&&e.options.dynamicLoad&&(o=e.getBounds(),t+="&f=bbox&v=",t+=o.getSouth()+","+o.getWest(),t+=","+o.getNorth()+","+o.getEast()),t}}),L.Contao.Attribution={setPrefix:function(t){return-1===t.indexOf(L.Contao.ATTRIBUTION)&&(t+=L.Contao.ATTRIBUTION),this.options.prefix=t,this._update(),this}},L.Control.Attribution.addInitHook(function(){this.options.prefix+=L.Contao.ATTRIBUTION}),L.Control.Attribution.include(L.Contao.Attribution),L.contao=new L.Contao,L.GeoJSON.include({refreshData:function(t){var e=L.geoJson(),o=this;e.on("ready",function(){var t,e=o.getLayers();for(t=0;t<e.length;t++)o.removeLayer(e[t]);for(e=this.getLayers(),t=0;t<e.length;t++)this.removeLayer(e[t]),o.addLayer(e[t])}),omnivore.geojson(L.contao.createRequestUrl(this.options.requestHash,t.target),null,e)}}),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.ignoreForBounds?L.MarkerClusterGroup&&t instanceof L.MarkerClusterGroup&&t.options.boundsMode&&"extend"==t.options.boundsMode?(e=t.getBounds(),e.isValid()&&(this._dynamicBounds?this._dynamicBounds.extend(e):this._dynamicBounds=L.latLngBounds(e.getSouthWest(),e.getNorthEast()))):(!t.options||t.options&&t.options.boundsMode&&"extend"==t.options.boundsMode)&&t.eachLayer&&t.eachLayer(this._scanForBounds,this):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))}});
|
||||
@@ -119,13 +119,25 @@ 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 url = this.createRequestUrl(hash, map),
|
||||
layer = omnivore[type](url, options, customLayer);
|
||||
|
||||
if (map) {
|
||||
// Required because Control.Loading tries to get _leafet_id which is created here.
|
||||
L.stamp(layer);
|
||||
|
||||
// Add listender for map bounds changes.
|
||||
if (map.options.dynamicLoad && layer.options.boundsMode == 'fit') {
|
||||
layer.options.requestHash = hash;
|
||||
map.on('moveend', layer.refreshData, layer);
|
||||
|
||||
map.on('layerremove', function(e) {
|
||||
if (e.layer === layer) {
|
||||
map.off('moveend', layer.updateBounds, layer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
map.fire('dataloading', {layer: layer});
|
||||
|
||||
layer.on('ready', function () {
|
||||
@@ -238,18 +250,20 @@ L.Contao = L.Class.extend({
|
||||
/**
|
||||
* Create request url by appending the hash to the current url.
|
||||
*
|
||||
* @param {string} value The hash
|
||||
* @param {string} value The hash.
|
||||
* @param {L.Map} map The map.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
createRequestUrl: function (value) {
|
||||
createRequestUrl: function (value, map) {
|
||||
var bounds,
|
||||
key = 'leaflet',
|
||||
params = document.location.search.substr(1).split('&');
|
||||
|
||||
value = encodeURIComponent(value);
|
||||
|
||||
var key = 'leaflet';
|
||||
var params = document.location.search.substr(1).split('&');
|
||||
|
||||
if (params == '') {
|
||||
return document.location.pathname + '?' + [key, value].join('=');
|
||||
value = document.location.pathname + '?' + [key, value].join('=');
|
||||
} else {
|
||||
var i = params.length;
|
||||
var x;
|
||||
@@ -267,8 +281,19 @@ L.Contao = L.Class.extend({
|
||||
params[params.length] = [key, value].join('=');
|
||||
}
|
||||
|
||||
return document.location.pathname + params.join('&');
|
||||
value = document.location.pathname + params.join('&');
|
||||
}
|
||||
|
||||
if (map) {
|
||||
if (map.options.dynamicLoad) {
|
||||
bounds = map.getBounds();
|
||||
value += '&f=bbox&v=';
|
||||
value += bounds.getSouth() + ',' + bounds.getWest();
|
||||
value += ',' + bounds.getNorth() + ',' + bounds.getEast();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
34
assets/maps/src/Mixin.GeoJSON.js
Normal file
34
assets/maps/src/Mixin.GeoJSON.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Add update bounds method for geo json layers. It is triggered when map bounds changed and make a new request
|
||||
* to get the data in the new bounds.
|
||||
*/
|
||||
L.GeoJSON.include({
|
||||
/**
|
||||
* Update bounds.
|
||||
*
|
||||
* @param {L.Event} e The subscribed event.
|
||||
*/
|
||||
refreshData: function(e) {
|
||||
var dataLayer = L.geoJson(),
|
||||
layer = this;
|
||||
|
||||
dataLayer.on('ready', function() {
|
||||
var i, layers = layer.getLayers();
|
||||
|
||||
// Clear old data.
|
||||
for (i = 0; i < layers.length; i++) {
|
||||
layer.removeLayer(layers[i]);
|
||||
}
|
||||
|
||||
// Copy data from temporary layer.
|
||||
layers = this.getLayers();
|
||||
for (i = 0; i < layers.length; i++) {
|
||||
this.removeLayer(layers[i]);
|
||||
layer.addLayer(layers[i]);
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: Allow other data formats.
|
||||
omnivore.geojson(L.contao.createRequestUrl(this.options.requestHash, e.target), null, dataLayer);
|
||||
}
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
/**
|
||||
* Extend map so that it can calculate their bounds depending of the features with the property affectBounds.
|
||||
* Extend map so that it can calculate their bounds depending of the features with the property boundsMode.
|
||||
*/
|
||||
L.Map.include({
|
||||
_dynamicBounds: null,
|
||||
@@ -63,7 +63,8 @@ L.Map.include({
|
||||
this._dynamicBounds = L.latLngBounds(source, source);
|
||||
}
|
||||
}
|
||||
} else if (L.MarkerClusterGroup && layer instanceof L.MarkerClusterGroup && layer.options.affectBounds) {
|
||||
} else if (L.MarkerClusterGroup && layer instanceof L.MarkerClusterGroup
|
||||
&& layer.options.boundsMode && layer.options.boundsMode == 'extend') {
|
||||
source = layer.getBounds();
|
||||
|
||||
if (source.isValid()) {
|
||||
@@ -73,7 +74,8 @@ L.Map.include({
|
||||
this._dynamicBounds = L.latLngBounds(source.getSouthWest(), source.getNorthEast());
|
||||
}
|
||||
}
|
||||
} else if ((!layer.options || (layer.options && layer.options.affectBounds)) && layer.eachLayer) {
|
||||
} else if ((!layer.options || (layer.options
|
||||
&& layer.options.boundsMode && layer.options.boundsMode == 'extend')) && layer.eachLayer) {
|
||||
layer.eachLayer(this._scanForBounds, this);
|
||||
}
|
||||
}
|
||||
@@ -171,6 +171,10 @@ $GLOBALS['LEAFLET_LAYERS'] = array
|
||||
'children' => false,
|
||||
'icon' => 'system/modules/leaflet/assets/img/markers.png',
|
||||
'markers' => true,
|
||||
'boundsMode' => array(
|
||||
'extend' => true,
|
||||
'fit' => 'deferred'
|
||||
),
|
||||
'label' => function ($row, $label) {
|
||||
$count = \Netzmacht\Contao\Leaflet\Model\MarkerModel::countBy('pid', $row['id']);
|
||||
$label .= sprintf(
|
||||
@@ -187,6 +191,9 @@ $GLOBALS['LEAFLET_LAYERS'] = array
|
||||
'children' => false,
|
||||
'icon' => 'system/modules/leaflet/assets/img/vectors.png',
|
||||
'vectors' => true,
|
||||
'boundsMode' => array(
|
||||
'extend' => true,
|
||||
),
|
||||
'label' => function ($row, $label) {
|
||||
$count = \Netzmacht\Contao\Leaflet\Model\VectorModel::countBy('pid', $row['id']);
|
||||
$label .= sprintf(
|
||||
@@ -307,3 +314,10 @@ $GLOBALS['LEAFLET_FEATURE_MODEL_PROPERTIES']['tl_leaflet_marker'][] = 'alias';
|
||||
$GLOBALS['LEAFLET_FEATURE_MODEL_PROPERTIES']['tl_leaflet_vector'][] = 'id';
|
||||
$GLOBALS['LEAFLET_FEATURE_MODEL_PROPERTIES']['tl_leaflet_vector'][] = 'title';
|
||||
$GLOBALS['LEAFLET_FEATURE_MODEL_PROPERTIES']['tl_leaflet_vector'][] = 'alias';
|
||||
|
||||
|
||||
/*
|
||||
* Filters can be passed to a data request to get only specific data from a layer.
|
||||
*/
|
||||
$GLOBALS['LEAFLET_FILTERS']['bbox'] = 'Netzmacht\Contao\Leaflet\Filter\BboxFilter';
|
||||
$GLOBALS['LEAFLET_FILTERS']['distance'] = 'Netzmacht\Contao\Leaflet\Filter\DistanceFilter';
|
||||
|
||||
@@ -148,15 +148,15 @@ $GLOBALS['TL_DCA']['tl_leaflet_layer'] = array
|
||||
),
|
||||
'markers extends default' => array(
|
||||
'+expert' => array('pointToLayer'),
|
||||
'+active' => array('deferred', 'affectBounds')
|
||||
'+config' => array('deferred', 'boundsMode')
|
||||
),
|
||||
'group extends default' => array(
|
||||
'+title' => array('groupType'),
|
||||
'+active' => array('affectBounds')
|
||||
'+active' => array('boundsMode')
|
||||
),
|
||||
'vectors extends default' => array(
|
||||
'+expert' => array('onEachFeature', 'pointToLayer'),
|
||||
'+active' => array('deferred', 'affectBounds'),
|
||||
'+config' => array('deferred', 'boundsMode'),
|
||||
),
|
||||
'reference extends default' => array(
|
||||
'+title' => array('reference', 'standalone')
|
||||
@@ -335,7 +335,7 @@ $GLOBALS['TL_DCA']['tl_leaflet_layer'] = array
|
||||
'exclude' => true,
|
||||
'inputType' => 'checkbox',
|
||||
'default' => true,
|
||||
'eval' => array('tl_class' => 'w50', 'submitOnChange' => false, 'isBoolean' => true),
|
||||
'eval' => array('tl_class' => 'w50 m12', 'submitOnChange' => true, 'isBoolean' => true),
|
||||
'sql' => "char(1) NOT NULL default '1'"
|
||||
),
|
||||
'groupType' => array
|
||||
@@ -530,14 +530,14 @@ $GLOBALS['TL_DCA']['tl_leaflet_layer'] = array
|
||||
'eval' => array('tl_class' => 'w50', 'submitOnChange' => false, 'isBoolean' => true),
|
||||
'sql' => "char(1) NOT NULL default ''"
|
||||
),
|
||||
'affectBounds' => array
|
||||
'boundsMode' => array
|
||||
(
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_leaflet_layer']['affectBounds'],
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_leaflet_layer']['boundsMode'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'checkbox',
|
||||
'default' => false,
|
||||
'eval' => array('tl_class' => 'w50'),
|
||||
'sql' => "char(1) NOT NULL default ''"
|
||||
'inputType' => 'select',
|
||||
'options_callback' => array('Netzmacht\Contao\Leaflet\Dca\Layer', 'getBoundsModes'),
|
||||
'eval' => array('tl_class' => 'w50', 'includeBlankOption' => true),
|
||||
'sql' => "varchar(6) NOT NULL default ''"
|
||||
),
|
||||
'tileUrl' => array
|
||||
(
|
||||
|
||||
@@ -94,7 +94,7 @@ $GLOBALS['TL_DCA']['tl_leaflet_map'] = array
|
||||
'metapalettes' => array(
|
||||
'default' => array(
|
||||
'title' => array('title', 'alias'),
|
||||
'zoom' => array('center', 'zoom', 'adjustZoomExtra', 'adjustBounds'),
|
||||
'zoom' => array('center', 'zoom', 'adjustZoomExtra', 'adjustBounds', 'dynamicLoad'),
|
||||
'locate' => array('locate'),
|
||||
'layers' => array('layers'),
|
||||
'interaction' => array(
|
||||
@@ -419,6 +419,15 @@ $GLOBALS['TL_DCA']['tl_leaflet_map'] = array
|
||||
'eval' => array('tl_class' => 'clr w50', 'multiple' => true, 'helpwizard' => true),
|
||||
'sql' => "varchar(255) NOT NULL default ''"
|
||||
),
|
||||
'dynamicLoad' => array
|
||||
(
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_leaflet_map']['dynamicLoad'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'checkbox',
|
||||
'default' => true,
|
||||
'eval' => array('tl_class' => 'w50', 'submitOnChange' => false),
|
||||
'sql' => "char(1) NOT NULL default ''"
|
||||
),
|
||||
'locate' => array
|
||||
(
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_leaflet_map']['locate'],
|
||||
|
||||
@@ -176,7 +176,8 @@ $GLOBALS['TL_DCA']['tl_leaflet_marker'] = array
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'save_callback' => array(
|
||||
array('Netzmacht\Contao\Leaflet\Dca\Leaflet', 'validateCoordinate')
|
||||
array('Netzmacht\Contao\Leaflet\Dca\Leaflet', 'validateCoordinate'),
|
||||
array('Netzmacht\Contao\Leaflet\Dca\Marker', 'saveCoordinates')
|
||||
),
|
||||
'wizard' => array(
|
||||
array('Netzmacht\Contao\Leaflet\Dca\Leaflet', 'getGeocoder')
|
||||
@@ -185,9 +186,34 @@ $GLOBALS['TL_DCA']['tl_leaflet_marker'] = array
|
||||
'maxlength' => 255,
|
||||
'tl_class' => 'long clr',
|
||||
'nullIfEmpty' => true,
|
||||
'doNotSaveEmpty' => true,
|
||||
),
|
||||
'sql' => "varchar(255) NULL"
|
||||
),
|
||||
'latitude' => array
|
||||
(
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_leaflet_marker']['latitude'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => array('mandatory' => false, 'maxlength' => 255, 'tl_class' => 'w50'),
|
||||
'sql' => "float NULL"
|
||||
),
|
||||
'longitude' => array
|
||||
(
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_leaflet_marker']['longitude'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => array('mandatory' => false, 'maxlength' => 255, 'tl_class' => 'w50'),
|
||||
'sql' => "float NULL"
|
||||
),
|
||||
'altitude' => array
|
||||
(
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_leaflet_marker']['altitude'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => array('mandatory' => false, 'maxlength' => 255, 'tl_class' => 'w50'),
|
||||
'sql' => "float NULL"
|
||||
),
|
||||
'active' => array
|
||||
(
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_leaflet_marker']['active'],
|
||||
|
||||
@@ -76,8 +76,8 @@ $GLOBALS['TL_LANG']['tl_leaflet_layer']['iconCreateFunction'][0] = 'Crea
|
||||
$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']['affectBounds'][0] = 'Affect map bounds';
|
||||
$GLOBALS['TL_LANG']['tl_leaflet_layer']['affectBounds'][1] = 'If the map support it the marker will be used to affect the initial map bounds.';
|
||||
$GLOBALS['TL_LANG']['tl_leaflet_layer']['boundsMode'][0] = 'Bounds relation';
|
||||
$GLOBALS['TL_LANG']['tl_leaflet_layer']['boundsMode'][1] = 'Choose a mode how the layer data should affect the map bounds.';
|
||||
$GLOBALS['TL_LANG']['tl_leaflet_layer']['minZoom'][0] = 'Minimum zoom';
|
||||
$GLOBALS['TL_LANG']['tl_leaflet_layer']['minZoom'][1] = 'Minimum zoom number.';
|
||||
$GLOBALS['TL_LANG']['tl_leaflet_layer']['maxZoom'][0] = 'Maximum zoom';
|
||||
|
||||
@@ -302,6 +302,30 @@ class Layer
|
||||
->execute($dataContainer->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bounds modes supported by the layer.
|
||||
*
|
||||
* @param \DataContainer $dataContainer The data container.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getBoundsModes($dataContainer)
|
||||
{
|
||||
$options = array();
|
||||
|
||||
if ($dataContainer->activeRecord && !empty($this->layers[$dataContainer->activeRecord->type]['boundsMode'])) {
|
||||
foreach ($this->layers[$dataContainer->activeRecord->type]['boundsMode'] as $mode => $enabled) {
|
||||
if ($enabled === true) {
|
||||
$options[] = $mode;
|
||||
} elseif ($enabled === 'deferred' && $dataContainer->activeRecord->deferred) {
|
||||
$options[] = $mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a button.
|
||||
*
|
||||
|
||||
@@ -51,4 +51,37 @@ class Marker
|
||||
|
||||
return $builder->getOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the coordinates.
|
||||
*
|
||||
* @param string $value The raw data.
|
||||
* @param \DataContainer $dataContainer The data container driver.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function saveCoordinates($value, $dataContainer)
|
||||
{
|
||||
$combined = array(
|
||||
'latitude' => null,
|
||||
'longitude' => null,
|
||||
'altitude' => null
|
||||
);
|
||||
|
||||
$values = trimsplit(',', $value);
|
||||
$keys = array_keys($combined);
|
||||
|
||||
if (count($values) >= 2 && count($values) <= 3) {
|
||||
for ($i = 0; $i < count($values); $i++) {
|
||||
$combined[$keys[$i]] = $values[$i];
|
||||
}
|
||||
}
|
||||
|
||||
\Database::getInstance()
|
||||
->prepare('UPDATE tl_leaflet_marker %s WHERE id=?')
|
||||
->set($combined)
|
||||
->execute($dataContainer->id);
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
|
||||
namespace Netzmacht\Contao\Leaflet\Frontend;
|
||||
|
||||
use Netzmacht\Contao\Leaflet\Filter\Filter;
|
||||
use Netzmacht\Contao\Leaflet\MapService;
|
||||
use Netzmacht\Contao\Leaflet\Model\LayerModel;
|
||||
|
||||
/**
|
||||
* The data controller handles ajax request for sub data.
|
||||
@@ -36,7 +36,9 @@ class DataController
|
||||
private $input = array(
|
||||
'format' => 'geojson',
|
||||
'type' => 'layer',
|
||||
'id' => null
|
||||
'id' => null,
|
||||
'filter' => null,
|
||||
'values' => null
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -61,7 +63,13 @@ class DataController
|
||||
public function execute()
|
||||
{
|
||||
try {
|
||||
list($data, $error) = $this->loadData($this->input['type'], $this->input['id']);
|
||||
if ($this->input['filter']) {
|
||||
$filter = $this->createFilter();
|
||||
} else {
|
||||
$filter = null;
|
||||
}
|
||||
|
||||
list($data, $error) = $this->loadData($this->input['type'], $this->input['id'], $filter);
|
||||
$this->encodeData($this->input['format'], $data);
|
||||
} catch (\Exception $e) {
|
||||
if (\Config::get('debugMode') || \Config::get('displayErrors')) {
|
||||
@@ -101,17 +109,18 @@ class DataController
|
||||
*
|
||||
* @param string $type The data type.
|
||||
* @param mixed $dataId The data id.
|
||||
* @param Filter $filter Optional request filter.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function loadData($type, $dataId)
|
||||
public function loadData($type, $dataId, Filter $filter = null)
|
||||
{
|
||||
$error = false;
|
||||
$data = null;
|
||||
|
||||
switch ($type) {
|
||||
case 'layer':
|
||||
$data = $this->mapService->getFeatureCollection($dataId);
|
||||
$data = $this->mapService->getFeatureCollection($dataId, $filter);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -122,4 +131,24 @@ class DataController
|
||||
|
||||
return array($data, $error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a filter.
|
||||
*
|
||||
* @return Filter
|
||||
* @throws \RuntimeException If the filter is not defined.
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.Superglobals)
|
||||
*/
|
||||
private function createFilter()
|
||||
{
|
||||
if (!isset($GLOBALS['LEAFLET_FILTERS'][$this->input['filter']])) {
|
||||
throw new \RuntimeException(sprintf('Undefined filter "%s".', $this->input['filter']));
|
||||
}
|
||||
|
||||
/** @var Filter $filter */
|
||||
$filter = $GLOBALS['LEAFLET_FILTERS'][$this->input['filter']];
|
||||
|
||||
return $filter::fromRequest($this->input['values']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ trait HybridTrait
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws \HttpRequestException If a bad leaflet param hash is given.
|
||||
* @throws \RuntimeException If a bad leaflet param hash is given.
|
||||
* @SuppressWarnings(ExitExpression)
|
||||
*/
|
||||
private function handleAjaxRequest()
|
||||
@@ -143,12 +143,14 @@ trait HybridTrait
|
||||
// Handle ajax request.
|
||||
if ($input) {
|
||||
$data = explode(',', base64_decode($input));
|
||||
$data[] = $this->input->get('f');
|
||||
$data[] = $this->input->get('v');
|
||||
|
||||
if (count($data) != 4) {
|
||||
throw new \HttpRequestException('Bad request. Could not resolve query params');
|
||||
if (count($data) != 6) {
|
||||
throw new \RuntimeException('Bad request. Could not resolve query params');
|
||||
}
|
||||
|
||||
$data = array_combine(array('for', 'type', 'id', 'format'), $data);
|
||||
$data = array_combine(array('for', 'type', 'id', 'format', 'filter', 'values'), $data);
|
||||
$data = array_filter($data);
|
||||
|
||||
if (empty($data['for']) || $data['for'] != $this->getIdentifier()) {
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace Netzmacht\Contao\Leaflet\Frontend;
|
||||
|
||||
use Netzmacht\Contao\Leaflet\Filter\Filter;
|
||||
|
||||
/**
|
||||
* Class RequestUrl creates the request url.
|
||||
*
|
||||
@@ -39,6 +41,13 @@ class RequestUrl implements \JsonSerializable
|
||||
*/
|
||||
private $url;
|
||||
|
||||
/**
|
||||
* Request filter.
|
||||
*
|
||||
* @var Filter|null
|
||||
*/
|
||||
private $filter;
|
||||
|
||||
/**
|
||||
* Create the request url.
|
||||
*
|
||||
@@ -47,10 +56,11 @@ class RequestUrl implements \JsonSerializable
|
||||
* @param int $dataId The data object id.
|
||||
* @param string|null $type Object type. If empty it assumes a layer.
|
||||
* @param string|null $format Data format. If empty it assumes geojson.
|
||||
* @param Filter $filter Optional filter.
|
||||
*
|
||||
* @return RequestUrl
|
||||
*/
|
||||
public static function create($dataId, $type = null, $format = null)
|
||||
public static function create($dataId, $type = null, $format = null, Filter $filter = null)
|
||||
{
|
||||
$params = array(
|
||||
'for' => static::$for,
|
||||
@@ -60,9 +70,15 @@ class RequestUrl implements \JsonSerializable
|
||||
);
|
||||
|
||||
$hash = base64_encode(implode(',', $params));
|
||||
$url = \Config::get('websitePath') . '/' . \Frontend::addToUrl('leaflet=' . $hash, false);
|
||||
$query = 'leaflet=' . $hash;
|
||||
|
||||
return new static($url, $hash);
|
||||
if ($filter) {
|
||||
$query .= '&f=' . $filter->getName() . '&v=' . $filter->toRequest();
|
||||
}
|
||||
|
||||
$url = \Config::get('websitePath') . '/' . \Frontend::addToUrl($query, false);
|
||||
|
||||
return new static($url, $hash, $filter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,6 +125,16 @@ class RequestUrl implements \JsonSerializable
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get request filter.
|
||||
*
|
||||
* @return Filter|null
|
||||
*/
|
||||
public function getFilter()
|
||||
{
|
||||
return $this->filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to string will always return the whole url.
|
||||
*
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace Netzmacht\Contao\Leaflet;
|
||||
|
||||
use Netzmacht\Contao\Leaflet\Event\GetJavascriptEvent;
|
||||
use Netzmacht\Contao\Leaflet\Filter\Filter;
|
||||
use Netzmacht\Contao\Leaflet\Mapper\DefinitionMapper;
|
||||
use Netzmacht\Contao\Leaflet\Model\LayerModel;
|
||||
use Netzmacht\Contao\Leaflet\Model\MapModel;
|
||||
@@ -68,12 +69,12 @@ class MapService
|
||||
* Get map definition.
|
||||
*
|
||||
* @param MapModel|int $mapId The map database id. MapModel accepted as well.
|
||||
* @param LatLngBounds $bounds Optional bounds where elements should be in.
|
||||
* @param Filter $filter Optional request filter.
|
||||
* @param string $elementId Optional element id. If none given the mapId or alias is used.
|
||||
*
|
||||
* @return Map
|
||||
*/
|
||||
public function getDefinition($mapId, LatLngBounds $bounds = null, $elementId = null)
|
||||
public function getDefinition($mapId, Filter $filter = null, $elementId = null)
|
||||
{
|
||||
if ($mapId instanceof MapModel) {
|
||||
$model = $mapId;
|
||||
@@ -81,7 +82,7 @@ class MapService
|
||||
$model = $this->getModel($mapId);
|
||||
}
|
||||
|
||||
return $this->mapper->handle($model, $bounds, $elementId);
|
||||
return $this->mapper->handle($model, $filter, $elementId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,13 +151,13 @@ class MapService
|
||||
* Get feature collection of a layer.
|
||||
*
|
||||
* @param LayerModel|int $layerId The layer database id or layer model.
|
||||
* @param LatLngBounds $bounds Filter features in the bounds.
|
||||
* @param Filter|null $filter Filter data.
|
||||
*
|
||||
* @return FeatureCollection
|
||||
*
|
||||
* @throws \InvalidArgumentException If a layer could not be found.
|
||||
*/
|
||||
public function getFeatureCollection($layerId, LatLngBounds $bounds = null)
|
||||
public function getFeatureCollection($layerId, Filter $filter = null)
|
||||
{
|
||||
if ($layerId instanceof LayerModel) {
|
||||
$model = $layerId;
|
||||
@@ -168,6 +169,6 @@ class MapService
|
||||
throw new \InvalidArgumentException(sprintf('Could not find layer "%s"', $layerId));
|
||||
}
|
||||
|
||||
return $this->mapper->handleGeoJson($model, $bounds);
|
||||
return $this->mapper->handleGeoJson($model, $filter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,21 +57,29 @@ class MarkersLayerMapper extends AbstractLayerMapper implements GeoJsonMapper
|
||||
$elementId = null
|
||||
) {
|
||||
if ($model->deferred) {
|
||||
if ($model->pointToLayer || $model->affectBounds) {
|
||||
if ($model->pointToLayer || $model->boundsMode) {
|
||||
$layer = new GeoJson($this->getElementId($model, $elementId));
|
||||
|
||||
if ($model->pointToLayer) {
|
||||
$layer->setPointToLayer(new Expression($model->pointToLayer));
|
||||
}
|
||||
|
||||
if ($model->affectBounds) {
|
||||
$layer->setOption('affectBounds', (bool) $model->affectBounds);
|
||||
if ($model->boundsMode) {
|
||||
$layer->setOption('boundsMode', $model->boundsMode);
|
||||
}
|
||||
|
||||
return array($this->getElementId($model, $elementId), RequestUrl::create($model->id), array(), $layer);
|
||||
return array(
|
||||
$this->getElementId($model, $elementId),
|
||||
RequestUrl::create($model->id, null, null, $filter),
|
||||
array(),
|
||||
$layer
|
||||
);
|
||||
}
|
||||
|
||||
return array($this->getElementId($model, $elementId), RequestUrl::create($model->id));
|
||||
return array(
|
||||
$this->getElementId($model, $elementId),
|
||||
RequestUrl::create($model->id, null, null, $filter)
|
||||
);
|
||||
}
|
||||
|
||||
return parent::buildConstructArguments($model, $mapper, $filter, $elementId);
|
||||
@@ -88,8 +96,8 @@ class MarkersLayerMapper extends AbstractLayerMapper implements GeoJsonMapper
|
||||
Definition $parent = null
|
||||
) {
|
||||
if ($definition instanceof GeoJson) {
|
||||
if ($model->affectBounds) {
|
||||
$definition->setOption('affectBounds', true);
|
||||
if ($model->boundsMode) {
|
||||
$definition->setOption('boundsMode', $model->boundsMode);
|
||||
}
|
||||
|
||||
$collection = $this->loadMarkerModels($model);
|
||||
@@ -117,7 +125,7 @@ class MarkersLayerMapper extends AbstractLayerMapper implements GeoJsonMapper
|
||||
public function handleGeoJson(\Model $model, DefinitionMapper $mapper, Filter $filter = null)
|
||||
{
|
||||
$feature = new FeatureCollection();
|
||||
$collection = $this->loadMarkerModels($model);
|
||||
$collection = $this->loadMarkerModels($model, $filter);
|
||||
|
||||
if ($collection) {
|
||||
foreach ($collection as $item) {
|
||||
@@ -137,11 +145,16 @@ class MarkersLayerMapper extends AbstractLayerMapper implements GeoJsonMapper
|
||||
* Load all layer markers.
|
||||
*
|
||||
* @param \Model $model The layer model.
|
||||
* @param Filter $filter null The request filter.
|
||||
*
|
||||
* @return \Model\Collection|null
|
||||
*/
|
||||
protected function loadMarkerModels(\Model $model)
|
||||
protected function loadMarkerModels(\Model $model, Filter $filter = null)
|
||||
{
|
||||
return MarkerModel::findActiveBy('pid', $model->id, array('order' => 'sorting'));
|
||||
if ($model->boundsMode == 'fit') {
|
||||
return MarkerModel::findByFilter($model->id, $filter);
|
||||
}
|
||||
|
||||
return MarkerModel::findByFilter($model->id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,18 +68,26 @@ class VectorsLayerMapper extends AbstractLayerMapper implements GeoJsonMapper
|
||||
$options['onEachFeature'] = new Expression($model->onEachFeature);
|
||||
}
|
||||
|
||||
if ($model->affectBounds) {
|
||||
$options['affectBounds'] = (bool) $model->affectBounds;
|
||||
if ($model->boundsMode) {
|
||||
$options['boundsMode'] = $model->boundsMode;
|
||||
}
|
||||
|
||||
if (!empty($options)) {
|
||||
$layer = new GeoJson($this->getElementId($model, $elementId));
|
||||
$layer->setOptions($options);
|
||||
|
||||
return array($this->getElementId($model, $elementId), RequestUrl::create($model->id), array(), $layer);
|
||||
return array(
|
||||
$this->getElementId($model, $elementId),
|
||||
RequestUrl::create($model->id, null, null, $filter),
|
||||
array(),
|
||||
$layer
|
||||
);
|
||||
}
|
||||
|
||||
return array($this->getElementId($model, $elementId), RequestUrl::create($model->id));
|
||||
return array(
|
||||
$this->getElementId($model, $elementId),
|
||||
RequestUrl::create($model->id, null, null, $filter)
|
||||
);
|
||||
}
|
||||
|
||||
return parent::buildConstructArguments($model, $mapper, $filter, $elementId);
|
||||
@@ -98,8 +106,8 @@ class VectorsLayerMapper extends AbstractLayerMapper implements GeoJsonMapper
|
||||
if ($definition instanceof GeoJson) {
|
||||
$collection = $this->loadVectorModels($model);
|
||||
|
||||
if ($model->affectBounds) {
|
||||
$definition->setOption('affectBounds', true);
|
||||
if ($model->boundsMode) {
|
||||
$definition->setOption('boundsMode', $model->boundsMode);
|
||||
}
|
||||
|
||||
if ($collection) {
|
||||
|
||||
@@ -100,6 +100,8 @@ class MapMapper extends AbstractMapper
|
||||
if ($model->options) {
|
||||
$map->setOptions(json_decode($model->options, true));
|
||||
}
|
||||
|
||||
$map->setOption('dynamicLoad', (bool) $model->dynamicLoad);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -205,23 +205,38 @@ class OptionsBuilder
|
||||
public static function applyOptions($options, $definition, $model)
|
||||
{
|
||||
foreach ($options as $option => $mapping) {
|
||||
$setter = 'set' . ucfirst($option);
|
||||
$default = static::getDefaultOption($option, $definition);
|
||||
|
||||
if ($model->$mapping === '1' || $model->$mapping === '') {
|
||||
if (((bool) $model->$mapping) !== $default) {
|
||||
$definition->$setter($model->$mapping);
|
||||
static::applyOption($option, $model->$mapping, $definition);
|
||||
}
|
||||
} elseif (is_numeric($default)) {
|
||||
if ($model->$mapping != $default) {
|
||||
$definition->$setter($model->$mapping);
|
||||
static::applyOption($option, $model->$mapping, $definition);
|
||||
}
|
||||
} elseif ($model->$mapping !== $default) {
|
||||
$definition->$setter($model->$mapping);
|
||||
static::applyOption($option, $model->$mapping, $definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $option
|
||||
* @param $value
|
||||
* @param Definition $definition
|
||||
*/
|
||||
private static function applyOption($option, $value, $definition)
|
||||
{
|
||||
$setter = 'set' . ucfirst($option);
|
||||
|
||||
if (method_exists($definition, $setter)) {
|
||||
$definition->$setter($value);
|
||||
} else {
|
||||
$definition->setOption($option, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default option value.
|
||||
*
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
|
||||
namespace Netzmacht\Contao\Leaflet\Model;
|
||||
|
||||
use Netzmacht\Contao\Leaflet\Filter\BboxFilter;
|
||||
use Netzmacht\Contao\Leaflet\Filter\Filter;
|
||||
use Netzmacht\LeafletPHP\Definition\Type\LatLngBounds;
|
||||
|
||||
/**
|
||||
* Class MarkerModel for the tl_leaflet_marker table.
|
||||
*
|
||||
@@ -24,4 +28,53 @@ class MarkerModel extends AbstractActiveModel
|
||||
* @var string
|
||||
*/
|
||||
protected static $strTable = 'tl_leaflet_marker';
|
||||
|
||||
/**
|
||||
* @param $pid
|
||||
* @param Filter $filter
|
||||
*
|
||||
* @return \Model\Collection|null
|
||||
*/
|
||||
public static function findByFilter($pid, Filter $filter = null)
|
||||
{
|
||||
if (!$filter) {
|
||||
return MarkerModel::findActiveBy('pid', $pid, array('order' => 'sorting'));
|
||||
}
|
||||
|
||||
switch ($filter->getName()) {
|
||||
case 'bbox':
|
||||
return static::findByBBoxFilter($pid, $filter);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $pid
|
||||
* @param BboxFilter $filter
|
||||
*
|
||||
* @return \Model\Collection|null
|
||||
*/
|
||||
public static function findByBBoxFilter($pid, BboxFilter $filter)
|
||||
{
|
||||
$columns = array(
|
||||
'active=1',
|
||||
'pid=?',
|
||||
'latitude > ? AND latitude < ?',
|
||||
'longitude > ? AND longitude < ?'
|
||||
);
|
||||
|
||||
/** @var LatLngBounds $bounds */
|
||||
$bounds = $filter->getValues()['bounds'];
|
||||
$values = array(
|
||||
$pid,
|
||||
$bounds->getSouthWest()->getLatitude(),
|
||||
$bounds->getNorthEast()->getLatitude(),
|
||||
$bounds->getSouthWest()->getLongitude(),
|
||||
$bounds->getNorthEast()->getLongitude()
|
||||
);
|
||||
|
||||
return static::findBy($columns, $values, array('order' => 'sorting'));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user