basic locate control

This commit is contained in:
Anton 2024-01-14 20:08:12 +01:00
parent 6d53d0d3f8
commit b52ae474cd
6 changed files with 81 additions and 11 deletions

6
package-lock.json generated
View File

@ -14,6 +14,7 @@
"@types/offscreencanvas": "^2019.7.1",
"axios": "^1.6.5",
"leaflet": "^1.9.4",
"leaflet.locatecontrol": "^0.79.0",
"prop-types": "^15.8.1",
"react-colorful": "^5.6.1",
"react-image-crop": "^10.1.8",
@ -2904,6 +2905,11 @@
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz",
"integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA=="
},
"node_modules/leaflet.locatecontrol": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/leaflet.locatecontrol/-/leaflet.locatecontrol-0.79.0.tgz",
"integrity": "sha512-h64QIHFkypYdr90lkSfjKvPvvk8/b8UnP3m9WuoWdp5p2AaCWC0T1NVwyuj4rd5U4fBW3tQt4ppmZ2LceHMIDg=="
},
"node_modules/leaflet.markercluster": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/leaflet.markercluster/-/leaflet.markercluster-1.5.3.tgz",

View File

@ -47,6 +47,7 @@
"@types/offscreencanvas": "^2019.7.1",
"axios": "^1.6.5",
"leaflet": "^1.9.4",
"leaflet.locatecontrol": "^0.79.0",
"prop-types": "^15.8.1",
"react-colorful": "^5.6.1",
"react-image-crop": "^10.1.8",

View File

@ -0,0 +1,53 @@
import * as React from 'react'
import * as L from 'leaflet'
import { useMap } from 'react-leaflet'
import 'leaflet.locatecontrol'
import 'leaflet.locatecontrol/dist/L.Control.Locate.css'
import { useEffect, useRef, useState } from 'react'
// Converts leaflet.locatecontrol to a React Component
export const LocateControl = () => {
const map = useMap();
// prevent react18 from calling useEffect twice
const init = useRef(false)
const [lc, setLc] = useState<any>(null);
const [active, setActive] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(false);
useEffect(() => {
if (!init.current) {
//@ts-ignore
setLc(L.control.locate().addTo(map));
init.current = true;
}
}, [])
return (<>
<div className="tw-card tw-w-14 tw-bg-base-100 tw-shadow-xl tw-items-center tw-justify-center">
<div className="tw-card-body hover:tw-bg-slate-300 tw-card tw-p-2 tw-h-10 tw-w-10 tw-transition-all tw-duration-300 hover:tw-cursor-pointer" onClick={() => {
if (active) {
lc.stop();
setActive(false);
}
else {
lc.start();
setActive(true);
}
}}>
<svg fill="currentColor" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" className='tw-mt-1 tw-p-[1px]'>
<path d="M30 14.75h-2.824c-0.608-5.219-4.707-9.318-9.874-9.921l-0.053-0.005v-2.824c0-0.69-0.56-1.25-1.25-1.25s-1.25 0.56-1.25 1.25v0 2.824c-5.219 0.608-9.318 4.707-9.921 9.874l-0.005 0.053h-2.824c-0.69 0-1.25 0.56-1.25 1.25s0.56 1.25 1.25 1.25v0h2.824c0.608 5.219 4.707 9.318 9.874 9.921l0.053 0.005v2.824c0 0.69 0.56 1.25 1.25 1.25s1.25-0.56 1.25-1.25v0-2.824c5.219-0.608 9.318-4.707 9.921-9.874l0.005-0.053h2.824c0.69 0 1.25-0.56 1.25-1.25s-0.56-1.25-1.25-1.25v0zM17.25 24.624v-2.624c0-0.69-0.56-1.25-1.25-1.25s-1.25 0.56-1.25 1.25v0 2.624c-3.821-0.57-6.803-3.553-7.368-7.326l-0.006-0.048h2.624c0.69 0 1.25-0.56 1.25-1.25s-0.56-1.25-1.25-1.25v0h-2.624c0.57-3.821 3.553-6.804 7.326-7.368l0.048-0.006v2.624c0 0.69 0.56 1.25 1.25 1.25s1.25-0.56 1.25-1.25v0-2.624c3.821 0.57 6.803 3.553 7.368 7.326l0.006 0.048h-2.624c-0.69 0-1.25 0.56-1.25 1.25s0.56 1.25 1.25 1.25v0h2.624c-0.571 3.821-3.553 6.803-7.326 7.368l-0.048 0.006z"></path>
</svg>
</div>
</div></>)
}

View File

@ -10,6 +10,7 @@ import { useTags } from '../../hooks/useTags';
import { useItems } from '../../hooks/useItems';
import { useLeafletRefs } from '../../hooks/useLeafletRefs';
import { getValue } from '../../../../Utils/GetValue';
import { LocateControl } from './LocateControl';
@ -58,16 +59,19 @@ export const SearchControl = ({ clusterRef }) => {
return (<>
{!(windowDimensions.height < 500) &&
<div className='tw-w-[calc(100vw-2rem)] tw-max-w-[22rem] '>
<input type="text" placeholder="search ..." autoComplete="off" value={value} className="tw-input tw-input-bordered tw-w-full tw-shadow-xl tw-rounded-lg"
ref={searchInput}
onChange={(e) => setValue(e.target.value)}
onFocus={() => setHideSuggestions(false)}
onBlur={async () => {
setTimeout(() => {
setHideSuggestions(true);
}, 200);
}} />
{value.length > 0 && <button className="tw-btn tw-btn-sm tw-btn-circle tw-absolute tw-right-2 tw-top-2" onClick={() => setValue("")}></button>}
<div className='flex tw-flex-row'>
<input type="text" placeholder="search ..." autoComplete="off" value={value} className="tw-input tw-input-bordered tw-w-full tw-shadow-xl tw-rounded-lg tw-mr-2"
ref={searchInput}
onChange={(e) => setValue(e.target.value)}
onFocus={() => setHideSuggestions(false)}
onBlur={async () => {
setTimeout(() => {
setHideSuggestions(true);
}, 200);
}} />
<LocateControl />
</div>
{value.length > 0 && <button className="tw-btn tw-btn-sm tw-btn-circle tw-absolute tw-right-16 tw-top-2" onClick={() => setValue("")}></button>}
{hideSuggestions || Array.from(geoResults).length == 0 && itemsResults.length == 0 && tagsResults.length == 0 || value.length == 0 ? "" :
<div className='tw-card tw-card-body tw-bg-base-100 tw-p-4 tw-mt-2 tw-shadow-xl'>
{tagsResults.length > 0 &&
@ -110,7 +114,7 @@ export const SearchControl = ({ clusterRef }) => {
{Array.from(geoResults).length > 0 && (itemsResults.length > 0 || tagsResults.length > 0) && <hr className='tw-opacity-50'></hr>}
{Array.from(geoResults).map((geo) => (
<div className='tw-flex tw-flex-row' key={Math.random()}>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth="1.5" stroke="currentColor" className="tw-text-current tw-mr-2 tw-mt-0 tw-w-5">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth="1.5" stroke="currentColor" className="tw-text-current tw-mr-2 tw-mt-0 tw-w-4">
<path strokeLinecap="round" strokeLinejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
</svg>

View File

@ -20,6 +20,10 @@
display: none;
}
.leaflet-control-locate {
display: none;
}
.leaflet-data-marker {
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAQCAYAAACcN8ZaAAAB3klEQVR42s3U4UdDURzG8czMXJnJ1Vwzc6VJZjaZJdlMlpQsKdmUFNOUspRSSqUolfQfr+fF98Vx5mwv9qbDx7LdznnO7/7Omej3+/+Ga0QMUYkhbvBgmhzCQxwxibIGrGEF8CQhU+LLtKQkQNqScUgjxRxTBIxbgfgD/BgnhM8kM5KTeclLQYqGkkMRBckzR8ic/mAgd5BAZplsUaqyIg2sDtHg2brUZJk5SmwopErJUWE8SpmTMhNvya60Zd/SNrR4bkeaskG4uiwRZk6yrJEYFibGAxn+scECHTmTnuVCzvmty3PHciB7bGKN6lQkzysPqIrHmpFhYbKUtckC1/Ioz4ZHuZdbuSLYiRxRpSZVWXZVxAzC0R4Ik5SQsu6w8yd5l2/5kg95I9SdXMoZQfYIUjeqEUrgOkXGPeN4TYRhxy8E+ZUf+eS7B7miIoeybVSjKDnm8u3+gH3pDTYwu1igATvs/pXqvBKiR4i2bNJfi1ZfUAnjgrOG8wY2quNzBKuU/ZS+uSFEl5O0xRGuUIlZCcw7xG5QPkeHYUSNV5WXGou2sC3rBC0LjenqCXGO0WEiTJa0Lr4KixdHBrDGuGGiRqCUpFk8pGIpQtCU7p4YPwxYxEMCk1aAMQZh8Ac8PfbIzYPJOwAAAABJRU5ErkJggg==') no-repeat;

View File

@ -20,6 +20,7 @@ import { QuestControl } from "./Subcomponents/Controls/QuestControl";
import { Control } from "./Subcomponents/Controls/Control";
import { Outlet } from "react-router-dom";
import { TagsControl } from "./Subcomponents/Controls/TagsControl";
import { LocateControl } from "./Subcomponents/Controls/LocateControl";
export interface MapEventListenerProps {
@ -40,6 +41,7 @@ function UtopiaMap({
children }
: UtopiaMapProps) {
let meta = document.getElementsByTagName('meta')
const [metaTags, setMetaTags] = useState<HTMLCollectionOf<HTMLMetaElement>>(meta);