为什么切换视图后,叶片地图变成灰色?它发生在与地图互动后,然后在视图之间切换

发布于 2025-02-08 10:37:35 字数 11693 浏览 2 评论 0原文

我正在制作一个对话框,该对话框具有两个名为地址和地图的选项卡,该选项卡允许用户在地址选项卡中的两个不同的Textfields中输入城市名称和街道名称,并能够在地图中查明或自动限制位置。在地图选项卡中,我使用了React-Leaflet Map向用户显示映射本身,到目前为止是如此出色,但是在选项卡之间切换后,映射更改为单调灰色图像。放大进出不会有帮助!

代码:
import * as React from 'react';
import { useEffect, useState } from 'react';

import Button from '@mui/material/Button';
import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';
import useMediaQuery from '@mui/material/useMediaQuery';
import CloseIcon from '@mui/icons-material/CloseOutlined';
import {   Divider, IconButton, InputLabel, } from '@mui/material';
import { Box, Grid, Tab, TextField, useTheme } from '@material-ui/core';
import { TabContext, TabList, TabPanel } from '@mui/lab';
import "leaflet/dist/leaflet.css";
import icon from "../../../../Account/components/constants";
import { MapContainer, TileLayer, Marker, useMapEvents, } from 'react-leaflet'

const useGeoLocation = () => {
    // this function will allow the user to get the current location of the device!
    const [location, setLocation] = useState({
        loaded: false,
        coordinates: { lat: "", lng: "" }
    });
    const onSuccess = (location) => {
        setLocation({
            loaded: true,
            coordinates: {
                lat: location.coords.latitude,
                lng: location.coords.longitude,
            }
        });
    };
    const onError = (error) => {
        setLocation({
            loaded: true,
            error,
        });
    };
    useEffect(() => {
        if (!("geolocation" in navigator)) {
            onError({
                code: 0,
                message: "Your device GPS is OFF!",
            });
        }
        navigator.geolocation.getCurrentPosition(onSuccess, onError);

    }, []);

    return location;
}
export default function AddressDialog() {
    // Genral Properties!
    const [open, setOpen] = useState(false);
    const theme = useTheme();
    const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));
    const [value, setValue] = useState(0);

    // Address Tab Properties!
    const [city, setCity] = useState("");
    const [street, setStreet] = useState();
    
    // Map Properties!
    const [initializerPos,] = useState([40.689247, -74.044502]);
    const [position, setPosition] = useState(initializerPos);
    const [mapState, setMapState] = useState({
        position: position,
        map: null
    });
    const zoom_level = 18;
    const location = useGeoLocation();

    // Arrow funcitons!
    const handleClickOpen = () => {
        setOpen(true);
    };

    const handleClose = () => {
        setOpen(false);
        setValue(0);
    };

    const handleSubmit = () => {
        // api update in here
    }

    const showMyLocation = () => {
        if (location.loaded && !location.error) {
            let pos = [location.coordinates.lat, location.coordinates.lng];
            setPosition([location.coordinates.lat, location.coordinates.lng]);
            setMapState((state) => ({
                ...state,
                position: pos,
            }));

            const { map } = mapState;
            if (map) {
                map.flyTo(pos, zoom_level);
            }
        } else {
            if (location.error) {
                alert(location.error.message)
            }
            else {
                alert("Problem in loading curent location!")
            }
        }
    };
    function AddMarkerToClick() {

        const [markers, setMarkers] = useState([]);
        useMapEvents({
            click(e) {
                const newMarker = e.latlng
                setMarkers([...markers, newMarker]);
                setPosition([e.latlng.lat, e.latlng.lng]);
                setMapState((state) => ({
                    ...state,
                    position: newMarker,
                }));
                const { map } = mapState;
                if (map)
                {
                    map.flyTo(newMarker, zoom_level);
                }
            },
        });

        return null
    };
    
    return (
        <div dir="ltr">
            <Button onClick={handleClickOpen} variant="contained" type="button" aria-label="Edit Info" fullWidth size="small">
                Edit Address Info
            </Button>
            <Dialog fullScreen={fullScreen} open={open} aria-labelledby="responsive-dialog-title">
                <DialogTitle>
                    <IconButton onClick={handleClose} aria-label="Close Dialog">
                        <CloseIcon fontSize="medium" />
                    </IconButton>
                </DialogTitle>
                <Divider />

                <DialogTitle>Edit Address</DialogTitle>
                <DialogContent id ="dialogContent" >
                    <DialogContentText>
                        In this section you are able to edit your address info
                    </DialogContentText>
                    <TabContext value={value.toString()} >
                        <Box >
                            <TabList
                                onChange={(event, newValue) => { setValue(parseInt(newValue, 10));}}
                                aria-label="address-map-tab">
                                <Tab label="Address" value="0" />
                                <Tab label="Map" value="1" />
                            </TabList>
                        </Box>
                        
                        <TabPanel value="0">
                            <Grid container spacing={theme.spacing(0)}

                            >
                                <Grid item xs={12} sm={6}>
                                    <TextField value={city} onChange={(e) => setCity(e.target.value)} margin="normal" variant="outlined"
                                        required
                                        fullWidth
                                        type="text"
                                        name="area"
                                        id="area"
                                        label={"city"}
                                        placeholder={"ex: New York"}

                                    />
                                </Grid>
                                <Grid item xs={12} sm={6}>

                                    <TextField
                                        value={street}
                                        onChange={(e) => setStreet(e.target.value)}
                                        margin="normal"
                                        variant="outlined"
                                        required
                                        fullWidth
                                        type="text"
                                        name="street"
                                        id="street"
                                        label={"Streen Name"}
                                        placeholder={"ex: wall street"}

                                    />
                                </Grid>
                               
                            </Grid>
                        </TabPanel>
                        <TabPanel value="1">

                            <Grid container>

                                <div style={{
                                    marginLeft: "auto", 
                                    marginRight: "auto",
                                    width: "100%"
                                }}>
                                    <InputLabel>
                                        Your location in map: 
                                    </InputLabel>
                                        <MapContainer
                                            center={mapState.position}
                                            zoom ={15}
                                            scrollWheelZoom
                                            style={{
                                                height: fullScreen ? 200 : 350,
                                                width: fullScreen ? "100%" : "100%",
                                                textAlign: "center",
                                                marginLeft: "auto",
                                                marginRight: "auto",
                                                marginTop: theme.spacing(1)
                                            }}
                                            whenCreated={map => setMapState({ map })}
                                        >
                                            <TileLayer
                                                url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                                            />
                                            <AddMarkerToClick />
                                            {
                                                position && (
                                                    <Marker position={position} icon={icon}></Marker>
                                                )
                                            }
                                        </MapContainer>
                                        <Button variant="outlined" color="primary" size="large" onClick={showMyLocation}>
                                            Here!
                                        </Button>
                                </div>
                            </Grid>
                        </TabPanel>
                    </TabContext>
                </DialogContent>
                <DialogActions style={{ marginLeft: theme.spacing(2), marginRight: theme.spacing(2) }}>
                    <Grid container direction="row" spacing={1}>
                        <Grid item container xs={4} dir="left" justifyContent="flex-end">
                            <Button variant="contained" type="button" color="error" fullWidth
                                name="cancel-btn" onClick={handleClose}
                            >
                                Cancel
                            </Button>
                        </Grid>
                        <Grid item container xs={8} >
                            <Button variant="contained" type="button" color="primary" fullWidth
                                name="submit-btn" onClick={handleSubmit} >
                                Save
                            </Button>
                        </Grid>
                    </Grid>
                </DialogActions>
            </Dialog>
        </div>
    );

在选项卡之间切换后,地图变成灰色,什么也没显示!

然后与映射进行交互,例如单击它,放大或输出结果导致错误!
未接收错误:设置地图中心并首先缩放。

I was making a dialog which has two tabs named Address and Map, which allows the user to enter city name and street name in two different textfields in address tab and be able to pinpoint or auto-locate the location in the map. In map tab I was using react-leaflet map to show the map itself to the user, so far so good but after switching between tabs the map changes to a monotonic gray image. zoom in and out won't help it!

Code:
import * as React from 'react';
import { useEffect, useState } from 'react';

import Button from '@mui/material/Button';
import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';
import useMediaQuery from '@mui/material/useMediaQuery';
import CloseIcon from '@mui/icons-material/CloseOutlined';
import {   Divider, IconButton, InputLabel, } from '@mui/material';
import { Box, Grid, Tab, TextField, useTheme } from '@material-ui/core';
import { TabContext, TabList, TabPanel } from '@mui/lab';
import "leaflet/dist/leaflet.css";
import icon from "../../../../Account/components/constants";
import { MapContainer, TileLayer, Marker, useMapEvents, } from 'react-leaflet'

const useGeoLocation = () => {
    // this function will allow the user to get the current location of the device!
    const [location, setLocation] = useState({
        loaded: false,
        coordinates: { lat: "", lng: "" }
    });
    const onSuccess = (location) => {
        setLocation({
            loaded: true,
            coordinates: {
                lat: location.coords.latitude,
                lng: location.coords.longitude,
            }
        });
    };
    const onError = (error) => {
        setLocation({
            loaded: true,
            error,
        });
    };
    useEffect(() => {
        if (!("geolocation" in navigator)) {
            onError({
                code: 0,
                message: "Your device GPS is OFF!",
            });
        }
        navigator.geolocation.getCurrentPosition(onSuccess, onError);

    }, []);

    return location;
}
export default function AddressDialog() {
    // Genral Properties!
    const [open, setOpen] = useState(false);
    const theme = useTheme();
    const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));
    const [value, setValue] = useState(0);

    // Address Tab Properties!
    const [city, setCity] = useState("");
    const [street, setStreet] = useState();
    
    // Map Properties!
    const [initializerPos,] = useState([40.689247, -74.044502]);
    const [position, setPosition] = useState(initializerPos);
    const [mapState, setMapState] = useState({
        position: position,
        map: null
    });
    const zoom_level = 18;
    const location = useGeoLocation();

    // Arrow funcitons!
    const handleClickOpen = () => {
        setOpen(true);
    };

    const handleClose = () => {
        setOpen(false);
        setValue(0);
    };

    const handleSubmit = () => {
        // api update in here
    }

    const showMyLocation = () => {
        if (location.loaded && !location.error) {
            let pos = [location.coordinates.lat, location.coordinates.lng];
            setPosition([location.coordinates.lat, location.coordinates.lng]);
            setMapState((state) => ({
                ...state,
                position: pos,
            }));

            const { map } = mapState;
            if (map) {
                map.flyTo(pos, zoom_level);
            }
        } else {
            if (location.error) {
                alert(location.error.message)
            }
            else {
                alert("Problem in loading curent location!")
            }
        }
    };
    function AddMarkerToClick() {

        const [markers, setMarkers] = useState([]);
        useMapEvents({
            click(e) {
                const newMarker = e.latlng
                setMarkers([...markers, newMarker]);
                setPosition([e.latlng.lat, e.latlng.lng]);
                setMapState((state) => ({
                    ...state,
                    position: newMarker,
                }));
                const { map } = mapState;
                if (map)
                {
                    map.flyTo(newMarker, zoom_level);
                }
            },
        });

        return null
    };
    
    return (
        <div dir="ltr">
            <Button onClick={handleClickOpen} variant="contained" type="button" aria-label="Edit Info" fullWidth size="small">
                Edit Address Info
            </Button>
            <Dialog fullScreen={fullScreen} open={open} aria-labelledby="responsive-dialog-title">
                <DialogTitle>
                    <IconButton onClick={handleClose} aria-label="Close Dialog">
                        <CloseIcon fontSize="medium" />
                    </IconButton>
                </DialogTitle>
                <Divider />

                <DialogTitle>Edit Address</DialogTitle>
                <DialogContent id ="dialogContent" >
                    <DialogContentText>
                        In this section you are able to edit your address info
                    </DialogContentText>
                    <TabContext value={value.toString()} >
                        <Box >
                            <TabList
                                onChange={(event, newValue) => { setValue(parseInt(newValue, 10));}}
                                aria-label="address-map-tab">
                                <Tab label="Address" value="0" />
                                <Tab label="Map" value="1" />
                            </TabList>
                        </Box>
                        
                        <TabPanel value="0">
                            <Grid container spacing={theme.spacing(0)}

                            >
                                <Grid item xs={12} sm={6}>
                                    <TextField value={city} onChange={(e) => setCity(e.target.value)} margin="normal" variant="outlined"
                                        required
                                        fullWidth
                                        type="text"
                                        name="area"
                                        id="area"
                                        label={"city"}
                                        placeholder={"ex: New York"}

                                    />
                                </Grid>
                                <Grid item xs={12} sm={6}>

                                    <TextField
                                        value={street}
                                        onChange={(e) => setStreet(e.target.value)}
                                        margin="normal"
                                        variant="outlined"
                                        required
                                        fullWidth
                                        type="text"
                                        name="street"
                                        id="street"
                                        label={"Streen Name"}
                                        placeholder={"ex: wall street"}

                                    />
                                </Grid>
                               
                            </Grid>
                        </TabPanel>
                        <TabPanel value="1">

                            <Grid container>

                                <div style={{
                                    marginLeft: "auto", 
                                    marginRight: "auto",
                                    width: "100%"
                                }}>
                                    <InputLabel>
                                        Your location in map: 
                                    </InputLabel>
                                        <MapContainer
                                            center={mapState.position}
                                            zoom ={15}
                                            scrollWheelZoom
                                            style={{
                                                height: fullScreen ? 200 : 350,
                                                width: fullScreen ? "100%" : "100%",
                                                textAlign: "center",
                                                marginLeft: "auto",
                                                marginRight: "auto",
                                                marginTop: theme.spacing(1)
                                            }}
                                            whenCreated={map => setMapState({ map })}
                                        >
                                            <TileLayer
                                                url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                                            />
                                            <AddMarkerToClick />
                                            {
                                                position && (
                                                    <Marker position={position} icon={icon}></Marker>
                                                )
                                            }
                                        </MapContainer>
                                        <Button variant="outlined" color="primary" size="large" onClick={showMyLocation}>
                                            Here!
                                        </Button>
                                </div>
                            </Grid>
                        </TabPanel>
                    </TabContext>
                </DialogContent>
                <DialogActions style={{ marginLeft: theme.spacing(2), marginRight: theme.spacing(2) }}>
                    <Grid container direction="row" spacing={1}>
                        <Grid item container xs={4} dir="left" justifyContent="flex-end">
                            <Button variant="contained" type="button" color="error" fullWidth
                                name="cancel-btn" onClick={handleClose}
                            >
                                Cancel
                            </Button>
                        </Grid>
                        <Grid item container xs={8} >
                            <Button variant="contained" type="button" color="primary" fullWidth
                                name="submit-btn" onClick={handleSubmit} >
                                Save
                            </Button>
                        </Grid>
                    </Grid>
                </DialogActions>
            </Dialog>
        </div>
    );

After switching between tabs, the map grayed out, and shows nothing!

enter image description here

Then interacting with map, e.g, clicking on it, zoom in or out results the error!
Uncaught Error: Set map center and zoom first.

enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

在风中等你 2025-02-15 10:37:35

我的解决方案:

我所做的是保存映射的当前(在与映射的第一次互动之后),然后尝试从保存状态重新启动它以备将来使用(切换到其他选项卡/视图)。
为了保存地图的状态,在从地图视图中切换之前,它应该正好发生!在这种情况下,在切换回地址选项卡或关闭对话框之前。

固定代码:
import * as React from 'react';
import { useEffect, useState } from 'react';

import Button from '@mui/material/Button';
import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';
import useMediaQuery from '@mui/material/useMediaQuery';
import CloseIcon from '@mui/icons-material/CloseOutlined';
import {   Divider, IconButton, InputLabel, } from '@mui/material';
import { Box, Grid, Tab, TextField, useTheme } from '@material-ui/core';
import { TabContext, TabList, TabPanel } from '@mui/lab';
import "leaflet/dist/leaflet.css";
import icon from "../../../../Account/components/constants";
import { MapContainer, TileLayer, Marker, useMapEvents, } from 'react-leaflet'

const useGeoLocation = () => {
    // this function will allow the user to get the current location of the device!
    const [location, setLocation] = useState({
        loaded: false,
        coordinates: { lat: "", lng: "" }
    });
    const onSuccess = (location) => {
        setLocation({
            loaded: true,
            coordinates: {
                lat: location.coords.latitude,
                lng: location.coords.longitude,
            }
        });
    };
    const onError = (error) => {
        setLocation({
            loaded: true,
            error,
        });
    };
    useEffect(() => {
        if (!("geolocation" in navigator)) {
            onError({
                code: 0,
                message: "Your device GPS is OFF!",
            });
        }
        navigator.geolocation.getCurrentPosition(onSuccess, onError);

    }, []);

    return location;
}


export default function AddressDialog() {
    // Genral Properties!
    const [open, setOpen] = useState(false);
    const theme = useTheme();
    const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));
    const [value, setValue] = useState(0);

    // Address Tab Properties!
    const [city, setCity] = useState("");
    const [street, setStreet] = useState();
    
    // Map Properties!
    const [initializerPos,] = useState([40.689247, -74.044502]);
    const [position, setPosition] = useState(initializerPos);
    const [mapState, setMapState] = useState({
        position: position,
        map: null
    });
    const zoom_level = 18;
    const location = useGeoLocation();

    // Two new properties to overcome the gray out problem.
    const initializeZoom_level = 15;
    const [mapZoom, setMapZoom] = useState(initializeZoom_level);

    // Arrow funcitons!
    const stabilizeMapData = (isItADialogClose ) => {
        setMapZoom(isItADialogClose ? initializeZoom_level : mapZoom);
        setPosition(isItADialogClose ? initializerPos : position);
        setMapState({
            position: isItADialogClose ? initializerPos : position,
            map: null
        });
    }

    const handleClickOpen = () => {
        setOpen(true);
    };

    const handleClose = () => {
        stabilizeMapData(true); // The user is about to close The Dialog!
        setOpen(false);
        setValue(0);
    };

    const handleSubmit = () => {
        // api update in here
    }

    const showMyLocation = () => {
        if (location.loaded && !location.error) {
            let pos = [location.coordinates.lat, location.coordinates.lng];
            setPosition([location.coordinates.lat, location.coordinates.lng]);
            setMapState((state) => ({
                ...state,
                position: pos,
            }));

            const { map } = mapState;
            if (map) {
                map.flyTo(pos, zoom_level);
                setMapZoom(zoom_level);
            }
        } else {
            if (location.error) {
                alert(location.error.message)
            }
            else {
                alert("Problem in loading curent location!")
            }
        }
    };

    function AddMarkerToClick() {

        const [markers, setMarkers] = useState([]);
        useMapEvents({
            click(e) {
                const newMarker = e.latlng
                setMarkers([...markers, newMarker]);
                setPosition([e.latlng.lat, e.latlng.lng]);
                setMapState((state) => ({
                    ...state,
                    position: newMarker,
                }));
                const { map } = mapState;
                if (map)
                {
                    map.flyTo(newMarker, zoom_level);
                    setMapZoom(zoom_level);
                }
            },
        });

        return null
    };
    
    return (
        <div dir="ltr">
            <Button onClick={handleClickOpen} variant="contained" type="button" aria-label="Edit Info" fullWidth size="small">
                Edit Address Info
            </Button>
            <Dialog fullScreen={fullScreen} open={open} aria-labelledby="responsive-dialog-title">
                <DialogTitle>
                    <IconButton onClick={handleClose} aria-label="Close Dialog">
                        <CloseIcon fontSize="medium" />
                    </IconButton>
                </DialogTitle>
                <Divider />

                <DialogTitle>Edit Address</DialogTitle>
                <DialogContent id ="dialogContent" >
                    <DialogContentText>
                        In this section you are able to edit your address info
                    </DialogContentText>
                    <TabContext value={value.toString()} >
                        <Box >
                            <TabList
                                onChange={(event, newValue) => {
                                    if (value === 1) {
                                        // if it is in The Map Tab and It's about to switch the tab!
                                        stabilizeMapData(false);
                                    }
                                    
                                    setValue(parseInt(newValue, 10));
                            }}
                                aria-label="address-map-tab">
                                <Tab label="Address" value="0" />
                                <Tab label="Map" value="1" />
                            </TabList>
                        </Box>
                        
                        <TabPanel value="0">
                            <Grid container spacing={theme.spacing(0)}

                            >
                                <Grid item xs={12} sm={6}>
                                    <TextField value={city} onChange={(e) => setCity(e.target.value)} margin="normal" variant="outlined"
                                        required
                                        fullWidth
                                        type="text"
                                        name="area"
                                        id="area"
                                        label={"city"}
                                        placeholder={"ex: New York"}

                                    />
                                </Grid>
                                <Grid item xs={12} sm={6}>

                                    <TextField
                                        value={street}
                                        onChange={(e) => setStreet(e.target.value)}
                                        margin="normal"
                                        variant="outlined"
                                        required
                                        fullWidth
                                        type="text"
                                        name="street"
                                        id="street"
                                        label={"Streen Name"}
                                        placeholder={"ex: wall street"}

                                    />
                                </Grid>
                               
                            </Grid>
                        </TabPanel>
                        <TabPanel value="1">

                            <Grid container>

                                <div style={{
                                    marginLeft: "auto", 
                                    marginRight: "auto",
                                    width: "100%"
                                }}>
                                    <InputLabel>
                                        Your location in map: 
                                    </InputLabel>
                                        <MapContainer
                                            center={mapState.position}
                                            zoom={mapZoom}
                                            scrollWheelZoom
                                            style={{
                                                height: fullScreen ? 200 : 350,
                                                width: fullScreen ? "100%" : "100%",
                                                textAlign: "center",
                                                marginLeft: "auto",
                                                marginRight: "auto",
                                                marginTop: theme.spacing(1)
                                            }}
                                            whenCreated={map => setMapState({ map })}
                                        >
                                            <TileLayer
                                                url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                                            />
                                            <AddMarkerToClick />
                                            {
                                                position && (
                                                    <Marker position={position} icon={icon}></Marker>
                                                )
                                            }
                                        </MapContainer>
                                        <Button variant="outlined" color="primary" size="large" onClick={showMyLocation}>
                                            Here!
                                        </Button>
                                </div>
                            </Grid>
                        </TabPanel>
                    </TabContext>
                </DialogContent>
                <DialogActions style={{ marginLeft: theme.spacing(2), marginRight: theme.spacing(2) }}>
                    <Grid container direction="row" spacing={1}>
                        <Grid item container xs={4} dir="left" justifyContent="flex-end">
                            <Button variant="contained" type="button" color="error" fullWidth
                                name="cancel-btn" onClick={handleClose}
                            >
                                Cancel
                            </Button>
                        </Grid>
                        <Grid item container xs={8} >
                            <Button variant="contained" type="button" color="primary" fullWidth
                                name="submit-btn" onClick={handleSubmit} >
                                Save
                            </Button>
                        </Grid>
                    </Grid>
                </DialogActions>
            </Dialog>
        </div>
    );
}

我在代码中做了一些评论以演示解决方案。如果您知道一个更好的解决方案,我期待看到它。

My Solution:

What I did is to save the current (after first interaction with map) state of the map and then try to restart it from saved state for future use (switching to other tabs/views).
To save the state of the map, It should happen right exactly before switching out from the map view! In this case before switching back to address tab or closing The Dialog.

Fixed Code:
import * as React from 'react';
import { useEffect, useState } from 'react';

import Button from '@mui/material/Button';
import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';
import useMediaQuery from '@mui/material/useMediaQuery';
import CloseIcon from '@mui/icons-material/CloseOutlined';
import {   Divider, IconButton, InputLabel, } from '@mui/material';
import { Box, Grid, Tab, TextField, useTheme } from '@material-ui/core';
import { TabContext, TabList, TabPanel } from '@mui/lab';
import "leaflet/dist/leaflet.css";
import icon from "../../../../Account/components/constants";
import { MapContainer, TileLayer, Marker, useMapEvents, } from 'react-leaflet'

const useGeoLocation = () => {
    // this function will allow the user to get the current location of the device!
    const [location, setLocation] = useState({
        loaded: false,
        coordinates: { lat: "", lng: "" }
    });
    const onSuccess = (location) => {
        setLocation({
            loaded: true,
            coordinates: {
                lat: location.coords.latitude,
                lng: location.coords.longitude,
            }
        });
    };
    const onError = (error) => {
        setLocation({
            loaded: true,
            error,
        });
    };
    useEffect(() => {
        if (!("geolocation" in navigator)) {
            onError({
                code: 0,
                message: "Your device GPS is OFF!",
            });
        }
        navigator.geolocation.getCurrentPosition(onSuccess, onError);

    }, []);

    return location;
}


export default function AddressDialog() {
    // Genral Properties!
    const [open, setOpen] = useState(false);
    const theme = useTheme();
    const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));
    const [value, setValue] = useState(0);

    // Address Tab Properties!
    const [city, setCity] = useState("");
    const [street, setStreet] = useState();
    
    // Map Properties!
    const [initializerPos,] = useState([40.689247, -74.044502]);
    const [position, setPosition] = useState(initializerPos);
    const [mapState, setMapState] = useState({
        position: position,
        map: null
    });
    const zoom_level = 18;
    const location = useGeoLocation();

    // Two new properties to overcome the gray out problem.
    const initializeZoom_level = 15;
    const [mapZoom, setMapZoom] = useState(initializeZoom_level);

    // Arrow funcitons!
    const stabilizeMapData = (isItADialogClose ) => {
        setMapZoom(isItADialogClose ? initializeZoom_level : mapZoom);
        setPosition(isItADialogClose ? initializerPos : position);
        setMapState({
            position: isItADialogClose ? initializerPos : position,
            map: null
        });
    }

    const handleClickOpen = () => {
        setOpen(true);
    };

    const handleClose = () => {
        stabilizeMapData(true); // The user is about to close The Dialog!
        setOpen(false);
        setValue(0);
    };

    const handleSubmit = () => {
        // api update in here
    }

    const showMyLocation = () => {
        if (location.loaded && !location.error) {
            let pos = [location.coordinates.lat, location.coordinates.lng];
            setPosition([location.coordinates.lat, location.coordinates.lng]);
            setMapState((state) => ({
                ...state,
                position: pos,
            }));

            const { map } = mapState;
            if (map) {
                map.flyTo(pos, zoom_level);
                setMapZoom(zoom_level);
            }
        } else {
            if (location.error) {
                alert(location.error.message)
            }
            else {
                alert("Problem in loading curent location!")
            }
        }
    };

    function AddMarkerToClick() {

        const [markers, setMarkers] = useState([]);
        useMapEvents({
            click(e) {
                const newMarker = e.latlng
                setMarkers([...markers, newMarker]);
                setPosition([e.latlng.lat, e.latlng.lng]);
                setMapState((state) => ({
                    ...state,
                    position: newMarker,
                }));
                const { map } = mapState;
                if (map)
                {
                    map.flyTo(newMarker, zoom_level);
                    setMapZoom(zoom_level);
                }
            },
        });

        return null
    };
    
    return (
        <div dir="ltr">
            <Button onClick={handleClickOpen} variant="contained" type="button" aria-label="Edit Info" fullWidth size="small">
                Edit Address Info
            </Button>
            <Dialog fullScreen={fullScreen} open={open} aria-labelledby="responsive-dialog-title">
                <DialogTitle>
                    <IconButton onClick={handleClose} aria-label="Close Dialog">
                        <CloseIcon fontSize="medium" />
                    </IconButton>
                </DialogTitle>
                <Divider />

                <DialogTitle>Edit Address</DialogTitle>
                <DialogContent id ="dialogContent" >
                    <DialogContentText>
                        In this section you are able to edit your address info
                    </DialogContentText>
                    <TabContext value={value.toString()} >
                        <Box >
                            <TabList
                                onChange={(event, newValue) => {
                                    if (value === 1) {
                                        // if it is in The Map Tab and It's about to switch the tab!
                                        stabilizeMapData(false);
                                    }
                                    
                                    setValue(parseInt(newValue, 10));
                            }}
                                aria-label="address-map-tab">
                                <Tab label="Address" value="0" />
                                <Tab label="Map" value="1" />
                            </TabList>
                        </Box>
                        
                        <TabPanel value="0">
                            <Grid container spacing={theme.spacing(0)}

                            >
                                <Grid item xs={12} sm={6}>
                                    <TextField value={city} onChange={(e) => setCity(e.target.value)} margin="normal" variant="outlined"
                                        required
                                        fullWidth
                                        type="text"
                                        name="area"
                                        id="area"
                                        label={"city"}
                                        placeholder={"ex: New York"}

                                    />
                                </Grid>
                                <Grid item xs={12} sm={6}>

                                    <TextField
                                        value={street}
                                        onChange={(e) => setStreet(e.target.value)}
                                        margin="normal"
                                        variant="outlined"
                                        required
                                        fullWidth
                                        type="text"
                                        name="street"
                                        id="street"
                                        label={"Streen Name"}
                                        placeholder={"ex: wall street"}

                                    />
                                </Grid>
                               
                            </Grid>
                        </TabPanel>
                        <TabPanel value="1">

                            <Grid container>

                                <div style={{
                                    marginLeft: "auto", 
                                    marginRight: "auto",
                                    width: "100%"
                                }}>
                                    <InputLabel>
                                        Your location in map: 
                                    </InputLabel>
                                        <MapContainer
                                            center={mapState.position}
                                            zoom={mapZoom}
                                            scrollWheelZoom
                                            style={{
                                                height: fullScreen ? 200 : 350,
                                                width: fullScreen ? "100%" : "100%",
                                                textAlign: "center",
                                                marginLeft: "auto",
                                                marginRight: "auto",
                                                marginTop: theme.spacing(1)
                                            }}
                                            whenCreated={map => setMapState({ map })}
                                        >
                                            <TileLayer
                                                url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                                            />
                                            <AddMarkerToClick />
                                            {
                                                position && (
                                                    <Marker position={position} icon={icon}></Marker>
                                                )
                                            }
                                        </MapContainer>
                                        <Button variant="outlined" color="primary" size="large" onClick={showMyLocation}>
                                            Here!
                                        </Button>
                                </div>
                            </Grid>
                        </TabPanel>
                    </TabContext>
                </DialogContent>
                <DialogActions style={{ marginLeft: theme.spacing(2), marginRight: theme.spacing(2) }}>
                    <Grid container direction="row" spacing={1}>
                        <Grid item container xs={4} dir="left" justifyContent="flex-end">
                            <Button variant="contained" type="button" color="error" fullWidth
                                name="cancel-btn" onClick={handleClose}
                            >
                                Cancel
                            </Button>
                        </Grid>
                        <Grid item container xs={8} >
                            <Button variant="contained" type="button" color="primary" fullWidth
                                name="submit-btn" onClick={handleSubmit} >
                                Save
                            </Button>
                        </Grid>
                    </Grid>
                </DialogActions>
            </Dialog>
        </div>
    );
}

I did some comments in the code to demonstrate the solution. If you know a better solution to this problem I looking forward to see it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文