在这个示例中,SVG 操作的更智能的链接方式?

huangapple go评论59阅读模式
英文:

Smarter way of chaining SVG operations in this example?

问题

在以下代码中,我创建文本SVG元素,对其进行自动换行,然后基于新的(换行后的)文本尺寸和矩形创建边界框。我只能以以下方式完成它,我想知道是否可以简化代码,以便可能在同一个函数中创建文本和边界框?

var a = settings.g.selectAll(".axislabel")
    .data(featureData)
    .join(
        enter => enter.append("text")
            .attr("x", d => d.label_coord.x)
            .attr("y", d => d.label_coord.y)
            .text(d => d.name)
            .attr("dy", "0.35em")
            .call(wrap, 60)
    );

var x = settings.g.selectAll("text");
// 获取刚刚创建的元素
for (let a of x['_groups'][0]) {
    // 遍历并创建边界框
    var v = a.getBBox();
    // 基于边界框创建矩形
    settings.g.selectAll("labelBack")
        .data([a.textContent])
        .join(
            enter => enter.append("rect")
                .attr("x", v.x)
                .attr("y", v.y)
                .attr("width", v.width)
                .attr("height", v.height)
                .attr("fill", "white")
                .attr("opacity", 1)
                .attr("stroke-width", 1)
                .attr("stroke", "black")
        );
}
英文:

In the following code, I create text svg elements, word-wrap it and then create bounding boxes based on the new (wrapped) text dimensions and recntagles. I was only able do it in the following way, and I would like to know if the code could not be simplified so that maybe the boxes are created in the same function as the text?

 var a=settings.g.selectAll(".axislabel")
                .data(featureData)
                .join(
                    enter => enter.append("text")
                        .attr("x", d => d.label_coord.x)
                        .attr("y", d => d.label_coord.y)
                        .text(d => d.name)
                        .attr("dy", "0.35em")
                        .call(wrap, 60)
                )
    
    var x=settings.g.selectAll("text")
/getting the elements I just created
    for(let a of x['_groups'][0])
    {
        //iterating through and create bounding boxes
        var v=a.getBBox();
       //createing rectangles based on the boundinx boxes
        settings.g.selectAll("labelBack")
        .data([a.textContent])
        .join(
            enter => enter.append("rect")
                .attr("x", v.x)
                .attr("y", v.y)
                .attr("width", v.width)
                .attr("height", v.height)
                .attr("fill", "white")
                        .attr("opacity", 1)
                        .attr("stroke-width", 1)
                        .attr("stroke", "black")
        );

答案1

得分: 2

当你使用 selection.join 时搭配一个函数参数,传入的函数会构建你想要的 DOM 元素。因此,你在构建时有很大的灵活性。特别是,你可以做如下操作:

enter => {
  let g = enter.append("g");
  let rect = g.append("rect");
  let text = g.append("text");
  // ...设置文本的代码
  rect
    .attr('height', ...设置高度的代码)
    .attr('width', ...设置宽度的代码)

这可以工作是因为在设置矩形大小时文本已经被设置。你可以在下面的代码中看到它实际运行的效果。

Credit: 尽管有些许不同,但部分代码基于 Gerardo 在这里的回答

英文:

When you use selection.join with a functional argument, the function that you pass in constructs the dom element you want. Thus, you've got a lot of flexibility in what you build. In particular, you can do something like

enter => {
  let g = enter.append("g");
  let rect = g.append("rect");
  let text = g.append("text")
     ...Code to set the text
  rect
    .attr('height', ...Code to set the height)
    .attr('width', ...Code to set the width)

This can work because the text was set by the time the rect is sized. You can see this in action in the code below.

Credit: While this is a little bit different, I based the code partly on Gerardo's answer here.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

  let pad = 2;
  let w = 200;
  let h = 100;
  let svg = d3
    .select(&#39;#viz&#39;)
    .append(&quot;svg&quot;)
    .attr(&quot;viewBox&quot;, [0, 0, w, h])
    .style(&quot;max-width&quot;, `${640}px`)
    .style(&#39;border&#39;, &#39;solid 1px black&#39;);
    
   let data = [
    { x: 10, y: 20, text: &quot;This&quot; },
    { x: 56, y: 50, text: &quot;should&quot; },
    { x: 120, y: 20, text: &quot;work&quot; }
  ];

  svg
    .append(&quot;g&quot;)
    .selectAll(null)
    .data(data)
    .join((enter) =&gt; {
      let g = enter.append(&quot;g&quot;);
      let rect = g.append(&quot;rect&quot;);
      let text = g
        .append(&quot;text&quot;)
        .attr(&quot;x&quot;, (d) =&gt; d.x)
        .attr(&quot;y&quot;, (d) =&gt; d.y)
        .text((d) =&gt; d.text)
        .call(wrap);
      rect
        .attr(&quot;x&quot;, (d) =&gt; d.x - pad)
        .attr(&quot;y&quot;, (d) =&gt; d.y - d.bbox.height + 2 * pad)
        .attr(&quot;width&quot;, (d) =&gt; d.bbox.width + 2 * pad)
        .attr(&quot;height&quot;, (d) =&gt; d.bbox.height + 2 * pad)
        .attr(&quot;fill&quot;, &quot;#ddd&quot;)
        .attr(&quot;stroke&quot;, &quot;black&quot;);
    });

  function wrap(selection) {
    selection.each(function (d) {
      d.bbox = this.getBBox();
    });
  }

<!-- language: lang-html -->

&lt;div id=&quot;viz&quot;&gt;&lt;/div&gt;
&lt;script src=&quot;https://d3js.org/d3.v7.min.js&quot;&gt;&lt;/script&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年6月1日 05:36:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76377451.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定