diff options
Diffstat (limited to 'old_stuff/src/components/RadarChart.astro')
| -rw-r--r-- | old_stuff/src/components/RadarChart.astro | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/old_stuff/src/components/RadarChart.astro b/old_stuff/src/components/RadarChart.astro new file mode 100644 index 0000000..0a3d434 --- /dev/null +++ b/old_stuff/src/components/RadarChart.astro @@ -0,0 +1,132 @@ +--- +import "@styles/terminal.css" + +interface Entry { + name: string; + weight: number; +} + +interface Props { + max: number + data: Entry[]; +} + +const { max, data } = Astro.props + +const chartPadding = 100; +const chartSize = 400; +const chartCenter = chartSize / 2; + +const chartData = data ;// .sort((a, b) => b.weight - a.weight).slice(0, data.length); +const pointPadding = 0; +const rings = [...Array(6).keys()]; + +const getX = (angle: number, value: number) => + Math.cos(angle - Math.PI / 2) * value; +const getY = (angle: number, value: number) => + Math.sin(angle - Math.PI / 2) * value; + +const axes = chartData.map((_, index) => { + const angle = (Math.PI * 2 * index) / chartData.length; + const x = getX(angle, chartSize / 2); + const y = getY(angle, chartSize / 2); + const points = [ + [0, 0], + [x, y], + ] + .map((point) => point[0] + "," + point[1]) + .join(" "); + return { + points: points, + }; +}); + +const properties = chartData.map((item, index) => { + const { name, weight: total } = item; + const clamp = Number(total / (max + pointPadding)); + const angle = (Math.PI * 2 * index) / chartData.length; + const x = getX(angle, (clamp * chartSize) / 2); + const y = getY(angle, (clamp * chartSize) / 2); + return { name: name, total: total, x: x, y: y }; +}); + +const shape = + properties.reduce((items, item, index) => { + const { x, y } = item; + const string = `${index === 0 ? "M" : "L"}${x},${y}`; + return items + string; + }, "") + "z"; + +const strokeColor = "stroke-[var(--alt)]"; +const shapeClass = "stroke-[var(--primary)] fill-[#7ed4fb]/50"; + +--- + <div class="w-full grid md:grid-cols-1 items-center gap-16 p-0"> + <svg + xmlns="http://www.w3.org/2000/svg" + viewBox={`-${chartPadding / 2} -${chartPadding / 2} ${chartSize + chartPadding} ${chartSize + chartPadding}`} + role="presentation" + > + <g transform={`translate(${chartCenter},${chartCenter})`}> + { + rings.map((_, index) => { + return ( + <circle + cx={0} + cy={0} + r={ + ((index / rings.length) * chartSize) / + Number((Math.PI / 2 + 0.1).toFixed(2)) + } + class={strokeColor} + fill="none" + stroke-width={1} + /> + ); + }) + } + { + axes.map((axis) => { + const { points } = axis; + return ( + <polyline + points={points} + class={strokeColor} + fill="none" + stroke-width={1} + /> + ); + }) + } + <path d={shape} class=`${shapeClass}` stroke-width={1.5}></path> + { + properties.map((property, index) => { + const length = 1.1; + const angle = (Math.PI * 2) * index / chartData.length; + const maxX = getX(angle, (length * chartSize) / 2); + const maxY = getY(angle, (length * chartSize) / 2); + let textAngle = (angle * (180 / Math.PI)) + if (90 < textAngle && textAngle < 270) { + textAngle += 180 + } + return ( + <g transform={`translate(${maxX},${maxY})`}> + <text + x={0} + y={0} + fill="var(--secondary)" + font-size="2rem" + font-weight="bold" + text-anchor="middle" + transform=`rotate(${textAngle})` + dominant-baseline="middle" + > + {property.name} + </text> + </g> + ); + }) + } + </g> + </svg> + </div> |
