我有一个svg rect和一个使用React创建的svg文本。文本可以是短的也可以是很长的,如果宽度大于阈值,我想简单地用省略号修饰文本。
我知道对此有很多疑问(例如this one),但我仍无法解决问题。
这是我的代码:
Band Names That Are Ridiculously Long
这是结果:
您可以看到Band Names That Are Ridiculously...
太长,所以我想要类似export class Labels extends React.Component<Props> {
textRef = React.createRef<SVGTextElement>()
/**
* Places textString in textObj and adds an ellipsis (...) if text can't fit in width.
* TODO: type of textObject (RefObject<SVGTextElement> doesn't work)
*/
placeTextWithEllipsis(textObj: any, textString: string, width: number) {
console.log('textObj: ', textObj) // null :()
textObj.textContent = textString
if (textObj.getSubStringLength(0, textString.length) >= width) {
for (let x = textString.length - 3; x > 0; x -= 3) {
if (textObj.getSubStringLength(0, x) <= width) {
textObj.textContent = textString.substring(0, x) + '...'
return
}
}
textObj.textContent = '...' // can't place at all
}
}
render() {
const { rectWidth, labelRectHeight, spaceBetweenRects } = this.props
const names = ['Cher', 'Madonna', 'Band Names That Are Ridiculously Long', 'U2']
const rectHeight = labelRectHeight
const paddingLeftRight = 0.05 * rectWidth
const plusWidth = rectHeight / 2
return (
<g>
{names.map((name, i) => {
const y = i * labelRectHeight + i * spaceBetweenRects
const maxTextwidth = rectWidth - plusWidth - 3 * paddingLeftRight // this is the maximum length that text can have
this.placeTextWithEllipsis(this.textRef, name, maxTextwidth)
return (
<g key={i}>
<React.Fragment>
<rect x={0} y={y} width={rectWidth} height={rectHeight} fill={'#E4E9EB'} />
</React.Fragment>
<text
ref={this.textRef}
x={rectWidth - paddingLeftRight}
y={y + rectHeight / 2}
textAnchor="end"
alignmentBaseline="middle"
>
{name}
</text>
</g>
)
})}
</g>
)
}
}
的东西。
我尝试使用 React Ref :
textObj
在这种情况下,timestamp with timezone
为空...
我尝试的最后一个选择是使用textPath,但是在那种情况下,我将仅修剪字符串,而没有最后3个点,因此我不很喜欢将其作为解决方案。
如果有人帮助我,我会很高兴,因为我不知道该怎么做。 非常感谢
答案 0 :(得分:2)
textObj
在渲染方法中为null。
您必须在componentDidMount()
中使用它。然后,创建一个ref数组,否则该ref将被循环中的每个元素覆盖。
export class Labels extends React.Component<Props> {
textRefs = new Array(React.createRef<SVGTextElement>())
componentDidMount() {
const { maxTextwidth } = this.props
this.textRefs.forEach((ref, i) => {
placeTextWithEllipsis(
this.textRefs[i].current,
this.textRefs[i].current.innerHTML,
maxTextwidth
)
})
}
render() {
return (
// ...
<text
ref={(this.textRefs[i] = React.createRef<SVGTextElement>())}
x={rectWidth - paddingLeftRight}
y={y + rectHeight / 2}
textAnchor="end"
alignmentBaseline="middle"
>
{...}
</text>
// ...
)
}
}
答案 1 :(得分:0)
我有同样的问题。我尝试了梦游提出的方法,但对我没有用。我使用了与钩子api,useRef和useLayoutEffect略有不同的方式。所以我想出了另一个在svg中使用foreignObject的解决方案。这样,我们可以使用标准的html和css解决方案。
<foreignObject x={0} y={0} width={maxTextwidth} height={20}>
<div style={{textOverflow: 'ellipsis', with: maxTextwidth, overflow: 'hidden', whiteSpace: 'nowrap'}}>
Long text to use ellipsis on
</div>
</foreignObject>