修改现有d3代码 - 动态矩形高度以匹配文本

时间:2015-06-14 23:13:14

标签: javascript html d3.js

我正在使用CodePen的代码作为基础,根据我的需求构建甘特图。但是,我试图修改代码,以便实际的Rectangle高度适应给予它们的文本。在所示的示例中,所有任务文本都是一个字长,因此它们适合矩形。但是,如果任务长度为几个字且矩形宽度较短,则文本不会换行并溢出。

我如何修改代码以便绘制矩形高度以适合其中的文本,或者使用文本换行并使矩形增长(高度)以容纳文本?

现在,CodePen示例中的矩形高度是硬编码的:

var barHeight = 20;

该示例还以如下方式将文本添加到矩形(参见下文)。我试图将html放在矩形而不是文本中无效:

 var rectText = rectangles.append("text")
               .text(function(d){
                return d.task;
               })

2 个答案:

答案 0 :(得分:1)

你真的在问两个问题。一,如何包装文本然后两个,如何将矩形高度缩放到包装文本。

1。)M. Bostock here提供了包装文本的规范示例。

2。)要将rect的高度缩放到文本,可以使用.getBBox()作为@BenLyall提示。首先包装文本,然后在文本节点上调用.getBBox()并将高度应用于矩形。

这是一个完整的例子:

var someWidth = Math.random() * 250;

var longText = "Now is the time for all good men to come to the aid of their country";

 var rect = g.append('rect')
    .style('fill','steelblue')
    .attr('width', someWidth) //<-- random width we don't know it
    .attr('height', 1); // <-- start with arbitrary height

  var txt = g.append('text')
    .text(longText) //<-- our super long text
    .attr('x', 4)
    .attr('y', 10)
    .attr('dy', '.71em')
    .style('fill', 'white')
    .call(wrap, someWidth); //<-- wrap it according to our width

  var height = txt.node().getBBox().height + 15; //<-- get our height plus a margin
  rect.attr('height', height); //<-- change our rect

这是一个有效的example

答案 1 :(得分:0)

以下是您链接到的示例的修改版本。

http://codepen.io/anon/pen/JdyGGp

有趣的一点:

var innerRects = rectangles.append("g")
             .attr("class", "rectangle");

  innerRects.append("rect")
             .attr("rx", 3)
             .attr("ry", 3)
             .attr("x", function(d){
              return timeScale(dateFormat.parse(d.startTime)) + theSidePad;
              })
             .attr("y", function(d, i){
                return i*theGap + theTopPad;
            })
             .attr("width", function(d){
                return (timeScale(dateFormat.parse(d.endTime))-timeScale(dateFormat.parse(d.startTime)));
             })
             //.attr("height", theBarHeight)
             .attr("stroke", "none")
             .attr("fill", function(d){
              for (var i = 0; i < categories.length; i++){
                  if (d.type == categories[i]){
                    return d3.rgb(theColorScale(i));
                  }
              }
             })


         var rectText = innerRects.append("text")
               .text(function(d){
                return d.task;
               })
               .attr("x", function(d){
                return (timeScale(dateFormat.parse(d.endTime))-timeScale(dateFormat.parse(d.startTime)))/2 + timeScale(dateFormat.parse(d.startTime)) + theSidePad;
                })
               .attr("y", function(d, i){
                  return i*theGap + 14+ theTopPad;
              })
               .attr("font-size", 11)
               .attr("text-anchor", "middle")
               .attr("text-height", theBarHeight)
               .attr("fill", "#fff");

  innerRects.each(function(r) {
    var bBox = d3.select(this).select("text").node().getBBox();
    d3.select(this).select("rect").attr("height", function(d) {
      return bBox.height;
    }).attr("y", function(d) {
      return bBox.y;

    });
  });

我没有直接将recttext元素直接添加到单个组中,而是为每个元素创建了一个新组,以便它们可以链接在一起,因为每个组都可以rect我们需要找出height对应的text元素。

创建recttext元素之后,我然后循环遍历我创建的g元素并获取边界框({​​{1}}函数调用)并将关联的getBBox()元素的height设置为从边界框返回的rect值。我还要设置height的{​​{1}}元素以匹配。

此外,将yrect元素组合在一起的新g元素会破坏工具提示定位代码,因此会相应更新:

rect

这里的变化是:

text

以前,这是使用innerRects.on('mouseover', function(e) { var tag = ""; if (d3.select(this).data()[0].details != undefined){ tag = "Task: " + d3.select(this).data()[0].task + "<br/>" + "Type: " + d3.select(this).data()[0].type + "<br/>" + "Starts: " + d3.select(this).data()[0].startTime + "<br/>" + "Ends: " + d3.select(this).data()[0].endTime + "<br/>" + "Details: " + d3.select(this).data()[0].details; } else { tag = "Task: " + d3.select(this).data()[0].task + "<br/>" + "Type: " + d3.select(this).data()[0].type + "<br/>" + "Starts: " + d3.select(this).data()[0].startTime + "<br/>" + "Ends: " + d3.select(this).data()[0].endTime; } var output = document.getElementById("tag"); var item = d3.select(this).select("rect").node(); var x = (item.x.animVal.value + item.width.animVal.value/2) + "px"; var y = item.y.animVal.value + 25 + "px"; output.innerHTML = tag; output.style.top = y; output.style.left = x; output.style.display = "block"; }).on('mouseout', function() { var output = document.getElementById("tag"); output.style.display = "none"; }); 来抓取 var item = d3.select(this).select("rect").node(); var x = (item.x.animVal.value + item.width.animVal.value/2) + "px"; var y = item.y.animVal.value + 25 + "px"; 元素的thisx位置。由于这些代码现在与y分组,因此需要更新代码以引用组中的rect子元素。这段代码就是这样。

当你开始包装文本时,还有很多问题。背景矩形也需要动态增长以包含它们。我建议重构一下这个例子来解决这个问题。

您需要执行以下操作:

  1. 为所有text添加占位符元素。对于背景和任务rect,您应该能够提前设置rect(背景rect宽度只是包含元素的宽度。任务的宽度{ {1}}由任务的开始和结束日期设置。

  2. 使用任务width的{​​{1}},您可以添加文本元素并以适当的宽度换行。 (此示例可能有助于执行http://bl.ocks.org/mbostock/7555321

  3. 根据所有子rect元素的计算rect,返回并设置所有背景和任务width的{​​{1}} s