Radar Chart with Optional Animation
by teknohippy
HTML
<link
href="https://fonts.googleapis.com/css2?family=Roboto:wght@600&display=swap"
rel="stylesheet"
/>
<div id="chart1-container" class="chart-container">
<svg id="radar-chart-1" width="600" height="500"></svg>
</div>
<div id="chart2-container" class="chart-container">
<svg id="radar-chart-2" width="600" height="500"></svg>
</div>
<div id="chart3-container" class="chart-container">
<svg id="radar-chart-3" width="600" height="500"></svg>
</div>
CSS
body {
position: relative;
}
.chart-container {
position: relative;
width: 600px;
height: 500px;
}
.label {
position: absolute;
padding: 7px 12px;
background-color: #f2f6fd;
color: #354c91;
border-radius: 12px;
font-family: "Roboto", sans-serif;
font-size: 13px;
font-weight: 500;
text-align: center;
white-space: nowrap;
transform: translate(-50%, -50%);
}
JavaScript
const width = 600
const height = 500
const centerX = width / 2
const centerY = height / 2
const maxRadius = 332 /2
const innerRadius = 40
const stepInRadius = 35
const minScore = 0
const maxScore = 10
const numLevels = 5
const rotationOffset = -Math.PI / 2
const labelOffset = 15
const labels = [
"Label 1",
"Label 2",
"Label 3",
"Label 4",
"Label 5",
"Label 6",
]
const numAxes = labels.length
const angleStep = (2 * Math.PI) / numAxes
function calculatePoint(angle, radius) {
return {
x: centerX + radius * Math.cos(angle),
y: centerY + radius * Math.sin(angle),
}
}
function mapScoreToRadius(score) {
return (
innerRadius +
((score - minScore) * (maxRadius - innerRadius)) /
(maxScore - minScore)
)
}
function drawRadarChart(
containerId,
svgId,
dataSets,
duration = 400,
delay = 500,
) {
const container = document.getElementById(containerId)
const svg = document.getElementById(svgId)
svg.innerHTML = "" // Clear previous chart if any
// Draw background levels
for (let level = numLevels; level >= 0; level--) {
const levelRadius =
innerRadius + (level / (numLevels)) * (maxRadius - innerRadius)
let levelPathData = ""
for (let i = 0; i < numAxes; i++) {
const angle = i * angleStep + rotationOffset
const point = calculatePoint(angle, levelRadius)
levelPathData += `${i === 0 ? "M" : "L"} ${point.x} ${point.y} `
}
levelPathData += "Z"
const levelPath = document.createElementNS(
"http://www.w3.org/2000/svg",
"path",
)
...