ringObjHTML = (ring) => {
const {
cx,
cy,
r,
innerR,
padAngle = 1,
color = () => "red",
data,
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;
};
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))
)
.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));
}
)
.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("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)
? +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;
}