Public
Edited
Nov 15, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
const root = tree(d3.hierarchy(data));

const offSet = 0;
const off = 38;
const rotRad = (rot * Math.PI) / 180;

const svg = d3.create("svg");

Object.defineProperty(Array.prototype, "first", {
value() {
return this.find(Boolean);
},
configurable: true
});

root.each((d) => (d.x += rotRad));
root.each((d) => (d.x %= 2 * Math.PI));
// root.each((d) => console.log(d.x));
console.log(root);
root.x = label ? Math.PI / 2 : (rootAngle * Math.PI) / 180;
root.y = label ? -10 : -RootOffSet;
if (label) root.children[3].y = 150;
root.children[4].y = RootOffSetP;

svg
.append("g")
.attr("fill", "none")
.attr("stroke", "#555")
.attr("stroke-opacity", 0.4)
.attr("stroke-width", 1.5) // 1.5 for B&W 1.75 good too
.selectAll("path")
.data(root.links())
.join("path")
.attr("stroke", (d) => getBackgroundColor(d.target.data.class, seed))
.attr(
"d",
d3
.linkRadial()
.angle((d) => d.x)
.radius((d) => d.y)
);

svg
.append("g")
.selectAll("circle")
.data(root.descendants())
.join("circle")
.attr(
"transform",
(d) => `
rotate(${(d.x * 180) / Math.PI - 90})
translate(${d.y},0)
`
)
.attr("fill", (d) => (d.children ? "#555" : "#999"))
.attr("fill", (d) =>
d.children
? getBackgroundColor(d.data.class, seed)
: getBackgroundColorFaded(d.data.class, seed)
)
.attr("r", (d) => {
if (d.depth == 0) {
return 1.75;
} // 11 or 12
else if (d.depth == 1) {
return 1.75;
} // 10 or 11
else if (d.height == 0) {
return 1.75;
} else if (d.depth == 2) {
return 1.75;
}
});

svg
.append("g")
.attr("font-family", "sans-serif")
// .attr("font-size", 9)
.attr("stroke-linejoin", "round")
.attr("stroke-width", 3)
.selectAll("text")
.data(root.descendants())
.join("text")
.attr("font-size", (d) => {
if (d.depth == 0) {
return 15;
} // 11 or 12
else if (d.depth == 1) {
return 11;
} // 10 or 11
else if (d.height == 0) {
return 10;
} else if (d.depth == 2) {
return 11;
}
})
.attr("fill", (d) => getBackgroundColor(d.data.class, seed))
.attr(
"transform",
(d) => `
rotate(${(d.x * 180) / Math.PI - 90})
translate(${d.y},0)
rotate(${d.x >= Math.PI - offSet ? 180 : 0})
`
)
.attr("dy", "0.31em")
// .attr("x", (d) => (d.x < Math.PI - offSet === !d.children ? 9 : -9))

.attr("x", (d) => {
if (d.depth == 0) {
return d.x < Math.PI - offSet === !d.children ? 8 : -8;
} // 11 or 12
else if (d.depth == 1) {
return d.x < Math.PI - offSet === !d.children ? 8 : -8;
} // 10 or 11
else if (d.height == 0) {
return d.x < Math.PI - offSet === !d.children ? 9 : -9;
} else if (d.depth == 2) {
return d.x < Math.PI - offSet === !d.children ? 8 : -8;
}
})
.attr("text-anchor", (d) =>
d.x < Math.PI - offSet === !d.children ? "start" : "end"
)
.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 label ? d.data.name : ""; //d.data.name;
} 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 label ? d.data.name : ""; //d.data.name;
}
})
.clone(true)
.lower()
.attr("stroke", "white");
// .clone(true)
// .attr("stroke-width", 0)
// .attr("x", (d) => (d.x < Math.PI - offSet === !d.children ? off : -off))
// .text((d) => {
// if (!d.children)
// return d.x > Math.PI - offSet
// ? d.data.name + " : "
// : " : " + d.data.name;
// });

////////////////////////////////////////////////////// Start of License ///////////////////////////////////////////////

if (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);

const text = svg
.append("text")
.attr("x", xLicense)
.attr("y", yLicense)
.style("font-weight", "bold")
.style("fill", "#828282")
.attr("font-family", fontName)
.attr("font-size", fLicense)
.text("DhammaCharts.org")
.attr("text-anchor", "end")
.attr("dy", "-1.1em")
.clone(true)
.text("For free distribution only")
.attr("dy", "0.25em");
// .clone(true)
// .text("No Right reserved")
// .attr("dy", "1.6em");
}

if (licenseNoLogo) {
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));

const text = svg
.append("text")
.attr("x", xLicense)
.attr("y", yLicense)
.style("font-weight", "bold")
.style("fill", "#828282")
.attr("font-family", fontName)
.attr("font-size", fLicense)
.text("CC-BY-NC")
.attr("text-anchor", "end")
.attr("dy", "-2.45em")
.clone(true)
.text("DhammaCharts.org")
.attr("dy", "-1.1em")
.clone(true)
.text("For free distribution only")
.attr("dy", "0.25em");
}

////////////////////////////////////////////////////// End of License ///////////////////////////////////////////////

return svg.attr("viewBox", autoBox).node();
}
Insert cell
Insert cell
Insert cell
yLicense = 680
Insert cell
xLicense = 720
Insert cell
fLicense = 10
Insert cell
import { GFontToDataURI } from "@7722371e7ecac8bd/suttapitaka"
Insert cell
Insert cell
Insert cell
data = {
let root = { name: "Bhikkhu Pāṭimokkha", parentId: null, class: "root" };
const tree = [];
tree.push(root);
const classOff = [];
let chapter = [];
const num = [];
const content = [];
const chapterTest = [];

csvData.forEach((d) => {
d.content = toTitleCase(d.content);
d.gravity = +d.gravity;
// d.related = d3.csvParse(d.related); // this code is for another chart that include relation between rules
// d.related = d.related.columns;
// forEach dosen't work below
// for (var i = 0, len = d.related.length; i < len; i++) {
// d.related[i] = d.related[i].trim();
// }

// class
if (!classOff.includes(d.class)) classOff.push(d.class);
// chapter
d.chapter = d.chapter.replace("The", "");
d.chapter = d.chapter.replace(" Chapter", "");
if (!chapter.includes(d.chapter) && d.chapter != "") {
const pushed = [];
pushed[d.chapter] = d.class;
if (!chapterTest.includes(d.chapter)) {
chapterTest.push(d.chapter);
chapter.push(pushed);
}
}
// num + content
if (!num.includes(d.num) && d.chapter != "") {
const pushed = [];
pushed[d.content] = d.chapter;
pushed[d.content + "Num"] = d.num;
pushed[d.centent + "class"] = d.class;
num.push(pushed);
}
if (!num.includes(d.num) && d.chapter == "") {
const pushed = [];
pushed[d.content] = d.class;
pushed[d.content + "Num"] = d.num;
pushed[d.centent + "class"] = d.class;
num.push(pushed);
}
});

// pushing everything into the tree
// class
for (var i = 0, len = classOff.length; i < len; i++) {
const pushed = {};
pushed.name = classOff[i];
pushed.parentId = Object.values(root)[0];
pushed.class = classOff[i];
tree.push(pushed);
}
// chapter
for (var i = 0, len = chapter.length; i < len; i++) {
const pushed = {};
pushed.name = Object.keys(chapter[i])[0];
pushed.parentId = Object.values(chapter[i])[0];
pushed.class = Object.values(chapter[i])[0];
tree.push(pushed);
}
// num
for (var i = 0, len = num.length; i < len; i++) {
const pushed = {};
pushed.name = Object.keys(num[i])[0];
pushed.parentId = Object.values(num[i])[0];
pushed.num = Object.values(num[i])[1];
pushed.class = Object.values(num[i])[2];
tree.push(pushed);
}

// from https://typeofnan.dev/an-easy-way-to-build-a-tree-with-object-references/
const idMapping = tree.reduce((acc, el, i) => {
acc[el.name] = i;
return acc;
}, {});
tree.forEach((el) => {
if (el.parentId === null) {
root = el;
return;
}
// Use our mapping to locate the parent element in our data array
const parentEl = tree[idMapping[el.parentId]];
// Add our current el to its parent's `children` array
parentEl.children = [...(parentEl.children || []), el];
});
return tree[0];
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
width = 975
Insert cell
radius = width / 2
Insert cell
tree = d3.cluster().size([2 * Math.PI, radius - 100])
Insert cell
d3 = require("d3@6")
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more