Skip to content

Commit

Permalink
Add geocoding support #298
Browse files Browse the repository at this point in the history
  • Loading branch information
m-mohr committed Jan 26, 2023
1 parent d2a1e2a commit fd9f02d
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 31 deletions.
3 changes: 3 additions & 0 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ export default {
mapLocation: [49.8, 9.9],
mapZoom: 4,

// OSM Nominatim compliant geocoder URL, remove to disable
geocoder: "https://nominatim.openstreetmap.org/search/",

// A message shown on the login page
loginMessage: '',

Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"build": "npm run build:database && npx vue-cli-service build --report"
},
"dependencies": {
"@kirtandesai/ol-geocoder": "^5.0.6",
"@musement/iso-duration": "^1.0.0",
"@openeo/js-client": "^2.5.1",
"@openeo/js-commons": "^1.4.1",
Expand All @@ -57,8 +58,8 @@
"jsonlint-mod": "^1.7.6",
"luxon": "^2.4.0",
"node-polyfill-webpack-plugin": "^2.0.0",
"ol": "^6.14.1",
"ol-ext": "^3.2.20",
"ol": "^7.2.2",
"ol-ext": "^4.0.4",
"proj4": "^2.7.5",
"splitpanes": "^2.3.6",
"v-clipboard": "^2.2.3",
Expand Down
42 changes: 18 additions & 24 deletions src/components/datatypes/MapAreaSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ import { transformExtent } from 'ol/proj';
import { containsXY } from 'ol/extent';
import { createDefaultStyle } from 'ol/style/Style';
import TextControl from '../maps/TextControl.vue';
import GeocoderMixin from '../maps/GeocoderMixin.vue';
export default {
name: 'MapAreaSelect',
mixins: [MapMixin],
mixins: [
GeocoderMixin,
MapMixin
],
components: {
TextControl
},
Expand All @@ -31,17 +35,9 @@ export default {
}
},
data() {
let extent = null;
if (Utils.isObject(this.value) && "west" in this.value && "south" in this.value && "east" in this.value && "north" in this.value) {
extent = [this.value.west, this.value.south, this.value.east, this.value.north];
}
else if (Array.isArray(this.value) && value.length >= 4) {
extent = this.value;
}
return {
interaction: null,
extent
extent: this.toExtent(this.value)
};
},
computed: {
Expand Down Expand Up @@ -71,22 +67,20 @@ export default {
}
this.$emit('input', this.returnAsObject ? this.bbox : this.extent);
},
ensureValidExtent(extent) {
if (!extent) {
return extent;
}
return [
Math.max(extent[0], -180),
Math.max(extent[1], -90),
Math.min(extent[2], 180),
Math.min(extent[3], 90)
];
},
async renderMap() {
let isWebMercatorCompatible = Utils.isBboxInWebMercator(this.bbox) !== false;
await this.createMap(isWebMercatorCompatible ? 'EPSG:3857' : 'EPSG:4326');
this.addBasemaps();
this.addGeocoder(bbox => {
if (!bbox) {
return;
}
let extent = this.toExtent(bbox);
extent = transformExtent(extent, 'EPSG:4326', this.map.getView().getProjection());
this.interaction.setExtent(extent);
this.fitMap();
});
let condition = (event) => {
if (!this.editable) {
Expand Down Expand Up @@ -129,14 +123,14 @@ export default {
pixelTolerance: 15
});
// let oldImplementation = this.interaction.setExtent.bind(this.interaction);
// this.interaction.setExtent = extent => oldImplementation(this.ensureValidExtent(extent));
if (this.editable) {
this.interaction.on('extentchanged', this.update);
}
this.map.addInteraction(this.interaction);
this.fitMap();
},
fitMap() {
// If not ediable, make a bigger extent visible so that user can get a better overview
if (this.projectedExtent) {
var fitOptions = this.getFitOptions(this.editable ? 10 : 33);
Expand Down
18 changes: 16 additions & 2 deletions src/components/maps/GeoJsonMapEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

<script>
import MapMixin from '../maps/MapMixin.vue';
import GeoJsonMixin from '../maps/GeoJsonMixin.vue';
import ExtentMixin from '../maps/ExtentMixin.vue';
import GeocoderMixin from '../maps/GeocoderMixin.vue';
import Utils from '../../utils.js';
import GeoJSON from 'ol/format/GeoJSON';
Expand All @@ -23,7 +24,11 @@ import UndoRedo from 'ol-ext/interaction/UndoRedo';
export default {
name: 'GeoJsonMapEditor',
mixins: [MapMixin, GeoJsonMixin],
mixins: [
GeocoderMixin,
MapMixin,
ExtentMixin
],
props: {
value: {
type: Object,
Expand Down Expand Up @@ -59,6 +64,15 @@ export default {
if (this.editable) {
var callback = () => this.$emit('input', this.getGeoJson());
this.geoJsonLayer.getSource().on('change', callback);
this.addGeocoder(polygon => {
if (!polygon) {
return;
}
let feature = (new GeoJSON()).readFeature(polygon, { featureProjection: this.map.getView().getProjection() });
this.geoJsonLayer.getSource().addFeature(feature);
this.map.getView().fit(this.geoJsonLayer.getSource().getExtent(), this.getFitOptions());
}, true);
}
},
Expand Down
58 changes: 58 additions & 0 deletions src/components/maps/GeocoderMixin.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<script>
import Geocoder from '@kirtandesai/ol-geocoder';
import OSMGeocoder from './osmgeocoder';
export default {
methods: {
addGeocoder(callback, geojson = false) {
if (!this.$config.geocoder) {
return;
}
const options = {
provider: new OSMGeocoder(this.$config.geocoder, geojson),
placeholder: 'Search for ...',
keepOpen: true,
preventDefault: true
};
const geocoder = new Geocoder('nominatim', options);
geocoder.on('addresschosen', event => {
if (geojson) {
callback(event.place?.original?.geojson, event);
}
else if (event.place.bbox) {
let bbox = event.place.bbox.map(i => parseFloat(i));
let bboxOpenEO = {
west: bbox[2],
east: bbox[3],
north: bbox[1],
south: bbox[0]
}
callback(bboxOpenEO, event);
}
else {
callback(null, event);
}
});
this.map.addControl(geocoder);
}
}
}
</script>
<style src="@kirtandesai/ol-geocoder/dist/ol-geocoder.min.css"></style>
<style lang="scss">
.ol-geocoder.gcd-gl-container {
z-index: 0;
left: calc(0.5em - 1px) !important;
top: calc(6.125em + 8px) !important;
.ol-control {
background-color: transparent;
}
ul.gcd-gl-result > li:nth-child(odd) {
background-color: #eee;
}
}
</style>
1 change: 0 additions & 1 deletion src/components/maps/MapMixin.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/* Customize layerswitcher control */
.ol-layerswitcher > button {
font-size: 1.14em;
background-color: rgba(0,60,136,.5);

&:before,
&:after {
Expand Down
11 changes: 11 additions & 0 deletions src/components/maps/MapMixin.vue
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,18 @@ export default {
fromLonLat(coords) {
return fromLonLat(coords, this.map.getView().getProjection());
},
toExtent(value) {
let extent = null;
if (Utils.isObject(value) && "west" in value && "south" in value && "east" in value && "north" in value) {
extent = [value.west, value.south, value.east, value.north];
}
else if (Array.isArray(value) && value.length >= 4) {
extent = value;
}
return extent;
}
}
}
</script>
41 changes: 41 additions & 0 deletions src/components/maps/osmgeocoder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
export default class OSMGeocoder {
constructor(url, geojson = false) {
this.url = url;
this.geojson = geojson;
}

getParameters(opt) {
return {
url: this.url,
params: {
q: opt.query,
format: 'json',
limit: 10,
'accept-language': 'en',
polygon_geojson: this.geojson ? 1 : 0,
polygon_threshold: 0.001,
},
};
}

handleResponse(results) {
if (results.length === 0) {
return [];
}
return results
.filter(result => ["boundary", "geological", "leisure", "natural", "place", "water", "waterway"].includes(result.class))
.map(result => ({
lon: result.lon,
lat: result.lat,
bbox: result.boundingbox,
address: {
name: result.display_name
},
original: {
formatted: result.display_name,
details: result.address,
geojson: result.geojson
}
}));
}
}
18 changes: 17 additions & 1 deletion src/components/viewer/MapViewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import JSON_ from '../../formats/json';
import { Splitpanes, Pane } from 'splitpanes';
import ExtentMixin from '../maps/ExtentMixin.vue';
import GeocoderMixin from '../maps/GeocoderMixin.vue';
import GeoTiffMixin from '../maps/GeoTiffMixin.vue';
import MapMixin from '../maps/MapMixin.vue';
import ScatterChart from './ScatterChart.vue';
Expand All @@ -37,6 +38,7 @@ import { Service } from '@openeo/js-client';
import Feature from 'ol/Feature';
import { fromExtent as PolygonFromExtent } from 'ol/geom/Polygon';
import { transformExtent } from 'ol/proj';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
Expand Down Expand Up @@ -112,7 +114,13 @@ GeoTIFFImage.prototype.getBitsPerSample = function(sampleIndex = 0) {
export default {
name: 'MapViewer',
mixins: [ExtentMixin, GeoTiffMixin, MapMixin, WebServiceMixin],
mixins: [
ExtentMixin,
GeocoderMixin,
GeoTiffMixin,
MapMixin,
WebServiceMixin
],
components: {
Pane,
ScatterChart,
Expand Down Expand Up @@ -169,6 +177,14 @@ export default {
await this.createMap(view);
this.addLayerSwitcher();
this.addGeocoder(data => {
if (!data) {
return;
}
let extent = this.toExtent(data);
extent = transformExtent(extent, 'EPSG:4326', this.map.getView().getProjection());
this.map.getView().fit(extent, this.getFitOptions());
});
if (this.isGeoJson) {
this.addBasemaps();
Expand Down
2 changes: 1 addition & 1 deletion src/export/r.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ export default class R extends Exporter {
async generateFunction(node) {
let variable = this.var(node.id, this.varPrefix());
let args = await this.generateArguments(node);
// ToDo: This doesn't seem to be supported in R yet
if (node.namespace) {
throw new Error("The R client doesn't support namespaced processes yet");
// ToDo: This doesn't seem to be supported in R yet
// args.namespace = this.e(node.namespace);
}
args = Utils.mapObject(args, (value, name) => `${name} = ${this.e(value)}`);
Expand Down

0 comments on commit fd9f02d

Please sign in to comment.