Skip to content

Commit

Permalink
feat(directions): added possibility to toggle between two routing sou…
Browse files Browse the repository at this point in the history
…rces (#1644)
  • Loading branch information
LAMM26 authored and alecarn committed Apr 4, 2024
1 parent 2317210 commit 7df42f0
Show file tree
Hide file tree
Showing 19 changed files with 299 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@ export interface DirectionsSourceOptions extends BaseDirectionsSourceOptions {
export type OsrmDirectionsSourceOptions = BaseDirectionsSourceOptions;

interface BaseDirectionsSourceOptions {
distance?: number;
name?: string;
baseUrl?: string;
profiles?: BaseDirectionsSourceOptionsProfile[];
}

export interface BaseDirectionsSourceOptionsProfile {
enabled?: boolean;
limit?: number;
logo?: string;
reverseUrl?: string;
type?: string;
url?: string;
name: string;
authorization?: BaseDirectionsSourceOptionsProfileAuthorization;
}

export interface BaseDirectionsSourceOptionsProfileAuthorization {
url: string;
property: string;
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { Position } from 'geojson';
import { Observable } from 'rxjs';

import { Direction, DirectionOptions } from '../shared/directions.interface';
import { BaseDirectionsSourceOptionsProfile } from './directions-source.interface';

export abstract class DirectionsSource {
abstract enabled: boolean;
abstract getName(): string;
abstract profiles: BaseDirectionsSourceOptionsProfile[];
abstract getSourceName(): string;
abstract getEnabledProfile(): BaseDirectionsSourceOptionsProfile;
abstract getProfileWithAuthorization(): BaseDirectionsSourceOptionsProfile;
abstract route(
coordinates: [number, number][],
coordinates: Position[],
directionsOptions: DirectionOptions
): Observable<Direction[]>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,64 +2,117 @@ import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';

import { ConfigService } from '@igo2/core';
import { customCacheHasher, uuid } from '@igo2/utils';
import { uuid } from '@igo2/utils';

import { Position } from 'geojson';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Cacheable } from 'ts-cacheable';

import {
DirectionsFormat,
SourceDirectionsType
} from '../shared/directions.enum';
import { Direction, DirectionOptions } from '../shared/directions.interface';
import { DirectionsSource } from './directions-source';
import { OsrmDirectionsSourceOptions } from './directions-source.interface';
import {
BaseDirectionsSourceOptionsProfile,
OsrmDirectionsSourceOptions
} from './directions-source.interface';

@Injectable()
export class OsrmDirectionsSource extends DirectionsSource {
get enabled(): boolean {
return this.options.enabled !== false;
get options(): OsrmDirectionsSourceOptions {
return this._options;
}

set options(value: OsrmDirectionsSourceOptions) {
this._options = value;
}

get sourceName(): string {
return this._options.name;
}

set sourceName(value: string) {
this._options.name = value;
}

get baseUrl(): string {
return this._options.baseUrl;
}

set baseUrl(value: string) {
this._options.baseUrl = value;
}

get url(): string {
return `${this.baseUrl}${this.getEnabledProfile().name}/`;
}

get profiles(): BaseDirectionsSourceOptionsProfile[] {
return this._options.profiles;
}
set enabled(value: boolean) {
this.options.enabled = value;

set profiles(value: BaseDirectionsSourceOptionsProfile[]) {
this._options.profiles = value;
}
static _name = 'OSRM Québec';
private directionsUrl =
'https://geoegl.msp.gouv.qc.ca/services/itineraire/route/v1/driving/';
private options: OsrmDirectionsSourceOptions;

private _options: OsrmDirectionsSourceOptions;

constructor(
private http: HttpClient,
private config: ConfigService
private _http: HttpClient,
private _config: ConfigService
) {
super();
this.options = this.config.getConfig('directionsSources.osrm') || {};
this.directionsUrl = this.options.url || this.directionsUrl;
this._options = this._config.getConfig('directionsSources.osrm');
if (!this.baseUrl) {
this.baseUrl = '/apis/itineraire/route/v1/';
}

if (!this.sourceName) {
this.sourceName = 'OSRM Québec';
}

if (!this.profiles) {
const profile: BaseDirectionsSourceOptionsProfile = {
enabled: true,
name: 'driving'
};
this.profiles = [profile];
} else {
if (!this.profiles.find((profile) => profile.enabled)) {
this.profiles[0].enabled = true;
}
}
}

getSourceName(): string {
return this.sourceName;
}

getEnabledProfile(): BaseDirectionsSourceOptionsProfile {
return this.profiles.find((profile) => profile.enabled);
}

getName(): string {
return OsrmDirectionsSource._name;
getProfileWithAuthorization(): BaseDirectionsSourceOptionsProfile {
return this.profiles.find((profile) => profile.authorization);
}

route(
coordinates: [number, number][],
coordinates: Position[],
directionsOptions: DirectionOptions = {}
): Observable<Direction[]> {
const directionsParams = this.getRouteParams(directionsOptions);
return this.getRoute(coordinates, directionsParams);
}

@Cacheable({
maxCacheCount: 20,
cacheHasher: customCacheHasher
})
private getRoute(
coordinates: [number, number][],
coordinates: Position[],
params: HttpParams
): Observable<Direction[]> {
return this.http
.get<JSON[]>(this.directionsUrl + coordinates.join(';'), {
const url: string = this.url;
return this._http
.get<JSON[]>(url + coordinates.join(';'), {
params
})
.pipe(map((res) => this.extractRoutesData(res)));
Expand Down Expand Up @@ -118,7 +171,7 @@ export class OsrmDirectionsSource extends DirectionsSource {
return {
id: uuid(),
title: roadNetworkRoute.legs[0].summary,
source: OsrmDirectionsSource._name,
source: this.url,
sourceType: SourceDirectionsType.Route,
order: 1,
format: DirectionsFormat.GeoJSON,
Expand Down
8 changes: 8 additions & 0 deletions packages/geo/src/lib/directions/directions.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@
>
{{ 'igo.geo.directionsForm.toggleActive' | translate }}
</mat-slide-toggle>
<mat-slide-toggle
*ngIf="hasOsrmPrivateAccess && twoSourcesAvailable"
[checked]="enabledProfileHasAuthorization"
[labelPosition]="'before'"
(change)="onTogglePrivateModeControl($event.checked)"
>
{{ 'igo.geo.directionsForm.toggleType' | translate }}
</mat-slide-toggle>
</div>

<igo-directions-buttons
Expand Down
88 changes: 71 additions & 17 deletions packages/geo/src/lib/directions/directions.component.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { HttpClient } from '@angular/common/http';
import {
ChangeDetectorRef,
Component,
Expand All @@ -7,7 +8,7 @@ import {
} from '@angular/core';

import { EntityStoreWatcher } from '@igo2/common';
import { LanguageService } from '@igo2/core';
import { LanguageService, MessageService } from '@igo2/core';
import { ChangeUtils, ObjectUtils } from '@igo2/utils';

import Collection from 'ol/Collection';
Expand All @@ -17,7 +18,7 @@ import { SelectEvent } from 'ol/interaction/Select';
import { TranslateEvent } from 'ol/interaction/Translate';
import * as olProj from 'ol/proj';

import { Subject, Subscription } from 'rxjs';
import { BehaviorSubject, Subject, Subscription } from 'rxjs';
import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators';

import { Feature } from '../feature/shared/feature.interfaces';
Expand All @@ -26,6 +27,8 @@ import { roundCoordTo, stringToLonLat } from '../map';
import { QueryService } from '../query/shared/query.service';
import { Research, SearchResult } from '../search/shared/search.interfaces';
import { SearchService } from '../search/shared/search.service';
import { BaseDirectionsSourceOptionsProfile } from './directions-sources';
import { DirectionsSourceService } from './shared/directions-source.service';
import { DirectionType, ProposalType } from './shared/directions.enum';
import {
DirectionOptions,
Expand Down Expand Up @@ -58,6 +61,8 @@ export class DirectionsComponent implements OnInit, OnDestroy {
private watcher: EntityStoreWatcher<Stop>;

public projection: string = 'EPSG:4326';
public hasOsrmPrivateAccess: boolean = false;
public twoSourcesAvailable: boolean = false;

private zoomRoute$$: Subscription;
private storeEmpty$$: Subscription;
Expand All @@ -73,6 +78,7 @@ export class DirectionsComponent implements OnInit, OnDestroy {
public previousStops: Stop[] = [];

private searchs$$: Subscription[] = [];
private authenticated$$: Subscription;

@Input() contextUri: string;
@Input() stopsStore: StopsStore;
Expand All @@ -83,6 +89,7 @@ export class DirectionsComponent implements OnInit, OnDestroy {
@Input() length: number = 2;
@Input() coordRoundedDecimals: number = 6;
@Input() zoomToActiveRoute$: Subject<void> = new Subject();
@Input() authenticated$: BehaviorSubject<boolean>;

/**
* Wheter one of the direction control is active
Expand All @@ -96,15 +103,39 @@ export class DirectionsComponent implements OnInit, OnDestroy {
return [this.selectStopInteraction, this.translateStop, this.selectedRoute];
}

get enabledProfileHasAuthorization() {
return this.directionsSourceService.sources[0].getEnabledProfile()
.authorization;
}

constructor(
private cdRef: ChangeDetectorRef,
private http: HttpClient,
private languageService: LanguageService,
private directionsService: DirectionsService,
private directionsSourceService: DirectionsSourceService,
private searchService: SearchService,
private queryService: QueryService
private queryService: QueryService,
private messageService: MessageService
) {}

ngOnInit(): void {
this.authenticated$$ = this.authenticated$.subscribe(
(authenticated: boolean) => {
if (authenticated) {
const profileWithAuth: BaseDirectionsSourceOptionsProfile =
this.directionsSourceService.sources[0].getProfileWithAuthorization();
this.http.get(profileWithAuth.authorization.url).subscribe((user) => {
this.hasOsrmPrivateAccess =
user[profileWithAuth.authorization.property];
});
}
}
);
this.twoSourcesAvailable =
this.directionsSourceService.sources[0].profiles.length === 2
? true
: false;
this.queryService.queryEnabled = false;
this.initEntityStores();
setTimeout(() => {
Expand All @@ -121,6 +152,7 @@ export class DirectionsComponent implements OnInit, OnDestroy {
this.storeChange$$.unsubscribe();
this.routesQueries$$.map((u) => u.unsubscribe());
this.zoomRoute$$.unsubscribe();
this.authenticated$$.unsubscribe();
this.freezeStores();
}

Expand Down Expand Up @@ -416,20 +448,18 @@ export class DirectionsComponent implements OnInit, OnDestroy {
isOverview ? overviewDirectionsOptions : undefined
);
if (routeResponse) {
routeResponse.map((res) =>
this.routesQueries$$.push(
res.subscribe((directions) => {
this.routesFeatureStore.deleteMany(this.routesFeatureStore.all());
directions.map((direction) =>
addDirectionToRoutesFeatureStore(
this.routesFeatureStore,
direction,
this.projection,
direction === directions[0] ? true : false
)
);
})
)
this.routesQueries$$.push(
routeResponse.subscribe((directions) => {
this.routesFeatureStore.deleteMany(this.routesFeatureStore.all());
directions.map((direction) =>
addDirectionToRoutesFeatureStore(
this.routesFeatureStore,
direction,
this.projection,
direction === directions[0] ? true : false
)
);
})
);
}
}
Expand All @@ -453,4 +483,28 @@ export class DirectionsComponent implements OnInit, OnDestroy {
: ol.removeInteraction(interaction)
);
}

onTogglePrivateModeControl(isActive: boolean) {
this.directionsSourceService.sources[0].profiles.forEach(
(profile) => (profile.enabled = false)
);
if (isActive) {
this.directionsSourceService.sources[0].profiles.find(
(profile) => profile.authorization
).enabled = true;
this.messageService.alert(
this.languageService.translate.instant(
'igo.geo.directionsForm.forestRoadsWarning.text'
),
this.languageService.translate.instant(
'igo.geo.directionsForm.forestRoadsWarning.title'
)
);
} else {
this.directionsSourceService.sources[0].profiles.find(
(profile) => !profile.authorization
).enabled = true;
}
this.getRoutes();
}
}
Loading

0 comments on commit 7df42f0

Please sign in to comment.