Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optmise Disbursement layers on map #35516

Merged
merged 12 commits into from
Dec 17, 2024
83 changes: 35 additions & 48 deletions corehq/apps/geospatial/static/geospatial/js/case_management.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'use strict';

Check warning on line 1 in corehq/apps/geospatial/static/geospatial/js/case_management.js

View workflow job for this annotation

GitHub Actions / Lint Javascript

'use strict' is unnecessary inside of modules

hqDefine("geospatial/js/case_management", [
"jquery",
Expand Down Expand Up @@ -65,43 +65,33 @@

self.handleDisbursementResults = function (result) {
// Clean stale disbursement results
mapModel.removeDisbursementLayers();
mapModel.removeDisbursementLayer();

let groupId = 0;
mapModel.caseGroupsIndex = {};
Object.keys(result).forEach((userId) => {
const user = mapModel.userMapItems().find((userModel) => {return userModel.itemId === userId;});
mapModel.caseGroupsIndex[userId] = {groupId: groupId, item: user};

let cases = [];
mapModel.caseMapItems().forEach((caseModel) => {
if (result[userId].includes(caseModel.itemId)) {
cases.push(caseModel);
mapModel.caseGroupsIndex[caseModel.itemId] = {
groupId: groupId,
item: caseModel,
assignedUserId: userId,
};
}
});
self.connectUserWithCasesOnMap(user, cases);
groupId += 1;
});
self.connectUserWithCasesOnMap();
self.setBusy(false);
};

self.clearConnectionLines = function (cases) {
let mapInstance = mapModel.mapInstance;
self.getCasesForDisbursement = function (cases) {
let caseData = [];
const hasSelectedCases = mapModel.hasSelectedCases();
cases.forEach(function (c) {
const layerId = mapModel.getLineFeatureId(c.itemId);
if (mapInstance.getLayer(layerId)) {
mapInstance.removeLayer(layerId);
}
if (mapInstance.getSource(layerId)) {
mapInstance.removeSource(layerId);
}

// Either select all if none selected, or only pick selected cases
if (!hasSelectedCases || c.isSelected()) {
caseData.push({
Expand All @@ -111,13 +101,13 @@
});
}
});

return caseData;
};

self.runCaseDisbursementAlgorithm = function (cases, users) {
self.setBusy(true);
const caseData = self.clearConnectionLines(cases);
mapModel.removeDisbursementLayer();
const caseData = self.getCasesForDisbursement(cases);

self.setDisbursementParameters = function (parameters) {
var parametersList = [
Expand Down Expand Up @@ -181,38 +171,35 @@
});
};

self.connectUserWithCasesOnMap = function (user, cases) {
cases.forEach((caseModel) => {
const lineCoordinates = [
[user.itemData.coordinates.lng, user.itemData.coordinates.lat],
[caseModel.itemData.coordinates.lng, caseModel.itemData.coordinates.lat],
];
let mapInstance = mapModel.mapInstance;
mapInstance.addLayer({
id: mapModel.getLineFeatureId(caseModel.itemId),
type: 'line',
source: {
type: 'geojson',
data: {
self.connectUserWithCasesOnMap = function () {
let disbursementLinesSource = generateDisbursementLinesSource();
mapModel.addDisbursementLinesLayer(disbursementLinesSource);
};

function generateDisbursementLinesSource() {
let disbursementLinesSource = {
'type': 'FeatureCollection',
'features': [],
};
for (const itemId of Object.keys(mapModel.caseGroupsIndex)) {
let element = mapModel.caseGroupsIndex[itemId];
if ('assignedUserId' in element) {
let user = mapModel.caseGroupsIndex[element.assignedUserId].item;
const lineCoordinates = [
[user.itemData.coordinates.lng, user.itemData.coordinates.lat],
[element.item.itemData.coordinates.lng, element.item.itemData.coordinates.lat],
];
disbursementLinesSource.features.push(
{
type: 'Feature',
properties: {},
geometry: {
type: 'LineString',
coordinates: lineCoordinates,
},
},
},
layout: {
'line-join': 'round',
'line-cap': 'round',
},
paint: {
'line-color': '#808080',
'line-width': 1,
},
});
});
};
geometry: { type: 'LineString', coordinates: lineCoordinates },
}
);
}
}
return disbursementLinesSource;
}

return self;
};
Expand Down Expand Up @@ -520,8 +507,8 @@
if (polygonFilterModel) {
selectMapItemsInPolygons();
}
if (mapModel.hasDisbursementLayers()) {
mapModel.removeDisbursementLayers();
if (mapModel.hasDisbursementLayer()) {
mapModel.removeDisbursementLayer();
}
}
});
Expand Down
68 changes: 35 additions & 33 deletions corehq/apps/geospatial/static/geospatial/js/models.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'use strict';

Check warning on line 1 in corehq/apps/geospatial/static/geospatial/js/models.js

View workflow job for this annotation

GitHub Actions / Lint Javascript

'use strict' is unnecessary inside of modules
hqDefine('geospatial/js/models', [
'jquery',
'knockout',
Expand Down Expand Up @@ -131,6 +131,8 @@

self.caseGroupsIndex = {};

self.DISBURSEMENT_LINES_LAYER_ID = 'disbursement-lines';

self.initMap = function (mapDivId, centerCoordinates) {
mapboxgl.accessToken = initialPageData.get('mapbox_access_token'); // eslint-disable-line no-undef
if (!centerCoordinates) {
Expand Down Expand Up @@ -513,24 +515,38 @@
});
};

self.hasDisbursementLayers = function () {
const mapLayers = self.mapInstance.getStyle().layers;
return _.any(
mapLayers,
function (layer) { return layer.id.includes(DISBURSEMENT_LAYER_PREFIX); }
);
self.hasDisbursementLayer = function () {
return self.mapInstance.getLayer(self.DISBURSEMENT_LINES_LAYER_ID);
};

self.removeDisbursementLayers = function () {
const mapLayers = self.mapInstance.getStyle().layers;
let layerRemoved = false;
mapLayers.forEach(function (layer) {
if (layer.id.includes(DISBURSEMENT_LAYER_PREFIX)) {
self.mapInstance.removeLayer(layer.id);
layerRemoved = true;
}
self.addDisbursementLinesLayer = function (source) {
let layerId = self.DISBURSEMENT_LINES_LAYER_ID;
self.mapInstance.addSource(layerId, {
'type': 'geojson',
'data': source,
});
return layerRemoved;
self.mapInstance.addLayer({
id: layerId,
type: 'line',
source: layerId,
layout: {
'line-join': 'round',
'line-cap': 'round',
},
paint: {
'line-color': '#808080',
'line-width': 1,
},
});
};

self.removeDisbursementLayer = function () {
if (self.mapInstance.getLayer(self.DISBURSEMENT_LINES_LAYER_ID)) {
self.mapInstance.removeLayer(self.DISBURSEMENT_LINES_LAYER_ID);
}
if (self.mapInstance.getSource(self.DISBURSEMENT_LINES_LAYER_ID)) {
self.mapInstance.removeSource(self.DISBURSEMENT_LINES_LAYER_ID);
}
};

self.hasSelectedUsers = function () {
Expand Down Expand Up @@ -685,11 +701,11 @@

function clearDisbursementBeforeProceeding() {
let proceedFurther = true;
if (self.mapObj.hasDisbursementLayers()) {
if (self.mapObj.hasDisbursementLayer()) {
// hide it by default and show it only if necessary
$('#disbursement-clear-message').hide();
if (confirmForClearingDisbursement()) {
self.mapObj.removeDisbursementLayers();
self.mapObj.removeDisbursementLayer();
$('#disbursement-clear-message').show();
$('#disbursement-params').hide();
} else {
Expand Down Expand Up @@ -1002,29 +1018,15 @@
};

self.finishAssignment = function () {
let userCasesToConnect = {};
let casesToClear = [];
for (const caseItem of self.caseData) {
const userItem = self.mapModel.caseGroupsIndex[caseItem.assignedUserId];
const groupId = (userItem) ? userItem.groupId : null;
self.mapModel.caseGroupsIndex[caseItem.caseId].assignedUserId = caseItem.assignedUserId;
self.mapModel.caseGroupsIndex[caseItem.caseId].groupId = groupId;

casesToClear.push(caseItem.mapItem);
if (caseItem.assignedUserId) {
if (!userCasesToConnect[caseItem.assignedUserId]) {
userCasesToConnect[caseItem.assignedUserId] = [];
}
userCasesToConnect[caseItem.assignedUserId].push(caseItem.mapItem);
}
}

self.disbursementModel.clearConnectionLines(casesToClear);
for (const userId in userCasesToConnect) {
const user = self.mapModel.caseGroupsIndex[userId].item;
const cases = userCasesToConnect[userId];
self.disbursementModel.connectUserWithCasesOnMap(user, cases);
}
self.mapModel.removeDisbursementLayer();
self.disbursementModel.connectUserWithCasesOnMap();
};

self.exportAssignments = function () {
Expand Down
Loading