问题
I am using openlayers 5 to implement a simple geolocation functionality :
When check the geolocation checkbox, the geolocation starts, zooms to the position with an animated transition and it automatically tracks the position constantly. It adds a feature in a vector layer.
When uncheck the geolocation checkbox, the geolocation is turned off, along with the tracking and that vector layer is cleared.
My problem is that I don't know how to wait until the geolocation has a value, so I can properly continue with the zooming in that position. I think is normal for geolocation to take a little time until it has a value, but I don't know how to wait until then. My code just zooms in its current position and after a while the geolocation point is rendered in the right place.
My code (openlayers 5 + angular 6)
ngOnInit(){ //while initializing everything else
this.vectorlayer = new VectorLayer({
source: this.vectorsource,
style: styleFunction,
title:'features'
});
this.geolocation = new Geolocation({
trackingOptions: {
enableHighAccuracy: true
},
projection: 'EPSG:3857'
});
this.geolocation.on('error', (error) => {
this.geolocationerror=true;
this.geolocationmsg = error;
});
this.accuracyFeature = new Feature();
this.geolocation.on('change:accuracyGeometry', ()=> {
this.accuracyFeature.setGeometry(this.geolocation.getAccuracyGeometry());
});
this.positionFeature = new Feature();
this.positionFeature.setStyle(new Style({
image: new CircleStyle({
radius: 6,
fill: new Fill({
color: '#3399CC'
}),
stroke: new Stroke({
color: '#fff',
width: 2
})
})
}));
this.geolocation.on('change:position', ()=> {
let coordinates = this.geolocation.getPosition();
this.positionFeature.setGeometry(coordinates ?
new Point(coordinates) : null);
});
if(window.innerWidth < 600){
this.isChecked = true;
}
this.geolocsource = new VectorSource({});
this.geoloclayer = new VectorLayer({
source: this.geolocsource,
title:'location'
});
this.view = new View({ ....
this.olmap = new Map({....
//turn on in smaller screenc, <600
this.toggleGeolocation(this.isChecked);
}//ngOnInit
outside the ngOnInit
toggleGeolocation(checked){
this.geolocationmsg='';
this.geolocationerror=false;
if(checked){ //turned on
this.geolocation.setTracking(checked);
this.geolocsource.addFeatures([this.accuracyFeature, this.positionFeature]);
this.geolocOn = true;
this.geolocLiveCoords = this.geolocation.getPosition();
let center = this.geolocation.getPosition();
this.olmap.getView().animate({
center: center,
duration: 2000,
zoom:10
});
}
else{ //turned off
this.geolocation.setTracking(checked);
this.geolocOn = false;
this.geolocsource.clear();
this.geolocLiveCoords='';
}
}
and the html part
<label for="track">track position<input id="trackpos" type="checkbox" [(ngModel)]="isChecked" (change)="toggleGeolocation(isChecked)"/></label>
<div *ngIf='geolocationerror'>{{geolocationmsg}}</div>
<div *ngIf='geolocOn'>{{geolocLiveCoords}}</div>
<div id="map" class="map" tabindex="0"></div>
I also tried using promises
outside the ngOnInit
, change toggleGeolocation
getpos() {
console.log('in');
return new Promise(resolve => {
resolve(this.geolocation.getPosition());
});
}
toggleGeolocation(checked){
this.geolocationmsg='';
this.geolocationerror=false;
if(checked){
this.getpos().then((value) => {
this.geolocsource.addFeatures([this.accuracyFeature, this.positionFeature]) ;
this.olmap.getView().animate({
center: value,
duration: 2000,
zoom:10
});
this.geolocation.setTracking(checked);
});
}
else{
this.geolocation.setTracking(checked);
this.geolocOn = false;
this.geolocsource.clear();
this.geolocLiveCoords='';
}
}
The getpos
is called (I can see the in
on the console), but it never has a value, so it returns undefined
.
回答1:
Excellent observation by @geocodezip. I had to change the toggleGeolocation
and the this.geolocation.on('change:position'
and it works.
A couple of things sometimes I click the geolocation, it gets the coords and then it gets them again, causeing the animation to be jerky and flicker as it goes. Any ideas?
I guess it should follow the movement, this is why the view animation should be in the this.geolocation.on('change:position'
. But is this calculation-intensive, causing the map to be non-responsive if the user moves constantly?
Thanks
Now my whole code is
ngOnInit() {
this.geolocation = new Geolocation({
trackingOptions: {
enableHighAccuracy: true
},
projection: 'EPSG:3857'
});
this.geolocation.on('error', (error) => {
this.geolocationerror=true;
this.geolocationmsg = error;
});
this.accuracyFeature = new Feature();
this.geolocation.on('change:accuracyGeometry', ()=> {
this.accuracyFeature.setGeometry(this.geolocation.getAccuracyGeometry());
});
this.positionFeature = new Feature();
this.positionFeature.setStyle(new Style({
image: new CircleStyle({
radius: 6,
fill: new Fill({
color: '#3399CC'
}),
stroke: new Stroke({
color: '#fff',
width: 2
})
})
}));
this.geolocation.on('change:position', ()=> {
console.log('in on chnage pos');
let coordinates = this.geolocation.getPosition();
console.log('coordinates > ',coordinates);
this.positionFeature.setGeometry(coordinates ? new Point(coordinates) : null);
this.geolocLiveCoords = coordinates;
let center = coordinates;
this.olmap.getView().animate({
center: center,
duration: 2000,
zoom:10
});
});
if(window.innerWidth < 600){
this.isChecked = true;
}
this.geolocsource = new VectorSource({});
this.geoloclayer = new VectorLayer({
source: this.geolocsource,
title:'location'
});
this.view = new View({ ....
this.olmap = new Map({....
this.toggleGeolocation(this.isChecked);
}//ngOnInit
toggleGeolocation(checked){
this.geolocationmsg='';
this.geolocationerror=false;
if(checked){
this.geolocation.setTracking(checked);
console.log('right before add features');
this.geolocsource.addFeatures([this.accuracyFeature, this.positionFeature]);
this.geolocOn = true;
}
else{
this.geolocation.setTracking(checked);
this.geolocOn = false;
this.geolocsource.clear();
this.geolocLiveCoords='';
}
}
来源:https://stackoverflow.com/questions/51726230/wait-until-openlayers-5-geolocation-returned-a-value