src/search/connectors/PhotonSearchConnector.js
import $ from 'jquery'
import { transform, transformExtent } from 'ol/proj'
import Polygon from 'ol/geom/Polygon'
import Point from 'ol/geom/Point'
import Feature from 'ol/Feature'
import { Debug } from '../../Debug'
import { SearchConnector } from './SearchConnector'
export class NominatimSearchConnector extends SearchConnector {
constructor (options) {
super(options)
this.dataProjection = 'EPSG:4326'
if (options.extent) {
this.userExtent_ = options.extent
}
}
setExtent (extent) {
const extentString = extent.join(',')
this.serviceURL.addParam(`format=json&q={searchstring}&addressdetails=1&dedupe=1&viewboxlbrt=${extentString}` +
'&bounded=1&extratags=1&namedetails=1')
}
setMap (map) {
super.setMap(map)
if (map) {
let userExtent = this.userExtent_
if (map.get('mapConfig').view.extent) {
userExtent = map.get('mapConfig').view.extent
}
if (userExtent) {
this.setExtent(transformExtent(userExtent, map.get('interfaceProjection'), this.dataProjection))
} else {
const extent = map.getView().calculateExtent(map.getSize())
this.setExtent(transformExtent(extent, this.featureProjection, this.dataProjection))
}
}
}
getAutoComplete (text) {
return new Promise(resolve => resolve([[], []]))
}
getSearchResult (searchTerm) {
return new Promise((resolve, reject) => {
const finalUrl = this.serviceURL.clone().expandTemplate('searchstring', searchTerm).finalize()
$.ajax({
url: finalUrl,
dataType: 'json',
success: results => {
resolve(SearchConnector.flipTuples(results.map(r => this.readFeature_(r))))
},
error: (jqXHR, textStatus) => {
reject(new Error('Problem while trying to get search results from the Server: ' +
`${textStatus} - ${jqXHR.responseText} (SearchURL: ${finalUrl})`))
}
})
})
}
/**
* @param {object} data
* @returns {[string, Feature]}
* @protected
*/
readFeature_ (data) {
// creates Features which may have the following data fields:
// id
// name
// description
// dropdowntext
// searchtext
//
// and will have a geometry and a style if anything was provided
const descriptionArray = []
/**
* Pushes an element to the description array
* @param {string} val
*/
function pushDescriptionArray (val) {
if (descriptionArray.length < 1 || val !== descriptionArray[descriptionArray.length - 1]) {
descriptionArray.push(val)
}
}
const featureOptions = {}
let id
if (data.hasOwnProperty('place_id')) {
id = data.place_id
}
if (data.hasOwnProperty('display_name')) {
featureOptions.searchtext = data.display_name
}
if (data.hasOwnProperty('namedetails')) {
const curLang = this.localiser.getCurrentLang()
if (data.namedetails.hasOwnProperty('name:' + curLang)) {
pushDescriptionArray(data.namedetails['name:' + curLang])
} else if (data.namedetails.hasOwnProperty('name')) {
pushDescriptionArray(data.namedetails.name)
}
} else {
throw new Error('Please add the option namedetails=1 to your searchstring in the config.')
}
if (data.hasOwnProperty('address')) {
if (data && data.address.hasOwnProperty('type')) {
pushDescriptionArray(data.address[data.type])
} else if (data.type === 'administrative') {
pushDescriptionArray(data.display_name.split(', ')[0])
}
let road
if (data.address.hasOwnProperty('road')) {
road = data.address.road
} else if (data.address.hasOwnProperty('pedestrian')) {
road = data.address.pedestrian
} else if (data.address.hasOwnProperty('cycleway')) {
road = data.address.cycleway
}
if (road) {
if (data.address.hasOwnProperty('house_number')) {
road += ' ' + data.address.house_number
}
pushDescriptionArray(road)
}
let postcode
if (data.address.hasOwnProperty('postcode')) {
postcode = data.address.postcode
}
let city = ''
if (data.address.hasOwnProperty('city')) {
city = data.address.city
} else if (data.address.hasOwnProperty('town')) {
city = data.address.town
} else if (data.address.hasOwnProperty('village')) {
city = data.address.village
}
if (postcode && city) {
pushDescriptionArray(postcode + ' ' + city)
} else if (postcode) {
pushDescriptionArray(postcode)
} else if (city) {
pushDescriptionArray(city)
}
if (data.address && (city !== data.address.hasOwnProperty('county'))) {
pushDescriptionArray(data.address.county)
}
} else {
throw new Error('Please add the option addressdetails=1 to your searchstring in the config.')
}
const dropdowntext = descriptionArray.join(',<br />')
featureOptions.name = descriptionArray.shift()
if (data.hasOwnProperty('extratags')) {
if (data.extratags.hasOwnProperty('website')) {
const linkText = this.localiser.localiseUsingDictionary('Nominatim website')
let url = data.extratags.website
if (url.slice(0, 7) !== 'http://') {
url = 'http://' + url
}
pushDescriptionArray(`<a href="${url}" target="_blank">${linkText}</a>`)
}
if (data.extratags.hasOwnProperty('wikipedia')) {
const comps = data.extratags.wikipedia.split(':')
const linkText = this.localiser.localiseUsingDictionary('Nominatim wikipedia')
const url = `http://${comps[0]}.wikipedia.org/wiki/${comps[1]}`
pushDescriptionArray(`<a href="${url}" target="_blank">${linkText}</a>`)
}
} else {
Debug.info('You can add the option extratags=1 to your searchstring in the config.')
}
featureOptions.description = descriptionArray.join('<br />')
if (data.hasOwnProperty('polygonpoints')) {
const polygonpoints = []
for (let i = 0, ii = data.polygonpoints.length; i < ii; i++) {
polygonpoints.push([parseFloat(data.polygonpoints[i][0]), parseFloat(data.polygonpoints[i][1])])
}
if (this.featureProjection) {
transform(polygonpoints, this.dataProjection, this.featureProjection)
}
featureOptions.geometry = new Polygon(polygonpoints)
} else if ((data.hasOwnProperty('lon')) && (data.hasOwnProperty('lat'))) {
let point = [parseFloat(data.lon), parseFloat(data.lat)]
if (this.featureProjection) {
const coords = [parseFloat(data.lon), parseFloat(data.lat)]
point = transform(coords, this.dataProjection, this.featureProjection)
}
featureOptions.geometry = new Point(point)
}
const feature = new Feature(featureOptions)
if (data.hasOwnProperty('icon')) {
feature.set('iconStyle', data.icon)
}
if (id) {
feature.setId(id)
}
return [dropdowntext, feature]
}
}