drawRadar = function(data, params) {
const { height, width, margin, axisTick, vennRatio } = params;
const axisName = ["NEVER", "1 TIMER", "REPEATER"];
const venn = ["#FAA9B2", "#F8CD29", "#1D95BB"];
const maxValue = 100;
const angleSlice = Math.PI * 2 / 3;
const lineStroke = "#201E1F";
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height + (2 * margin)])
.style("background-color", "#FCF4EB")
.style("border-radius", "12px")
let placement = {
radius: (height - 2 * margin) / 2,
xOffset: width / 2,
yOffset: margin + (height / 2)
};
let rScale = d3.scaleLinear()
.domain([0, maxValue])
.range([0, placement.radius])
let radarLine = d3.lineRadial()
.curve(d3.curveLinearClosed)
.radius(d => rScale(d))
.angle((d, i) => i * angleSlice)
const axisGrid = svg.append("g")
.attr("class", "axisWrapper")
.attr('transform', `translate(${placement.xOffset}, ${placement.yOffset})`);
const vennRadius = (placement.radius / (axisTick * 2)) * axisTick * vennRatio;
const transR = (placement.radius - vennRadius * 2) / 2;
axisGrid.append("g")
.attr("class", "venn")
.selectAll("circle")
.data(venn)
.enter()
.append("circle")
.attr("cx", (d, i) => rScale(maxValue / 2) * Math.cos(angleSlice * i - Math.PI / 2))
.attr("cy", (d, i) => rScale(maxValue / 2) * Math.sin(angleSlice * i - Math.PI / 2))
.attr("r", vennRadius)
.attr("fill", d => d)
.attr("fill-opacity", 0.2)
.attr("stroke", d => d)
.attr("transform", (d, i) =>
`translate(
${transR * Math.cos(angleSlice * i - Math.PI / 2)},
${transR * Math.sin(angleSlice * i - Math.PI / 2)})
`)
const tickData = new Array(axisTick)
.fill([])
.map((item, index) => {
let r = (maxValue / axisTick) * (index + 1);
return [r, r, r];
});
axisGrid.append("g")
.selectAll("g")
.data(tickData)
.join("g")
.attr("fill", "transparent")
.attr("opacity", 0.3)
.attr("stroke", lineStroke)
.attr("stroke-dasharray", "5 5")
.append("path")
.attr("d", d => radarLine(d))
let axisLine = axisGrid.selectAll(".axis-line")
.data(axisName)
.enter()
.append("g")
.attr("class", "axis-line");
axisLine.append("line")
.attr("x1", (d, i) => rScale(0) * Math.cos(angleSlice * i - Math.PI / 2))
.attr("y1", (d, i) => rScale(0) * Math.sin(angleSlice * i - Math.PI / 2))
.attr("x2", (d, i) => rScale(maxValue) * Math.cos(angleSlice * i - Math.PI / 2))
.attr("y2", (d, i) => rScale(maxValue) * Math.sin(angleSlice * i - Math.PI / 2))
.attr("stroke", lineStroke)
.attr("opacity", 0.3);
axisLine.append("circle")
.attr("cx", (d, i) => rScale(maxValue) * Math.cos(angleSlice * i - Math.PI / 2))
.attr("cy", (d, i) => rScale(maxValue) * Math.sin(angleSlice * i - Math.PI / 2))
.attr("r", 3)
.attr("stroke", "#201E1F");
axisLine.append("text")
.attr("x", (d, i) => rScale(maxValue) * Math.cos(angleSlice * i - Math.PI / 2))
.attr("y", (d, i) => rScale(maxValue) * Math.sin(angleSlice * i - Math.PI / 2))
.attr("dy", (d, i) => i > 0? 20: -10)
.attr("text-anchor", "middle")
.attr("fill", "rgba(32,30,31,1)")
.style("font-size", 14)
.text(d => d);
const photoImgWidth = 48;
const shapeColor = "#CF141E";
data().then(data => {
let shape = axisGrid.append("g")
.attr("class", "color-shape")
.append("path")
.attr("d", d => "M0,0L0,0L0,0Z")
.attr("stroke", shapeColor)
.attr("stroke-width", 2)
.attr("fill", shapeColor)
.attr("fill-opacity", 0.25);
const photoGroup = axisGrid.append("g")
.attr("class", "photo")
.selectAll("g")
.data(data.map(d => ({ ...d, center: polygonCentroid(radarLine(d.score)) })))
.enter()
.append("g")
const photos = photoGroup.append("image")
.attr("x", (d) => d.center[0])
.attr("y", (d) => d.center[1])
.attr("xlink:href", d => d.photo)
.attr("width", photoImgWidth)
.attr("transform", `translate(${-photoImgWidth / 2}, ${-photoImgWidth / 2})`)
const borders = photoGroup.append("circle")
.attr("cx", (d) => d.center[0])
.attr("cy", (d) => d.center[1])
.attr("r", photoImgWidth / 2)
.attr("fill", "none")
.attr("stroke-width", 2)
.attr("stroke", "#fff")
photos.on("mouseenter", (curItem) => {
borders
.transition()
.duration(1500)
.attr("stroke", (d) => curItem.photo === d.photo? "rgba(207,20,30,1)": "#fff");
shape.datum(curItem)
.transition()
.duration(1500)
.attr("d", d => radarLine(d.score))
})
})
return svg.node();
}