chart = {
const height = marginTop + (metrics.length * rowHeight);
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.style("display", "block");
const strategyGroup = svg.selectAll('.strategyGroup')
.data(strategies)
.join((group) => {
const enter = group.append('g').attr('class', 'strategyGroup');
enter.append('rect').attr('class', 'strategyBox');
enter.append('text').attr('class', 'strategyLabel');
enter.append('path').attr("class", 'strategyLine');
return enter;
});
strategyGroup.select(".strategyBox")
.attr("id", (d,i) => "strategy" + i)
.attr("width", 56)
.attr("height", 14)
.attr("fill", (d) => colorScale(d))
.attr("stroke", "grey")
.attr("stroke-width", 0.25)
.attr("rx", 2)
.attr("ry", 2)
.attr("y", 2)
.attr("x", (d,i) => i * 60)
.attr("transform", "translate(" + (width - (strategies.length * 60))/2 + ",0)")
.on("mouseover",(event, d) => {
d3.selectAll(".strategyLine").attr("opacity",0);
d3.selectAll(".strategyDot").attr("opacity",0);
d3.selectAll("#"+ event.currentTarget.id).attr("opacity",1);
})
.on("mouseout",(event, d) => {
d3.selectAll(".strategyLine").attr("opacity",1);
d3.selectAll(".strategyDot").attr("opacity",0);
});
;
strategyGroup.select(".strategyLabel")
.attr("pointer-events", "none")
.attr("fill", (d,i) => colorScale(strategies[7-i]))
.attr("font-size", 10)
.attr("text-anchor", "middle")
.attr("x", (d,i) => (i * 60) + 28)
.attr("y", 12)
.text((d) => d)
.attr("transform", "translate(" + (width - (strategies.length * 60))/2 + ",0)");
strategyGroup.select(".strategyLine")
.attr("id", (d,i) => "strategy" + i)
.attr("stroke", "#A0A0A0")
.attr("opacity",0)
.attr("fill", "transparent")
.attr("stroke-width", 0.5)
.attr("d", (d) => d3.line().x((l) => l.x).y((l) => l.y)(strategyData[d]))
.attr("transform", "translate(0," + marginTop + ")")
.on("mouseover",(event, d) => {
d3.selectAll(".strategyLine").attr("opacity",0);
d3.selectAll(".strategyDot").attr("opacity",0);
d3.selectAll("#"+ event.currentTarget.id).attr("opacity",1);
})
.on("mouseout",(event, d) => {
d3.selectAll(".strategyLine").attr("opacity",1);
d3.selectAll(".strategyDot").attr("opacity",1);
});
const metricGroup = svg.selectAll('.metricGroup')
.data(metrics)
.join((group) => {
const enter = group.append('g').attr('class', 'metricGroup');
const gradient = enter.append('defs')
.append('linearGradient').attr("class", "linearGradient");
gradient.append('stop').attr("class", "stopLeft");
gradient.append('stop').attr("class", "stopLeftMid");
gradient.append('stop').attr("class", "stopRightMid");
gradient.append('stop').attr("class", "stopRight");
enter.append('text').attr('class', 'metricLabel');
enter.append('g').attr('class', 'metricXAxis');
enter.append('rect').attr('class', 'metricLine');
enter.append('g').attr('class', 'metricDotGroup');
return enter;
});
metricGroup.select(".linearGradient")
.attr('id', (d, i) => 'linear-gradient' + i)
.attr('x1', '0%')
.attr('y1', '0%')
.attr('x2', '100%')
.attr('y2', '0%');
const calculateZeroPoint = (i) => {
const zeroPoint = scales[i](0);
const extent = scales[i].domain()[1] - scales[i].domain()[0];
if(!zeroPoint || extent === 0) {return "100%"}
console.log(String((zeroPoint/extent) * 100) + "%")
return String((zeroPoint/extent)) + "%";
}
metricGroup.select(".stopLeft")
.attr('offset', '0%')
.attr('stop-color', '#fc9272');
metricGroup.select(".stopLeftMid")
.attr('offset', (d,i) => calculateZeroPoint(i))
.attr('stop-color', '#fc9272');
metricGroup.select(".stopRightMid")
.attr('offset', (d,i) => calculateZeroPoint(i))
.attr('stop-color', '#99d8c9');
metricGroup.select(".stopRight")
.attr('offset', '100%')
.attr('stop-color', '#99d8c9');
metricGroup.attr("transform", (d,i) => "translate(0," + (marginTop + (rowHeight * i)) + ")");
metricGroup.select(".metricLabel")
.attr("fill", "black")
.attr("font-size", 12)
.attr("text-anchor", "end")
.attr("x", marginLeft - 10)
.attr("y",4)
.text((d) => d);
metricGroup.select(".metricLine")
.attr("x", marginLeft)
.attr("width", width - marginLeft - marginRight)
.attr("height", 3)
.attr("fill", (d,i) => "url(#linear-gradient" + i + ")");
metricGroup.select(".metricXAxis")
.each((d,i, axisGroups) => {
const axis = d3.select(axisGroups[i])
.call(d3.axisBottom(scales[i]));
axis.selectAll("path").attr("display","none");
axis.selectAll("text")
.attr("font-size", 8)
.attr("fill","grey")
.attr("dy","10");
axis.selectAll("line")
.attr("y1",-4)
.attr("stroke", "#A0A0A0")
.attr("stroke-width",0.5)
.attr("y2",8)
const metricDotsGroup = metricGroup.select(".metricDotGroup")
.selectAll('.metricDotsGroup')
.data((d,i) => {
const matchingRow = paperData.find((f) => f.Metric === d);
const dotData = [];
strategies.forEach((s, sIndex) => {
if(matchingRow[s] !== null){
dotData.push({strategyIndex: sIndex, strategy: s, value: matchingRow[s], scale: scales[i]})
}
})
return dotData
})
.join((group) => {
const enter = group.append('g').attr('class', 'metricDotsGroup');
enter.append('circle').attr('class', 'strategyDot');
return enter;
});
metricDotsGroup.select(".strategyDot")
.attr("id", (d) => "strategy" + d.strategyIndex)
.attr("r", 4)
.attr("fill", (d) => colorScale(d.strategy))
.attr("stroke", "grey")
.attr("stroke-width", 0.25)
.attr("cx", (d) => d.scale(d.value))
.attr("cy", 1.5)
.on("mouseover",(event, d) => {
d3.selectAll(".strategyL").attr("opacity",0);
d3.selectAll(".strategyDot").attr("opacity",0);
d3.selectAll("#"+ event.currentTarget.id).attr("opacity",1);
})
.on("mouseout",(event, d) => {
d3.selectAll(".strategyLine").attr("opacity",1);
d3.selectAll(".strategyDot").attr("opacity",1);
});
})
d3.selectAll(".metricXAxis path");
return svg.node();
}