viewof pizzaCategories = {
function onLineClick(e) {
const index = getTargetIndex(e);
if (focus === index) {
focus = null;
return;
}
if (focus !== null) fill(focus);
if (index >= 0) {
fill(index, true);
focus = index;
updateCategory(lookupCategory(index));
} else {
focus = null;
updateCategory(null);
line.nodes().forEach((node, idx) => {
fill(idx);
});
}
}
function handlePointerDown(e) {
const index = getTargetIndex(e);
if (index >= 0) fill(index, true, 0.5);
}
function handlePointerUp(e) {
const index = getTargetIndex(e);
if (index >= 0) {
fill(index, true);
line.nodes().forEach((node, idx) => {
if (idx !== index) {
fill(idx, false, true);
}
});
}
d3.select(this).style("default");
}
function highlight(e) {
if (focus !== null) return;
const index = getTargetIndex(e);
d3.select(this).style("cursor", index >= 0 ? "pointer" : "default");
fill(index, true);
if (timeout) clearTimeout(timeout);
timeout = setTimeout(
() => updateCategory(index >= 0 ? lookupCategory(index) : null),
25
);
}
function restore(e) {
if (focus !== null) return;
const index = getTargetIndex(e);
fill(index);
}
function fillType(color, darker, lowlight) {
if (darker) return d3.color(color).darker(darker);
else if (lowlight) return "grey";
else return color;
}
function fill(index, highlight, lowlight, darker) {
if (index >= 0) {
const color = categoryColors[index].color;
d3.select(line.nodes()[index])
.attr("stroke", fillType(color, darker, lowlight))
.attr("stroke-width", highlight ? 10 : 5);
}
}
function getTargetIndex(e) {
let tar = e.target;
return tar instanceof SVGPathElement
? [...tar.parentElement.children].indexOf(tar)
: -1;
}
const plot = Plot.plot({
style: {fontSize: "20px"},
ariaLabel: "categoryChart",
title: "Pizza Categories",
width: 2000,
height: 800,
margin: 100,
grid: true,
x: { label: "Month", ariaHidden: true },
y: { label: "Revenue", ariaHidden: true },
symbol: { legend: true },
color: {
legend: true,
range: [
categoryColors[0].color,
categoryColors[1].color,
categoryColors[2].color,
],
},
marks: [
Plot.gridX({ ariaHidden: true }),
Plot.dot(
monthlyRevenuesPerCategory.filter((d) =>
obtenirAnysFiltre().includes(d.year)
),
{
x: "date",
y: "sumRevenue",
r: "sumRevenue",
fill: "grey",
ariaHidden: true,
}
),
Plot.line(
monthlyRevenuesPerCategory.filter((d) =>
obtenirAnysFiltre().includes(d.year)
),
{
x: "date",
y: "sumRevenue",
z: "category",
ariaHidden: false,
stroke: "category",
opacity: 0.8,
strokeWidth: 5,
curve: "bump-x",
tip: {
fontSize: 20,
dy: -20,
format: {
y: (d) => `${d3.format(".1f")(d)}$`,
z: false,
x: (d) => `${d.toLocaleString("en-US", "numeric")}`,
},
},
}
),
Plot.ruleY([0], { ariaHidden: true }),
],
});
const plotMap = d3.select(plot);
let timeout,
focus = null;
const line = plotMap.selectAll("[aria-label*='line']").selectChildren();
plotMap
.on("pointerover", highlight)
.on("pointerout", restore)
.on("click", onLineClick)
.on("pointerdown", handlePointerDown)
.on("pointerup", handlePointerUp)
.style("cursor", "default");
const map = html`<div>
${plotMap.node()}
<div style="display:flex;justify-content:space-between">
<div
style="align-self:self-end;font-style:italic;font-size:9pt;text-align:end"
></div>
</div>
</div>`;
updateCategory(null);
return map;
function lookupCategory(index) {
return categoryMap[index].category;
}
function updateCategory(category) {
map.value = category;
map.dispatchEvent(new CustomEvent("input"));
}
}