Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions commcare_connect/microplanning/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ def test_queryset_annotates_location_point(self, opportunity, visit_data):

assert round(visit["location_point"].x, 1) == 77.1
assert round(visit["location_point"].y, 1) == 28.6
assert visit["work_area_id"] == visit_data.work_area.id

def test_queryset_only_includes_visits_for_opportunity(self, opportunity, visit_data):
other_opp = OpportunityFactory()
Expand Down
4 changes: 2 additions & 2 deletions commcare_connect/microplanning/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ def get_layers(self):

class UserVisitVectorLayer(VectorLayer):
id = "user-visits"
tile_fields = ()
tile_fields = ("work_area_id",)
geom_field = "location_point"
min_zoom = WORKAREA_MIN_ZOOM

Expand Down Expand Up @@ -342,7 +342,7 @@ def get_queryset(self):
output_field=PointField(srid=4326),
)
)
.values("location_point")
.values("location_point", "work_area_id")
)


Expand Down
110 changes: 93 additions & 17 deletions commcare_connect/templates/microplanning/map_handler.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
Alpine.data("mapController", () => ({
map: null,
selectedFeature: null,
highlightedWorkAreaId: null,
showWorkAreaEditModal: false,
showVisits: false,
filterQuery: '',
Expand Down Expand Up @@ -35,6 +36,84 @@
.then(() => this.showWorkAreaEditModal = true)
},

updateHighlightedWorkAreaId() {
this.highlightedWorkAreaId = (this.assignmentMode || !this.selectedFeature)
? null
: this.selectedFeature._id;
},

buildVisitCirclePaint() {
const hasSelection = this.highlightedWorkAreaId !== null;
return {
'circle-radius': [
'interpolate', ['linear'], ['zoom'],
8, 2,
14, 5,
],
'circle-color': '#e74c3c',
'circle-opacity': hasSelection ? 0.2 : 0.7,
'circle-stroke-width': 1,
'circle-stroke-color': '#ffffff',
'circle-stroke-opacity': 0.5,
};
},

addVisitHighlightLayer() {
if (!this.map || this.map.getLayer('user-visits-highlight')) return;
this.map.addLayer({
id: 'user-visits-highlight',
type: 'symbol',
source: 'user-visits',
'source-layer': 'user-visits',
layout: {
'text-field': '◆',
'text-size': [
'interpolate', ['linear'], ['zoom'],
8, 13,
14, 22,
],
'text-font': ['DIN Pro Medium', 'Arial Unicode MS Regular'],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Can these be replaced with commonly available fonts or browser generics like "Sans", "Serif" etc?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got the following response after investigating it with Claude:

text-font here isn't a CSS font — Mapbox GL renders text from SDF glyphs served by the style's glyphs endpoint, so the value has to match a font the active style actually ships. Generics like Sans/Serif aren't resolved and the layer would fail to render glyphs. DIN Pro Medium + Arial Unicode MS Regular are the fonts bundled with the mapbox://styles/mapbox/standard style we're using (Arial Unicode is the standard CJK fallback). Happy to swap to another Mapbox-hosted stack if you'd prefer, but browser generics won't work here.

Given the above, I'm opted to keep the current font as it ships with the Mapbox style. For verification I did switch it to Sans font and received a 404 error in the browser's dev console which confirms that generic fonts won't work.

'text-allow-overlap': true,
'text-ignore-placement': true,
'visibility': 'none',
},
paint: {
'text-color': '#22c55e',
'text-halo-color': '#000000',
'text-halo-width': 2.5,
},
});
},

refreshVisitStyling() {
if (!this.map) return;

if (this.map.getLayer('user-visits-circle')) {
this.map.setPaintProperty(
'user-visits-circle',
'circle-opacity',
this.highlightedWorkAreaId !== null ? 0.2 : 0.7,
);
}

if (this.map.getLayer('user-visits-highlight')) {
const id = this.highlightedWorkAreaId;
if (id === null) {
this.map.setLayoutProperty('user-visits-highlight', 'visibility', 'none');
} else {
this.map.setFilter(
'user-visits-highlight',
['==', ['get', 'work_area_id'], id],
);
this.map.setLayoutProperty(
'user-visits-highlight',
'visibility',
this.showVisits ? 'visible' : 'none',
);
}
}
},
Comment thread
coderabbitai[bot] marked this conversation as resolved.

getDownloadUrl() {
const baseUrl = '{{ download_url|escapejs }}';
return this.filterQuery ? `${baseUrl}?${this.filterQuery}` : baseUrl;
Expand Down Expand Up @@ -339,6 +418,9 @@
this.initializeMap();
});

this.$watch('selectedFeature', () => this.updateHighlightedWorkAreaId());
this.$watch('highlightedWorkAreaId', () => this.refreshVisitStyling());

if (this.assignmentMode) {
const assigneesEl = document.getElementById('assignees-data');
if (assigneesEl) this.assignees = JSON.parse(assigneesEl.textContent);
Expand Down Expand Up @@ -566,26 +648,20 @@
type: 'circle',
source: 'user-visits',
'source-layer': 'user-visits',
paint: {
'circle-radius': [
'interpolate', ['linear'], ['zoom'],
8, 2,
14, 5
],
'circle-color': '#e74c3c',
'circle-opacity': 0.7,
'circle-stroke-width': 1,
'circle-stroke-color': '#ffffff',
'circle-stroke-opacity': 0.5,
}
paint: this.buildVisitCirclePaint(),
});
this.addVisitHighlightLayer();
visitsLayerAdded = true;
this.refreshVisitStyling();
} else if (visitsLayerAdded) {
this.map.setLayoutProperty(
'user-visits-circle',
'visibility',
visible ? 'visible' : 'none'
);
this.map.setLayoutProperty('user-visits-circle', 'visibility', visible ? 'visible' : 'none');
if (this.map.getLayer('user-visits-highlight')) {
if (!visible) {
this.map.setLayoutProperty('user-visits-highlight', 'visibility', 'none');
} else {
this.refreshVisitStyling();
}
}
}
});

Expand Down
Loading