chart = {
const height = 360;
const marginTop = 25;
const marginRight = 40;
const marginBottom = 45
; const marginLeft = 40;
const ramp_semi_height = 22;
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height)
.attr("style", "max-width: 100%; height: auto;");
const breaks = [
{ start: 0, end: 15, color: "#00BB00" },
{ start: 15, end: 30, color: "#FFDF5F" },
{ start: 30, end: 45, color: "#FF8A0F" },
{ start: 45, end: 75, color: "#EE0000" },
{ start: 75, end: 100, color: "#555" }
];
let recipes = [
{ name: "Tartiflette", co2: 18.4 },
{ name: "Hamburger", co2: 64.3 },
{ name: "Chili con carne", co2: 46.4 },
{ name: "Salade composée", co2: 9.9 },
{ name: "Dahl de lentilles", co2: 8.6 },
{ name: "Poisson pané", co2: 18.2 },
{ name: "Saucisse frites", co2: 36.2 },
{ name: "Couscous poulet", co2: 24.3 },
{ name: "Pâtes à la carbonara", co2: 13.0 }
];
recipes.sort((x, y) => d3.ascending(x.co2, y.co2));
const x_scale = d3
.scaleLinear()
.domain([0, 100])
.range([marginLeft, width - marginRight]);
const y_scale = d3
.scaleLinear()
.domain([-50, 50])
.range([height - marginBottom, marginTop]);
const xAxis = d3.axisBottom(x_scale).tickFormat((d) => `${d}%`);
const ramp_top = y_scale(0) - ramp_semi_height;
const ramp_bottom = y_scale(0) + ramp_semi_height;
let svg_defs = svg.append("defs");
let grad = svg_defs.append("linearGradient").attr("id", "grad");
grad
.selectAll("stop")
.data(breaks)
.join("stop")
.attr("offset", (d) => `${d.start}%`)
.attr("stop-color", (d) => d.color);
let lines_grad_top = svg_defs
.append("linearGradient")
.attr("id", "linesGradTop")
.attr("x1", 0)
.attr("x2", 0)
.attr("y1", 0)
.attr("y2", 1);
lines_grad_top
.append("stop")
.attr("offset", "0%")
.attr("stop-color", "white")
.attr("stop-opacity", "1");
lines_grad_top
.append("stop")
.attr("offset", "35%")
.attr("stop-color", "white")
.attr("stop-opacity", "0");
let lines_grad_bottom = svg_defs
.append("linearGradient")
.attr("id", "linesGradBottom")
.attr("x1", 0)
.attr("x2", 0)
.attr("y1", 0)
.attr("y2", 1);
lines_grad_bottom
.append("stop")
.attr("offset", "65%")
.attr("stop-color", "white")
.attr("stop-opacity", "0");
lines_grad_bottom
.append("stop")
.attr("offset", "100%")
.attr("stop-color", "white")
.attr("stop-opacity", "1");
svg
.append("rect")
.attr("x", x_scale(0))
.attr("y", ramp_top)
.attr("rx", 10)
.attr("width", x_scale(100) - x_scale(0))
.attr("height", ramp_semi_height * 2)
.attr("fill", "url(#grad)");
svg
.append("g")
.selectAll("text")
.data([10, 20, 30, 40, 50, 60, 70, 80, 90])
.join("text")
.attr("x", (d) => x_scale(d))
.attr("y", y_scale(0))
.attr("text-anchor", "middle")
.attr("dominant-baseline", "middle")
.style("fill", "white")
.text((d) => `${d}%`);
svg
.append("g")
.selectAll("line")
.data(recipes)
.join("line")
.attr("x1", (d) => x_scale(d.co2))
.attr("x2", (d) => x_scale(d.co2))
.attr("y1", (_, i) => (i % 2 == 0 ? ramp_top : ramp_bottom))
.attr("y2", (_, i) => (i % 2 == 0 ? ramp_top - 10 : ramp_bottom + 10))
.attr("stroke", "black");
svg
.append("g")
.selectAll("rect")
.data(recipes)
.join("rect")
.attr("x", (d) => x_scale(d.co2) - 1)
.attr("y", ramp_top)
.attr("height", ramp_semi_height * 2)
.attr("width", 1)
.attr("fill", (_, i) =>
i % 2 == 0 ? "url(#linesGradTop)" : "url(#linesGradBottom)"
)
.attr("stroke-width", 0);
svg
.append("g")
.selectAll("circle")
.data(recipes)
.join("circle")
.attr("cx", (d) => x_scale(d.co2))
.attr("cy", (d, i) => (i % 2 == 0 ? ramp_top - 15 : ramp_bottom + 15))
.attr("r", 6)
.attr("fill", "white")
.attr("stroke", "#55BBEE")
.attr("stroke-width", 5);
svg
.append("g")
.selectAll("text")
.data(recipes)
.join("text")
.attr("x", (d, i) => (i % 2 == 0 ? x_scale(d.co2) : x_scale(d.co2) + 5))
.attr("y", (d, i) => (i % 2 == 0 ? ramp_top - 30 : ramp_bottom + 38))
.attr(
"transform",
(d, i) =>
`rotate(-35, ${i % 2 == 0 ? x_scale(d.co2) : x_scale(d.co2) + 5}, ${
i % 2 == 0 ? ramp_top - 30 : ramp_bottom + 38
})`
)
.attr("text-anchor", (_, i) => (i % 2 == 0 ? "start" : "end"))
.append("tspan")
.text((d) => `${d.name}`);
svg
.append("text")
.attr("x", width / 2)
.attr("y", height - 10)
.attr("text-anchor", "middle")
.attr("font-style", "italic")
.text("Pourcentage du budget carbone quotidien total par personne");
return svg.node();
}