add base routing

This commit is contained in:
2026-05-20 08:54:41 +03:30
parent 83587962fd
commit 6b70eb8e27
4 changed files with 142 additions and 108 deletions

View File

@@ -0,0 +1,18 @@
<svg width="20" height="23" viewBox="0 0 20 23" fill="none" xmlns="http://www.w3.org/2000/svg">
<foreignObject x="-63" y="-64" width="146" height="149"><div xmlns="http://www.w3.org/1999/xhtml" style="backdrop-filter:blur(32.5px);clip-path:url(#bgblur_0_2302_1310_clip_path);height:100%;width:100%"></div></foreignObject><g filter="url(#filter0_d_2302_1310)" data-figma-bg-blur-radius="65">
<path d="M9.38305 1.02444C15.543 0.551472 19.9197 7.03396 17.1518 12.6025C15.8547 15.2112 13.6759 15.7958 11.9558 17.881C11.6271 18.2796 10.7507 19.7126 10.4472 19.8829C9.98265 20.1439 9.56634 19.9365 9.25987 19.5758C8.76416 18.992 8.37012 18.2543 7.83732 17.6549C6.56763 16.2249 4.84751 15.4187 3.69508 13.9418C-0.231962 8.90724 3.07767 1.50856 9.38305 1.02444ZM9.55002 5.15175C6.61587 5.45517 5.13915 8.92434 6.86743 11.3212C8.38571 13.4272 11.6293 13.425 13.1468 11.3212C15.1415 8.554 12.925 4.80298 9.55076 5.15175H9.55002Z" fill="#EF4444"/>
</g>
<defs>
<filter id="filter0_d_2302_1310" x="-63" y="-64" width="146" height="149" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="1"/>
<feGaussianBlur stdDeviation="1"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.235294 0 0 0 0 0.25098 0 0 0 0 0.262745 0 0 0 0.3 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2302_1310"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2302_1310" result="shape"/>
</filter>
<clipPath id="bgblur_0_2302_1310_clip_path" transform="translate(63 64)"><path d="M9.38305 1.02444C15.543 0.551472 19.9197 7.03396 17.1518 12.6025C15.8547 15.2112 13.6759 15.7958 11.9558 17.881C11.6271 18.2796 10.7507 19.7126 10.4472 19.8829C9.98265 20.1439 9.56634 19.9365 9.25987 19.5758C8.76416 18.992 8.37012 18.2543 7.83732 17.6549C6.56763 16.2249 4.84751 15.4187 3.69508 13.9418C-0.231962 8.90724 3.07767 1.50856 9.38305 1.02444ZM9.55002 5.15175C6.61587 5.45517 5.13915 8.92434 6.86743 11.3212C8.38571 13.4272 11.6293 13.425 13.1468 11.3212C15.1415 8.554 12.925 4.80298 9.55076 5.15175H9.55002Z"/>
</clipPath></defs>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,18 @@
<svg width="20" height="19" viewBox="0 0 20 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<foreignObject x="-42.6271" y="-43.6271" width="105.045" height="105.045"><div xmlns="http://www.w3.org/1999/xhtml" style="backdrop-filter:blur(22.31px);clip-path:url(#bgblur_0_2302_1307_clip_path);height:100%;width:100%"></div></foreignObject><g filter="url(#filter0_d_2302_1307)" data-figma-bg-blur-radius="44.6271">
<path d="M10.3018 1.00977C14.4733 1.22136 17.7908 4.67141 17.791 8.89551C17.7908 13.2559 14.2559 16.7908 9.89551 16.791C5.67141 16.7908 2.22136 13.4733 2.00977 9.30176L2 8.89551L2.00977 8.48926C2.22119 4.31755 5.6713 1.00017 9.89551 1L10.3018 1.00977ZM9.89551 5.80566C8.18945 5.80584 6.80584 7.18945 6.80566 8.89551L6.80957 9.05371C6.89208 10.6863 8.2425 11.9842 9.89551 11.9844C11.5485 11.9842 12.898 10.6863 12.9805 9.05371L12.9844 8.89551L12.9805 8.73633C12.9003 7.1565 11.6336 5.88942 10.0537 5.80957L9.89551 5.80566Z" fill="#16A795"/>
</g>
<defs>
<filter id="filter0_d_2302_1307" x="-42.6271" y="-43.6271" width="105.045" height="105.045" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="0.686571"/>
<feGaussianBlur stdDeviation="0.686571"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.235294 0 0 0 0 0.25098 0 0 0 0 0.262745 0 0 0 0.3 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2302_1307"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2302_1307" result="shape"/>
</filter>
<clipPath id="bgblur_0_2302_1307_clip_path" transform="translate(42.6271 43.6271)"><path d="M10.3018 1.00977C14.4733 1.22136 17.7908 4.67141 17.791 8.89551C17.7908 13.2559 14.2559 16.7908 9.89551 16.791C5.67141 16.7908 2.22136 13.4733 2.00977 9.30176L2 8.89551L2.00977 8.48926C2.22119 4.31755 5.6713 1.00017 9.89551 1L10.3018 1.00977ZM9.89551 5.80566C8.18945 5.80584 6.80584 7.18945 6.80566 8.89551L6.80957 9.05371C6.89208 10.6863 8.2425 11.9842 9.89551 11.9844C11.5485 11.9842 12.898 10.6863 12.9805 9.05371L12.9844 8.89551L12.9805 8.73633C12.9003 7.1565 11.6336 5.88942 10.0537 5.80957L9.89551 5.80566Z"/>
</clipPath></defs>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,116 +1,113 @@
import { Delete, Route } from "@mui/icons-material";
import { Box, Button, Stack, Typography } from "@mui/material";
import { useReducer } from "react";
import DrawBound from "./DrawBound";
"use client";
const statusType = [
{
id: 0,
message: "برای آغاز ترسیم مسیر، کلیک کنید!",
buttons: [
{
label: "شروع ترسیم مسیر",
key: "start",
color: "primary",
icon: <Route />,
onclick: (controlDispach) => {
controlDispach({ type: "SET_STATUS", status: 1 });
},
},
],
},
{
id: 1,
message: "مسیر موردنظر را با کلیک روی نقشه مشخص کنید. برای اتمام، روی نقطه‌ی پایانی کلیک کنید!",
buttons: [],
},
{
id: 2,
message: "برای اصلاح مسیر، گوشه‌ها را بکشید. برای ترسیم دوباره، آن را حذف کنید",
buttons: [
{
label: "حذف",
key: "end",
color: "error",
icon: <Delete />,
onclick: (controlDispach) => {
controlDispach({ type: "SET_STATUS", status: 0 });
},
},
],
},
];
import { useEffect, useState } from "react";
import { Marker, Polyline, useMap } from "react-leaflet";
import L from "leaflet";
const createInitialState = (bound) => {
if (bound) {
return { status: 2 };
}
return { status: 0 };
};
// ===== Icons =====
const originIcon = new L.Icon({
iconUrl: "/icons/origin-marker.png",
iconSize: [32, 32],
iconAnchor: [16, 32],
});
const reducer = (state, action) => {
switch (action.type) {
case "SET_STATUS":
return { ...state, status: action.status };
default:
return state;
}
};
const destinationIcon = new L.Icon({
iconUrl: "/icons/destination-marker.png",
iconSize: [32, 32],
iconAnchor: [16, 32],
});
const MapControlPolyline = ({ bound, setBound }) => {
const [control, controlDispach] = useReducer(reducer, bound, createInitialState);
// ===== Track Center =====
function MapCenterTracker({ setCenter }) {
const map = useMap();
useEffect(() => {
const updateCenter = () => {
setCenter(map.getCenter());
};
updateCenter();
map.on("move", updateCenter);
return () => {
map.off("move", updateCenter);
};
}, [map, setCenter]);
return null;
}
// ===== Fixed Center Marker =====
function FixedCenterMarker() {
return (
<div
style={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -100%)",
zIndex: 1000,
pointerEvents: "none",
}}
>
<img src="/icons/pin-center.png" width={40} height={40} alt="center" />
</div>
);
}
export default function Example() {
const [center, setCenter] = useState(null);
const [origin, setOrigin] = useState(null);
const [destination, setDestination] = useState(null);
const [step, setStep] = useState("origin");
const handleOk = () => {
if (!center) return;
if (step === "origin") {
setOrigin(center);
setStep("destination");
return;
}
if (step === "destination") {
setDestination(center);
setStep("done");
}
};
return (
<>
<DrawBound bound={bound} setBound={setBound} control={control} controlDispach={controlDispach} />
<Stack
direction={"row"}
justifyContent={"center"}
sx={{ position: "absolute", left: 0, top: 0, zIndex: 2000, width: "100%" }}
>
<Box
sx={{
background: (theme) => theme.palette.info.main,
borderBottomLeftRadius: 8,
borderBottomRightRadius: 8,
py: 0.5,
px: 2,
}}
>
<Typography align="center" component={"div"} variant="caption" color={"#fff"}>
{statusType.find((st) => st.id == control.status).message}
</Typography>
</Box>
</Stack>
<Box
sx={{
position: "absolute",
left: 0,
bottom: 0,
zIndex: 2000,
width: "100%",
py: 1,
background: "linear-gradient(to top, rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0))",
<div>
<div
style={{
position: "relative",
height: "400px",
}}
>
<Stack direction={"row"} justifyContent={"center"} spacing={2}>
{statusType
.find((st) => st.id == control.status)
.buttons.map((button) => (
<Button
size="small"
key={button.key}
variant="contained"
onClick={() => button.onclick(controlDispach)}
color={button.color}
startIcon={button.icon}
>
{button.label}
</Button>
))}
</Stack>
</Box>
</>
<MapCenterTracker setCenter={setCenter} />
{/* saved markers */}
{origin && <Marker position={origin} icon={originIcon} />}
{destination && <Marker position={destination} icon={destinationIcon} />}
{/* route line */}
{origin && destination && <Polyline positions={[origin, destination]} />}
{/* fixed center pin */}
{step !== "done" && <FixedCenterMarker />}
</div>
<div style={{ marginTop: 16, position: "absolute", z : 50, top : 5 }}>
<button onClick={handleOk}>
{step === "origin" && "Set Origin"}
{step === "destination" && "Set Destination"}
{step === "done" && "Completed"}
</button>
</div>
</div>
);
};
export default MapControlPolyline;
}

View File

@@ -3,6 +3,7 @@ import { Box, Button, DialogActions, DialogContent, Stack } from "@mui/material"
import dynamic from "next/dynamic";
import { useCallback, useState } from "react";
import MapControlPolyline from "./MapControlPolyline";
import Example from "./MapControlPolyline";
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
loading: () => <MapLoading />,
ssr: false,
@@ -22,7 +23,7 @@ const Area = ({ allData, setAllData, handlePrev, setTabState }) => {
<Stack spacing={2}>
<Box sx={{ width: "100%", height: "400px" }}>
<MapLayer style={{ borderRadius: "4px" }}>
<MapControlPolyline bound={bound} setBound={setBound} boundType={"polyline"} />
<Example />
</MapLayer>
</Box>
</Stack>