Implement geocoding search

This commit is contained in:
Anton Tananaev 2022-06-19 09:36:12 -07:00
parent e67aafb900
commit e3827fbad0
5 changed files with 283 additions and 0 deletions

1
modern/.npmrc Normal file
View File

@ -0,0 +1 @@
legacy-peer-deps=true

View File

@ -6,6 +6,7 @@
"@emotion/react": "^11.9.0",
"@emotion/styled": "^11.8.1",
"@mapbox/mapbox-gl-draw": "^1.3.0",
"@maplibre/maplibre-gl-geocoder": "^1.3.1",
"@mui/icons-material": "^5.8.0",
"@mui/lab": "^5.0.0-alpha.82",
"@mui/material": "^5.8.0",

View File

@ -34,6 +34,7 @@ import { useDeviceReadonly } from '../common/util/permissions';
import MapPositions from '../map/MapPositions';
import MapDirection from '../map/MapDirection';
import MapOverlay from '../map/overlay/MapOverlay';
import MapGeocoder from '../map/geocoder/MapGeocoder';
const useStyles = makeStyles((theme) => ({
root: {
@ -213,6 +214,7 @@ const MainPage = () => {
<PoiMap />
</MapView>
<MapCurrentLocation />
<MapGeocoder />
{desktop && <MapPadding left={parseInt(theme.dimensions.drawerWidthDesktop, 10)} />}
<Button
variant="contained"

View File

@ -0,0 +1,56 @@
import './geocoder.css';
import maplibregl from 'maplibre-gl';
import MaplibreGeocoder from '@maplibre/maplibre-gl-geocoder';
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { map } from '../core/MapView';
import { errorsActions } from '../../store';
const MapGeocoder = () => {
const dispatch = useDispatch();
useEffect(() => {
const geocoder = {
forwardGeocode: async (config) => {
const features = [];
try {
const request = `https://nominatim.openstreetmap.org/search?q=${config.query}&format=geojson&polygon_geojson=1&addressdetails=1`;
const response = await fetch(request);
const geojson = await response.json();
geojson.features.forEach((feature) => {
const center = [
feature.bbox[0] + (feature.bbox[2] - feature.bbox[0]) / 2,
feature.bbox[1] + (feature.bbox[3] - feature.bbox[1]) / 2,
];
features.push({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: center,
},
place_name: feature.properties.display_name,
properties: feature.properties,
text: feature.properties.display_name,
place_type: ['place'],
center,
});
});
} catch (e) {
dispatch(errorsActions.push(e.message));
}
return { features };
},
};
const control = new MaplibreGeocoder(geocoder, {
maplibregl,
collapsed: true,
});
map.addControl(control);
return () => map.removeControl(control);
}, [dispatch]);
return null;
};
export default MapGeocoder;

View File

@ -0,0 +1,223 @@
/* Basics */
.maplibregl-ctrl-geocoder,
.maplibregl-ctrl-geocoder *,
.maplibregl-ctrl-geocoder *:after,
.maplibregl-ctrl-geocoder *:before {
box-sizing: border-box;
}
.maplibregl-ctrl-geocoder {
font-size: 15px;
line-height: 20px;
font-family: "Open Sans", "Helvetica Neue", Arial, Helvetica, sans-serif;
position: relative;
background-color: #fff;
width: 100%;
min-width: 240px;
max-width: 360px;
z-index: 1;
border-radius: 4px;
transition: width 0.25s, min-width 0.25s;
}
.maplibregl-ctrl-geocoder--input {
font: inherit;
width: 100%;
border: 0;
background-color: transparent;
margin: 0;
height: 29px;
color: #404040; /* fallback */
color: rgba(0, 0, 0, 0.75);
padding: 6px 30px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.maplibregl-ctrl-geocoder--input:focus {
color: #404040; /* fallback */
color: rgba(0, 0, 0, 0.75);
outline: 0;
box-shadow: none;
outline: thin dotted;
}
.maplibregl-ctrl-geocoder .maplibregl-ctrl-geocoder--pin-right > * {
z-index: 2;
position: absolute;
right: 5px;
top: 5px;
display: none;
}
.maplibregl-ctrl-geocoder,
.maplibregl-ctrl-geocoder .suggestions {
box-shadow: 0 0 0 2px rgb(0 0 0 / 10%);
}
/* Collapsed */
.maplibregl-ctrl-geocoder.maplibregl-ctrl-geocoder--collapsed {
width: 29px;
min-width: 29px;
transition: width 0.25s, min-width 0.25s;
}
/* Suggestions */
.maplibregl-ctrl-geocoder .suggestions {
background-color: #fff;
border-radius: 4px;
left: 0;
list-style: none;
margin: 0;
padding: 0;
position: absolute;
width: 100%;
top: 110%; /* fallback */
top: calc(100% + 6px);
z-index: 1000;
overflow: hidden;
font-size: 13px;
}
.maplibregl-ctrl-bottom-left .suggestions,
.maplibregl-ctrl-bottom-right .suggestions {
top: auto;
bottom: 100%;
}
.maplibregl-ctrl-geocoder .suggestions > li > a {
cursor: default;
display: block;
padding: 6px 12px;
color: #404040;
}
.maplibregl-ctrl-geocoder .suggestions > .active > a,
.maplibregl-ctrl-geocoder .suggestions > li > a:hover {
color: #404040;
background-color: #f3f3f3;
text-decoration: none;
cursor: pointer;
}
.maplibregl-ctrl-geocoder--suggestion {
display: flex;
flex-direction: row;
align-items: center;
}
.maplibre-ctrl-geocoder--suggestion-icon {
min-width: 30px;
min-height: 24px;
max-width: 30px;
max-height: 24px;
padding-right: 12px;
}
.maplibregl-ctrl-geocoder--suggestion-info {
display: flex;
flex-direction: column;
}
.maplibregl-ctrl-geocoder--suggestion-match {
font-weight: bold;
}
.maplibregl-ctrl-geocoder--suggestion-title,
.maplibregl-ctrl-geocoder--suggestion-address {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.maplibregl-ctrl-geocoder--result {
display: flex;
flex-direction: row;
align-items: center;
}
.maplibre-ctrl-geocoder--result-icon {
min-width: 30px;
min-height: 24px;
max-width: 30px;
max-height: 24px;
padding-right: 12px;
}
.maplibregl-ctrl-geocoder--result-title {
font-weight: bold;
}
.maplibregl-ctrl-geocoder--result-title,
.maplibregl-ctrl-geocoder--result-address {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
/* Icons */
.maplibregl-ctrl-geocoder--icon {
display: inline-block;
vertical-align: middle;
}
.maplibregl-ctrl-geocoder--icon-search {
position: absolute;
top: 3px;
left: 3px;
width: 23px;
height: 23px;
}
.maplibregl-ctrl-geocoder--button {
padding: 0;
margin: 0;
border: none;
cursor: pointer;
background: #fff;
line-height: 1;
}
.maplibregl-ctrl-geocoder--icon-close {
width: 20px;
height: 20px;
}
.maplibregl-ctrl-geocoder--icon-loading {
width: 20px;
height: 20px;
-moz-animation: rotate 0.8s infinite cubic-bezier(0.45, 0.05, 0.55, 0.95);
-webkit-animation: rotate 0.8s infinite cubic-bezier(0.45, 0.05, 0.55, 0.95);
animation: rotate 0.8s infinite cubic-bezier(0.45, 0.05, 0.55, 0.95);
}
/* Animation */
@-webkit-keyframes rotate {
from {
-webkit-transform: rotate(0);
transform: rotate(0);
}
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes rotate {
from {
-webkit-transform: rotate(0);
transform: rotate(0);
}
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.maplibre-gl-geocoder--error {
color: #909090;
padding: 6px 12px;
font-size: 16px;
text-align: center;
}