D3.js中是否有任何替代方法来使用.append()?

3

.append()方法是将D3对象添加到HTML中的唯一方式吗?

我正在使用append()方法将一个treemap添加到我的HTML文件的body中,但我想将treemap添加到一个元素的内部。问题在于,append()方法是将元素添加在当前元素之后,而不是在当前元素之内。我想要将treemap的大小调整为浏览器初始高度和宽度的100%(像这样)。添加CSS似乎是最直接的方法。

我尝试通过将treemap附加到一个div内部的div来“欺骗”D3.js,但这没有起作用。

也许我问错了问题,我应该在d3.js脚本内调整treemap的大小?我已经尝试过更改bl.ock.org提供的默认样式,但我还没有使treemap扩展到全屏。

这里是我认为初始化treemap的代码。

var margin = {top: 40, right: 10, bottom: 10, left: 10},
    width = 1000 - margin.left - margin.right,
    height = 650 - margin.top - margin.bottom;

var color = d3.scale.category20c();

var treemap = d3.layout.treemap()
    .size([width, height])
    .sticky(false)
    .value(function(d) { return d.size; });

var div = d3.select("body").append("div")
    .style("position", "relative")
    .style("width", (width + margin.left + margin.right) + "px")
    .style("height", (height + margin.top + margin.bottom) + "px")
    .style("left", margin.left + "px")
    .style("top", margin.top + "px");

以下是更改节点大小以适应 JavaScript 值的代码。

var root;

socket.on('update', function(stream) {
  console.log('tweets')

  div.datum(root).selectAll(".node").remove();

  root = stream.masterlist;

  var node = div.datum(root).selectAll(".node")
      .data(treemap.nodes)
    .enter().append("div")
      .attr("class", "node")
      .call(position)
      .style("background", function(d) { return d.children ? color(d.name) : null; })
      .text(function(d) { return d.children ? null : d.name; });

  });


});

function position() {
  this.style("left", function(d) { return d.x + "px"; })
      .style("top", function(d) { return d.y + "px"; })
      .style("width", function(d) { return Math.max(0, d.dx - 1) + "px"; })
      .style("height", function(d) { return Math.max(0, d.dy - 1) + "px"; });
}

1
至少有.insert(element[, before])这个方法可以微调D3添加元素的位置。 - musically_ut
2个回答

4
我会以稍微不同的方式解决这个问题。我将使用 viewBox 属性 来保持可视化的坐标系恒定。个人而言,我喜欢 <svg viewBox="-100 -100 200 200">,意思是 (-100, -100) 是左上角,(100, 100) 是右下角。你也可以选择 0 0 100 100。然后,我不会在 svg 元素上显式设置任何 widthheight,而是依赖于 CSS 给它们正确的尺寸(例如 display: block; width: 80%; margin: auto; height: 80%),然后使用 preserveAspectRatio 属性 控制可视化的缩放方式。通常,我发现默认值(xMidYMidmeet)对我来说已经足够了。但是,你的情况可能有所不同。
这是使用此方法调整可视化大小以在不重新绘制可视化的情况下更改容器大小的示例:http://jsfiddle.net/ss47m/ 在这里:http://jsfiddle.net/ss47m/1/容器的大小被设置为覆盖整个窗口。

另一种方法是绑定到windowresize事件(就像nvd3对windowResize做的那样),每次窗口大小变化时重新绘制图表。我觉得这有点过度。


我对你的方法很感兴趣...能否提供一个简单的样例,演示一下你的想法呢?(包括任何你认为重要的细节)。点赞以示激励 :) - FernOfTheAndes
@FernOfTheAndes 添加了一个示例。 - musically_ut
1
谢谢您,非常感激 :) - FernOfTheAndes

3

首先,明确一下:

问题是append会在当前元素之后添加,而不是在当前元素内部添加。

这并不正确。如果您执行d3.select("div.parent").append("div"),新的div将位于父div内部,但在任何已经存在于父div中的子内容之后。要使新元素成为父元素的第一个子元素,您可以执行d3.select("div").insert("div", function(){return this.children[0];})。但我不认为这真的是您在这里遇到的问题...

对于如何计算树状图以使其自动填充浏览器窗口的问题:

如果您只想让地图填充窗口的初始大小,并且不用担心调整大小,那么您需要(a)找出窗口大小;(b)将容器div的高度和宽度设置为该大小;(c)将这些尺寸作为treemap函数的输入尺寸。

基本上,只需更改以下行:

width = 1000 - margin.left - margin.right,
height = 650 - margin.top - margin.bottom;

为了

width = window.innerWidth - margin.left - margin.right,
height = window.innerHeight - margin.top - margin.bottom;

然后,您的其余代码与原来相同。

如果您还希望树状图随窗口缩放,则应使用百分比值设置子元素的位置和大小。如果您使用[100,100]作为大小初始化树状图,那么您只需将所有位置函数中的"px"替换为"%"即可最轻松地实现此目标。

但是,您仍需要一些CSS来使容器div填满浏览器窗口并随其调整大小。这取决于页面布局中有多少其他元素。您可能还想查看此答案。如果无法使CSS正常工作,则始终可以侦听窗口调整大小事件,并根据窗口大小重置容器的宽度和高度。如果所有子元素都基于百分比设置大小,则它们将调整到您为父元素设置的任何大小。

最后,您可能希望在容器上设置min-heightmin-width属性,以确保您的树状图元素始终具有合适的大小,即使需要滚动也是如此。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接