Public
Edited
Aug 13, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof colorCessation = Inputs.color({ label: "Cessation", value: "#4e6073" })
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
FileAttachment("88x31-1.png").image()
Insert cell
Insert cell
ww = 50
Insert cell
qq = -2
Insert cell
ff = 18
Insert cell
fo = 0.8
Insert cell
fillOpacity = 1
Insert cell
darkenFactor = 1
Insert cell
darkenFactor8Fold = 1.2
Insert cell
viewof darkK = Inputs.range([0, 5], { label: "dark", value: 1.3 })
Insert cell
viewof limit = Inputs.range([0, 100], { label: "limit", value: 5 })
Insert cell
Insert cell
dataRingFormless = [
{
text: "Infinit Space",
class: "Jhana",
startAngle: 0,
endAngle: (360 / 4) * 1,
fontSize: font5 - 1,
letterSpace: 0,
fill: 18,
fill: 18,
fillOpacity: 0.3
},
{
text: "Infinit Consciousness",
class: "Jhana",
startAngle: (360 / 4) * 1,
endAngle: (360 / 4) * 2,
fontSize: font5 - 1,
letterSpace: 0,
fill: 18,
fillOpacity: 0.3,
fill: 18,
fillOpacity: 0.3
},
{
text: "Nothingness",
class: "Jhana",
startAngle: (360 / 4) * 2,
endAngle: (360 / 4) * 3,
fontSize: font5 - 1,
letterSpace: 0,
fill: 18,
fillOpacity: 0.3,
fill: 18,
fillOpacity: 0.3
},
{
text: "Neither Perception \nnor Non-Perception",
class: "Jhana",
startAngle: (360 / 4) * 3,
endAngle: (360 / 4) * 4,
fontSize: font5 - 2,
letterSpace: 0,
fill: 18,
fillOpacity: 0.3,
fill: 18,
fillOpacity: 0.3
}
]
Insert cell
chartSati = {
const svg = d3
.create("svg")
.attr("viewBox", [-width / 2, -width / 2, width, width]);

GFontToDataURI(
"https://fonts.googleapis.com/css2?family=Cormorant SC&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("defs")
// .append("style")
// .attr("type", "text/css")
// .html(
// '@import url("https://fonts.googleapis.com/css2?family=Cormorant SC&display=swap");'
// );

const text = svg
.append("text")
.style("font-weight", "bold")
.style("fill", color0)
.attr("font-family", fontName)
.attr("font-size", 22)
.attr("text-anchor", "middle")
.text("Nibbāna")
.attr("dy", "0.35em");

// see https://jarrettmeyer.com/2018/06/05/svg-multiline-text-with-tspan

const ringCessation = {
cx: 0,
cy: 0,
r: 52,
innerR: 48 + qq - 6 - 7,
padAngle: 0,
color: () => colorCessation,
strokeWidth: strokeW,
bold: true,
data: dataRingCessation,
fontName: fontName
};
svg.append("g").html(ringObjHTML(ringCessation));

const ringFormless = {
cx: 0,
cy: 0,
r: 40 + ww + 3,
innerR: 48 + qq - 7,
padAngle: 3,
color: () => colorCessation,
strokeWidth: strokeW,
bold: true,
data: dataRingFormless,
fontName: fontName
};
svg.append("g").html(ringObjHTML(ringFormless));

const ringF = {
cx: 0,
cy: 0,
r: 370 + ww,
innerR: 48,
padAngle: 0.8,
color: color37,
strokeWidth: strokeW,
bold: true,
data: dataRingF,
fontName: fontName
};
svg.append("g").html(ringObjHTML(ringF));

const ring0 = {
cx: 0,
cy: 0,
r: 315 + ww,
innerR: 48 + qq,
padAngle: 0.9,
color: color37,
strokeWidth: strokeW,
bold: true,
data: dataRing0,
fontName: fontName
};
svg.append("g").html(ringObjHTML(ring0));

const ring1 = {
cx: 0,
cy: 0,
r: 260 + ww,
innerR: 48 + qq,
padAngle: 1.1,
color: color37,
strokeWidth: strokeW,
bold: true,
data: dataRing1,
fontName: fontName
};
svg.append("g").html(ringObjHTML(ring1));

const ring2 = {
cx: 0,
cy: 0,
r: 205 + ww,
innerR: 48 + qq,
padAngle: 1.3,
color: color37,
strokeWidth: strokeW,
bold: true,
data: dataRing2,
fontName: fontName
};

svg.append("g").html(ringObjHTML(ring2));

const ring3 = {
cx: 0,
cy: 0,
r: 150 + ww,
innerR: 48 + qq,
padAngle: 1.6,
color: color37,
strokeWidth: strokeW,
bold: true,
data: dataRing3,
fontName: fontName
};

svg.append("g").html(ringObjHTML(ring3));

const ring4 = {
cx: 0,
cy: 0,
r: 95 + ww,
innerR: 48 + qq,
padAngle: 2.1,
color: color37,
strokeWidth: strokeW,
bold: true,
data: dataRing4,
fontName: fontName
};

svg.append("g").html(ringObjHTML(ring4));

return svg.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
colorCessation
Insert cell
// Function that create a HTML layer arc of multile labels with options.
// data contains the angles, text, font-size & letter-spacing...

ringObjHTML = (ring) => {
const {
cx,
cy,
r,
innerR,
padAngle = 1,
color = () => "red",
data, // contains : d.startAngle d.endAngle d.text d.fontSize=12 d.letterSpace=1 d.textOffAngle
// d.uid (d.index?) is created in this function
strokeWidth = 2, //
bold = true,
fontName,
fontSize = 12,
fill = 0
} = ring;

const fade = (color, f) => {
const { l, c, h } = d3.lch(color);

return d3.lch(l + f, c, h);
};
const dark = (color, f) => {
const { l, c, h } = d3.lch(color);

return d3.lch(l - f, c, h);
};

const haveClass = (d) => (d.class ? d.class : d.uid);
const dFlipLetters = (d) =>
d.flipLetters != undefined ? d.flipLetters : false;
const dStrokeWidth = (d) =>
d.strokeWidth != undefined ? d.strokeWidth : strokeWidth;
const dFill = (d) => (d.fill != undefined ? d.fill : fill);
const dFillOpacity = (d) =>
d.fillOpacity != undefined ? d.fillOpacity : fillOpacity;
const dDarkenFactor = (d) =>
d.darkenFactor != undefined ? d.darkenFactor : darkenFactor;
const dBottomAjust = (d) => (d.bottomAjust != undefined ? d.bottomAjust : 0);
const dTopAjust = (d) => (d.topAjust != undefined ? d.topAjust : 0);
const halfPI = Math.PI / 2;
const svg = d3.create("svg");
const arc = d3
.arc()
.innerRadius(r)
.outerRadius(r + innerR)
.padAngle((Math.PI / 180) * padAngle)
.startAngle((d) => (Math.PI / 180) * d.startAngle)
.endAngle((d) => (Math.PI / 180) * d.endAngle);
const atBottom = (d) => {
const middle =
((Math.PI / 180) * d.startAngle -
halfPI +
(Math.PI / 180) * d.endAngle -
halfPI) /
2;
const bottom = middle >= 0 && middle < Math.PI;
return bottom ^ d.flipLetters; // XOR
};
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,
(Math.PI / 180) * d.endAngle - halfPI,
(Math.PI / 180) * d.startAngle - halfPI,
true
);
} else {
context.arc(
0,
0,
r,
(Math.PI / 180) * d.startAngle - halfPI,
(Math.PI / 180) * d.endAngle - halfPI,
false
);
}
return context.toString();
});
g.append("path")
.style(
"stroke",
(d) => color(haveClass(d))
// dStrokeWidth(d) == 0 ? null : color(haveClass(d))
)
// .style("stroke-width", strokeWidth)
.style("stroke-width", (d) => dStrokeWidth(d))
.style(
"fill",
(d) => {
console.log(
dFill(d),
d3.rgb(color(haveClass(d))),
fade(color(haveClass(d)))
);
console.log("---");
return dFill(d) == 0
? "transparent"
: fade(color(haveClass(d)), dFill(d));
}
// dFill(d) == 0 ? "transparent" : fade(color(haveClass(d)), dFill(d))
// strokeWidth != 0 ? "transparent" : (d) => color(haveClass(d))
)
// .style("fill-opacity", (d) => dFill(d))
// .style("stroke-opacity", (d) => (dFill(d) != 0 ? 0 : 1))
.style("fill-opacity", (d) => dFillOpacity(d))
.attr("d", (d) => arc(d));
g.append("text")
.style("fill", (d) =>
dFill(d) > limit || dFillOpacity < 0.5
? dark(color(haveClass(d)), dFill(d) * darkK * dDarkenFactor(d))
: "white"
)
// .style("fill", (d) =>
// dFill(d) > limit ? dark(color(haveClass(d)), dFill(d) * darkK) : "white"
// )
// .style("fill", strokeWidth != 0 ? (d) => color(haveClass(d)) : "white")
.style("font-size", (d) => (d.fontSize ? d.fontSize : fontSize))
.style("font-weight", bold ? "bold" : "normal")
// .attr("dy", (d) => (innerR / 2) * (atBottom(d) ? +1 : -0.9))
.attr("font-family", fontName)
.attr("dy", (d) => (innerR / 2) * (atBottom(d) ? +1 : -0.9))
.attr("dominant-baseline", "middle")
.attr("text-anchor", "middle")
.append("textPath")
.attr("startOffset", "50%")
// .attr("startOffset", (d) =>
// d.textOffAngle ? 50 + d.textOffAngle + "%" : "50%"
// )
.attr("xlink:href", (d) => d.uid.href)
.text((d) => {
let rawText = d.text;
if (!rawText.includes("\n")) {
return d.letterSpace
? rawText.split("").join("\u200A".repeat(d.letterSpace))
: rawText;
}
})
.select(function () {
return this.parentNode;
})
// In case of \n in text
.clone()
.attr(
"dy",
(d) =>
(innerR / 2) *
(atBottom(d)
? +1 + 0.45 + dBottomAjust(d)
: -0.9 - 0.45 + dTopAjust(d))
)
.append("textPath")
.attr("startOffset", "50%")
.attr("xlink:href", (d) => d.uid.href)
.text((d) => {
let rawText = d.text;
if (rawText.includes("\n")) {
let arrText = rawText.split("\n");
return d.letterSpace
? arrText[0].split("").join("\u200A".repeat(d.letterSpace))
: arrText[0];
}
})
.select(function () {
return this.parentNode;
})
.clone()
.attr(
"dy",
(d) =>
(innerR / 2) *
(atBottom(d)
? +1.5 - 0.45 + dTopAjust(d)
: -0.9 + 0.3 + dBottomAjust(d))
)
.append("textPath")
.attr("startOffset", "50%")
.attr("xlink:href", (d) => d.uid.href)
.text((d) => {
let rawText = d.text;
if (rawText.includes("\n")) {
let arrText = rawText.split("\n");
return d.letterSpace
? arrText[1].split("").join("\u200A".repeat(d.letterSpace))
: arrText[1];
}
});
};
data.forEach((d) => (d.uid = DOM.uid("p-" + d.index)));

svg.selectAll("g.arcLabel").data(data).join(enter);
return svg.node().innerHTML;
}
Insert cell
function capitalizeTheFirstLetterOfEachWord(words) {
var separateWord = words.toLowerCase().split(" ");
for (var i = 0; i < separateWord.length; i++) {
separateWord[i] =
separateWord[i].charAt(0).toUpperCase() + separateWord[i].substring(1);
}
return separateWord.join(" ");
}
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