Created
April 28, 2023 10:49
-
-
Save ruvasik/ebd55d354ededfdd9655d3cc7d0478cf to your computer and use it in GitHub Desktop.
SC & TS examples
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export interface IMapPoint { | |
x: number; | |
y: number; | |
} | |
export interface IMapPointItem { | |
title?: string; | |
point: IMapPoint; | |
} | |
export interface IMapLineItem { | |
title?: string; | |
start: IMapPoint; | |
end: IMapPoint; | |
} | |
export interface IMapElements { | |
points?: IMapPointItem[]; | |
lines?: IMapLineItem[]; | |
} | |
interface IRegionMapProps { | |
ref?: React.RefObject<SVGSVGElement>; | |
region: TMapRegion; | |
id?: string; | |
elements?: IMapElements; | |
onClick?: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void; | |
} | |
const SvgRegion = forwardRef(function SvgRegion( | |
{ region, ...props }: ISvgRegionProps, | |
ref: ForwardedRef<SVGSVGElement> | |
) { | |
let Tag = SvgRussia; | |
if (region === "world") Tag = SvgWorld; | |
else if (region === "eurasia") Tag = SvgEurasia; | |
return <Tag ref={ref} {...props} />; | |
}); | |
const StyledMap = styled(SvgRegion)<{ id: string }>` | |
& path[id] { | |
fill: ${theme.palette.map.background}; | |
cursor: pointer; | |
outline: none; | |
stroke: ${theme.palette.map.border}; | |
&.arc { | |
stroke: ${APP_RED}; | |
fill: none; | |
} | |
} | |
& path[id]:hover { | |
fill: ${theme.palette.map.background}aa; | |
} | |
`; | |
const useMap = (refMap: RefObject<SVGSVGElement>, reg: string) => { | |
const mapInstance = useRef<Svg>(); | |
const [region, setRegion] = useState(""); | |
useEffect(() => { | |
if (refMap.current && region !== reg) { | |
mapInstance.current = SVG(refMap.current); | |
setRegion(reg); | |
} | |
}, [region, refMap.current]); | |
return mapInstance.current || SVG(); | |
}; | |
function RegionMap({ | |
region = "russia", | |
id, | |
elements, | |
...props | |
}: IRegionMapProps) { | |
const ref = useRef<SVGSVGElement>(null); | |
const [elems, setElems] = useState<SVGElement[]>([]); | |
const map = useMap(ref, region); | |
const [popover, setPopover] = useState(null); | |
const [popoverContent, setPopoverContent] = useState(null); | |
const closePopover = useCallback((event) => { | |
if (event) { | |
event.stopPropagation(); | |
event.preventDefault(); | |
} | |
setPopover(null); | |
}, []); | |
const showPopover = useCallback(function (event) { | |
event.stopPropagation(); | |
event.preventDefault(); | |
setPopover(event.target); | |
const data = SVG(event.target).data(); | |
setPopoverContent(data); | |
}, []); | |
const generateElems = useCallback(() => { | |
{ | |
const elemsList: SVGElement[] = []; | |
elements?.lines?.forEach((elem, i) => { | |
const arc = map | |
.path( | |
generateArcPath( | |
elem.end.x, | |
elem.end.y, | |
elem.start.x, | |
elem.start.y, | |
ref.current?.clientWidth | |
) | |
) | |
.stroke({ color: "yellow", width: POINT_SIZE / 2 }) | |
.fill("none") | |
.addClass("arc") | |
.id("circle" + (i + 1)); | |
elemsList.push(arc); | |
elemsList.push(svgTrain(map as Element, arc, 0.5, APP_RED)); | |
}); | |
elements?.points?.forEach((elem) => { | |
const { point, title } = elem; | |
const popover = title ? { title, text: "text" } : undefined; | |
elemsList.push( | |
svgPin(map as Element, point.x, point.y, { | |
onShow: popover ? showPopover : undefined, | |
onHide: closePopover, | |
data: popover, | |
}) | |
); | |
}); | |
setElems(elemsList); | |
} | |
}, [map, elements]); | |
useEffect(() => { | |
elems.forEach((node) => node.remove()); | |
generateElems(); | |
}, [map, region, elements]); | |
return ( | |
<> | |
<StyledMap ref={ref} id={id || region} region={region} {...props} /> | |
<Popover | |
open={!!popover} | |
anchorEl={popover} | |
onClose={closePopover} | |
anchorOrigin={{ | |
vertical: "top", | |
horizontal: "right", | |
}} | |
> | |
<Typography sx={{ fontWeight: 700 }}> | |
{popoverContent?.title || ""} | |
</Typography> | |
<Typography sx={{ fontSize: "0.9rem" }}> | |
{popoverContent?.text || ""} | |
</Typography> | |
</Popover> | |
</> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment