/**
* JavaScript for Leaflet in the Maps extension.
* @see https://www.mediawiki.org/wiki/Extension:Maps
*
* @author Pavel Astakhov < pastakhov@yandex.ru >
* @author Peter Grassberger < petertheone@gmail.com >
*/
(function ($, mw, L, MQ) {
$.fn.leafletmaps = function ( options ) {
var _this = this;
this.map = null;
this.options = options;
this.markers = [];
this.markercluster = null;
var apikeys = mw.config.get('egMapsLeafletLayersApiKeys') ;
/**
* array point of all map elements (markers, lines, polygons, etc.)
* for map fit
*/
this.points = [];
/**
* Creates a new marker with the provided data and returns it.
* @param {Object} properties Contains the fields lat, lon, title, text and icon
* @return {L.Marker}
*/
this.createMarker = function (properties) {
this.points.push( new L.LatLng(properties.lat, properties.lon) );
var markerOptions = {
title:properties.title
};
var marker = L.marker( [properties.lat, properties.lon], markerOptions );
if (properties.hasOwnProperty('icon') && properties.icon !== '') {
marker.setOpacity(0);
var img = new Image();
img.onload = function() {
var icon = new L.Icon({
iconUrl: properties.icon,
iconSize: [ img.width, img.height ],
iconAnchor: [ img.width / 2, img.height ],
popupAnchor: [ -img.width % 2, -img.height*2/3 ]
});
marker.setIcon(icon);
marker.setOpacity(1);
};
img.src = properties.icon;
}
if( properties.hasOwnProperty('text') && properties.text.length > 0 ) {
marker.bindPopup( properties.text );
}
if ( options.copycoords ) {
marker.on(
'contextmenu',
function( e ) {
prompt(mw.msg('maps-copycoords-prompt'), e.latlng.lat + ',' + e.latlng.lng);
}
);
}
return marker;
};
/**
* Creates a new marker with the provided data, adds it to the map
* and returns it.
* @param {Object} properties Contains the fields lat, lon, title, text and icon
* @return {L.Marker}
*/
this.addMarker = function (properties) {
var marker = this.createMarker(properties);
if (!this.options.markercluster) {
marker.addTo( this.map );
}
this.markers.push( marker );
return marker;
};
this.removeMarker = function (marker) {
this.map.removeLayer(marker);
this.points = [];
this.markers = this.markers.filter(function(object) {
return object !== marker;
});
};
this.removeMarkers = function () {
if (this.markercluster) {
this.map.removeLayer(this.markercluster);
this.markercluster = null;
}
var map = this.map;
$.each(this.markers, function(index, marker) {
map.removeLayer(marker);
});
this.points = [];
this.markers = [];
};
this.addLine = function (properties) {
var options = {
color: properties.strokeColor,
weight:properties.strokeWeight,
opacity:properties.strokeOpacity
};
var latlngs = [];
for (var x = 0; x < properties.pos.length; x++) {
latlngs.push([properties.pos[x].lat, properties.pos[x].lon]);
this.points.push( new L.LatLng(properties.pos[x].lat, properties.pos[x].lon) );
}
var line = L.polyline(latlngs, options).addTo(this.map);
if( properties.hasOwnProperty('text') && properties.text.trim().length > 0 ) {
line.bindPopup( properties.text );
}
};
this.addPolygon = function (properties) {
properties.pos.forEach(function(position) {
_this.points.push( new L.LatLng(position.lat, position.lon) );
});
var polygon = L.polygon(
properties.pos.map(function(position) {
return [position.lat, position.lon];
}),
{
color: properties.strokeColor,
weight:properties.strokeWeight,
opacity:properties.strokeOpacity,
fillColor:properties.fillColor,
fillOpacity:properties.fillOpacity
}
);
polygon.addTo(this.map);
if( properties.hasOwnProperty('text') && properties.text.trim().length > 0 ) {
console.log(properties.text);
polygon.bindPopup( properties.text );
}
};
this.addCircle = function (properties) {
var circle = L.circle(
[properties.centre.lat, properties.centre.lon],
{
radius: properties.radius,
color: properties.strokeColor,
weight:properties.strokeWeight,
opacity:properties.strokeOpacity,
fillColor:properties.fillColor,
fillOpacity:properties.fillOpacity,
}
).addTo(this.map);
this.points.push( new L.LatLng(properties.centre.lat, properties.centre.lon) );
if( properties.hasOwnProperty('text') && properties.text.trim().length > 0 ) {
circle.bindPopup( properties.text );
}
};
this.addRectangle = function (properties) {
this.points.push( new L.LatLng(properties.sw.lat, properties.sw.lon) );
this.points.push( new L.LatLng(properties.ne.lat, properties.ne.lon) );
var options = {
color: properties.strokeColor,
weight:properties.strokeWeight,
opacity:properties.strokeOpacity,
fillColor:properties.fillColor,
fillOpacity:properties.fillOpacity
};
var bounds = [[properties.sw.lat, properties.sw.lon], [properties.ne.lat, properties.ne.lon]];
var rectangle = L.rectangle( bounds, options ).addTo(this.map);
if( properties.hasOwnProperty('text') && properties.text.trim().length > 0 ) {
rectangle.bindPopup( properties.text );
}
};
this.createMarkerCluster = function () {
if ( !options.markercluster ) {
return;
}
var markers = this.markers;
var markercluster = new L.MarkerClusterGroup({
maxClusterRadius: options.clustermaxradius,
disableClusteringAtZoom: options.clustermaxzoom + 1,
zoomToBoundsOnClick: options.clusterzoomonclick,
spiderfyOnMaxZoom: options.clusterspiderfy,
iconCreateFunction: function(cluster) {
var childCount = cluster.getChildCount();
var imagePath = mw.config.get( 'egMapsScriptPath' ) + '/resources/leaflet/cluster/';
var styles = [
{
iconUrl: imagePath + 'm1.png',
iconSize: [53, 52]
},
{
iconUrl: imagePath + 'm2.png',
iconSize: [56, 55]
},
{
iconUrl: imagePath + 'm3.png',
iconSize: [66, 65]
},
{
iconUrl: imagePath + 'm4.png',
iconSize: [78, 77]
},
{
iconUrl: imagePath + 'm5.png',
iconSize: [90, 89]
}
];
var index = 0;
var dv = childCount;
while (dv !== 0) {
dv = parseInt(dv / 10, 10);
index++;
}
var index = Math.min(index, styles.length);
index = Math.max(0, index - 1);
index = Math.min(styles.length - 1, index);
var style = styles[index];
return new L.divIcon({
iconSize: style.iconSize,
className: '',
html: '' +
'' + childCount + ''
});
}
});
$.each(this.markers, function(index, marker) {
markercluster.addLayer(marker);
});
if (this.markercluster) {
this.map.removeLayer(this.markercluster);
this.markercluster = null;
}
this.map.addLayer(markercluster);
this.markercluster = markercluster;
};
this.addGeoJson = function(options) {
if (options.geojson !== '') {
var geoJson = options.geojson;
var geoJsonLayer = L.geoJSON( geoJson ).addTo( this.map );
this.points.push( geoJsonLayer.getBounds().getNorthEast() );
this.points.push( geoJsonLayer.getBounds().getSouthWest() );
}
};
this.setup = function () {
var mapOptions = {};
if (options.minzoom !== false ) mapOptions.minZoom = options.minzoom;
if (options.maxzoom !== false ) mapOptions.maxZoom = options.maxzoom;
if (options.enablefullscreen) {
mapOptions.fullscreenControl = true;
mapOptions.fullscreenControlOptions= {
position: 'topleft'
};
}
mapOptions.scrollWheelZoom = options.scrollwheelzoom;
if (options.static) {
mapOptions.scrollWheelZoom = false;
mapOptions.doubleClickZoom = false;
mapOptions.touchZoom = false;
mapOptions.boxZoom = false;
mapOptions.tap = false;
mapOptions.keyboard = false;
mapOptions.zoomControl = false;
mapOptions.dragging = false;
}
var map = L.map( this.get(0), mapOptions ).fitWorld();
this.map = map;
var layers = {};
$.each(options.layers.reverse(), function(index, layerName) {
var options = {} ;
var providerName = layerName.split('.')[0] ;
if (apikeys.hasOwnProperty(providerName) && apikeys[providerName] !== '') {
options.apikey = apikeys[providerName] ;
}
if (layerName === 'MapQuestOpen') {
layers[layerName] = new MQ.TileLayer().addTo(map);
} else {
layers[layerName] = new L.tileLayer.provider(layerName,options).addTo(map);
}
});
var overlaylayers = {};
$.each(options.overlaylayers, function(index, overlaylayerName) {
overlaylayers[overlaylayerName] = new L.tileLayer.provider(overlaylayerName).addTo(_this.map);
});
if (options.layers.length > 1) {
L.control.layers(layers, overlaylayers).addTo(map);
}
if (options.resizable) {
//TODO: Fix moving map when resized
_this.resizable();
}
if (!options.locations) {
options.locations = [];
}
// Add the markers.
for (var i = options.locations.length - 1; i >= 0; i--) {
this.addMarker(options.locations[i]);
}
// Add markercluster
if (options.markercluster) {
this.createMarkerCluster();
}
// Add lines
if (options.lines) {
for (var i = 0; i < options.lines.length; i++) {
this.addLine(options.lines[i]);
}
}
// Add polygons
if (options.polygons) {
for (var i = 0; i < options.polygons.length; i++) {
this.addPolygon(options.polygons[i]);
}
}
// Add circles
if (options.circles) {
for (var i = 0; i < options.circles.length; i++) {
this.addCircle(options.circles[i]);
}
}
// Add rectangles
if (options.rectangles) {
for (var i = 0; i < options.rectangles.length; i++) {
this.addRectangle(options.rectangles[i]);
}
}
this.addGeoJson(options);
// Set map position (centre and zoom)
var centre;
if (options.centre === false) {
switch ( this.points.length ) {
case 0:
centre = new L.LatLng(0, 0);
break;
case 1:
centre = this.points[0];
break;
default:
var bounds = new L.LatLngBounds( this.points );
if (options.zoom === false) {
map.fitBounds( bounds );
centre = false;
} else {
centre = bounds.getCenter();
}
break;
}
this.points = [];
} else {
centre = new L.LatLng(options.centre.lat, options.centre.lon);
}
if(centre) {
map.setView( centre, options.zoom !== false ? options.zoom : options.defzoom );
}
};
this.getDependencies = function ( options ) {
var dependencies = [];
if (options.layers !== ['MapQuestOpen'] || options.overlaylayers.length > 0) {
dependencies.push( 'ext.maps.leaflet.providers' );
}
if (options.enablefullscreen) {
dependencies.push( 'ext.maps.leaflet.fullscreen' );
}
if (options.resizable) {
dependencies.push( 'ext.maps.resizable' );
}
if (options.markercluster) {
dependencies.push( 'ext.maps.leaflet.markercluster' );
}
return dependencies;
};
mw.loader.using( this.getDependencies( options ) ).then( function() {
_this.setup();
} );
return this;
};
})(jQuery, window.mediaWiki, L, window.MQ);