Skip to content

Commit

Permalink
Added a geocoding text field
Browse files Browse the repository at this point in the history
  • Loading branch information
ronitjadhav committed Feb 3, 2024
1 parent 95201f8 commit 2327832
Show file tree
Hide file tree
Showing 17 changed files with 259 additions and 1 deletion.
1 change: 1 addition & 0 deletions apps/map-viewer/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
class="absolute"
style="top: 20px; left: 20px; bottom: 20px"
></gn-ui-layers-panel>
<gn-ui-geocoding class="absolute w-72 top-4 right-4"></gn-ui-geocoding>
</div>
4 changes: 3 additions & 1 deletion jest.preset.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ module.exports = {
...nxPreset,
coverageReporters: ['text'],
setupFiles: ['jest-canvas-mock'],
transformIgnorePatterns: ['node_modules/(?!(color-*|ol|@mapbox|.*.mjs$))'],
transformIgnorePatterns: [
'node_modules/(?!(color-*|ol|@mapbox|@geospatial-sdk|.*.mjs$))',
],
transform: {
'^.+\\.(ts|mjs|js|html)$': [
'jest-preset-angular',
Expand Down
3 changes: 3 additions & 0 deletions libs/feature/map/src/lib/feature-map.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { UiInputsModule } from '@geonetwork-ui/ui/inputs'
import { AddLayerFromWmsComponent } from './add-layer-from-wms/add-layer-from-wms.component'
import { AddLayerFromFileComponent } from './add-layer-from-file/add-layer-from-file.component'
import { AddLayerFromWfsComponent } from './add-layer-from-wfs/add-layer-from-wfs.component'
import { GeocodingComponent } from './geocoding/geocoding.component'

@NgModule({
declarations: [
Expand All @@ -35,13 +36,15 @@ import { AddLayerFromWfsComponent } from './add-layer-from-wfs/add-layer-from-wf
AddLayerFromWmsComponent,
AddLayerFromFileComponent,
AddLayerFromWfsComponent,
GeocodingComponent,
],
exports: [
MapContextComponent,
MapInstanceDirective,
LayersPanelComponent,
AddLayerFromCatalogComponent,
MapContainerComponent,
GeocodingComponent,
],
imports: [
CommonModule,
Expand Down
Empty file.
39 changes: 39 additions & 0 deletions libs/feature/map/src/lib/geocoding/geocoding.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<gn-ui-search-input
[(value)]="searchText"
(valueChange)="onSearchChange($event)"
(keyup.enter)="onEnterPress()"
[placeholder]="'map.geocoding.placeholder' | translate"
>
</gn-ui-search-input>
<ul
class="bg-gray-50 border border-gray-200 w-full mt-2 shadow-sm rounded-lg"
*ngIf="results && results.length"
>
<li
*ngFor="let result of results"
(click)="zoomToLocation(result)"
class="flex items-center pl-8 pr-4 py-2 border-b border-gray-200 relative cursor-pointer hover:bg-blue-100 hover:text-gray-800 transition duration-300 ease-in-out"
>
<svg
class="stroke-current text-blue-500 absolute w-5 h-5 left-3 top-3"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"
/>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"
/>
</svg>
<span class="font-sans font-semibold ml-4">{{ result.label }}</span>
</li>
</ul>
115 changes: 115 additions & 0 deletions libs/feature/map/src/lib/geocoding/geocoding.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { GeocodingComponent } from './geocoding.component'
import { MapManagerService } from '../manager/map-manager.service'
import { NO_ERRORS_SCHEMA } from '@angular/core'
import Map from 'ol/Map'
import TileLayer from 'ol/layer/Tile'
import XYZ from 'ol/source/XYZ'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import GeoJSON from 'ol/format/GeoJSON'
import { FEATURE_COLLECTION_POINT_FIXTURE_4326 } from '@geonetwork-ui/common/fixtures'
import Feature from 'ol/Feature'
import { Geometry } from 'ol/geom'
import { TranslateModule } from '@ngx-translate/core'

const vectorLayer = new VectorLayer({
source: new VectorSource({
features: new GeoJSON().readFeatures(
FEATURE_COLLECTION_POINT_FIXTURE_4326,
{
featureProjection: 'EPSG:3857',
dataProjection: 'EPSG:4326',
}
),
}) as VectorSource<Feature<Geometry>>,
})

const mapMock = new Map({
layers: [
new TileLayer({
source: new XYZ({
url: 'http://test',
}),
}),
vectorLayer,
],
})

const mapManagerMock = {
map: mapMock,
}

describe('GeocodingComponent', () => {
let component: GeocodingComponent
let fixture: ComponentFixture<GeocodingComponent>

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [TranslateModule.forRoot()],
declarations: [GeocodingComponent],
providers: [{ provide: MapManagerService, useValue: mapManagerMock }],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents()

fixture = TestBed.createComponent(GeocodingComponent)
component = fixture.componentInstance
fixture.detectChanges()
})

it('should create', () => {
expect(component).toBeTruthy()
expect(component.searchText).toBe('')
expect(component.results).toEqual([])
})

describe('On Search Change', () => {
describe('when search text is empty', () => {
beforeEach(() => {
component.onSearchChange('')
})
it('should not show any results', () => {
expect(component.searchText).toEqual('')
expect(component.results).toEqual([])
})
})
describe('when search text is not empty', () => {
beforeEach(() => {
component.searchText = 'test'
})
it('should show results', () => {
expect(component.searchText).toEqual('test')
expect(component.results).toEqual([])
})
})
})

describe('zoomToLocation', () => {
it('should zoom to the location of the result', () => {
const result = {
geom: {
coordinates: [[0, 0]],
},
}
const viewMock = {
fit: jest.fn(),
}
mapMock.getView = jest.fn().mockReturnValue(viewMock)
component.zoomToLocation(result)
expect(viewMock.fit).toHaveBeenCalled()
})
})
describe('onEnterPress', () => {
it('should zoom to the location of the first result', () => {
const result = {
geom: {
coordinates: [[0, 0]],
},
}
component.results = [result]
const zoomToLocationSpy = jest.spyOn(component, 'zoomToLocation')
component.onEnterPress()
expect(zoomToLocationSpy).toHaveBeenCalledWith(result)
})
})
})
83 changes: 83 additions & 0 deletions libs/feature/map/src/lib/geocoding/geocoding.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Component, OnDestroy } from '@angular/core'
import { queryGeoadmin, GeoadminOptions } from '@geospatial-sdk/geocoding'
import { catchError, from, Subject, takeUntil } from 'rxjs'
import { debounceTime, switchMap } from 'rxjs/operators'
import { MapManagerService } from '../manager/map-manager.service'
import { fromLonLat } from 'ol/proj'
import { Polygon } from 'ol/geom'

@Component({
selector: 'gn-ui-geocoding',
templateUrl: './geocoding.component.html',
styleUrls: ['./geocoding.component.css'],
})
export class GeocodingComponent implements OnDestroy {
searchText = ''
results: any[] = []
searchTextChanged = new Subject<string>()
destroy$ = new Subject<void>()

constructor(private mapManager: MapManagerService) {
this.searchTextChanged
.pipe(
debounceTime(300),
switchMap((searchText) => {
const options: GeoadminOptions = {
origins: ['zipcode', 'gg25', 'address'],
limit: 6,
}
return from(queryGeoadmin(searchText, options)).pipe(
catchError((error) => {
console.error(error)
return []
})
)
}),
takeUntil(this.destroy$)
)
.subscribe((results) => {
this.results = results
})
}

ngOnDestroy() {
this.destroy$.next()
this.destroy$.complete()
}

onSearchChange(searchText: string) {
if (!searchText) {
this.clearSearch()
return
} else {
this.searchTextChanged.next(searchText)
}
}

clearSearch() {
this.searchText = ''
this.results = []
}

zoomToLocation(result) {
const map = this.mapManager.map
const view = map.getView()
const geometry = result.geom

const polygonCoords = geometry.coordinates
const transformedCoords = polygonCoords[0].map((coord) => fromLonLat(coord))

const polygon = new Polygon([transformedCoords])

view.fit(polygon, {
duration: 100,
maxZoom: 12,
})
}

onEnterPress() {
if (this.results && this.results.length > 0) {
this.zoomToLocation(this.results[0])
}
}
}
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"@bartholomej/ngx-translate-extract": "^8.0.2",
"@biesbjerg/ngx-translate-extract-marker": "^1.0.0",
"@camptocamp/ogc-client": "^0.4.0",
"@geospatial-sdk/geocoding": "^0.0.5-alpha.1",
"@ltd/j-toml": "~1.35.2",
"@messageformat/core": "^3.0.1",
"@nestjs/common": "10.1.3",
Expand Down
1 change: 1 addition & 0 deletions translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
"map.add.layer.wfs": "Aus WFS",
"map.add.layer.wms": "Aus WMS",
"map.addFromFile.placeholder": "Klicke hier oder ziehe eine Datei herein",
"map.geocoding.placeholder": "",
"map.help.addFromFile": "Klicke oder ziehe eine Datei herein um eine Karte hinzuzufügen (momentan wird nur das GeoJSON-Format unterstützt).",
"map.layer.add": "Hinzufügen",
"map.layers.available": "Verfügbare Layer",
Expand Down
1 change: 1 addition & 0 deletions translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
"map.add.layer.wfs": "From WFS",
"map.add.layer.wms": "From WMS",
"map.addFromFile.placeholder": "Click or drop a file here",
"map.geocoding.placeholder": "Search for a place",
"map.help.addFromFile": "Click or drag and drop a file to add to the map (currently supports GeoJSON format only).",
"map.layer.add": "Add",
"map.layers.available": "Available Layers",
Expand Down
1 change: 1 addition & 0 deletions translations/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
"map.add.layer.wfs": "",
"map.add.layer.wms": "",
"map.addFromFile.placeholder": "",
"map.geocoding.placeholder": "",
"map.help.addFromFile": "",
"map.layer.add": "",
"map.layers.available": "",
Expand Down
1 change: 1 addition & 0 deletions translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
"map.add.layer.wfs": "",
"map.add.layer.wms": "",
"map.addFromFile.placeholder": "",
"map.geocoding.placeholder": "",
"map.help.addFromFile": "",
"map.layer.add": "",
"map.layers.available": "",
Expand Down
1 change: 1 addition & 0 deletions translations/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
"map.add.layer.wfs": "Da un WFS",
"map.add.layer.wms": "Da un WMS",
"map.addFromFile.placeholder": "",
"map.geocoding.placeholder": "",
"map.help.addFromFile": "",
"map.layer.add": "",
"map.layers.available": "",
Expand Down
1 change: 1 addition & 0 deletions translations/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
"map.add.layer.wfs": "",
"map.add.layer.wms": "",
"map.addFromFile.placeholder": "",
"map.geocoding.placeholder": "",
"map.help.addFromFile": "",
"map.layer.add": "",
"map.layers.available": "",
Expand Down
1 change: 1 addition & 0 deletions translations/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
"map.add.layer.wfs": "",
"map.add.layer.wms": "",
"map.addFromFile.placeholder": "",
"map.geocoding.placeholder": "",
"map.help.addFromFile": "",
"map.layer.add": "",
"map.layers.available": "",
Expand Down
1 change: 1 addition & 0 deletions translations/sk.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
"map.add.layer.wfs": "Z WFS",
"map.add.layer.wms": "Z WMS",
"map.addFromFile.placeholder": "",
"map.geocoding.placeholder": "",
"map.help.addFromFile": "",
"map.layer.add": "",
"map.layers.available": "",
Expand Down

0 comments on commit 2327832

Please sign in to comment.