Is there a way to set maximum and minimum radius for circle in react-google-maps? - react-google-maps

I'm using react-google-maps circle and while changing the circle radius I'm unable to prevent it to the maximum and minimum radius limits, can anyone help me with this, Thank you. and below is my code
<Circle
center={this.circleCenter}
radius={this.circleRadius}
draggable={false}
editable={true}
ref={circle => { this.circle = circle; }}
onCenterChanged={(e) => this.onRadiusChange(e)}
onRadiusChanged={(e) => this.onRadiusChange(e)} />

You can do something like this:
<Circle
center={this.circleCenter}
radius={Math.min(Math.max(this.circleRadius, MIN_VALUE), MAX_VALUE)}
draggable={false}
editable={true}
ref={circle => { this.circle = circle; }}
onCenterChanged={(e) => this.onRadiusChange(e)}
onRadiusChanged={(e) => this.onRadiusChange(e)} />

Related

onClick in variables does not invoke the designated function

I am new to MUI and don't understand why this does not work:
const anlagendaten_array = [];
for (let x = 0; x < anlagendaten.length; x++) {
anlagendaten_array.push (
<ListItem
button
key={anlagendaten[x].name}
className="menu-unterpunkt"
onClick={() => setOpen(false)}
>
<ListItemIcon>
<LocationOn fontSize="small" />
</ListItemIcon>
<ListItemText primary={anlagendaten[x].name} />
</ListItem>
)
}
The onClick-function does not work. When using the <listIem>...</ListItem> at the place where I put {anlagendaten_array} it works.
Thx for any help
Oliver
Sorry for having bothered you. It was an I/O-error (Idiot Operator). When trying to build the codesandbox I realized my error.
Thx to all helping around here

#mui/lab/DateRangePicker - How to add custom toolbar with action buttons above and under calendar

I'm using DateRangePicker from #mui/lab and now, there is need to add custom toolbar with action buttons above or under calendar (for example, buttons apply or cancel). I struggled to find solution but couldn't find something useful. It should be on both desktop and mobile versions of datepicker.
For all those who suffer from the lack of simple and necessary solutions.
Hope this will help 🫡
Here the docs, but there is huge lack of information and examples
<LocalizationProvider dateAdapter={AdapterDateFns} localeText={{ start: 'from', end: 'to' }}>
<DateRangePicker
components={{ //edit component
PaperContent: data => { //exactly PaperContent
const childCopy = [...data.children]; //duplicate to avoid errors
const Component = () => <Box>BUILD YOUR COMPONENT</Box>;
childCopy.push(<Component />);
return childCopy; //return array of childrens
}
}}
value={value}
onChange={newValue => {
setValue(newValue);
}}
renderInput={(startProps, endProps) => (
<>
<MNVTTextField {...startProps} />
<Box>-</Box>
<MNVTTextField {...endProps} />
</>
)}
/>
</LocalizationProvider>;

Material UI Autocomplete + Infinite Scrolling together?

Problem : Getting double Scrollbars - Removing Paper Scrollbar makes the autocomplete content not scrollable hence showing ONLY the contents in the visible height of the dropdown.
If I hide the other scroll then the Infinite Scroll API does not get invoked. How can I get it working :
Description -
I am trying to create a Infinite Scroll with Material UI Autocomplete for which I am using react-infinite-scroll-component attached link for reference
The way I implemented is :
As we need to attach the Infinite Scroll to the Popper that renders the list items; hence I have written my custom PAPER Component (as per documentation it is responsible for rendering items in the dropdown )
PaperComponent={myCustomComponent}
My InfiniteScrollAutoComplete definition is attached below :
<Autocomplete
options={list.data && list.data !== null ? list.data : []}
getOptionLabel={(option) => option.name}
PaperComponent={(param) => (
<InfiniteScroll
height={200}
dataLength={list.total}
next={this.handleFetchNext.bind(this)}
hasMore={list.data.length < list.total ? true : false}
loader={
<p style={{ textAlign: "center", backgroundColor: "#f9dc01" }}>
<b>Loading...</b>
</p>
}
endMessage={
<p style={{ textAlign: "center", backgroundColor: "#f9dc01" }}>
<b>Yay! You have seen it all</b>
</p>
}
>
<Paper {...param} />
</InfiniteScroll>
)}
renderInput={(params) => (
<TextField {...params} label="" variant="outlined" />
)}
/>
const observer = useRef();
const lastOptionElementRef = useCallback((node) => {
if (observer.current) observer.current.disconnect();
observer.current = new IntersectionObserver(async (entries) => {
if (entries[0].isIntersecting && props.hasMore) {
setPageNumber((pageNumber) => pageNumber + 1);
}
});
if (node) observer.current.observe(node);
}, [props.loader]);
you can add this lastOptionElementRef to the last element of the options using the render option prop. This will trigger an function whenever the last option is visible in the viewport. Also, it avoids the scrolling issue

Performance issues with 1k+ markers with popups in React Leaflet

I have a React application with the React Leaflet library and I'm displaying a marker for each building in the map, in a small town. I have about 5k markers in total and a filter to display only the markers I want.
However, I noticed that I was having a huge performance hit with the code below. I've looked at some alternatives such as PixiOverlay and marker clustering, but the former is quite complicated to migrate the current code base to and the latter doesn't solve my problems at all.
My current code:
import React, {
useRef, useEffect, useContext, useState,
} from 'react';
import ReactDOMServer from 'react-dom/server';
import {
Marker, useLeaflet, Popup, Tooltip, CircleMarker, Circle,
} from 'react-leaflet';
import L from 'leaflet';
import styled from 'styled-components';
interface IProps {
coords: [number, number]
description: string,
name: string
}
let timeoutPopupRef: any = null;
let timeoutPopupRefClose: any = null;
const DynamicMarker: React.FC<IProps> = ({ coords, description, name }) => {
const markerRef = useRef<any>(null);
const popupRef = useRef<Popup>(null);
const tooltipRef = useRef<Tooltip>(null);
const leaflet = useLeaflet();
const divIcon: L.DivIcon = L.divIcon({
iconSize: [25, 25],
className: 'marker-white',
});
const onComponentMount = () => {
if (!leaflet.map) return;
if (!markerRef.current) return;
const mapZoom: number = leaflet.map.getZoom();
if (popupRef.current) {
if (mapZoom <= 17) {
markerRef.current.leafletElement.unbindPopup();
} else if (mapZoom > 17) {
markerRef.current.leafletElement.bindPopup(popupRef.current!.leafletElement);
}
}
if (tooltipRef.current) {
if (mapZoom <= 15) {
markerRef.current.leafletElement.unbindTooltip();
} else if (mapZoom > 15) {
markerRef.current.leafletElement.bindTooltip(tooltipRef.current!.leafletElement);
}
}
leaflet.map!.on('zoomend', onMapZoomEnd);
};
useEffect(onComponentMount, []);
const onMapZoomEnd = () => {
if (!markerRef.current) return;
if (!popupRef.current) return;
if (!leaflet.map) return;
const zoom = leaflet.map.getZoom();
if (zoom < 17) {
if (!markerRef.current!.leafletElement.isPopupOpen()) {
markerRef.current!.leafletElement.unbindPopup();
}
} else if (zoom >= 17) {
markerRef.current!.leafletElement.bindPopup(popupRef.current.leafletElement);
}
};
const handlePopupVisible = (value: boolean) => {
if (!markerRef.current) return;
if (timeoutPopupRefClose) clearTimeout(timeoutPopupRefClose);
if (value) {
if (!markerRef.current!.leafletElement.isPopupOpen()) {
timeoutPopupRef = setTimeout(() => {
markerRef.current!.leafletElement.openPopup();
}, 400);
}
} else {
if (timeoutPopupRef) {
clearTimeout(timeoutPopupRef);
}
if (markerRef.current!.leafletElement.isPopupOpen()) {
timeoutPopupRefClose = setTimeout(() => {
markerRef.current!.leafletElement.closePopup();
}, 100);
}
}
};
const onComponentDismount = () => {
leaflet.map!.off('zoomend', onMapZoomEnd);
if (!markerRef.current) return;
markerRef.current.leafletElement.remove();
};
useEffect(() => onComponentDismount, []);
return (
<Marker
icon={divIcon}
position={coords}
onmouseover={() => handlePopupVisible(true)}
onmouseout={() => handlePopupVisible(false)}
ref={markerRef}
>
<Popup className="custom-popup-content" ref={popupRef} closeButton={false}>
<div
onMouseEnter={() => handlePopupVisible(true)}
onMouseLeave={() => handlePopupVisible(false)}
>
<img
className="popup-img"
alt='image'
src='https://cdn.discordapp.com/attachments/578931223775281162/644181902215086094/default_geocode-1x.png'
/>
<div className="popup-content">
<span className="popup-content-title">{name}</span>
{description && <span className="popup-content-subtitle">{description}</span>}
</div>
</div>
</Popup>
</Marker>
);
};
export default DynamicMarker;
The code above unbinds popups from markers if the map zoom is below a threshold, and binds them when the zoom is above the threshold. I also implemented event handlers to onMouseOver and onMouseOut events on the marker component to open my popup when the user hovers the marker icon and it will only close the popup if the cursor isn't hovering over the popup or the marker icon.
When I zoom in or out with about 2k markers being displayed, the map freezes for about 5-10 seconds and updates all of the components inside the Map component exported by react-leaflet.
After testing with marker clustering via react-leaflet-markercluster, I noticed that the performance issues were still present. I tried commenting out the Popup component passed as a children to the marker component and the lag issues I had were gone.
With that in mind, I realized that my bottleneck was actually rendering 2k popups in the DOM even though they were invisible. So, after some trial and error, I came across a solution: states.
I added a boolean state called shouldDrawPopup, with a default value of false and only changed its value inside the handlePopupVisible function. The value of this boolean state will change only if:
Map zoom is above a threshold; and
Popup is not open
And then I changed the render function of my component to include a popup only if the shouldDrawPopup state is true:
return (
{shouldDrawPopup && (
<Marker
icon={divIcon}
position={coords}
onmouseover={() => handlePopupVisible(true)}
onmouseout={() => handlePopupVisible(false)}
ref={markerRef}
>
<Popup className="custom-popup-content" ref={popupRef} closeButton={false}>
<div
onMouseEnter={() => handlePopupVisible(true)}
onMouseLeave={() => handlePopupVisible(false)}
>
<img
className="popup-img"
alt='image'
src='https://cdn.discordapp.com/attachments/578931223775281162/644181902215086094/default_geocode-1x.png'
/>
<div className="popup-content">
<span className="popup-content-title">{name}</span>
{description && <span className="popup-content-subtitle">{description}</span>}
</div>
</div>
</Popup>
</Marker>
)}
);
If anyone has other solutions or any feedback to this problem, feel free to share!

How to display binary data as image in react-native

I am very new to react, an i have a use case like, getting the books details in a API response with the image. I need to iterate over the response and I need to display the image.
as suggested displaying binary data as image below is the code i have used for this. But image is not displayed. Any suggestions would be appreciated. What Am i doing wrong?
<View>
<FlatList data={books} renderItem={
data => {
console.log("data is -? " + books.author);
//const buffer = Buffer.from(data.item.image.data, 'binary').toString('base64');
/* let image = btoa(
new Uint8Array(data.item.image.data)
.reduce((d, byte) => d + String.fromCharCode(byte), '')
);*/
const encoded = data.item.image.data;
<View style={styles.imageContainer}>
<Image
source={{
uri: `data:image/jpeg;base64,${encoded}`
} }
//source="{URL.createObjectUrl(encoded)}"
style={styles.stretch}
/>
</View>
}
} />
</View>
Here am sharing the solution how did solve the problem, hope this might help someone. Just sharing the working code.
<FlatList data={books} keyExtractor={(item, index) => item.id.title+index}
renderItem={({ item }) =>
<Item title={item} />
} />
function Item({ title }) {
let ed = 'data:image/png;base64,' + title.image.data;
return (
<View>
<Image source={{ uri: ed }} /></View>
);
}