Closed wibed closed 7 months ago
to put it into perspective. ive had a look at the source code from the old geocoder and it resulted in this:
a full example would be appreciated
const getMapboxMap = () => {
const { mapRef } = props
return (mapRef && mapRef.current && mapRef.current.getMap()) || null
}
const getContainerNode = () => {
const { containerRef } = props
return (containerRef && containerRef.current) || null
}
const geocoder = useControl<MapboxGeocoder>(
() => {
const ctrl = new MapboxGeocoder({
...props,
marker: false,
accessToken: props.mapboxAccessToken,
reverseGeocode: false
});
ctrl.on('clear', event => {
onClear(event)
setMarker(null)
});
ctrl.on('error', onError);
ctrl.on('loading', event => {
onLoading(event)
});
ctrl.on('results', onResults);
ctrl.on('result', event => {
onResult(event);
const { result } = event;
const location = result && (
result.center || (result.geometry?.type === 'Point' && result.geometry.coordinates)
);
if (location) { setMarker(<Marker longitude={location[0]} latitude={location[1]} />) }
else { setMarker(null) }
});
ctrl.on('error', onError);
const mapboxMap = getMapboxMap()
const containerNode = getContainerNode()
if (mapboxMap && containerNode) {
console.log("append")
containerNode.appendChild(ctrl.onAdd(mapboxMap))
}
return ctrl;
},
{}
);
i ended up with a working example. the culprit was me passing refs wrong.
here is my version, feel free to use it in any way you like.
import React, { forwardRef, useRef, useState, PropsWithChildren } from 'react';
import mapboxgl from 'mapbox-gl';
import ReactMapGL, { useControl, Marker } from 'react-map-gl';
import MapboxGeocoder, { GeocoderOptions } from '@mapbox/mapbox-gl-geocoder';
type GeocoderControlProps = Omit<GeocoderOptions, 'accessToken' | 'mapboxgl' | 'marker'> & {
mapboxAccessToken: string;
onMarker?: any; //boolean | Omit<MarkerProps, 'longitude' | 'latitude'>;
position?: any; //ControlPosition;
onClear?: (e: object) => void;
onLoading?: (e: object) => void;
onResults?: (e: object) => void;
onResult?: (e: object) => void;
onError?: (e: object) => void;
}
export const GeocoderControl = forwardRef(({
...props
}: GeocoderControlProps, ref: any) => {
const { mapRef, containerRef } = ref
const [marker, setMarker] = useState<any>(null);
const {
onClear = () => true,
onResult = () => true,
onError = () => true,
onResults = () => true,
onLoading = () => true
} = props
const getMapboxMap = () => {
return (mapRef && mapRef.current && mapRef.current.getMap()) || null
}
const getContainerNode = () => {
return (containerRef && containerRef.current) || null
}
const geocoder = useControl<MapboxGeocoder>(
() => {
const mapboxMap = getMapboxMap()
const containerNode = getContainerNode()
const ctrl = new MapboxGeocoder({
...props,
marker: false,
accessToken: props.mapboxAccessToken,
reverseGeocode: false
});
if (mapboxMap && containerNode && !containerNode.hasChildNodes()) {
containerNode.appendChild(ctrl.onAdd(mapboxMap))
}
ctrl.on('clear', event => {
onClear(event)
setMarker(null)
});
ctrl.on('error', onError);
ctrl.on('loading', event => {
onLoading(event)
});
ctrl.on('results', event => {
onResults(event)
});
ctrl.on('result', event => {
onResult(event);
const { result } = event;
const location = result && (
result.center || (result.geometry?.type === 'Point' && result.geometry.coordinates)
);
if (location) { setMarker(<Marker longitude={location[0]} latitude={location[1]} />) }
else { setMarker(null) }
});
ctrl.on('error', onError);
return ctrl;
}, {}
);
// @ts-ignore (TS2339) private member
if (geocoder._map) {
if (geocoder.getProximity() !== props.proximity && props.proximity !== undefined) {
geocoder.setProximity(props.proximity);
}
if (geocoder.getRenderFunction() !== props.render && props.render !== undefined) {
geocoder.setRenderFunction(props.render);
}
if (geocoder.getLanguage() !== props.language && props.language !== undefined) {
geocoder.setLanguage(props.language);
}
if (geocoder.getZoom() !== props.zoom && props.zoom !== undefined) {
geocoder.setZoom(props.zoom);
}
if (geocoder.getFlyTo() !== props.flyTo && props.flyTo !== undefined) {
geocoder.setFlyTo(props.flyTo);
}
if (geocoder.getPlaceholder() !== props.placeholder && props.placeholder !== undefined) {
geocoder.setPlaceholder(props.placeholder);
}
if (geocoder.getCountries() !== props.countries && props.countries !== undefined) {
geocoder.setCountries(props.countries);
}
if (geocoder.getTypes() !== props.types && props.types !== undefined) {
geocoder.setTypes(props.types);
}
if (geocoder.getMinLength() !== props.minLength && props.minLength !== undefined) {
geocoder.setMinLength(props.minLength);
}
if (geocoder.getLimit() !== props.limit && props.limit !== undefined) {
geocoder.setLimit(props.limit);
}
if (geocoder.getFilter() !== props.filter && props.filter !== undefined) {
geocoder.setFilter(props.filter);
}
if (geocoder.getOrigin() !== props.origin && props.origin !== undefined) {
geocoder.setOrigin(props.origin);
}
// Types missing from @types/mapbox__mapbox-gl-geocoder
// if (geocoder.getAutocomplete() !== props.autocomplete && props.autocomplete !== undefined) {
// geocoder.setAutocomplete(props.autocomplete);
// }
// if (geocoder.getFuzzyMatch() !== props.fuzzyMatch && props.fuzzyMatch !== undefined) {
// geocoder.setFuzzyMatch(props.fuzzyMatch);
// }
// if (geocoder.getRouting() !== props.routing && props.routing !== undefined) {
// geocoder.setRouting(props.routing);
// }
// if (geocoder.getWorldview() !== props.worldview && props.worldview !== undefined) {
// geocoder.setWorldview(props.worldview);
// }
}
return marker
})
// type FloorMapProps = Pick<PropsWithChildren> & {
// initial: any;
// onMove: any;
// onResult: any;
// onClear: any;
// setSelection: any;
// searchResult: any;
// }
export const FloorMap = forwardRef(({
initial,
onMove,
onResult,
onClear,
setSelection,
searchResult,
// containerRef,
viewportRef,
...props
}: any, ref: any) => {
const { mapRef } = ref
const settingPadding = 2
const element = viewportRef
const parent = element.parentNode
const paddingTop = element.offsetTop
const paddingLeft = element.offsetLeft
const paddingRight = parent.offsetWidth - paddingLeft - element.offsetWidth - settingPadding
const paddingBottom = parent.offsetHeight - paddingTop - element.offsetHeight - settingPadding
// const { MAPBOX_PUBLIC_TOKEN, MAPBOX_STYLE_URL } = process.env
if (!MAPBOX_PUBLIC_TOKEN) throw new Error("No public token for the maxbox api implemented")
if (!MAPBOX_STYLE_URL) throw new Error("No style url for the mapbox api implemented")
const [isSearch, setIsSearch] = useState<boolean | undefined>(false)
const _onResult = (e) => {
onResult(e)
setIsSearch(undefined)
}
const _onClear = (e) => {
onClear(e)
setIsSearch(false)
}
return (
<ReactMapGL
ref={mapRef}
onMove={(e) => onMove(e)}
onLoad={(e) => {
if (mapRef.current !== null) {
const obj: any = mapRef.current
if (obj.resize) {
obj.easeTo({
padding: {
left: paddingLeft,
top: paddingTop,
right: paddingRight,
bottom: paddingBottom
}
})
obj.resize()
}
}
}}
mapStyle={`${MAPBOX_STYLE_URL}`}
mapboxAccessToken={`${MAPBOX_PUBLIC_TOKEN}`}
{...initial}
width={'100%'}
height={'100%'}
>
<style>{`
.mapboxgl-map {
position: absolute !important;
top: 0;
bottom: 0;
width: 100% !important;
height: 100% !important;
}
.mapboxgl-canvas {
left: 0;
}
.mapboxgl-ctrl-logo,
.mapboxgl-ctrl-attrib,
.mapboxgl-ctrl-geocoder--powered-by {
display: none !important;
}
`}</style>
{mapRef && mapRef.current !== undefined
&&
< GeocoderControl
ref={ref}
mapboxAccessToken={MAPBOX_PUBLIC_TOKEN}
/>
}
{searchResult.map((el, idx) => (
<div key={el.lon}>
<Marker
longitude={el.lon}
latitude={el.lat}
>
<p
className="h-6 w-6 cursor-pointer fill-white"
onClick={() => setSelection(
(prev) => prev === idx
? undefined
: idx
)}
>
<div>H</div>
</p>
</Marker>
</div>
))}
</ReactMapGL>
)
})
Description
https://github.com/visgl/react-map-gl/issues/771#issuecomment-489800371
along this comment, there is a common use to pass the mapRef to the geocoder instance as one could before the major update. now missing examples make it hard to figure out on how to approach this
Expected Behavior
-
Steps to Reproduce
-
Environment
Logs
No response