chart = {
const scale = 1.03;
const scaleWord = 1.8;
const sw = 0.4;
const so = 0.95;
const k = 2;
const myColor = blackWhite
? (d) => (darkMode ? "white" : "black")
: colorFunc(colorNumber, colorRotation, colorSeed, darkenFactor);
const width = 1500;
const margin = 80;
const height = width;
const cx = width * 0.5;
const cy = height * 0.5;
const radius = Math.min(width, height) / 2 - 137;
links.forEach((d) => {
if (d.title == "Akusala-sādhārana-cetasika")
d.title = "Akusala-sādhārana-c.";
if (d.title == "Vutthāna-gāminī-vipassanā") d.title = "Vutthāna-gāminī-v.";
});
const tree = d3
.cluster()
.size([2 * Math.PI, radius])
.separation((a, b) => {
const depth2Ancestor = a
.ancestors()
.find((ancestor) => ancestor.depth === 2);
const depth3Ancestor = a
.ancestors()
.find((ancestor) => ancestor.depth === 3);
const bDepth2Ancestor = b
.ancestors()
.find((ancestor) => ancestor.depth === 2);
const bDepth3Ancestor = b
.ancestors()
.find((ancestor) => ancestor.depth === 3);
// If both have a common ancestor at depth 3
if (depth3Ancestor && depth3Ancestor === bDepth3Ancestor) {
return 0.52; // Moderate separation for shared depth 3 ancestor
}
// If both have a common ancestor at depth 2
if (depth2Ancestor && depth2Ancestor === bDepth2Ancestor) {
return 0.7; // Larger separation for shared depth 2 ancestor
}
// Default separation for other cases
return 1;
});
// Sort the tree and apply the layout.
const root = tree(hierarchie);
root.leaves().forEach((leaf) => {
leaf.outgoing = [];
leaf.incoming = [];
const link = links.find((node) => node.file === leaf.data.name);
if (link) {
link.links.forEach((targetLink) => {
const targetNode = root.find((d) => d.data.name === targetLink.file);
if (targetNode) {
leaf.outgoing.push([leaf, targetNode]);
console.log(targetNode);
}
});
}
links.forEach((node) => {
node.links.forEach((link) => {
if (link.file === leaf.data.name) leaf.incoming.push([node, leaf]);
});
});
leaf.degree = leaf.incoming.length + leaf.outgoing.length;
});
console.log(root);
// Creates the SVG container.
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [
-cx * scale - margin / 2,
-cy * scale - margin / 2,
width * scale + margin,
height * scale + margin
])
.attr("style", "width: 100%; height: auto; font: 10px sans-serif;");
// if (darkMode)
svg
.append("rect")
.attr("x", -width / 2 - margin)
.attr("y", -height / 2 - margin)
.attr("width", width + 2 * margin)
.attr("height", height + 2 * margin)
.attr("fill", darkMode ? "black" : "white");
// Append links.
if (structure)
svg
.append("g")
.attr("fill", "none")
.attr("stroke", "#555")
.attr("stroke-opacity", 0.4)
.attr("stroke-width", 1.5)
.selectAll()
.data(root.links())
.join("path")
.attr(
"d",
d3
.linkRadial()
.angle((d) => d.x)
.radius((d) => d.y)
)
.attr("stroke", (d) =>
myColor(
d.target.ancestors().find((ancestor) => ancestor.depth == colorDepth)
)
);
// Append nodes.
svg
.append("g")
.selectAll()
.data(root.leaves())
.join("circle")
.attr(
"transform",
(d) => `rotate(${(d.x * 180) / Math.PI - 90}) translate(${d.y},0)`
)
.attr("fill", (d) => (d.children ? "#555" : "#999"))
.attr("r", (d) => 1 + 0.05 * d.degree)
.attr("fill", (d) => {
const col = myColor(
d.ancestors().find((ancestor) => ancestor.depth == colorDepth)
);
return d.children ? col : darkMode ? darken(col, 0.8) : lighten(col, 0);
// return d.children ? col : darkMode ? darken(col, 0.8) : lighten(col, 0.8);
});
// Append labels.
svg
.append("g")
.attr("stroke-linejoin", "round")
.attr("stroke-width", 3)
.selectAll()
.data(root.leaves())
.join("text")
.attr(
"transform",
(d) =>
`rotate(${(d.x * 180) / Math.PI - 90}) translate(${d.y},0) rotate(${
d.x >= Math.PI ? 180 : 0
})`
)
.attr("dy", "0.31em")
.attr("x", (d) =>
d.x < Math.PI === !d.children ? 6 * scaleWord : -6 * scaleWord
)
.attr("text-anchor", (d) =>
d.x < Math.PI === !d.children ? "start" : "end"
)
// .attr("font-size", (d) => 9.5) // 9.5 + 0.05 * d.degree)
.attr("font-size", (d) => 9.5 + 0.05 * d.degree)
.attr("font-size", (d) =>
d.data.name == "bodhipakkhiya_dh.htm" ? 10 : 9.5 + 0.1 * d.degree
)
.attr("paint-order", "stroke")
.attr("stroke", darkMode ? "black" : "white")
.attr("fill", "currentColor")
.attr("fill", (d) => {
const col = myColor(
d.ancestors().find((ancestor) => ancestor.depth == colorDepth)
);
return darkMode ? lighten(col, 0.4) : col;
})
.text((d) =>
d.height == 0
? links.find((node) => node.file == d.data.name).title
: d.depth
);
if (edge)
svg
.append("g")
.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", "normal")
.style("mix-blend-mode", darkMode ? "normal" : "multiply")
.style("opacity", so)
.attr("d", ([i, o]) => line(i.path(o)))
.each(function (d) {
d.path = this;
})
.attr("stroke", (d) =>
lighten(
myColor(
d[1].ancestors().find((ancestor) => ancestor.depth == colorDepth)
),
LighenFactor
)
);
const g = svg.append("g");
const drawRingAround = (
level = 2,
radiusCat = 1000,
catRadius = 50,
fontSize = 10,
offAngle = 0,
withText = false,
withEdges = true,
cornerRadius = 5,
arrayName,
arrayTopAdjust,
arrayBottomAdjust
) => {
let leaves = root.leaves();
let currentCategory = leaves[0]
.ancestors()
.find((ancestor) => ancestor.depth == level).data.name;
console.log(currentCategory);
let currentColor = myColor(
leaves[0].ancestors().find((ancestor) => ancestor.depth == colorDepth)
);
let currentFirstX = leaves[0].x;
let currentLastX = leaves[0].x;
let catArray = [];
for (let i = 1; i < leaves.length; i++) {
if (
leaves[i].ancestors().find((ancestor) => ancestor.depth == level).data
.name !== currentCategory
) {
catArray.push({
color: currentColor,
name: currentCategory,
start: currentFirstX,
end: currentLastX
});
currentColor = myColor(
leaves[i].ancestors().find((ancestor) => ancestor.depth == colorDepth)
);
currentCategory = leaves[i]
.ancestors()
.find((ancestor) => ancestor.depth == level).data.name;
currentFirstX = leaves[i].x;
}
currentLastX = leaves[i].x;
}
catArray.push({
color: currentColor,
name: currentCategory,
start: currentFirstX,
end: currentLastX
});
const catData = catArray.map((d, i) => {
return {
color: d.color,
text: withText ? arrayName[i] : "", //d.name,
startAngle: (d.start / Math.PI) * 180,
endAngle: (d.end / Math.PI) * 180,
topAdjust: arrayTopAdjust && arrayTopAdjust[i],
bottomAdjust: arrayBottomAdjust && arrayBottomAdjust[i]
};
});
drawRing(g, {
fontSize: fontSize,
r: radiusCat,
innerR: catRadius,
opacity: 0,
padAngle: 0,
endsPadAngle: -offAngle,
opaque: false,
//radial: true,
cornerRadius: cornerRadius,
data: catData,
strokeWidth: withEdges ? undefined : 0
});
};
drawRing(g, {
fontSize: 20,
r: 778,
innerR: 20,
opacity: 0,
opaque: false,
strokeWidth: 0,
color: darkMode
? d3.color("steelblue").brighter(0.5)
: d3.color("steelblue").darker(1),
data: [
{
text: " BUDDHIST DICTIONARY: A MANUAL OF BUDDHIST TERMS AND DOCTRINES",
// text: "THE ILLUSTRATED MANUAL OF BUDDHIST TERMS AND DOCTRINES",
//"The Illustrated Manual of Buddhist Terms and Doctrines",
// Buddhist Dictionary: A Manual of Buddhist Terms and Doctrines By Nyanatiloka Thera
// BUDDHIST DICTIONARY: A MANUAL OF BUDDHIST TERMS AND DOCTRINES
startAngle: -90,
endAngle: 90,
letterSpacing: 5
}
]
});
drawRing(g, {
fontSize: 20,
r: 778,
innerR: 20,
opacity: 0,
opaque: false,
strokeWidth: 0,
color: darkMode
? d3.color("steelblue").brighter(0.5)
: d3.color("steelblue").darker(1),
data: [
{
text: "By Nyanatiloka Thera",
// text: "THE ILLUSTRATED MANUAL OF BUDDHIST TERMS AND DOCTRINES",
//"The Illustrated Manual of Buddhist Terms and Doctrines",
// Buddhist Dictionary: A Manual of Buddhist Terms and Doctrines By Nyanatiloka Thera
// BUDDHIST DICTIONARY: A MANUAL OF BUDDHIST TERMS AND DOCTRINES
startAngle: 90,
endAngle: 270,
letterSpacing: 2
}
]
});
drawRingAround(2, 618, 150, 10, 0.9, false, true, undefined);
drawRingAround(
2,
743,
30,
12,
0.9,
true,
false,
undefined,
paliCategories,
paliCategoriesAdjustTop,
paliCategoriesAdjustBottom
);
drawRingAround(3, 621, 125, 10, 0.6, false, true, 3);
drawRingAround(
3,
724,
30,
8,
0.7,
true,
false,
3,
categories,
categoriesAdjustTop,
categoriesAdjustBottom
);
////////////////////////////////////////////////////// Start of License ///////////////////////////////////////////////
const fontName = "Poppins";
GFontToDataURI(
"https://fonts.googleapis.com/css2?family=Poppins&display=swap"
)
.then((cssRules) => {
let fontRules = cssRules.join("\n");
d3.select("svg")
.append("defs")
.append("style")
.attr("type", "text/css")
.text(fontRules);
console.log("Added Font");
})
.catch((reason) => console.log(reason));
// svg
// .append("svg:image")
// .attr("x", xLicense - 55)
// .attr("y", yLicense - 43)
// .attr("width", 55)
// // .attr("height", 31)
// .attr(
// "xlink:href",
// // "https://mirrors.creativecommons.org/presskit/buttons/88x31/svg/cc-zero.svg"
// "https://mirrors.creativecommons.org/presskit/buttons/88x31/svg/by-nc.svg"
// // await FileAttachment("88x31-1.png").url()
// )
// .attr("opacity", 0.75);
svg
.append("g")
.attr("transform", ` translate(${790 - 70}, ${790 - 46}) scale(0.8)`)
//.attr("fill", "#828282")
.attr("opacity", 0.75)
.html(logo);
const text = svg
.append("text")
.attr("x", 790)
.attr("y", 790)
.style("font-weight", "bold")
.style("fill", "#828282")
.attr("font-family", fontName)
.attr("font-size", 9)
.text("DhammaCharts.org")
.attr("text-anchor", "end")
.attr("dy", "-1.1em")
.clone(true)
.text("PaliKanon.com")
.attr("dy", "0.25em");
////////////////////////////////////////////////////// End of License ///////////////////////////////////////////////
return svg.node();
}