I've inherited this IIFE javascript function and tasked to add the markerCluster addon. But there are no examples I can find that shows how to add it to such a function.
Here's the function:
var map = function() {
var self = {
config: {
circleMarker: function(point, feature) {
return new L.circleMarker(point, {
fillColor: "#DA3248",
fillOpacity: 0.8,
color: "white",
radius: 9,
className: "event-marker campaign-" + feature.properties.campaign_name +
" event-accessible-" + (feature.properties.is_accessible ? "y" : "n")
});
},
Marker: function(point, feature) {
return new L.circleMarker(point, {
fillColor: "#2B9CD9",
fillOpacity: 1.0,
color: "white",
radius: 9,
strokeWidth: 1,
className: "event-marker campaign-" + feature.properties.campaign_name + " event-accessible-" + (feature.properties.is_accessible ? "y" : "n")
});
},
tileLayer: new L.tileLayer('https://{s}.tiles.mapbox.com/v4/mapbox.streets/{z}/{x}/{y}.png?access_token=' + MAPBOX_TOKEN, {
attribution: '<a href="http://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>'
})
},
data: {},
init: function() {
self.init_map();
self.lc = L.control.locate({
keepCurrentZoomLevel: false,
locateOptions: {
maxZoom: 10
},
strings: {
title: "Locate me"
}
}).addTo(self.map);
},
init_map: function() {
self.map = new L.Map("map", {
center: [37.8, -96.9],
zoom: self.get_init_zoom(),
tap: false
}).addLayer(self.config.tileLayer);
self.load_event_data();
self.load_zip_codes();
self.bind_events();
self.handle_filter_params();
},
handle_filter_params: function() {
var event_types = new URLSearchParams(window.location.search).get("event_types");
if (event_types == null) {
return;
}
event_types = event_types.split(',');
var filters = document.querySelectorAll('#filter-type-list input[name="type[]"]');
for (var i = 0; i < filters.length; i++) {
var filter = filters[i];
if (event_types.indexOf(filter.getAttribute('id')) == -1) {
filter.click();
}
}
},
bind_events: function() {
document.getElementById('zipcode').addEventListener('keyup', self.handle_zipcode_keydown);
document.getElementById('filter-type-list').addEventListener('click', self.handle_filter_type_click);
document.getElementById('distance').addEventListener('change', self.handle_radius_change);
self.map.on('moveend', self.filter_events_by_viewport);
self.map._container.addEventListener('mouseover', self.handle_map_hover);
self.map._container.addEventListener('mouseout', self.handle_map_mouseout);
},
is_mobile: function() {
return window.navigator.userAgent.toLowerCase().indexOf('mobile') !== -1;
},
get_init_zoom: function() {
if (!self.is_mobile()) {
return 4;
} else {
return 3;
}
},
filter_events_by_viewport: function() {
if (self.map.getZoom() < 8) {
self.clear_events_list();
} else {
var center = self.map.getCenter();
var bounds = self.map.getBounds();
var events = [];
window.bounds = bounds;
for (var i = 0; i < self.data.events.features.length; i++) {
var event = self.data.events.features[i];
var coords = event.geometry.coordinates;
var p = L.latLng(coords[1], coords[0]);
if (bounds.contains(p)) {
events.push(event);
}
}
events = self.sort_by_distance(events, center);
self.data.filtered_events = events;
self.populate_events_list();
}
},
sort_by_distance: function(events, center) {
for (var i = 0; i < events.length; i++) {
var event = events[i];
event.distance = center.distanceTo(L.latLng(event.geometry.coordinates[1], event.geometry.coordinates[0]));
}
events.sort(function(a, b) {
return a.distance - b.distance
});
return events;
},
handle_filter_type_click: function() {
if (event.target.tagName != 'INPUT') {
return;
}
var events_list = document.getElementById('events-list');
var event_accessible_id = 'event_accessible';
var event_accessible_toggle_class = 'event-show-accessible';
if (event.target.id == event_accessible_id) {
self.map._container.classList.toggle(event_accessible_toggle_class);
events_list.classList.toggle(event_accessible_toggle_class);
} else if (event.target.checked) {
self.map._container.classList.remove('hide-campaign-' + event.target.value);
events_list.classList.remove('hide-campaign-' + event.target.value);
} else {
self.map._container.classList.add('hide-campaign-' + event.target.value);
events_list.classList.add('hide-campaign-' + event.target.value);
}
},
handle_radius_change: function(event) {
if (event.target.tagName != 'SELECT') {
return;
}
var value = event.target.options[event.target.selectedIndex].value;
if (value == "5") {
self.map.setZoom(12);
} else if (value == "20") {
self.map.setZoom(10);
} else if (value == "50") {
self.map.setZoom(9);
} else if (value == "100") {
self.map.setZoom(6);
}
},
handle_zipcode_keydown: function(event) {
if (event.target.value.length != 5) {
return;
}
var latlng = self.data.zipcodes[event.target.value];
if(latlng != undefined){
self.map.setView(new L.LatLng(latlng[0], latlng[1]), 9, {
pan: true
});
}
},
load_event_data: function() {
self.xhr('GET', events_url, function(xhr) {
var newJson = JSON.parse(xhr.responseText);
var oldJson = {};
oldJson["type"]="FeatureCollection";
oldJson["features"] = [];
for (var i = 0; i < newJson.data.length; i++) {
if(newJson.data[i]['location'] != undefined) {
var address1="";
var address2="";
if(newJson.data[i]['location']['address_lines'] != undefined){
address1= newJson.data[i]['location']['address_lines'][0];
address2= newJson.data[i]['location']['address_lines'][1];
}
var city="";
if(newJson.data[i]['location']['locality'] != undefined){
city = newJson.data[i]['location']['locality'];
}
var postal_code="";
if(newJson.data[i]['location']['postal_code'] != undefined){
postal_code = newJson.data[i]['location']['postal_code'];
}
var region="";
if(newJson.data[i]['location']['region'] != undefined){
region = newJson.data[i]['location']['region'];
}
var start_time="";
var end_time="";
if(newJson.data[i]['timeslots'][0] != undefined){
var lengthOfTimeslots=newJson.data[i]['timeslots'];
start_time = newJson.data[i]['timeslots'][0]['start_date'];
if(newJson.data[i]['timeslots'][lengthOfTimeslots-1] != undefined && newJson.data[i]['timeslots'][lengthOfTimeslots-1]['end_date'] != undefined ){
end_time = newJson.data[i]['timeslots'][lengthOfTimeslots-1]['end_date'];
}else{
end_time = newJson.data[i]['timeslots'][0]['end_date'];
}
}
var features = {
"type": "Feature",
"properties": {
"id": newJson.data[i]['id'],
"campaign_name": newJson.data[i]['event_type'],
"title": newJson.data[i]['title'],
"starts_at": (new Date(start_time*1000)).toLocaleString("en-US", {timeZone: newJson.data[i]['timezone']}),
"ends_at": (new Date(end_time*1000)).toLocaleString("en-US", {timeZone: newJson.data[i]['timezone']}),
"is_accessible": true,
"status":"active",
"address1": address1,
"address2": address2,
"city": city,
"state": region,
"is_private":false,
"venue":"Private",
"starts_at_utc":(new Date(start_time*1000)).toUTCString(),
"ends_at_utc":(new Date(end_time*1000)).toUTCString(),
"zip": postal_code
},
"geometry": {
"type": "Point",
"coordinates": [
newJson.data[i]['location']['location']['longitude'],
newJson.data[i]['location']['location']['latitude']
]
},
};
oldJson["features"].push(features);
}
}
self.data.events = oldJson;
L.geoJson(self.data.events, {
pointToLayer: function(feature, latlng) {
if (['-town-hall', '-rally-campaign'].indexOf(feature.properties.campaign_name) !== -1) {
return self.config.Marker(latlng, feature);
} else {
return self.config.circleMarker(latlng, feature);
}
},
onEachFeature: function(feature, layer) {
var tpl = document.getElementById('popup-template').innerHTML;
var event = feature.properties;
layer.bindPopup(eval("`" + tpl + "`"), {
className: 'event',
maxWidth: 260
});
layer.addTo(self.map);
}
}).addTo(self.map);
});
},
load_zip_codes: function() {
self.xhr('GET', zipcodes_url, function(xhr) {
self.data.zipcodes = JSON.parse(xhr.responseText);
});
},
clear_events_list: function() {
var events_list = document.getElementById('events-list');
while (events_list.firstChild) {
events_list.removeChild(events_list.firstChild);
}
},
populate_events_list: function() {
self.clear_events_list();
var tpl = document.getElementById('event-template').innerHTML;
var events_list_frag = document.createDocumentFragment();
for (var i = 0; i < self.data.filtered_events.length; i++) {
var event = self.data.filtered_events[i].properties;
var item = document.createElement('li');
item.setAttribute('class', 'event campaign-' + event.campaign_name + " event-accessible-" + (event.is_accessible ? "y" : "n"));
item.innerHTML = eval("`" + tpl + "`");
item.setAttribute('data-id', event.id);
item.setAttribute('data-date', moment(event.starts_at_utc).format("X"));
var coords = self.data.filtered_events[i]['geometry']['coordinates'];
item.setAttribute('data-point', JSON.stringify(coords));
events_list_frag.appendChild(item);
}
var events_list = document.getElementById('events-list');
events_list.appendChild(events_list_frag);
},
xhr: function(method, url, callback, data) {
if (typeof data == "undefined") {
data = null;
}
var xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.send(data);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
callback(xhr);
}
}
},
signup_url: function(event) {
var base = "https://www.mobilize.us/event/";
return base + event.id;
}
};
self.init();
}();
I've tried adding the cluster by editing here:
init: function() {
self.init_map();
self.lc = L.control.locate({
keepCurrentZoomLevel: false,
locateOptions: {
maxZoom: 10
},
strings: {
title: "Locate me"
}
}).addTo(self.map);
self.cluster = L.markerClusterGroup({ disableClusteringAtZoom: 17 });
},
and here:
onEachFeature: function(feature, layer) {
var tpl = document.getElementById('popup-template').innerHTML;
var event = feature.properties;
layer.bindPopup(eval("`" + tpl + "`"), {
className: 'event',
maxWidth: 260
});
cluster.addLayer(layer);
layer.addTo(self.map);
}
}).addTo(self.map).addLayer(cluster);
But it shows cluster
is not defined. I have to admit, I'm not familiar with IIFE functions, and I suspect my placement for cluster
is incorrect.
To add the plugin to your IIFE you should create one more function for instance exactly under the init
function and instantiate the plugin like this:
...
cluster: function() {
var markers = L.markerClusterGroup();
for (var i = 0; i < addressPoints.length; i++) {
var a = addressPoints[i];
var title = a[2];
var marker = L.marker(new L.LatLng(a[0], a[1]), {
title: title
});
marker.bindPopup(title);
markers.addLayer(marker);
}
self.map.addLayer(markers);
},
...
and then invoke it inside init
function
init_map: function() {
self.map = new L.Map("map", {
center: [37.8, -96.9],
zoom: self.get_init_zoom(),
tap: false
}).addLayer(self.config.tileLayer);
/* self.load_event_data();
self.load_zip_codes();
*/
//self.bind_events();
//self.handle_filter_params();
// invoke the function here
self.cluster();
},
I temporary commented some other function invocations because there were returning some errors just to be able to reproduce the issue and run the code.
If you pan the map and go to new Zealand you will the see the marker clusters exactly like the example in the plugin demonstration page.