Skip to content
This repository was archived by the owner on Sep 24, 2024. It is now read-only.

Commit 423bb4b

Browse files
syffsolefirenko
authored andcommitted
feat: handle input coordinates and current location (olefirenko#64)
* feat(geolocation): added exposed geolocate method to navigator location * refactor(geolocation): flow is now more modular to handle input coordinates * fix: types needs to be set for filtering
1 parent e7aa890 commit 423bb4b

File tree

4 files changed

+184
-42
lines changed

4 files changed

+184
-42
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ Default: `false`
108108

109109
Bias the search towards user current location.
110110

111+
#### geolocationOptions
112+
Type: [`Object`](https://developer.mozilla.org/fr/docs/Web/API/PositionOptions)
113+
Default: `{}`
114+
115+
Allow to configure Options for [`navigator.getCurrentPosition`](https://developer.mozilla.org/fr/docs/Web/API/Geolocation/getCurrentPosition)
116+
111117
### Events
112118
The component emits next events, which you can listen in your application:
113119

@@ -136,6 +142,10 @@ Gets triggered when the autocomplete results got changed
136142
#### keypress
137143
Gets triggered when a key gets pressed
138144

145+
#### error
146+
Gets triggered when an error is encountered
147+
148+
139149
### Exposed component functions
140150

141151
These functions are accessible by setting "ref" on the component ([Refs documentation](https://vuejs.org/v2/guide/components.html#Child-Component-Refs)). See example below how to use these functions.
@@ -156,6 +166,14 @@ Call blur to blur (unfocus) the element
156166

157167
Call to update the user input with a new value
158168

169+
#### updateCoordinates([latlng](https://developers.google.com/maps/documentation/javascript/reference#LatLng))
170+
171+
Call to force coordinates and update the input accordingly
172+
173+
#### geolocate()
174+
175+
Call to retrieve current position from `navigator` and update the input accordingly
176+
159177

160178
### Example
161179

example/src/index.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ <h2 class="subtitle">A Vue.js autosuggest component for the Google Maps Places A
1818
<section class="hero">
1919
<div class="hero-body">
2020
<div class="container" id="app">
21-
<h3 class="title is-4">Start typing an address and below you will see found result</h3>
21+
<h3 class="title is-4">Start typing an address and below you will see found result,
22+
<a v-on:click="$refs.address.geolocate()">or force current location</a>
23+
</h3>
2224
<p class="control">
2325
<vue-google-autocomplete
2426
id="map"
27+
ref="address"
2528
classname="input"
2629
placeholder="Start typing"
2730
v-on:placechanged="getAddressData"

src/VueGoogleAutocomplete.vue

Lines changed: 157 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@
1515
</template>
1616

1717
<script>
18+
const ADDRESS_COMPONENTS = {
19+
street_number: 'short_name',
20+
route: 'long_name',
21+
locality: 'long_name',
22+
administrative_area_level_1: 'short_name',
23+
administrative_area_level_2: 'county',
24+
country: 'long_name',
25+
postal_code: 'short_name'
26+
};
27+
28+
const CITIES_TYPE = ['locality', 'administrative_area_level_3'];
29+
const REGIONS_TYPE = ['locality', 'sublocality', 'postal_code', 'country',
30+
'administrative_area_level_1', 'administrative_area_level_2'];
31+
1832
export default {
1933
name: 'VueGoogleAutocomplete',
2034
@@ -44,6 +58,11 @@
4458
enableGeolocation: {
4559
type: Boolean,
4660
default: false
61+
},
62+
63+
geolocationOptions: {
64+
type: Object,
65+
default: null
4766
}
4867
},
4968
@@ -62,6 +81,29 @@
6281
* @type {String}
6382
*/
6483
autocompleteText: '',
84+
85+
geolocation: {
86+
/**
87+
* Google Geocoder Objet
88+
* @type {Geocoder}
89+
* @link https://developers.google.com/maps/documentation/javascript/reference#Geocoder
90+
*/
91+
geocoder: null,
92+
93+
/**
94+
* Filled after geolocate result
95+
* @type {Coordinates}
96+
* @link https://developer.mozilla.org/en-US/docs/Web/API/Coordinates
97+
*/
98+
loc: null,
99+
100+
/**
101+
* Filled after geolocate result
102+
* @type {Position}
103+
* @link https://developer.mozilla.org/en-US/docs/Web/API/Position
104+
*/
105+
position: null
106+
}
65107
}
66108
},
67109
@@ -94,8 +136,14 @@
94136
options
95137
);
96138
97-
this.autocomplete.addListener('place_changed', () => {
139+
this.autocomplete.addListener('place_changed', this.onPlaceChanged);
140+
},
98141
142+
methods: {
143+
/**
144+
* When a place changed
145+
*/
146+
onPlaceChanged() {
99147
let place = this.autocomplete.getPlace();
100148
101149
if (!place.geometry) {
@@ -105,48 +153,21 @@
105153
return;
106154
}
107155
108-
let addressComponents = {
109-
street_number: 'short_name',
110-
route: 'long_name',
111-
locality: 'long_name',
112-
administrative_area_level_1: 'short_name',
113-
administrative_area_level_2: 'county',
114-
country: 'long_name',
115-
postal_code: 'short_name'
116-
};
117-
118-
let returnData = {};
119-
120156
if (place.address_components !== undefined) {
121-
// Get each component of the address from the place details
122-
for (let i = 0; i < place.address_components.length; i++) {
123-
let addressType = place.address_components[i].types[0];
124-
125-
if (addressComponents[addressType]) {
126-
let val = place.address_components[i][addressComponents[addressType]];
127-
returnData[addressType] = val;
128-
}
129-
}
130-
131-
returnData['latitude'] = place.geometry.location.lat();
132-
returnData['longitude'] = place.geometry.location.lng();
133-
134157
// return returnData object and PlaceResult object
135-
this.$emit('placechanged', returnData, place, this.id);
158+
this.$emit('placechanged', this.formatResult(place), place, this.id);
136159
137160
// update autocompleteText then emit change event
138161
this.autocompleteText = document.getElementById(this.id).value
139162
this.onChange()
140163
}
141-
});
142-
},
164+
},
143165
144-
methods: {
145166
/**
146167
* When the input gets focus
147168
*/
148169
onFocus() {
149-
this.geolocate();
170+
this.biasAutocompleteLocation();
150171
this.$emit('focus');
151172
},
152173
@@ -209,24 +230,119 @@
209230
this.autocompleteText = value
210231
},
211232
233+
/**
234+
* Update the coordinates of the input
235+
* @param {Coordinates} value
236+
*/
237+
updateCoordinates (value) {
238+
if (!value && !(value.lat || value.lng)) return;
239+
if (!this.geolocation.geocoder) this.geolocation.geocoder = new google.maps.Geocoder();
240+
this.geolocation.geocoder.geocode({'location': value}, (results, status) => {
241+
if (status === 'OK') {
242+
results = this.filterGeocodeResultTypes(results);
243+
if (results[0]) {
244+
this.$emit('placechanged', this.formatResult(results[0]), results[0], this.id);
245+
this.update(results[0].formatted_address);
246+
} else {
247+
this.$emit('error', 'no result for provided coordinates');
248+
}
249+
} else {
250+
this.$emit('error', 'error getting address from coords');
251+
}
252+
})
253+
},
254+
255+
/**
256+
* Update location based on navigator geolocation
257+
*/
258+
geolocate () {
259+
this.updateGeolocation ((geolocation, position) => {
260+
this.updateCoordinates(geolocation)
261+
})
262+
},
263+
264+
/**
265+
* Update internal location from navigator geolocation
266+
* @param {Function} (geolocation, position)
267+
*/
268+
updateGeolocation (callback = null) {
269+
if (navigator.geolocation) {
270+
let options = {};
271+
if(this.geolocationOptions) Object.assign(options, this.geolocationOptions);
272+
navigator.geolocation.getCurrentPosition(position => {
273+
let geolocation = {
274+
lat: position.coords.latitude,
275+
lng: position.coords.longitude
276+
};
277+
this.geolocation.loc = geolocation;
278+
this.geolocation.position = position;
279+
280+
if (callback) callback(geolocation, position);
281+
}, err => {
282+
this.$emit('error', 'Cannot get Coordinates from navigator', err);
283+
}, options);
284+
}
285+
},
286+
287+
212288
// Bias the autocomplete object to the user's geographical location,
213289
// as supplied by the browser's 'navigator.geolocation' object.
214-
geolocate() {
290+
biasAutocompleteLocation () {
215291
if (this.enableGeolocation) {
216-
if (navigator.geolocation) {
217-
navigator.geolocation.getCurrentPosition(position => {
218-
let geolocation = {
219-
lat: position.coords.latitude,
220-
lng: position.coords.longitude
221-
};
292+
this.updateGeolocation((geolocation, position) => {
222293
let circle = new google.maps.Circle({
223-
center: geolocation,
224-
radius: position.coords.accuracy
294+
center: geolocation,
295+
radius: position.coords.accuracy
225296
});
226297
this.autocomplete.setBounds(circle.getBounds());
227-
});
298+
})
299+
}
300+
},
301+
302+
/**
303+
* Format result from Geo google APIs
304+
* @param place
305+
* @returns {{formatted output}}
306+
*/
307+
formatResult (place) {
308+
let returnData = {};
309+
for (let i = 0; i < place.address_components.length; i++) {
310+
let addressType = place.address_components[i].types[0];
311+
312+
if (ADDRESS_COMPONENTS[addressType]) {
313+
let val = place.address_components[i][ADDRESS_COMPONENTS[addressType]];
314+
returnData[addressType] = val;
315+
}
316+
}
317+
318+
returnData['latitude'] = place.geometry.location.lat();
319+
returnData['longitude'] = place.geometry.location.lng();
320+
return returnData
321+
},
322+
323+
/**
324+
* Extract configured types out of raw result as
325+
* Geocode API does not allow to do it
326+
* @param results
327+
* @returns {GeocoderResult}
328+
* @link https://developers.google.com/maps/documentation/javascript/reference#GeocoderResult
329+
*/
330+
filterGeocodeResultTypes (results) {
331+
if (!results || !this.types) return results;
332+
let output = [];
333+
let types = [this.types];
334+
if (types.includes('(cities)')) types = types.concat(CITIES_TYPE);
335+
if (types.includes('(regions)')) types = types.concat(REGIONS_TYPE);
336+
337+
for (let r of results) {
338+
for (let t of r.types) {
339+
if (types.includes(t)) {
340+
output.push(r);
341+
break;
342+
}
228343
}
229344
}
345+
return output;
230346
}
231347
}
232348
}

test/helpers/google_stub.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ export default function googleStub() {
66
return {
77
addListener: function () { }
88
}
9+
},
10+
Geocoder: function () {
11+
return {
12+
geocode: function () { }
13+
}
914
}
1015
},
1116
}

0 commit comments

Comments
 (0)