chart = {
const sw = 0.3;
const so = 1;
const cols = 6;
const offSet = 0;
const off = 38;
const strokeWidth = 2;
const ray = 55 + 22;
const ray2 = 100 + 22;
const ray3 = 22 + 22;
const offnumber = 22;
const offAngle = (Math.PI / 180) * 1.3;
const magic = (d) => d.data.cat;
const myColor = d3.scaleOrdinal(d3.quantize(d3.interpolateRainbow, cols));
function darken(color, k = 1) {
const { l, c, h } = d3.lch(color);
return d3.lch(l - 30 * k, c, h);
}
const root = tree(
rootWithIngoing.sort((a, b) => d3.ascending(a.data.subcat, b.data.subcat))
);
const svg = d3
.create("svg")
.attr("viewBox", [-width / 2, -width / 2, width, width]);
const node = svg
.append("g")
// .attr("font-family", "sans-serif")
.attr("font-size", 9.2)
// .attr("font-kerning", "none")
// .attr("font-variant-numeric", "tabular-nums")
.selectAll("g")
.data(root.leaves())
.join("g")
.attr(
"transform",
(d) => `rotate(${(d.x * 180) / Math.PI - 90}) translate(${d.y},0)`
)
.append("text")
.attr("dy", "0.31em")
.attr("x", (d) => (d.x < Math.PI ? 6 : -6 - offnumber))
.attr("text-anchor", (d) => (d.x < Math.PI ? "start" : "start"))
.attr("transform", (d) => (d.x >= Math.PI ? "rotate(180)" : null))
.style("fill", (d) => darken(myColor(magic(d))))
.text((d) => {
if (d.x < Math.PI - offSet) {
if (typeof d.data.num !== "undefined") {
if (d.data.num.length <= 4) {
var str = d.data.num;
var nameOnly = str.substring(0, str.length - 1);
var numOnly = str.substring(str.length - 1, str.length);
d.data.num = nameOnly + "\xa0\xa0" + numOnly;
}
return d.data.num;
} else return d.data.content;
} else {
if (typeof d.data.num !== "undefined") {
if (d.data.num.length <= 4) {
var str = d.data.num;
var nameOnly = str.substring(0, str.length - 1);
var numOnly = str.substring(str.length - 1, str.length);
d.data.num = nameOnly + "\xa0\xa0" + numOnly;
}
return d.data.num;
} else return d.data.content;
}
})
.clone(true)
.lower()
.attr("stroke", "white")
.clone(true)
.attr("stroke-width", 0)
// .attr("transform", (d) => `translate(${ray3},0)`) // .attr("transform", `translate(${ray3},0)`)
// .attr("dy", "0.31em")
.attr("text-anchor", (d) => (d.x < Math.PI ? "start" : "end"))
.attr("transform", (d) => (d.x >= Math.PI ? "rotate(180)" : null))
.attr("x", (d) =>
d.x < Math.PI - offSet === !d.children ? off + ray3 : -off - ray3
)
.style("fill", (d) => darken(myColor(magic(d))))
.text((d) => {
// return d.data.content + " (" + magic(d).slice(1) + ")";
return d.data.content;
});
// CONNECTIONS //
const line = d3
.lineRadial()
.curve(d3.curveBundle.beta(0.85))
.radius((d) => d.y)
.angle((d) => d.x);
const link = svg
.append("g")
// .attr("stroke", "red")
.attr("fill", "none")
.attr("stroke-width", sw)
.attr("stroke-opacity", so)
.selectAll("path")
.data(root.leaves().flatMap((leaf) => leaf.outgoing))
.join("path")
.style("mix-blend-mode", "multiply")
.style("opacity", so)
.attr("d", ([i, o]) => line(i.path(o)))
.attr("stroke", (d) => myColor(magic(d[inout])))
.each(function (d) {
d.path = this;
});
// svg
// .append("g")
// .attr("fill", "none")
// .selectAll("path")
// .data(
// d3.transpose(
// root
// .leaves()
// .filter((rule) => rule.outgoing)
// .flatMap((leaf) => leaf.outgoing.map(path))
// .map((path) => Array.from(path.split(k)))
// )
// )
// .join("path")
// .style("mix-blend-mode", "darken")
// .attr("stroke", (d, i) => color(d3.easeQuad(i / ((1 << k) - 1))))
// // .attr("stroke", (d, i) => {
// // // const magic = d.data.subcat != "" ? d.data.subcat : d.data.cat;
// // color(d3.easeQuad(i / (1 << k)));
// // })
// // .attr("stroke", (d, i) => color(i - 1))
// .attr("d", (d) => d.join(""));
// RING //
const halfPI = Math.PI / 2;
const cx = 0;
const cy = 0;
const r = radius - 100 + ray;
const arc = d3
.arc()
.innerRadius(r - 24)
.outerRadius(r);
// .padAngle(Math.PI / 180);
const atBottom = (d) => {
const middle = (d.startAngle - halfPI + d.endAngle - halfPI) / 2;
return middle >= 0 && middle < Math.PI;
};
const enter = (enter) => {
const g = enter
.append("g")
.attr("class", "arcLabel")
.attr("transform", `translate(${cx}, ${cy})`);
g.append("path")
.attr("id", (d) => d.uid.id)
.style("fill", "none")
.attr("d", (d) => {
const context = d3.path();
if (atBottom(d)) {
context.arc(
0,
0,
r,
d.endAngle - halfPI,
d.startAngle - halfPI,
true
);
} else {
context.arc(
0,
0,
r,
d.startAngle - halfPI,
d.endAngle - halfPI,
false
);
}
return context.toString();
});
g.append("path")
.style("fill", "grey")
.attr("d", (d) => arc(d));
g.append("text")
.style("fill", "white")
.style("font-size", 14)
.style("font-weight", "bold")
.attr("dy", (d) => 13 * (atBottom(d) ? -0.8 : 1.1))
.attr("dominant-baseline", "middle")
.attr("text-anchor", "middle")
.append("textPath")
.attr("startOffset", "50%")
.attr("xlink:href", (d) => d.uid.href)
.text((d) => d.data);
};
const myDataArc1 = myDataArc(offAngle);
myDataArc1.forEach((d) => (d.uid = DOM.uid("p-" + d.index)));
svg.selectAll("g.arcLabel").data(myDataArc1).join(enter);
///////////// subcat ///////////
return svg.node();
}