function drawtriangle(id,text,colour,values,rag,offset,mean) { const svg = d3.select(`${id}`); const width = 500; // Fixed size. Was +svg.attr("width"); const height = 500; // Fixed size. Was +svg.attr("height"); const radius = 200; const center = { x: (width / 2) + offset.x, y: (height / 2) + offset.y}; let textcolour = colour; let polycolour = colour; let opacity = 0.3; if (rag !== "") { polycolour = rag; textcolour = "black"; console.log("rag: "+rag); opacity = 0.6; } // Define axes with A at the top (rotate -90 degrees) const axes = [ { name: "Feature A", angle: 0 }, { name: "Feature B", angle: 120 }, { name: "Feature C", angle: 240 } ]; axes.forEach(d => d.angle = (d.angle - 90) * Math.PI / 180); // Sample data: [0-1] scale // const values = [0.8, 0.1, 0.76]; Now passed in function args // Draw axis lines svg.append("g") .attr("class", "axis") .selectAll("line") .data(axes) .join("line") .attr("x1", center.x) .attr("y1", center.y) .attr("x2", d => center.x + radius * Math.cos(d.angle)) .attr("y2", d => center.y + radius * Math.sin(d.angle)); // Draw grid rings (polygons) const levels = 7; for (let i = 1; i <= levels; i++) { const r = (radius / levels) * i; const points = axes.map(d => { return [ center.x + r * Math.cos(d.angle), center.y + r * Math.sin(d.angle) ]; }); svg.append("polygon") .attr("class", "grid") .attr("points", points.map(p => p.join(",")).join(" ")); } // Draw axis ticks const tickLength = 5; axes.forEach(axis => { for (let i = 1; i <= levels; i++) { const r = (radius / levels) * i; const angle = axis.angle; const x1 = center.x + r * Math.cos(angle); const y1 = center.y + r * Math.sin(angle); // Perpendicular tick const perpAngle = angle + Math.PI / 2; const x2 = x1 + tickLength * Math.cos(perpAngle); const y2 = y1 + tickLength * Math.sin(perpAngle); svg.append("line") .attr("x1", x1) .attr("y1", y1) .attr("x2", x2) .attr("y2", y2) .attr("class", "tick"); } }); // Convert values to coordinates const valuePoints = axes.map((d, i) => { const r = radius * values[i]; return [ center.x + r * Math.cos(d.angle), center.y + r * Math.sin(d.angle) ]; }); // Draw data area svg.append("polygon") .attr("class", "area") .attr("points", valuePoints.map(p => p.join(",")).join(" ")) .attr("fill", polycolour) // #d76a23 with 30% opacity (translucent) .attr("fill-opacity", opacity) .attr("stroke", polycolour) // Outer line color .attr("stroke-width", 1); // Thin outer line // Draw outer triangle border (goes to edge of chart) const outerPoints = axes.map(d => [ center.x + radius * Math.cos(d.angle), center.y + radius * Math.sin(d.angle) ]); // Draw border separately (on top) svg.append("polygon") .attr("points", outerPoints.map(p => p.join(",")).join(" ")) .attr("fill","none") .attr("stroke", colour) // Outer line color .attr("stroke-width", 9); // Thicker outer line // Put label in bottom centre of triangle const bottomLeft = outerPoints[1]; const bottomRight = outerPoints[2]; const midX = (bottomLeft[0] + bottomRight[0]) / 2; const midY = (bottomLeft[1] + bottomRight[1]) / 2; svg.append("text") .attr("x", midX) .attr("y", midY - 15) // Alter for correct height .attr("text-anchor", "middle") .attr("fill", textcolour) /// My Colour .attr("font-size", "22px") .attr("font-weight", "bold") .text(`${text}`); // And now a central number svg.append("text") .attr("x", midX) .attr("y", midY -60) .attr("text-anchor", "middle") .attr("fill", "black") // 🎨 customize color .attr("font-size", "24px") .attr("font-weight", "bold") .attr("font-family", "Courier New, monospace") .text(`${mean}`); // Add axis labels /* svg.selectAll(".label") .data(axes) .join("text") .attr("class", "label") .attr("x", d => center.x + (radius + 20) * Math.cos(d.angle)) .attr("y", (d,i) => { if (i === 0) { //adjust for 1st access, rather than using d.name return center.y + (radius + 20) * Math.sin(d.angle) } else return center.y + (radius + 20 + 30) * Math.sin(d.angle) }) .text(d => d.name); */ }