cl-react-graph
Version:
React D3 Charts
77 lines (72 loc) • 2.13 kB
text/typescript
const ns = "http://www.w3.org/2000/svg";
const makeSvgNode = (name: "text" | "tspan" | "svg", doc: Document) =>
doc.createElementNS(ns, name);
const makeTextSpanNode = (text: string, dy: string, doc: Document) => {
const node = doc.createTextNode(text);
const span = makeSvgNode("tspan", doc);
span.setAttribute("x", "0");
span.setAttribute("y", "0");
span.setAttribute("dy", dy);
span.appendChild(node);
return span;
};
const makeTextNode = (
texts: string[],
attrs: Record<string, any> = {},
doc: Document,
) => {
const node = makeSvgNode("text", doc);
node.setAttribute("x", "0");
node.setAttribute("y", "0");
for (let attr in attrs) {
node.setAttribute(attr, attrs[attr]);
}
texts.forEach((t, i) => node.appendChild(makeTextSpanNode(t, `${i}em`, doc)));
return node;
};
// Takes a string, or array of strings, some svg attrs, and gives you back a
// {width, height} of the resulting svg box containing the strings.
const svgTextSize = (
texts: string[] | string,
attrs: Record<string, any>,
doc = document,
) => {
if (typeof window === "undefined") {
return { width: 0, height: 0 };
}
const textArr = Array.isArray(texts) ? texts : [texts];
const svg = makeSvgNode("svg", doc);
const textNode = makeTextNode(textArr, attrs, doc);
svg.appendChild(textNode);
doc.body.appendChild(svg);
const { width, height } = textNode.getBBox();
doc.body.removeChild(svg);
return { width, height };
};
export const svgTextWrap = (
text: string,
width: number,
attrs: Record<string, any>,
) => {
if (typeof window === "undefined") {
return [text];
}
const words = text.split(/\s+/);
const lines: string[] = [];
let currentLine: string[] = [];
words.forEach((word) => {
const newLine = [...currentLine, word];
const size = svgTextSize(newLine.join(" "), attrs, window.document);
if (size.width > width) {
lines.push(currentLine.join(" "));
currentLine = [word];
} else {
currentLine.push(word);
}
});
lines.push(currentLine.join(" "));
if (lines[0] === "") {
lines.shift();
}
return lines;
};