in src/core/prototypes/marks/textbox.ts [334:564]
public getGraphics(
cs: Graphics.CoordinateSystem,
offset: Point,
// eslint-disable-next-line
glyphIndex: number,
// eslint-disable-next-line
manager: ChartStateManager
): Graphics.Element {
const attrs = this.state.attributes;
const props = this.object.properties;
if (
!attrs.text ||
(!attrs.color && !attrs.outline) ||
!attrs.visible ||
attrs.opacity == 0
) {
return Graphics.makeGroup([]);
}
if (!attrs.backgroundColorFilterId) {
attrs.backgroundColorFilterId = `text-color-filter-${getRandomNumber()}`;
}
const metrics = Graphics.TextMeasurer.Measure(
attrs.text,
attrs.fontFamily,
attrs.fontSize
);
const helper = new Graphics.CoordinateSystemHelper(cs);
const cheight = (metrics.middle - metrics.ideographicBaseline) * 2;
let y = 0;
switch (props.alignY) {
case "start":
{
y = attrs.y1 - metrics.ideographicBaseline + props.paddingY;
}
break;
case "middle":
{
y = attrs.cy - cheight / 2 - metrics.ideographicBaseline;
}
break;
case "end":
{
y = attrs.y2 - cheight - metrics.ideographicBaseline - props.paddingY;
}
break;
}
let textElement: Graphics.Element;
const applyStyles = (
textElement: Graphics.TextOnPath,
attrs: TextboxElementAttributes
) => {
if (attrs.outline) {
if (attrs.color) {
const g = Graphics.makeGroup([
<Graphics.TextOnPath>{
...textElement,
style: {
strokeColor: attrs.outline,
},
},
<Graphics.TextOnPath>{
...textElement,
style: {
fillColor: attrs.color,
},
},
]);
g.style = { opacity: attrs.opacity };
return g;
} else {
return <Graphics.TextOnPath>{
...textElement,
style: {
strokeColor: attrs.outline,
opacity: attrs.opacity,
},
};
}
} else {
return <Graphics.TextOnPath>{
...textElement,
style: {
fillColor: attrs.color,
opacity: attrs.opacity,
},
};
}
};
const textContent = replaceNewLineBySymbol(attrs.text);
if (
(textContent && splitStringByNewLine(textContent).length > 1) ||
props.wordWrap
) {
const height = attrs.fontSize;
// set limit of lines depends of height bounding box
let maxLines = 1000;
// if option enabled and no space for rest of text, set limit of lines count
if (!props.overFlow) {
maxLines = Math.floor(Math.abs(attrs.y2 - attrs.y1) / height);
}
let textContentList = [textContent];
// auto wrap text content
if (props.wordWrap) {
textContentList = splitByWidth(
replaceSymbolByTab(replaceSymbolByNewLine(attrs.text)),
Math.abs(attrs.x2 - attrs.x1) - 10,
maxLines,
attrs.fontFamily,
attrs.fontSize
);
}
// add user input wrap
textContentList = textContentList.flatMap((line) =>
splitStringByNewLine(line)
);
const lines: Graphics.Element[] = [];
let textBoxShift = 0;
switch (props.alignY) {
case "start":
{
switch (props.alignText) {
case "start":
textBoxShift = -height;
break;
case "middle":
textBoxShift = (textContentList.length * height) / 2 - height;
break;
case "end":
textBoxShift = textContentList.length * height - height;
break;
}
}
break;
case "middle":
{
switch (props.alignText) {
case "start":
textBoxShift = -height / 2;
break;
case "middle":
textBoxShift =
(textContentList.length * height) / 2 - height / 2;
break;
case "end":
textBoxShift = textContentList.length * height - height / 2;
break;
}
}
break;
case "end":
{
switch (props.alignText) {
case "start":
textBoxShift = 0;
break;
case "middle":
textBoxShift = (textContentList.length * height) / 2;
break;
case "end":
textBoxShift = textContentList.length * height;
break;
}
}
break;
}
for (let index = 0; index < textContentList.length; index++) {
const pathMaker = new Graphics.PathMaker();
helper.lineTo(
pathMaker,
attrs.x1 + offset.x + props.paddingX,
y + offset.y + textBoxShift - height * index,
attrs.x2 + offset.x - props.paddingX,
y + offset.y + textBoxShift - height * index,
true
);
const cmds = pathMaker.path.cmds;
const textElement = applyStyles(
<Graphics.TextOnPath>{
key: index,
type: "text-on-path",
pathCmds: cmds,
text: textContentList[index],
fontFamily: attrs.fontFamily,
fontSize: attrs.fontSize,
align: props.alignX,
},
attrs
);
lines.push(textElement);
}
return Graphics.makeGroup(lines);
} else {
const pathMaker = new Graphics.PathMaker();
helper.lineTo(
pathMaker,
attrs.x1 + offset.x + props.paddingX,
y + offset.y,
attrs.x2 + offset.x - props.paddingX,
y + offset.y,
true
);
const cmds = pathMaker.path.cmds;
textElement = <Graphics.TextOnPath>{
type: "text-on-path",
pathCmds: cmds,
text: attrs.text,
fontFamily: attrs.fontFamily,
fontSize: attrs.fontSize,
align: props.alignX,
};
const background = <Graphics.Rect>{
type: "rect",
x1: attrs.x1 + offset.x,
y1: attrs.y1 + offset.y,
x2: attrs.x2 + offset.x,
y2: attrs.y2 + offset.y,
style: {
fillColor: attrs.backgroundColor,
},
};
return Graphics.makeGroup([
background,
applyStyles(<Graphics.TextOnPath>textElement, attrs),
]);
}
}