Skip to content

Commit

Permalink
feat: Pre solve map layers controls (#197)
Browse files Browse the repository at this point in the history
  • Loading branch information
jmccollum-woolpert authored Jan 23, 2025
1 parent 3902328 commit e3497ee
Show file tree
Hide file tree
Showing 11 changed files with 72 additions and 67 deletions.
4 changes: 2 additions & 2 deletions application/frontend/src/app/core/actions/map.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const editPreSolveVehicle = createAction(

export const editVisit = createAction('[Map] Edit Visit', props<{ visitId: number }>());

export const setPostSolveLayerVisible = createAction(
'[Map] Set Post Solve Layer Visible',
export const setLayerVisible = createAction(
'[Map] Set Layer Visible',
props<{ layerId: MapLayerId; visible: boolean }>()
);
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
border: none;
box-shadow: none;
gap: 1rem;
position: absolute;
top: 0;
left: 50px;
margin: 10px;
}

.add-button {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
position: relative;
}

app-post-solve-map-legend {
.map-controls {
position: absolute;
z-index: 1;
top: 10px;
left: 50px;
display: flex;
gap: 1rem;
}

app-map-type-button {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
<app-map-wrapper [options]="options$ | async" (mapInitialize)="onMapInitialize($event)">
</app-map-wrapper>
<app-post-solve-map-legend
*ngIf="!isPreSolve()"
[mapLayers]="layers$ | async"
(setLayerVisibility)="onSetLayerVisibility($event)">
</app-post-solve-map-legend>
<app-map-add-buttons
*ngIf="isPreSolve()"
(addShipment)="addShipment()"
(addVehicle)="addVehicle()"></app-map-add-buttons>
<div class="map-controls">
<app-post-solve-map-legend
[mapLayers]="layers$ | async"
(setLayerVisibility)="onSetLayerVisibility($event)">
</app-post-solve-map-legend>
<app-map-add-buttons
*ngIf="isPreSolve()"
(addShipment)="addShipment()"
(addVehicle)="addVehicle()"></app-map-add-buttons>
</div>
<app-map-type-button (typeChange)="onTypeChange($event)"> </app-map-type-button>
<app-toggle-selection-filter-button
*ngIf="mapSelectionToolsVisible$ | async"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export class MapComponent implements OnInit, OnDestroy {
this.options$ = this.store.pipe(select(fromConfig.selectMapOptions), take(1));
this.mapSelectionToolsVisible$ = this.store.pipe(select(selectMapSelectionToolsVisible));
this.selectionFilterActive$ = this.store.pipe(select(selectSelectionFilterActive));
this.layers$ = this.store.pipe(select(fromMap.selectPostSolveMapLayers));
this.layers$ = this.store.pipe(select(fromMap.selectUsedMapLayers));
this.travelSimulatorVisible$ = this.store.pipe(
select(TravelSimulatorSelectors.selectTravelSimulatorVisible)
);
Expand Down Expand Up @@ -131,14 +131,15 @@ export class MapComponent implements OnInit, OnDestroy {
this.store.pipe(select(fromPreSolve.selectActive)),
this.store.pipe(select(fromPostSolve.selectActive)),
this.store.pipe(select(fromUI.selectHasMap)),
this.store.pipe(select(fromMap.selectPostSolveMapLayers)),
]).subscribe(([preSolve, postSolve, hasMap, postSolveMapLayers]) => {
this.store.pipe(select(fromMap.selectUsedMapLayers)),
]).subscribe(([preSolve, postSolve, hasMap, visibleMapLayers]) => {
this.routeLayer.visible = hasMap && postSolve;
this.preSolveVehicleLayer.visible = hasMap && preSolve;
this.preSolveVisitRequestLayer.visible = hasMap && preSolve;
this.preSolveVisitRequestLayer.visible =
hasMap && preSolve && visibleMapLayers[MapLayerId.VisitRequests].visible;
this.postSolveVehicleLayer.visible = hasMap && postSolve;
this.postSolveVisitRequestLayer.visible =
hasMap && postSolve && postSolveMapLayers[MapLayerId.PostSolveVisitRequests].visible;
hasMap && postSolve && visibleMapLayers[MapLayerId.VisitRequests].visible;
this.depotLayer.visible = hasMap;
}),

Expand Down Expand Up @@ -262,7 +263,7 @@ export class MapComponent implements OnInit, OnDestroy {

onSetLayerVisibility(event: { layerId: MapLayerId; visible: boolean }): void {
this.store.dispatch(
MapActions.setPostSolveLayerVisible({ layerId: event.layerId, visible: event.visible })
MapActions.setLayerVisible({ layerId: event.layerId, visible: event.visible })
);
}
}
6 changes: 3 additions & 3 deletions application/frontend/src/app/core/models/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ limitations under the License.
import { TravelMode } from './dispatcher.model';

export enum MapLayerId {
PostSolveVisitRequests,
PostSolveFourWheel,
PostSolveWalking,
VisitRequests,
FourWheel,
Walking,
}

export interface MapLayer {
Expand Down
22 changes: 11 additions & 11 deletions application/frontend/src/app/core/reducers/map.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,23 @@ import { TravelMode } from '../models';
export const mapFeatureKey = 'map';

export interface State {
postSolveMapLayers: { [id in MapLayerId]: MapLayer };
visibleMapLayers: { [id in MapLayerId]: MapLayer };
}

export const initialState: State = {
postSolveMapLayers: {
[MapLayerId.PostSolveVisitRequests]: {
visibleMapLayers: {
[MapLayerId.VisitRequests]: {
name: 'Shipments',
icon: 'pickup',
visible: true,
},
[MapLayerId.PostSolveFourWheel]: {
[MapLayerId.FourWheel]: {
name: 'Driving',
icon: 'vehicle_icon',
visible: true,
travelMode: TravelMode.DRIVING,
},
[MapLayerId.PostSolveWalking]: {
[MapLayerId.Walking]: {
name: 'Walking',
icon: 'walking',
visible: true,
Expand All @@ -49,17 +49,17 @@ export const initialState: State = {

export const reducer = createReducer(
initialState,
on(MapActions.setPostSolveLayerVisible, (state, { layerId, visible }) => ({
on(MapActions.setLayerVisible, (state, { layerId, visible }) => ({
...state,
postSolveMapLayers: {
...state.postSolveMapLayers,
visibleMapLayers: {
...state.visibleMapLayers,
[layerId]: {
...state.postSolveMapLayers[layerId],
...state.visibleMapLayers[layerId],
visible,
},
},
}))
);

export const selectPostSolveMapLayers = (state: State): { [id in MapLayerId]: MapLayer } =>
state.postSolveMapLayers;
export const selectVisibleMapLayers = (state: State): { [id in MapLayerId]: MapLayer } =>
state.visibleMapLayers;
4 changes: 2 additions & 2 deletions application/frontend/src/app/core/selectors/map.selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,9 +324,9 @@ export const selectSelectionFilterActive = createSelector(
}
);

export const selectAllMapLayers = createSelector(selectMapState, fromMap.selectPostSolveMapLayers);
export const selectAllMapLayers = createSelector(selectMapState, fromMap.selectVisibleMapLayers);

export const selectPostSolveMapLayers = createSelector(
export const selectUsedMapLayers = createSelector(
selectAllMapLayers,
fromVehicle.selectAll,
(layers, vehicles) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@ limitations under the License.
*/

import { createSelector } from '@ngrx/store';
import {
selectPostSolveMapLayers,
selectVehicleLocationsOnRouteWithHeadings,
} from './map.selectors';
import { selectUsedMapLayers, selectVehicleLocationsOnRouteWithHeadings } from './map.selectors';
import { vehicleToDeckGL } from './pre-solve-vehicle-layer.selectors';
import RoutesChartSelectors from './routes-chart.selectors';
import * as fromVehicle from './vehicle.selectors';
Expand All @@ -33,7 +30,7 @@ export const selectFilteredVehicles = createSelector(
selectVehicleLocationsOnRouteWithHeadings,
RoutesChartSelectors.selectFilteredRoutesWithTransitionsLookup,
RoutesMetadataSelectors.selectFilteredRouteLookup,
selectPostSolveMapLayers,
selectUsedMapLayers,
(
vehicles,
currentPage,
Expand All @@ -50,8 +47,8 @@ export const selectFilteredVehicles = createSelector(
(v) =>
lookup.has(v.id) &&
((v.travelMode ?? TravelMode.DRIVING) === TravelMode.DRIVING
? mapLayers[MapLayerId.PostSolveFourWheel].visible
: mapLayers[MapLayerId.PostSolveWalking].visible)
? mapLayers[MapLayerId.FourWheel].visible
: mapLayers[MapLayerId.Walking].visible)
)
: [];
return filteredVehicles.map((vehicle) =>
Expand All @@ -67,7 +64,7 @@ export const selectFilteredVehiclesSelected = createSelector(
RoutesChartSelectors.selectFilteredRoutesSelectedWithTransitionsLookup,
RoutesMetadataSelectors.selectFilteredRoutesSelectedLookup,
RoutesChartSelectors.selectSelectedRoutesColors,
selectPostSolveMapLayers,
selectUsedMapLayers,
(
vehicles,
currentPage,
Expand All @@ -83,8 +80,8 @@ export const selectFilteredVehiclesSelected = createSelector(
(v) =>
lookup.has(v.id) &&
((v.travelMode ?? TravelMode.DRIVING) === TravelMode.DRIVING
? mapLayers[MapLayerId.PostSolveFourWheel].visible
: mapLayers[MapLayerId.PostSolveWalking].visible)
? mapLayers[MapLayerId.FourWheel].visible
: mapLayers[MapLayerId.Walking].visible)
);
return selectedVehicles.map((vehicle) => ({
...vehicleToDeckGL(vehicle, locations[vehicle.id].location, locations[vehicle.id].heading),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ import { createSelector } from '@ngrx/store';
import { Feature, Point } from '@turf/helpers';
import { fromDispatcherLatLng, fromDispatcherToTurfPoint } from 'src/app/util';
import * as fromLinearReferencing from '../../util/linear-referencing';
import { MapVehicle, Vehicle } from '../models';
import { MapVehicle, TravelMode, Vehicle } from '../models';
import * as fromDepot from './depot.selectors';
import { selectVehicleInitialHeadings } from './map.selectors';
import { selectUsedMapLayers, selectVehicleInitialHeadings } from './map.selectors';
import PreSolveVehicleSelectors from './pre-solve-vehicle.selectors';
import { MapLayerId } from '../models/map';

export const vehicleToDeckGL = (
vehicle: Vehicle,
Expand Down Expand Up @@ -66,17 +67,24 @@ export const selectFilteredVehiclesSelected = createSelector(
PreSolveVehicleSelectors.selectFilteredVehiclesSelected,
selectVehicleInitialHeadings,
fromDepot.selectDepot,
(vehicles, headings, depot) => {
selectUsedMapLayers,
(vehicles, headings, depot, visibleMapLayers) => {
const selectedVehicles: MapVehicle[] = [];
vehicles.forEach((vehicle) => {
if (vehicle.startWaypoint?.location?.latLng) {
const position = fromDispatcherLatLng(vehicle.startWaypoint.location.latLng);
const atDepot = depot
? fromLinearReferencing.pointsAreCoincident(position, fromDispatcherLatLng(depot))
: false;
selectedVehicles.push(vehicleToDeckGL(vehicle, position, headings[vehicle.id], atDepot));
}
});
vehicles
.filter((vehicle) =>
vehicle.travelMode ?? TravelMode.DRIVING
? visibleMapLayers[MapLayerId.FourWheel].visible
: visibleMapLayers[MapLayerId.Walking].visible
)
.forEach((vehicle) => {
if (vehicle.startWaypoint?.location?.latLng) {
const position = fromDispatcherLatLng(vehicle.startWaypoint.location.latLng);
const atDepot = depot
? fromLinearReferencing.pointsAreCoincident(position, fromDispatcherLatLng(depot))
: false;
selectedVehicles.push(vehicleToDeckGL(vehicle, position, headings[vehicle.id], atDepot));
}
});
return selectedVehicles;
}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import RoutesChartSelectors from './routes-chart.selectors';
import { Page, ShipmentRoute, TravelMode } from '../models';
import { Feature, LineString } from '@turf/helpers';
import { toTurfLineString } from 'src/app/util';
import { selectPostSolveMapLayers } from './map.selectors';
import { selectUsedMapLayers } from './map.selectors';
import * as fromVehicle from './vehicle.selectors';
import { MapLayerId } from '../models/map';
import RoutesMetadataSelectors from './routes-metadata.selectors';
Expand Down Expand Up @@ -50,16 +50,16 @@ export const selectFilteredRoutes = createSelector(
RoutesMetadataSelectors.selectFilteredRouteIds,
fromUi.selectPage,
fromVehicle.selectAll,
selectPostSolveMapLayers,
selectUsedMapLayers,
(paths, chartFilteredRouteIds, tableFilteredRouteIds, page, vehicles, mapLayers) => {
const filteredRouteIds =
page === Page.RoutesChart ? chartFilteredRouteIds : new Set(tableFilteredRouteIds);
return (filteredRouteIds ? paths.filter((p) => filteredRouteIds.has(p.id)) : paths).filter(
(route) => {
return (vehicles[route.vehicleIndex]?.travelMode ?? TravelMode.DRIVING) ===
TravelMode.DRIVING
? mapLayers[MapLayerId.PostSolveFourWheel].visible
: mapLayers[MapLayerId.PostSolveWalking].visible;
? mapLayers[MapLayerId.FourWheel].visible
: mapLayers[MapLayerId.Walking].visible;
}
);
}
Expand All @@ -72,7 +72,7 @@ export const selectFilteredRoutesSelected = createSelector(
fromUi.selectPage,
RoutesChartSelectors.selectSelectedRoutesColors,
fromVehicle.selectAll,
selectPostSolveMapLayers,
selectUsedMapLayers,
(
paths,
chartSelectedRoutesLookup,
Expand All @@ -88,8 +88,8 @@ export const selectFilteredRoutesSelected = createSelector(
(p) =>
lookupSet.has(p.id) &&
((vehicles[p.vehicleIndex]?.travelMode ?? TravelMode.DRIVING) === TravelMode.DRIVING
? mapLayers[MapLayerId.PostSolveFourWheel].visible
: mapLayers[MapLayerId.PostSolveWalking].visible)
? mapLayers[MapLayerId.FourWheel].visible
: mapLayers[MapLayerId.Walking].visible)
);
return selectedRoutes.map((route) => ({
...route,
Expand Down

0 comments on commit e3497ee

Please sign in to comment.