A Guide for Developers Traveling Through OpenLayers - 14. Displaying the User's Location on the Map
A Guide for Developers Traveling Through OpenLayers - 14. Displaying the User's Location on the Map
Based on the user's location, various services can be provided, but among them, the most basic feature is directly displaying the user's location on the map.
Based on the geolocation explained in the previous chapter, we display the location on the map using OpenLayers.
Displaying the user's location on the map means adding one Feature. Since the primary entity managing a Feature is the source, and the source is managed by a layer, the first step is to choose the layer to which the Feature will be added.
For this, we first need to add a dedicated layer for displaying the user's location. After that, we simply add a Feature to that layer. Therefore, the flow of operations is as follows.
- During the rendering process of the button component, add a VectorLayer to use as a dedicated layer.
- When the button is clicked, perform geolocation to obtain the user's location.
- Create a VectorSource and add it to the layer.
- Create a Feature using the user's location.
- Add the created feature to the VectorSource.
You might think, "wouldn't it be fine to just use an already-existing layer?" but having a dedicated layer is much more useful from a management standpoint.
If you use an existing layer, it may have unwanted effects on the Source object that layer originally had, and if there's no VectorLayer among the layers, you'll end up having to add one anyway.
TSX
/** * Method that returns the location marker add button Element * * @param {SubProps} props: properties * * @returns {JSX.Element} Element */ export function LocationWithMarker({ map }: SubProps) { // If the map object is valid if (map) { // When dragging, clear all Features from the layer map.on('pointerdrag', () => { map.getAllLayers().filter(layer => layer.get('name') === 'location')[0].getSource().clear(); }); // If the location vector layer doesn't exist if (map.getAllLayers().filter(layer => layer.get('name') === 'location').length === 0) { // Add a dedicated layer map.addLayer(new VectorLayer({ source: new VectorSource(), properties: { name: 'location' }, style: new Style({ image: new Icon({ src: 'https://tsauerwein.github.io/ol3/animation-flights/examples/data/icon.png' }) }), minZoom: 15, zIndex: 10 })); } const onClick = () => { // If geolocation is available if ('geolocation' in navigator) { const tag = document.querySelector('button.location') as HTMLButtonElement; navigator.geolocation.getCurrentPosition(position => { const { latitude, longitude } = position.coords; // Move the map map.getView().setCenter([ longitude, latitude ]); // Add a Feature to the location layer's Source map.getAllLayers().filter(layer => layer.get('name') === 'location')[0].getSource().addFeature(new Feature({ geometry: new Point([ longitude, latitude ]) })); }, () => alert('실패'), { enableHighAccuracy: true }); } // Otherwise else { alert('사용자 위치를 확인할 수 없습니다.'); } }; return ( <button className='location' title='현재 위치 이동' onClick={onClick}><BiCurrentLocation size={25} color="white" /></button> ); } // Otherwise else { return null; } }
The overall structure is the same as the Location component from the previous chapter, but there are a few differences.
- Drag event
TYPESCRIPT
// When dragging, clear all Features from the layer map.on('pointerdrag', () => { map.getAllLayers().filter(layer => layer.get('name') === 'location')[0].getSource().clear(); });
Add a drag event so that every time the map is dragged, all Features of the location layer are cleared.
In other words, if the user drags the map, the user's current location displayed on the map is removed.
- Adding a dedicated layer
TYPESCRIPT
// If the location vector layer doesn't exist if (map.getAllLayers().filter(layer => layer.get('name') === 'location').length === 0) { // Add a dedicated layer map.addLayer(new VectorLayer({ source: new VectorSource(), properties: { name: 'location' }, style: new Style({ image: new Icon({ src: 'https://tsauerwein.github.io/ol3/animation-flights/examples/data/icon.png' }) }), minZoom: 15, zIndex: 10 })); }
If a dedicated layer doesn't exist, add one. With this configuration, simply using the LocationWithMarker component makes it possible to add the dedicated layer.
- Adding a Feature
TYPESCRIPT
// Add a Feature to the location layer's Source map.getAllLayers().filter(layer => layer.get('name') === 'location')[0].getSource().addFeature(new Feature({ geometry: new Point([ longitude, latitude ]) }));
Create and add a Feature using the location information collected through Geolocation.
TSX
<LocationWithMarker map={mapState} />
Usage is as above. If map is not specified as a property, it's configured to return null so the button isn't displayed.
This feature is implemented as the LocationWithMarker sub-component of the project's MapInteraction component.
You can check an example implementing this at OpenLayers6 Sandbox - Feature.
Click the green button in the bottom-left to move to the user's location, and the location is displayed as a blue circle.
Depending on your internet line configuration, note that sometimes the physical location of the line's server shows up instead of the user's actual location.
Mobile internet such as LTE or 5G doesn't have this issue, but with wired internet like LAN, it's not uncommon for the server's location to show up instead of your own on occasion.
