如何创建< dl>使用d3.js [英] How do I create a <dl> using d3.js

查看:72
本文介绍了如何创建< dl>使用d3.js的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用d3.js从一些数据列表中创建一系列 dl 标签。



我提出的代码是:

  var x = d3.select(body)
.append('ol')
.selectAll('li')
.data(data)
.enter()
.append('li')
.append('dl')
.selectAll()
.data(d => Object.entries(d.volumeInfo))。enter();

x.append('dt')
.text(d => d [0]);

x.append('dd')
.text(d => d [1]);

其中 data 是一个对象数组。一切正常,但元素的顺序不正确。



这是我设法获得的订单:

 < DL> 
< dt> key1< / dt>
< dt> key2< / dt>
< dd> value1< / dd>
< dd> value2< / dd>
< / dl>

但它应该是这样的:

 < DL> 
< dt> key1< / dt>
< dd> value1< / dd>
< dt> key2< / dt>
< dd> value2< / dd>
< / dl>

我已经做了相当多的谷歌搜索,没有回答这个问题,至少不适用于v5 没有多个dt / dd对



这似乎是d3.js应该能做的基本事情。

解决方案

在你的解决方案中:

  x.append('dt')
.text(d => d [0]);

x.append('dd')
.text(d => d [1]);

所有元素附加 enter()。append() cycle按照它们的附加顺序附加到父级,对于你运行的顺序如下:首先是所有 dt s,然后是所有 dd s,如您所见。由enter语句创建的占位符节点(这些不是附加元素)不会以您希望它们出现的方式嵌套子节点。



尽管d3不包含使用方法实现所需内容的方法,只需简单的 selection.append() 方法,使用标准d3方法和额外的一两步可以很容易地实现所需的行为。或者,我们可以自己在d3.selection中构建该功能。



对于我的回答,我将完成一个使用您的数据结构并输入模式的示例,但要开始我将简化这里的嵌套 - 而不是嵌套的附加,我只是演示几种可能的方法来附加有序的兄弟姐妹。首先,我还简化了数据结构,但原理保持不变。






第一种方法可能最直接:使用 selection.each()功能。使用输入选择(使用父输入或输入的占位符),使用each方法追加两个单独的元素:



  var data = [{name:a,description:The first letter},{name:b,description:The second letter}]; d3.select (body)。selectAll(null).data(data).enter().each(function(d){var selection = d3.select(this); // append siblings:selection.append(dt) .html(function(d){return d.name;}); selection.append(dd)。html(function(d){return d.description;})}) 

 < script src =https://cdnjs.cloudflare.com/ajax/libs/d3 /4.10.0/d3.min.js\"></script>  






但是,或许更优雅的选择是挖掘d3.selectio n()并用它玩具给我们一些新的行为。下面我添加了一个 selection.appendSibling()方法,它允许您在选择中的每个项目的正下方追加一个配对的兄弟元素:

  d3.selection.prototype.appendSibling = function(type){
var siblings = this.nodes()。map(function(n){
return n.parentNode.insertBefore(document.createElement(type),n.nextSibling);
})
return d3.selectAll(siblings).data(this.data());
}

它选择每个节点,创建一个新的配对兄弟节点(每个节点)紧接在指定类型的DOM中的原始节点之后的一个,然后将新节点放在d3选择中并绑定数据。这允许您将方法链接到它上以设置元素的样式等,并允许您访问绑定的基准。请参阅下面的操作:



  //修改d3.selection以便我们可以附加siblingd3.selection.prototype.appendSibling = function(type){var siblings = this.nodes()。map(function(n){return n.parentNode.insertBefore(document.createElement(type),n.nextSibling) ;})return d3.selectAll(siblings).data(this.data());} var data = [{name:a,description:the first letter},{name:b,description: 第二个字母}]; d3.select(body)。selectAll(null).data(data).enter()。append(dt)。html(function(d){return d.name; } .appendSibling(dd)//追加兄弟姐妹.html(函数(d){return d.description;})//修改兄弟姐妹 

 < script src =https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/ d3.min.js>< / script>  



当然,将兄弟姐妹分开选择是很明智的,这样你就可以管理每个兄弟姐妹的更新/进入/退出等。



这种方法很容易应用到你的例如,这是一个嵌套的解决方案,使用的结构与您期望的结果和appendSibling方法相同:



  //修改d3.selection,以便我们可以附加siblingd3.selection.prototype.appendSibling = function(type){var siblings = this.nodes()。map(function(n){ return n.parentNode.insertBefore(document.createElement(type),n.nextSibling); })return d3.selectAll(siblings).data(this.data());} var data = [{volumeInfo:{a:1,b:2,c:3}},{volumeInfo :{α:1,β:2}}] var items = d3.select(body)。append('ol')。selectAll('li')。data(data).enter() .append('li')。append('dl')。selectAll()。data(d => Object.entries(d.volumeInfo))。enter(); var dt = items.append(dt)。text(function(d){return d [0];})var dd = dt.appendSibling(dd)。text(function(d){return d [1 ];}) 

 < script src =https: //cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js\"></script>  


I'd like to create a series of dl tags in a list from some data using d3.js.

The code I came up with is this:

var x=d3.select("body")
    .append('ol')
    .selectAll('li')
    .data(data)
    .enter()
    .append('li')
    .append('dl')
    .selectAll()
    .data(d=>Object.entries(d.volumeInfo)).enter();

x.append('dt')
    .text(d=>d[0]);

x.append('dd')
    .text(d=>d[1]);

where data is an array of objects. Everything works except the elements are not in the correct order.

Here is the order I manage to get:

<dl>
    <dt>key1</dt>
    <dt>key2</dt>
    <dd>value1</dd>
    <dd>value2</dd>
</dl>

But it should be like this:

<dl>
    <dt>key1</dt>
    <dd>value1</dd>
    <dt>key2</dt>
    <dd>value2</dd>
</dl>

I've done a fair amount of googling and nothing answers the question, at least not in a way that works in v5 or not with more than one dt/dd pair.

This seems like something basic that d3.js should be able to do.

解决方案

In your solution:

x.append('dt')
    .text(d=>d[0]);

x.append('dd')
    .text(d=>d[1]);

All elements appended with an enter().append() cycle are appended to the parent, in the order they are appended, which for you runs like this: first all the dts, then all the dds, as you have seen. The placeholder nodes (these are not the appended elements) created by the enter statement do not nest children in a manner it appears you might expect them to.

Despite the fact that d3 doesn't include methods to achieve what you are looking for with methods as easy as a simple selection.append() method, the desired behavior can be achieved fairly easily with standard d3 methods and an extra step or two. Alternatively, we can build that functionality into d3.selection ourselves.

For my answer I'll finish with an example that uses your data structure and enter pattern, but to start I'll simplify the nesting here a bit - rather than a nested append I'm just demonstrating several possible methods for appending ordered siblings. To start I've also simplified the data structure, but the principle remains the same.


The first method might be the most straightforward: using a selection.each() function. With the enter selection (either with a parent or the entered placeholders), use the each method to append two separate elements:

var data = [
{name:"a",description:"The first letter"},
{name:"b",description:"The second letter"}
];


d3.select("body")
  .selectAll(null)
  .data(data)
  .enter()
  .each(function(d) {
	var selection = d3.select(this);
	
	// append siblings:
	selection.append("dt")
	  .html(function(d) { return d.name; });
	selection.append("dd")
	  .html(function(d) { return d.description; })
    
})

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>


But, perhaps a more elegant option is to dig into d3.selection() and toy with it to give us some new behaivor. Below I've added a selection.appendSibling() method which lets you append a paired sibling element immediately below each item in a selection:

d3.selection.prototype.appendSibling = function(type) {
    var siblings =  this.nodes().map(function(n) {
        return n.parentNode.insertBefore(document.createElement(type), n.nextSibling);
    })
    return d3.selectAll(siblings).data(this.data());
}

It takes each node in a selection, creates a new paired sibling node (each one immediately after the original node in the DOM) of a specified type, and then places the new nodes in a d3 selection and binds the data. This allows you to chain methods onto it to style the element etc and gives you access to the bound datum. See it in action below:

// modify d3.selection so that we can append a sibling
d3.selection.prototype.appendSibling = function(type) {
  var siblings =  this.nodes().map(function(n) {
    return n.parentNode.insertBefore(document.createElement(type), n.nextSibling);
  })
  return d3.selectAll(siblings).data(this.data());
}

var data = [
    {name:"a",description:"The first letter"},
    {name:"b",description:"The second letter"}
    ];

d3.select("body")
  .selectAll(null)
  .data(data)
  .enter()
  .append("dt")
  .html(function(d) { return d.name; })
  .appendSibling("dd")  // append siblings
  .html(function(d) { return d.description; })  // modify the siblings

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

Of course it is probably wise to keep the siblings in separate selections so you can manage each one for updates/entering/exiting etc.

This method is very easily applied to your example, here's a nested solution using data that is structured like you expect and the appendSibling method:

// modify d3.selection so that we can append a sibling
d3.selection.prototype.appendSibling = function(type) {
  var siblings =  this.nodes().map(function(n) {
    return n.parentNode.insertBefore(document.createElement(type), n.nextSibling);
  })
  return d3.selectAll(siblings).data(this.data());
}

var data = [
 {volumeInfo: {"a":1,"b":2,"c":3}},
 {volumeInfo: {"α":1,"β":2}}
]

var items = d3.select("body")
    .append('ol')
    .selectAll('li')
    .data(data)
    .enter()
    .append('li')
    .append('dl')
    .selectAll()
    .data(d=>Object.entries(d.volumeInfo)).enter();
  
var dt = items.append("dt")
  .text(function(d) { return d[0]; })
  
var dd = dt.appendSibling("dd")
  .text(function(d) { return d[1]; })

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

这篇关于如何创建&lt; dl&gt;使用d3.js的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆