drawRing = (svgOrigin, ring) => {
const {
cx = 0,
cy = 0,
r = 100,
innerR = 20,
padAngle = 1,
color = "black",
data,
strokeWidth = 2,
fontSize = 12,
fontName = "Cormorant SC",
letterSpace = 0,
fillFade = 0,
fillFadeLimit = 60,
fillOpacity = 1,
fillOpacityLimit = 0.5,
bold = true,
darkenFactor = 0
} = ring;
const halfPI = Math.PI / 2;
const fade = (color, f) => {
const { l, c, h } = d3.lch(color);
return d3.lch(l + f, c, h);
};
const darken = (color, f) => {
const { l, c, h } = d3.lch(color);
return d3.lch(l - f, c, h);
};
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;
};
const dFlipLetters = (d) =>
d.flipLetters != undefined ? d.flipLetters : false;
const dColor = (d) => (d.color != undefined ? d.color : color);
const dStrokeWidth = (d) =>
d.strokeWidth != undefined ? d.strokeWidth : strokeWidth;
const dFillFade = (d) => (d.fillFade != undefined ? d.fillFade : fillFade);
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 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 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) => dColor(d))
.style("stroke-width", (d) => dStrokeWidth(d))
.style("fill", (d) => fade(dColor(d), dFillFade(d)))
.style("fill-opacity", (d) => dFillOpacity(d))
.attr("d", (d) => arc(d));
g.append("text")
.style("fill", (d) =>
dFillOpacity(d) < fillOpacityLimit || dFillFade(d) > fillFadeLimit
? darken(dColor(d), dFillOpacity(d) * dDarkenFactor(d))
: "white"
)
.style("font-size", (d) => (d.fontSize ? d.fontSize : fontSize))
.style("font-weight", bold ? "bold" : "normal")
.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("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;
})
.clone()
.attr(
"dy",
(d) =>
(innerR / 2) *
(atBottom(d) ? +0.7 + dBottomAjust(d) : -1.3 + 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 + dTopAjust(d) : -0.55 + 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);
const svgRing = svg.node().innerHTML;
svgOrigin.append("g").html(svgRing);
}