Building on my previous post, I have improved the mapping of leads.
Hot on the heels of Plot your Salesforce leads on a map, I’ve made some updates to the code to improve the experience and provide some additional functionality.
Remove the custom fields on the user object
The field “Base location” on the User object doesn’t need to be queried anymore, so it can be removed.
Modify the Server-side controller class
Next, open the developer console and open the “LeadVisualiserSSController” Apex class. Change the class definition to this:
public with sharing class LeadVisualiserSSController {
@AuraEnabled
public static List<Lead> getLeads() {
return [
SELECT Id, Name, Latitude, Longitude
FROM Lead
WHERE OwnerId = :UserInfo.getUserId() AND Latitude != NULL AND Longitude != NULL
];
}
}
We’ve removed the call to get details about the user.
Component
Modify the lightning component markup to remove references to the user data:
<aura:component implements="force:appHostable" controller="LeadVisualiserSSController">
<aura:attribute name="leads" type="Lead[]" />
<ltng:require styles="/resource/leaflet/leaflet.css" />
<ltng:require scripts="/resource/leaflet/leaflet.js" afterScriptsLoaded="{!c.mapLoaded}" />
<div class="map" id="map"></div>
</aura:component>
Controller
The controller code gets slimmed down now we’re not querying for user details. However, we now link to the lead record and re-calculate the distance to the leads based on the users lat/long. The map also follows the user. Lastly, we add a marker for the user in the maps centre. Phew!
({
mapLoaded: function(component, event, helper) {
var leadsAction = component.get("c.getLeads");
var leads = {};
var map = window.L.map("map", {zoomControl: true, center: [51.505, -0.00], zoom: 16});
var userPosition;
var userLatLng;
var leadPopups = [];
// https://github.com/pointhi/leaflet-color-markers
var redIcon = new L.Icon({
iconUrl: "https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-red.png",
shadowUrl: "https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png",
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
// Draw the map
window.L.tileLayer("https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}",
{
attribution: "Tiles © Esri"
}).addTo(map);
// Center the map
map.locate({watch: true, setView: true, maxZoom: 16});
// Draw the user
userLatLng = map.getCenter();
userPosition = L.marker([userLatLng.lat, userLatLng.lng], {icon: redIcon}).addTo(map);
// Draw the markers, including links to the lead records
// - Whenever a popup is opened, call the function
leadsAction.setCallback(
this,
function(response) {
var state = response.getState();
if (component.isValid() && state === "SUCCESS") {
leads = response.getReturnValue();
component.set("v.leads", leads);
// Get all Leads, plot as Markers
for (var i = 0; i < leads.length; i++) {
if (leads[i].Latitude !== null && leads[i].Longitude !== null) {
leadPopups[i] = L.marker([leads[i].Latitude, leads[i].Longitude])
.bindPopup("<a href=\"/one/one.app#/sObject/" +
leads[i].Id + "/view\">" + leads[i].Name +
"</a><br /><br />Distance from your location: " +
helper.calculateHaversineDistance(leads[i].Latitude, leads[i].Longitude, userLatLng.lat, userLatLng.lng) +
" miles"
)
.addTo(map);
}
}
}
// Update the user position whenever the map center updates
map.on("locationfound", function(e) {
userPosition.setLatLng(e.latlng);
userLatLng = map.getCenter();
if (leadPopups !== null && leadPopups !== undefined) {
for (var i = 0; i < leadPopups.length; i++) {
leadPopups[i].setPopupContent("<a href=\"/one/one.app#/sObject/" +
leads[i].Id + "/view\">" + leads[i].Name +
"</a><br /><br />Distance from your location: " +
helper.calculateHaversineDistance(leads[i].Latitude, leads[i].Longitude, userLatLng.lat, userLatLng.lng) +
" miles");
}
}
});
}
);
$A.enqueueAction(leadsAction);
}
})
Helper
The help stays exactly the same:
({
// Calculate the Haversine Distance between a pair of lat/long co-ordinates.
// See "What formulae does the Geolocation Distance" at http://salesforce.stackexchange.com/questions/32585/what-formulae-does-the-geolocation-distance-use for more information
calculateHaversineDistance: function(lat1, lon1, lat2, lon2) {
// Earth's radius varies from 6356.752 km at the poles to 6378.137 km at the equator
var radius = 6371.00;
var dLat = this.toRadians(lat2 - lat1);
var dLon = this.toRadians(lon2 - lon1);
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(this.toRadians(lat1)) * Math.cos(this.toRadians(lat2)) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.asin(Math.sqrt(a));
var kmToMiles = 0.621371;
return (radius * c * kmToMiles).toFixed(2);
},
// Given a degree, calculate the value in radians
toRadians: function(degree) {
return ((degree * 3.1415926) / 180);
}
})
Styling
This one stays as simple as before, thankfully!
.THIS.map {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
Try it!
Finally, load the component in Salesforce Lightning. From the App Launcher, select “Other Items” and select “Lead Visualiser”. Here’s the finished result.
With a few code modifications (and much slimming down), we’re able to dramatically improve the experience!
I’ve shared this code on Github also: https://github.com/aaronallport/SFMapLeadsNearMe