legend = (colorScale, var1_label, var2_label, var1_definition, var2_definition) => {
const highlightColor = "#ffd700";
const width = 300;
const height = 200;
const labelMarginVar1 = 100;
const labelMarginVar2 = 30;
const svg = d3.create("svg")
.attr("width", 300 + labelMarginVar2)
.attr("height", 200 + labelMarginVar1);
const labelOffset = 0;
const var1LabelX = width / 10;
const var1LabelY = 210 + labelOffset;
const var2LabelX = -labelOffset;
const var2LabelY = height / 4;
const squares = d3.cross([0, 1, 2], [0, 1, 2]);
const squareSize = 50;
const squareSpacing = 51;
svg.selectAll("rect")
.data(squares)
.join("rect")
.attr("x", d => squareSpacing * d[0] + (width - squareSpacing * 3) / 2 - squareSize / 2)
.attr("y", d => height - squareSpacing * (d[1] + 1) + (height - squareSpacing * 3) / 2 - squareSize / 2)
.attr("width", squareSize)
.attr("height", squareSize)
.attr("fill", d => scheme[3 * d[1] + d[0]])
.attr("stroke", "grey")
.attr("stroke-width", 1)
.attr("class", d => `legend-item legend-color-${d[1] * 3 + d[0]}`)
.on("mouseover", function(event, d) {
let summary = ""; // Your existing logic for summary
// Highlight the legend box
d3.select(this)
.attr("stroke", highlightColor)
.attr("stroke-width", 5);
// Highlight corresponding counties on the map
const legendClass = `class-${d[1]}-${d[0]}`;
d3.selectAll(`.${legendClass}`)
.attr("stroke", highlightColor)
.attr("stroke-width", 8);
const color = scheme[3 * d[1] + d[0]];
const message = getLegendMessage(d, var1_label, var2_label, scheme);
tooltip_message.html(message);
})
.on("mouseout", function(event, d) {
tooltip_message.html("ⓘ");
// Remove highlight from the legend box
d3.select(this)
.attr("stroke", "grey")
.attr("stroke-width", 1);
// Remove highlight from corresponding counties on the map
const legendClass = `class-${d[1]}-${d[0]}`;
d3.selectAll(`.${legendClass}`)
.attr("stroke", "white")
.attr("stroke-width", 0.125);
});
// Add Variable 1 axis label (bottom) with tooltip
svg.append("text")
.attr("x", width / 2.2)
.attr("y", height + labelMarginVar1 / 2)
.attr("text-anchor", "middle")
.text(var1_label)
.on("mouseover", function() {
tooltip_message.html(`<strong>${var1_label}</strong><br>${var1_definition}`);
})
.on("mouseout", function() {
tooltip_message.html("ⓘ");
});
// Add Variable 2 axis label (side) with tooltip
svg.append("text")
.attr("transform", `translate(${labelMarginVar2 / 1.5}, ${height / 1.65}) rotate(-90)`)
.attr("text-anchor", "middle")
.text(var2_label)
.on("mouseover", function() {
tooltip_message.html(`<strong>${var2_label}</strong><br>${var2_definition}`);
})
.on("mouseout", function() {
tooltip_message.html("ⓘ");
});
// Definitions for arrow markers
const arrowDefs = svg.append('defs');
arrowDefs.append('marker')
.attr('id', 'arrowhead')
.attr('markerWidth', 10)
.attr('markerHeight', 7)
.attr('refX', 10)
.attr('refY', 3.5)
.attr('orient', 'auto')
.append('polygon')
.attr('points', '0 0, 10 3.5, 0 7');
// X-axis arrow
svg.append('line')
.attr('x1', squareSize - 2)
.attr('x2', (squareSpacing + 4) * 4) // size of arrow
.attr('y1', height - 2)
.attr('y2', height - 2)
.attr('stroke-width', 2)
.attr('stroke', 'black')
.attr('marker-end', 'url(#arrowhead)');
// Y-axis arrow
svg.append('line')
.attr('x1', squareSize - 2)
.attr('x2', squareSize - 2)
.attr('y1', (squareSpacing) * 4 - 6)
.attr('y2', labelMarginVar1 / 2.5 - 12) // size of arrow
.attr('stroke-width', 2)
.attr('stroke', 'black')
.attr('marker-end', 'url(#arrowhead)');
// Threshold values along the x-axis
var1_thresholds.forEach((threshold, i) => {
svg.append('text')
.attr('x', squareSpacing * (i + 2))
.attr('y', height + labelMarginVar1 / 2 - 45) // Adjust as needed
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'hanging')
.text(threshold);
});
// X-axis ticks
var1_thresholds.forEach((threshold, i) => {
const xPos = squareSpacing * (i + 2) - 3;
svg.append('line')
.attr('x1', xPos)
.attr('y1', height - 2)
.attr('x2', xPos)
.attr('y2', height + 4) // Adjust as needed for tick length
.attr('stroke', 'black')
.attr('stroke-width', 1);
});
// Threshold values along the y-axis
var2_thresholds.forEach((threshold, i) => {
svg.append('text')
.attr('transform', `translate(${30}, ${(height - squareSpacing * (i + 1))}) rotate(-90)`) // Adjust as needed
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'hanging')
.text(threshold);
});
// Y-axis ticks
var2_thresholds.forEach((threshold, i) => {
const yPos = height - squareSpacing * (i + 1) - 2;
svg.append('line')
.attr('x1', squareSize - 2)
.attr('y1', yPos)
.attr('x2', squareSize - 6) // Adjust as needed for tick length
.attr('y2', yPos)
.attr('stroke', 'black')
.attr('stroke-width', 1);
});
return svg.node();
}