majic / src /components /charts /singleChart /SimpleChartTripPurpose.tsx
nolual's picture
Upload 55 files
0c20ea8
raw
history blame
3.93 kB
import React, { useMemo, useState } from "react";
import { Bar } from "@visx/shape";
import { Group } from "@visx/group";
import { LinearGradient } from "@visx/gradient";
import { AxisBottom, AxisLeft } from "@visx/axis";
import { scaleBand, scaleLinear } from "@visx/scale";
const verticalMargin = 20;
const leftMargin = 50;
const barPadding = 4;
interface tripPurpose {
trip_purpose_group: string;
percentage: number;
}
export type BarsProps = {
data: tripPurpose[];
width: number;
height: number;
events?: boolean;
};
const getTripPurposeValue = (d: tripPurpose) => Number(d.percentage);
export default function SimpleChartTripPurpose({
data,
width,
height,
events = false,
}: BarsProps) {
const xMax = width - leftMargin;
const yMax = height - verticalMargin - 20;
const xScale = useMemo(
() =>
scaleBand<number>({
range: [0, xMax],
round: true,
domain: data.map((d: any) => d.trip_purpose_group),
paddingInner: 0.2,
paddingOuter: 0.1,
}),
[xMax]
);
const yScale = useMemo(
() =>
scaleLinear<number>({
range: [yMax, 0],
round: true,
domain: [0, Math.max(...data.map(getTripPurposeValue))],
}),
[yMax]
);
const [isHover, setIsHover] = useState(Array(data.length).fill(false));
return width < 10 ? null : (
<svg
width={width}
height={height}
style={{
borderBottomLeftRadius: "14px",
borderBottomRightRadius: "14px",
boxShadow: "0 0 8px rgba(0, 0, 0, 0.2)",
}}
>
<LinearGradient from="#351CAB" to="#621A61" id="teal" />
<rect width={width} height={height} fill="url(#teal)" />
<Group top={verticalMargin}>
{data.map((d: any, index: any) => {
const barWidth = xScale.bandwidth();
const barHeight = yMax - (yScale(d.percentage) ?? 0);
const barX = xScale(d.trip_purpose_group) ?? 0;
const barY = yMax - barHeight;
return (
<Bar
key={`bar-${d.trip_purpose_group}`}
className={isHover[index] ? "hovered" : ""}
style={{
cursor: "pointer",
transition: "all 0.5s",
opacity: "1",
}}
x={barX + 35}
y={barY - 10}
rx={5}
ry={5}
width={barWidth - barPadding}
height={barHeight}
fill={isHover[index] ? "#FFFFFF" : "#AAB1FF"}
onClick={() => {
if (events) alert(`clicked: ${JSON.stringify(d)}`);
}}
onMouseMove={() => {
const updatedHover = [...isHover];
updatedHover[index] = true;
setIsHover(updatedHover);
}}
onMouseLeave={() => {
const updatedHover = [...isHover];
updatedHover[index] = false;
setIsHover(updatedHover);
}}
/>
);
})}
<AxisBottom
top={height - verticalMargin - 30}
left={leftMargin - 15}
scale={xScale}
tickStroke="white"
stroke="white"
strokeWidth={2}
tickLabelProps={() => ({
fill: "white",
fontSize: 10,
textAnchor: "middle",
fontWeight: "bold",
})}
/>
<AxisLeft
left={leftMargin - 15}
top={verticalMargin - 30}
scale={yScale}
tickFormat={(value) => value.toString()}
tickStroke="white"
strokeWidth={2}
stroke="white"
tickLabelProps={() => ({
fill: "white",
fontSize: 11,
textAnchor: "end",
dy: "0.3em",
dx: "-0.25em",
fontWeight: "bold",
})}
/>
</Group>
</svg>
);
}