import * as React from "react"; import { Grid, Paper, CssBaseline, ButtonBase, Divider, Typography, } from "@material-ui/core"; import AddIcon from "@material-ui/icons/Add"; import RemoveIcon from "@material-ui/icons/Remove"; import { makeStyles, Theme } from "@material-ui/core/styles"; import { USA as ComponentUSA } from "../index"; import { USAProps, StatesListRendererMap, StatesListUnrendered, } from "../index.d"; import { STATES_LIST } from "../STATES_LIST"; import { throttle } from "../utils/throttle"; import { getRandomArbitrary } from "../utils/getRandomArbitrary"; import { HtmlTooltip } from "./HtmlTooltip"; let DataMap = new Map(); let Filter: StatesListUnrendered[] = ["AS", "GU", "MH", "MP", "VI"]; Object.keys(STATES_LIST) .filter((item) => !Filter.includes(item as StatesListUnrendered)) .forEach((abbr) => { DataMap.set(abbr as keyof StatesListRendererMap, { count: getRandomArbitrary(0, 128), }); }); let getFillColor = (count: number | null | undefined) => { if (count == null) { return "#DDDDDD"; } if (10 > count && count >= 0) { return "#C7E4FF"; } if (50 > count && count >= 10) { return "#95CCFF"; } if (100 > count && count >= 50) { return "#519BDE"; } if (count >= 100) { return "#28537A"; } }; let getSVGProps = (key: keyof StatesListRendererMap) => { let dataObject = DataMap.get(key); let count = dataObject?.count; // Filter and nullify n/a states if (key === "HI" || key === "AK" || key === "NY") { count = null; } return { fill: getFillColor(count), }; }; type EventElementData = { scrollTop: number; scrollLeft: number; scrollHeight: number; scrollWidth: number; clientWidth: number; clientHeight: number; }; export function USA(props: USAProps) { let [width, setWidth] = React.useState<"100%" | "200%" | "350%" | "500%">( "100%" ); let [activeState, setActiveState] = React.useState< keyof typeof STATES_LIST | null >(null); let refFrame = React.useRef(null); let [scrollData, setScrollData] = React.useState({ scrollTop: 0, scrollLeft: 0, scrollHeight: 0, scrollWidth: 0, clientWidth: 0, clientHeight: 0, }); let [refScroll, setRefScroll] = React.useState({ scrollTop: 0, scrollLeft: 0, scrollHeight: 0, scrollWidth: 0, }); let classes = useStyles({ width }); let throttled = React.useMemo(() => { return throttle((data: EventElementData) => { setScrollData(data); }, 128); }, [setScrollData, refFrame]); let onFrameScroll = React.useCallback( (ev: React.UIEvent) => { let element: HTMLDivElement = ev.target as any; let clientWidth = element.clientWidth; let clientHeight = element.clientHeight; let scrollTop = element.scrollTop; let scrollLeft = element.scrollLeft; let scrollHeight = element.scrollHeight; let scrollWidth = element.scrollWidth; throttled({ scrollTop, scrollLeft, scrollHeight, scrollWidth, clientWidth, clientHeight, }); }, [setScrollData, throttled, refFrame] ); let _props: USAProps = { ...props, SVGFilters: [ () => ( ), ], ExtraRenderers: [ () => { return ( {/*
*/}
Extra renderer
); }, ], HOC: ({ renderer: Renderer, svg_props: _svg_props, abbr }) => { let svg_props = _svg_props != null ? _svg_props : {}; /* Key point: Need for Tooltip to pass ref*/ return ( {STATES_LIST[abbr]}
} placement={"top"} > { setActiveState(abbr); }, onMouseLeave: () => { setActiveState(null); }, stroke: activeState === abbr ? `white` : undefined, strokeWidth: activeState === abbr ? `2px` : undefined, filter: activeState === abbr ? "url(#filterDropShadow)" : undefined, }} /> ); }, getSVGProps, }; let onZoomIn = () => { switch (width) { case "100%": { setWidth("200%"); setRefScroll({ ...scrollData, scrollTop: scrollData.scrollTop * 2 + scrollData.clientHeight / 4, scrollLeft: scrollData.scrollLeft * 2 + scrollData.clientWidth / 4, }); break; } case "200%": { setWidth("350%"); setRefScroll({ ...scrollData, scrollTop: (scrollData.scrollTop * 3.5) / 2 + scrollData.clientHeight / 4, scrollLeft: (scrollData.scrollLeft * 3.5) / 2 + scrollData.clientWidth / 4, }); break; } case "350%": { setWidth("500%"); setRefScroll({ ...scrollData, scrollTop: (scrollData.scrollTop * 5) / 3.5 + scrollData.clientHeight / 4, scrollLeft: (scrollData.scrollLeft * 5) / 3.5 + scrollData.clientWidth / 4, }); break; } default: { break; } } }; let onZoomOut = () => { switch (width) { case "200%": { setWidth("100%"); setRefScroll({ ...scrollData, scrollTop: scrollData.scrollTop / 2 - scrollData.clientHeight / 4, scrollLeft: scrollData.scrollLeft / 2 - scrollData.clientWidth / 4, }); break; } case "350%": { setWidth("200%"); setRefScroll({ ...scrollData, scrollTop: (scrollData.scrollTop * 2) / 3.5 - scrollData.clientHeight / 4, scrollLeft: (scrollData.scrollLeft * 2) / 3.5 - scrollData.clientWidth / 4, }); break; } case "500%": { setWidth("350%"); setRefScroll({ ...scrollData, scrollTop: (scrollData.scrollTop * 3.5) / 5 - scrollData.clientHeight / 4, scrollLeft: (scrollData.scrollLeft * 3.5) / 5 - scrollData.clientWidth / 4, }); break; } default: { break; } } }; React.useEffect(() => { if (refFrame.current != null) { refFrame.current.scrollTop = refScroll.scrollTop; refFrame.current.scrollLeft = refScroll.scrollLeft; } }, [refScroll, refFrame]); return (
0–10
10-50
50-100
100+
Unavailable
); } const useStyles = makeStyles((theme: Theme) => { let yAspectCorrection = 16; return { frame: { overflow: "scroll", height: 0, paddingTop: `${(593 / (959 - yAspectCorrection)) * 100}%`, position: "relative", }, frame__inner: { height: "auto", position: "absolute", top: 0, left: 0, }, paper: { padding: theme.spacing(4), maxWidth: 1200, }, range: { display: "flex", alignItems: "center", }, rangeText: {}, rangeCircle: { width: 16, height: 16, borderRadius: "50%", display: "inline-block", marginRight: 8, }, }; });