Unlisted
Edited
Aug 13, 2023
Paused
1 star
Insert cell
Insert cell
Insert cell
Insert cell
function curvedTextOriginal(
txt,
{
cPath,
showPath = false,
anchor = "middle",
fontSize = 10,
letterSpacing = 1,
wordSpacing = 1
} = {}
) {
const smooth = d3.line().curve(d3.curveCatmullRom);
return (_, { x, y }) => {
const pathData = smooth(cPath.map(([px, py]) => [x(px), y(py)]));

// We could calculate the path and text lengths by creating tempory
// addtions to the DOM. Path lengths are identical in both browsers
// but the text length is not.
/*
const svgNamespace = "http://www.w3.org/2000/svg";
const tempSvg = document.createElementNS(svgNamespace, "svg");
const tempPath = document.createElementNS(svgNamespace, "path");
tempPath.setAttribute("d", pathData);
tempSvg.appendChild(tempPath);
const tempText = document.createElementNS(svgNamespace, "text");
tempText.textContent = txt;
tempText.style.fontSize = `${fontSize}px`;
tempText.style.letterSpacing = `${letterSpacing}px`;
tempText.style.wordSpacing = `${wordSpacing}px`;
tempSvg.appendChild(tempText);
document.body.appendChild(tempSvg);
const pathLength = tempPath.getTotalLength();
const textLength = tempText.getComputedTextLength();
document.body.removeChild(tempSvg);
console.log("Lengths", pathLength, textLength);
*/
return htl.svg`
<path
id="curve"
fill="transparent"
stroke=${showPath ? "red" : "invisible"}
stroke-width=2
stroke-dasharray="8,4"
d="${pathData}" />
<text>
<textPath
startOffset="${
anchor === "start" ? "0%" : anchor === "end" ? "100%" : "50%"
}"
text-anchor="${anchor}"
font-size=${fontSize}
word-spacing=${wordSpacing}
letter-spacing=${letterSpacing}
xlink:href="#curve">
${txt}
</textPath>
</text>`;
};
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Plot.plot({
width: 640,
height: 300,
x: { domain: [0, 640], grid: true, tickSpacing: 50 },
y: { domain: [0, 300], grid: true, tickSpacing: 50 },
marks: [
curvedText("This is some text that should curve along a path", {
cPath: curves[opt.cType],
showPath: opt.showPath,
anchor: opt.anchor,
fontSize: opt.fontSize,
letterSpacing: opt.letterSpacing,
wordSpacing: opt.wordSpacing
})
]
})
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