当前位置: 首页 > 知识库问答 >
问题:

用React计算SVG包围盒?

谭敏学
2023-03-14

我正在用React生成SVG编写一个可视化应用程序。我需要的部分之一是一个标签--即文本,由一个封闭框包围,带有可变文本,可能旋转和样式化。

因此,我有一个nodelabel的组件,当前具有固定的维度:

render() {
        return <g>
            <rect className="label" x={this.props.x} y={this.props.y-10} width={20} height={40}></rect>
            <text className="labelText" x={this.props.x} y={this.props.y}>{this.props.children}</text>
        </g>
    }

我在DOM中找到了一些关于这样做的信息,这里是:SVG文本周围的矩形边框

更新:2018年1月,我再次回到这里:-)实际的应用程序是一个开源的网络图绘制工具,目前使用GD和PHP,但我希望可以使用JS、React和SVG。

这里的带宽标签是我试图重现的,尽管节点标签在当前的非SVG版本中使用了相同的功能。

下面是我新的最小示例

// MyLabel should be centred at x,y, rotated by angle, 
// and have a bounding box around it, 2px from the text.
class MyLabel extends React.Component {
  render() {
    const label = <text x={this.props.x} y={this.props.y} textAnchor="middle" alignmentBaseline="central">{this.props.children}</text>;
        
    // label isn't a DOM element, so you can't call label.getBoundingClientRect() or getBBox()

    // (Magic happens here to find bbox of label..)        
    // make up a static one for now
    let bb = {x: this.props.x-20, y: this.props.y-6, width: 40, height: 12};
    
    // add margin
    const margin = 2;
    bb.width += margin * 2;
    bb.height += margin * 2;
    bb.x -= margin;
    bb.y -= margin;
    
    // rect uses bbox to decide its size and position
    const outline = <rect x={bb.x} y={bb.y} width={bb.width} height={bb.height} className="labeloutline"></rect>;
    
    const rot = `rotate(${this.props.angle} ${this.props.x} ${this.props.y})`;
    // build the final label (plus an x,y spot for now)
    return <g transform={rot}>{outline}{label}<circle cx={this.props.x} cy={this.props.y} r="2" fill="red" /></g>;
  }
}

class Application extends React.Component {
  render() {
    return <svg width={300} height={300}>
      <MyLabel x={100} y={100} angle={0}>Dalmation</MyLabel>
      <MyLabel x={200} y={100} angle={45}>Cocker Spaniel</MyLabel>
      <MyLabel x={100} y={200} angle={145}>Pug</MyLabel>
      <MyLabel x={200} y={200} angle={315}>Pomeranian</MyLabel>
    </svg>;
  }
}

/*
 * Render the above component into the div#app
 */
ReactDOM.render(<Application />, document.getElementById('app'));
body { background: gray; }
svg {background: lightgray;}
.labeloutline { fill: white; stroke: black;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="app"></div>

共有1个答案

爱亮
2023-03-14

您要么预先计算/测量您的字体几何形状,并根据输入字符串得到对文本尺寸的合理估计(这是最简单的解决方案,但如果字体发生变化,显然会中断),要么执行两阶段呈现:

也就是说,您通过ref获得dom元素,在mount上获取框,最后通过更新状态重新呈现,如下所示:

class MyLabel extends React.Component {
  constructor(props){
    super(props);
    this.state = {text_extents:null};
  }
  componentDidMount() {
   const box = this.text.getBBox();

   this.setState({text_extents:[box.width,box.height]});
  }
 render() {
   const margin = 2;
   const extents = this.state.text_extents;
   const label = <text ref={(t) => { this.text = t; }} textAnchor="middle" dy={extents?(extents[1]/4):0} >{this.props.children}</text>;
   const outline = extents ?
         <rect x={-extents[0]/2-margin} y={-extents[1]/2-margin} width={extents[0]+2*margin} height={extents[1]+2*margin} className="labeloutline"></rect>
         : null;

   return <g transform={`translate(${this.props.x},${this.props.y}) rotate(${this.props.angle})`}>{outline}{label}</g>;
 }
}

请注意,根据最新的react文档,这不应在任何用户可见的闪烁中产生:

componentDidMount():在这个方法中调用setState()会触发一个额外的呈现,但它会发生在浏览器更新屏幕之前。这保证了即使在这种情况下会两次调用render(),用户也不会看到中间状态。请谨慎使用此模式,因为它经常会导致性能问题。然而,对于情态词和工具提示这样的情况,当您需要在呈现依赖于其大小或位置的东西之前测量DOM节点时,它可能是必要的。

最后,请注意,如果标签字符串更改(通过props或其他方法),则需要相应地更新扩展区(通过componentdidupdate())。

 类似资料:
  • 我参加了一个编程比赛,我无法解决问题,问题是: 给定一个n个整数的数组A,我需要计算给定范围内求逆的次数。提供一个整数m,它表示范围的数量,然后是m行,在每一行中给出两个整数li和ri。 我们必须只计算指定范围内的反转,即从li到ri(包括0)的反转(基于0的索引)。 如果 A[i] 两个元素 A[i] 和 A[j] 添加到反演中 反转是: 输入: 输出: 约束: 我知道在整个数组上计算O(nlo

  • 我是一个角度开发人员和新的反应,这是简单的反应组件,但不工作 错误:在JSX作用域中使用JSX React/React时,“React”必须在作用域中

  • 我正试图根据用户输入的角度绘制一个圆的周长。角度决定周长完成度:360°为整圆,180度为半圆,以此类推。 我的问题是:给定半径、角度和圆心坐标,我如何动态计算周长的路径? 我知道这可能是基本的数学,但到目前为止我所尝试的一切都不起作用。 下面是我正在尝试做的一个示例:请注意,应该只绘制黑色的周长:我只是使用虚线红线给出了一个可视化的示例,说明如何根据用户给出的值绘制周长。

  • 在Java中,当我们声明 它会给编译时间错误,但是 编译得很好。为什么会这样?

  • 问题内容: 假设我有一组任意的纬度和经度对,它们代表一些简单的闭合曲线上的点。在笛卡尔空间中,我可以使用格林定理轻松计算出此类曲线所包围的面积。计算球体表面面积的类似方法是什么?我想我所追求的是Matlabareaint函数背后的算法(甚至是近似算法)。 问题答案: 有几种方法可以做到这一点。 1)整合纬度带的贡献。此处每个条带的面积为(Rcos(A)(B1-B0))(RdA),其中A为纬度,B1

  • 问题内容: 我有一个对象,该对象带有一种方法,希望以类似以下方式向库客户端(尤其是脚本客户端)公开: 但是我可以使用的原始“东西”是一组事件驱动的类: 在其中,ImplementingThing接受输入,执行一些不可思议的工作,例如将任务排队入队列,然后稍后在发生结果时,在可能与调用ImplementingThing.doSomethingAsync()相同的线程上调用该线程。 有没有一种方法可以