mirror of
https://github.com/DerTyp7/osm-routing-angular.git
synced 2025-10-30 04:47:09 +01:00
added search
This commit is contained in:
@@ -1,32 +0,0 @@
|
|||||||
interface PhotonGeometry {
|
|
||||||
coordinates: Array<number>;
|
|
||||||
type?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PhotonProperties {
|
|
||||||
osm_id?: number;
|
|
||||||
osm_type?: string;
|
|
||||||
extent?: Array<number>;
|
|
||||||
country?: string;
|
|
||||||
osm_key?: "place";
|
|
||||||
countrycode?: string;
|
|
||||||
osm_value?: string;
|
|
||||||
name?: string;
|
|
||||||
type?: string;
|
|
||||||
postcode?: string;
|
|
||||||
city?: string;
|
|
||||||
housenumber?: number;
|
|
||||||
street?: string;
|
|
||||||
state?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Photon {
|
|
||||||
properties: PhotonProperties;
|
|
||||||
geometry?: PhotonGeometry;
|
|
||||||
type?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PhotonFeatureCollection {
|
|
||||||
features?: Array<Photon>;
|
|
||||||
type?: string;
|
|
||||||
}
|
|
||||||
8
src/app/interfaces/searchResponse.ts
Normal file
8
src/app/interfaces/searchResponse.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export interface SearchWay{
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SearchResponse{
|
||||||
|
ways: Array<SearchWay>;
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ import LineString from 'ol/geom/LineString';
|
|||||||
import { Feature } from 'ol';
|
import { Feature } from 'ol';
|
||||||
import Geometry from 'ol/geom/Geometry';
|
import Geometry from 'ol/geom/Geometry';
|
||||||
import { RouteResponse } from '../interfaces/routeResponse';
|
import { RouteResponse } from '../interfaces/routeResponse';
|
||||||
|
import {Circle, Fill, Stroke, Style} from 'ol/style';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-map',
|
selector: 'app-map',
|
||||||
@@ -22,6 +23,14 @@ export class MapComponent implements AfterViewInit {
|
|||||||
|
|
||||||
map: Map;
|
map: Map;
|
||||||
|
|
||||||
|
lineStyle: Style = new Style({
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: "blue",
|
||||||
|
width: 2
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
this.map = new Map({
|
this.map = new Map({
|
||||||
target: 'map',
|
target: 'map',
|
||||||
@@ -54,14 +63,15 @@ export class MapComponent implements AfterViewInit {
|
|||||||
console.log(routeResponse);
|
console.log(routeResponse);
|
||||||
|
|
||||||
const nodes = routeResponse.nodes || [];
|
const nodes = routeResponse.nodes || [];
|
||||||
|
|
||||||
const fCoordinates: number[][] = nodes.map(node => (transform([node.lon, node.lat], 'EPSG:4326', 'EPSG:3857')));
|
const fCoordinates: number[][] = nodes.map(node => (transform([node.lon, node.lat], 'EPSG:4326', 'EPSG:3857')));
|
||||||
const lineString: LineString = new LineString(fCoordinates);
|
const lineString: LineString = new LineString(fCoordinates);
|
||||||
const feature: Feature<Geometry> = new Feature({ geometry: lineString });
|
const feature: Feature<Geometry> = new Feature({ geometry: lineString });
|
||||||
|
feature.setStyle(this.lineStyle);
|
||||||
const vectorSource = new VectorSource({ features: [ feature ]});
|
const vectorSource = new VectorSource({ features: [ feature ]});
|
||||||
const vectorLayer = new VectorLayer({ source: vectorSource });
|
const vectorLayer = new VectorLayer({ source: vectorSource });
|
||||||
|
this.map.removeLayer(this.map.getLayers().item(1))
|
||||||
this.map.addLayer(vectorLayer);
|
this.map.addLayer(vectorLayer);
|
||||||
|
|
||||||
// this.features = new GeoJSON().readFeatures(new openLayersGeoJSON())
|
// this.features = new GeoJSON().readFeatures(new openLayersGeoJSON())
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,46 +1,25 @@
|
|||||||
|
|
||||||
<div class="searchField">
|
<div class="searchField">
|
||||||
|
|
||||||
<div class="autocomplete">
|
<div class="autocomplete">
|
||||||
<input #inputFrom (click)="getValue(inputFrom.value, true)" (change)="getValue(inputFrom.value, true)" type="text" name="inputFrom" id="inputFrom" placeholder="From" value="{{ inputFromValue }}">
|
<input #inputFrom (click)="getValue(inputFrom.value, true)" (input)="getValue(inputFrom.value, true)" type="text" name="inputFrom" id="inputFrom" placeholder="From" value="{{ inputFromValue }}">
|
||||||
<div #inputautocompleteList class="autocomplete-items autocomplete-items-from">
|
<div class="autocomplete-items autocomplete-items-from">
|
||||||
|
<div *ngFor="let item of searchItemsFrom" (click)="select(true, item)">
|
||||||
<!-- PHOTON -->
|
<label>{{ item.name }}</label>
|
||||||
<div *ngFor="let item of photonItemsFrom"
|
|
||||||
(click)="selectPhoton(true, item);" >
|
|
||||||
<!--IF TYPE == STREET-->
|
|
||||||
<label *ngIf="item.properties.type == 'street'">
|
|
||||||
{{ item.properties.name }} {{item.properties.housenumber}}<br>
|
|
||||||
{{item.properties.postcode}} {{item.properties.city}} {{item.properties.country}}
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<label *ngIf="item.properties.type != 'street'">
|
|
||||||
{{ item.properties.name }} <br>
|
|
||||||
{{item.properties.street}} {{item.properties.housenumber}} {{item.properties.postcode}} {{item.properties.city}} {{item.properties.countrycode}}
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="autocomplete" id="autocompleteTo">
|
<div class="autocomplete" id="autocompleteTo">
|
||||||
<input #inputTo (click)="getValue(inputTo.value, false)" (change)="getValue(inputTo.value, false)" type="text" name="inputTo" id="inputTo" placeholder="To" value="{{ inputToValue }}">
|
<input #inputTo (click)="getValue(inputTo.value, false)" (input)="getValue(inputTo.value, false)" type="text" name="inputTo" id="inputTo" placeholder="To" value="{{ inputToValue }}">
|
||||||
<div #inputautocompleteList class="autocomplete-items autocomplete-items-to">
|
<div #inputautocompleteList class="autocomplete-items autocomplete-items-to">
|
||||||
|
<div *ngFor="let item of searchItemsTo" (click)="select(false, item)">
|
||||||
<div *ngFor="let item of photonItemsTo"
|
<label>{{ item.name }}</label>
|
||||||
(click)="selectPhoton(false, item)">
|
</div>
|
||||||
<!--IF TYPE == STREET-->
|
|
||||||
<label *ngIf="item.properties.type == 'street'">
|
|
||||||
{{ item.properties.name }} {{item.properties.housenumber}}<br>
|
|
||||||
{{item.properties.postcode}} {{item.properties.city}} {{item.properties.country}}
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<label *ngIf="item.properties.type != 'street'">
|
|
||||||
{{ item.properties.name }} <br>
|
|
||||||
{{item.properties.street}} {{item.properties.housenumber}} {{item.properties.postcode}} {{item.properties.city}} {{item.properties.countrycode}}
|
|
||||||
</label>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="routeBtn" (click)="getRoute()">Route</button>
|
|
||||||
|
<button *ngIf="getRouteBtnEnabled" class="routeBtn" (click)="getRoute()">Route</button>
|
||||||
|
<img *ngIf="!getRouteBtnEnabled"src="/assets/images/loading.gif" style="margin-top:15px; margin-left:10px;width:25px;height: 25px;" />
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { Component, ElementRef, Output, ViewChild } from '@angular/core';
|
import { Component, Output } from '@angular/core';
|
||||||
import { Photon, PhotonFeatureCollection } from '../interfaces/photon';
|
|
||||||
import { PhotonService } from '../services/photon.service';
|
|
||||||
import { EventEmitter } from '@angular/core';
|
import { EventEmitter } from '@angular/core';
|
||||||
import { PythonBackendService } from '../services/python-backend.service';
|
import { PythonBackendService } from '../services/python-backend.service';
|
||||||
import { RouteResponse } from '../interfaces/routeResponse';
|
import { RouteResponse } from '../interfaces/routeResponse';
|
||||||
|
import { SearchResponse, SearchWay } from '../interfaces/searchResponse';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-search',
|
selector: 'app-search',
|
||||||
@@ -13,67 +12,31 @@ import { RouteResponse } from '../interfaces/routeResponse';
|
|||||||
export class SearchComponent {
|
export class SearchComponent {
|
||||||
|
|
||||||
@Output() emitter = new EventEmitter<RouteResponse>();
|
@Output() emitter = new EventEmitter<RouteResponse>();
|
||||||
@ViewChild("inputautocompleteList") autocompleteList: ElementRef;
|
|
||||||
|
|
||||||
|
searchItemsFrom: SearchWay[] = [];
|
||||||
|
searchItemsTo: SearchWay[] = [];
|
||||||
|
|
||||||
|
selectedSearchWayFrom: SearchWay;
|
||||||
photonItemsFrom: Photon[] = [];
|
selectedSearchWayTo: SearchWay;
|
||||||
photonItemsTo: Photon[] = [];
|
|
||||||
|
|
||||||
inputFromValue: string;
|
inputFromValue: string;
|
||||||
inputToValue: string;
|
inputToValue: string;
|
||||||
|
|
||||||
longFrom: number = 0;
|
getRouteBtnEnabled: boolean = true;
|
||||||
latFrom: number = 0;
|
|
||||||
longTo: number = 0;
|
|
||||||
latTo: number = 0;
|
|
||||||
|
|
||||||
selectedPhotonFrom: Photon;
|
|
||||||
selectedPhotonTo: Photon;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private photonService: PhotonService,
|
|
||||||
private pythonBackendService: PythonBackendService,
|
private pythonBackendService: PythonBackendService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
getFormattedPhotonValue(p: Photon): string{
|
select(isFrom: boolean, item: SearchWay): void{
|
||||||
let formatted: string = "";
|
if(isFrom){
|
||||||
|
this.selectedSearchWayFrom = item;
|
||||||
if (p.properties.name) {
|
this.inputFromValue = item.name;
|
||||||
formatted += " " + p.properties.name;
|
this.searchItemsFrom = [];
|
||||||
}
|
}else{
|
||||||
if (p.properties.housenumber) {
|
this.selectedSearchWayTo = item;
|
||||||
formatted += " " + p.properties.housenumber;
|
this.inputToValue = item.name;
|
||||||
}
|
this.searchItemsTo = [];
|
||||||
if (p.properties.postcode) {
|
|
||||||
formatted += " " + p.properties.postcode;
|
|
||||||
}
|
|
||||||
if (p.properties.city) {
|
|
||||||
formatted += " " + p.properties.city;
|
|
||||||
}
|
|
||||||
if (p.properties.countrycode) {
|
|
||||||
formatted += " " + p.properties.countrycode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return formatted;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
selectPhoton(isFrom: boolean, p: Photon): void{
|
|
||||||
if (isFrom) {
|
|
||||||
this.selectedPhotonFrom = p;
|
|
||||||
this.longFrom = <number> p.geometry?.coordinates[0];
|
|
||||||
this.latFrom = <number> p.geometry?.coordinates[1];
|
|
||||||
this.inputFromValue = <string> p.properties.name;
|
|
||||||
this.inputFromValue = this.getFormattedPhotonValue(p);
|
|
||||||
this.photonItemsFrom = [];
|
|
||||||
} else {
|
|
||||||
this.selectedPhotonTo = p;
|
|
||||||
this.longTo = <number>p.geometry?.coordinates[0];
|
|
||||||
this.latTo = <number>p.geometry?.coordinates[1];
|
|
||||||
this.inputToValue = <string> p.properties.name + " " + p.properties.countrycode;
|
|
||||||
this.inputToValue = this.getFormattedPhotonValue(p);
|
|
||||||
this.photonItemsTo = [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,39 +44,28 @@ export class SearchComponent {
|
|||||||
* Gets called in "app.component.html" when an input changes its value
|
* Gets called in "app.component.html" when an input changes its value
|
||||||
*/
|
*/
|
||||||
getValue(value: string, isFrom: boolean): void {
|
getValue(value: string, isFrom: boolean): void {
|
||||||
|
this.searchItemsFrom = [];
|
||||||
|
this.searchItemsTo = [];
|
||||||
|
|
||||||
//this.updateAutoCompleteList([{display_name: 'Hallo'}, {display_name: 'Test2'}], [{display_name: 'Halload'}, {display_name: 'Test4'}]);
|
this.pythonBackendService.sendSearchQueryRequest(value, "10")
|
||||||
|
.subscribe((response: SearchResponse) => response.ways?.forEach(way =>{
|
||||||
/*
|
if(isFrom){
|
||||||
this.nominatimService.sendQueryRequest(valueFrom)
|
this.searchItemsFrom.push(way);
|
||||||
.subscribe((response: Nominatim[]) => this.nominatimItemsFrom = response);
|
this.selectedSearchWayFrom = way;
|
||||||
|
}else{
|
||||||
this.nominatimService.sendQueryRequest(valueTo)
|
this.searchItemsTo.push(way);
|
||||||
.subscribe((response: Nominatim[]) => this.nominatimItemsTo = response);
|
this.selectedSearchWayTo = way;
|
||||||
*/
|
}
|
||||||
|
}));
|
||||||
this.photonItemsFrom = [];
|
|
||||||
this.photonItemsTo = [];
|
|
||||||
|
|
||||||
this.photonService.sendQueryRequest(value)
|
|
||||||
.subscribe((response: PhotonFeatureCollection) => response.features?.forEach(feature => {
|
|
||||||
if (isFrom) {
|
|
||||||
this.photonItemsFrom.push(feature);
|
|
||||||
this.longFrom = <number>this.photonItemsFrom[0].geometry?.coordinates![0];
|
|
||||||
this.latFrom = <number>this.photonItemsFrom[0].geometry?.coordinates![1];
|
|
||||||
} else {
|
|
||||||
this.photonItemsTo.push(feature);
|
|
||||||
this.longTo = <number>this.photonItemsFrom[0].geometry?.coordinates![0];
|
|
||||||
this.latTo = <number>this.photonItemsFrom[0].geometry?.coordinates![1];
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getRoute(): void{
|
getRoute(): void{
|
||||||
this.pythonBackendService.sendQueryRequest(this.latFrom.toString(), this.longFrom.toString(), this.latTo.toString(), this.longTo.toString())
|
this.getRouteBtnEnabled = false;
|
||||||
|
this.pythonBackendService.sendRouteQueryRequest(this.selectedSearchWayFrom.id.toString(), this.selectedSearchWayTo.id.toString())
|
||||||
.subscribe((response: RouteResponse) => {
|
.subscribe((response: RouteResponse) => {
|
||||||
|
console.log(response);
|
||||||
this.emitter.emit(response);
|
this.emitter.emit(response);
|
||||||
|
this.getRouteBtnEnabled = true;
|
||||||
/*
|
/*
|
||||||
this.mapComponent.updateSidebar(response);
|
this.mapComponent.updateSidebar(response);
|
||||||
this.mapComponent.drawPath(response);
|
this.mapComponent.drawPath(response);
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { PhotonService } from './photon.service';
|
|
||||||
|
|
||||||
describe('PhotonService', () => {
|
|
||||||
let service: PhotonService;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
TestBed.configureTestingModule({});
|
|
||||||
service = TestBed.inject(PhotonService);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be created', () => {
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { HttpClient } from '@angular/common/http';
|
|
||||||
import { PhotonFeatureCollection } from '../interfaces/photon';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Communicates with Photon (https://photon.komoot.io/)
|
|
||||||
*/
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class PhotonService{
|
|
||||||
|
|
||||||
constructor(private http: HttpClient) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a query request to Photon and gets response (https://photon.komoot.io/)
|
|
||||||
*/
|
|
||||||
sendQueryRequest(queryString: string): Observable<PhotonFeatureCollection> {
|
|
||||||
return this.http.get<PhotonFeatureCollection>("https://photon.komoot.io/api/?q=" + queryString + "&limit=10&zoom=12");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -2,20 +2,25 @@ import { Injectable } from '@angular/core';
|
|||||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
import { RouteResponse } from '../interfaces/routeResponse';
|
import { RouteResponse } from '../interfaces/routeResponse';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
import { SearchResponse } from '../interfaces/searchResponse';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class PythonBackendService {
|
export class PythonBackendService {
|
||||||
url: string = "http://127.0.0.1:5555/getRouteByCoordinates/"
|
urlRoute: string = "http://127.0.0.1:5555/getRoute/"
|
||||||
|
urlSearch: string = "http://127.0.0.1:5555/search/"
|
||||||
constructor(private http: HttpClient) { }
|
constructor(private http: HttpClient) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sends a query request to Osrm and gets response (http://project-osrm.org/docs/v5.24.0/api/?language=cURL#table-service)
|
* sends a query request to Osrm and gets response (http://project-osrm.org/docs/v5.24.0/api/?language=cURL#table-service)
|
||||||
*/
|
*/
|
||||||
sendQueryRequest(fromWayLat: string, fromWayLon: string, toWayLat: string, toWayLon: string): Observable<RouteResponse> {
|
sendRouteQueryRequest(wayStart: string, wayEnd: string): Observable<RouteResponse> {
|
||||||
console.log(this.url + fromWayLat + "/" + fromWayLon + "/" + toWayLat + "/" + toWayLon);
|
console.log(this.urlRoute + wayStart + "/" + wayEnd);
|
||||||
return this.http.get<RouteResponse>(this.url + fromWayLat + "/" + fromWayLon + "/" + toWayLat + "/" + toWayLon);
|
return this.http.get<RouteResponse>(this.urlRoute + wayStart + "/" + wayEnd);
|
||||||
|
}
|
||||||
|
sendSearchQueryRequest(query: string, limit: string): Observable<SearchResponse>{
|
||||||
|
console.log(this.urlSearch + query + "/" + limit);
|
||||||
|
return this.http.get<SearchResponse>(this.urlSearch + query + "/" + limit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
src/assets/images/loading.gif
Normal file
BIN
src/assets/images/loading.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
Reference in New Issue
Block a user