D3.js:添加名称基于数据的类

Ond*_*žka 3 javascript css d3.js

D3有两种设置类的方法:

selection.attr("class", (d) => d.isFoo ? "foo" : "");
selection.classed("foo", (d) => d.isFoo)
Run Code Online (Sandbox Code Playgroud)

我正在寻找一种方法来添加一个按照数据命名的类.就像这样:

selection.classed((d) => "node" + d.id, true);
Run Code Online (Sandbox Code Playgroud)
  • 我不想使用,id因为多个DOM元素将共享该类.
  • 我不想使用attr它,因为它可能会覆盖已存在的其他类.

所以我能做到

selection.attr("class", (d) => d3.select(this).attr("class") + " node" + d.id);
Run Code Online (Sandbox Code Playgroud)

感觉有点hackish.

更好的解决方案?或正在进行的功能?

alt*_*lus 6

虽然Gerardo的答案是正确的并且有正确的解释,但我认为,弄乱元素类的最简单方法是求助于classList它从Element接口继承的属性.

Element.classList是一个只读属性,它返回DOMTokenList元素的类属性的实时集合.

虽然属性本身是只读的,它提供了方法添加,删除和切换类.调用.add()将自动处理先前设置的类,并检查要添加的类是否已分配给元素:

add(String [,String])

添加指定的类值.如果这些类已存在于元素的属性中,则忽略它们.

因此,可以使用selection.each()以下方法添加基于数据的类:

divs.each(function(d) {
  this.classList.add("node" + d.name);
});
Run Code Online (Sandbox Code Playgroud)

.each()方法内this指向实际元素,可用于直接访问classList属性.

var data = [{name: "foo"}, 
            {name: "bar"},
            {name: "baz"}];

var body = d3.select("body");

var divs = body.selectAll("myDivs")
    .data(data)
    .enter()
    .append("div")
      .attr("class", "someClass");

divs.each(function(d) {
  this.classList.add("node" + d.name);
});

//log the classes, you can see the previous class ("someClass") was not overwritten:
divs.each(function() {
    console.log(d3.select(this).attr("class"))
})
Run Code Online (Sandbox Code Playgroud)
<script src="https://d3js.org/d3.v4.min.js"></script>
Run Code Online (Sandbox Code Playgroud)


Ger*_*ado 5

不幸的是,您无法按照您想要的方式传递函数classed()(即作为第一个参数)。该文档清楚地说明了classed()

选择.classed(名称[, 值])

如果指定了值,则通过设置 class 属性或修改 classList 属性来分配或取消分配所选元素上指定的 CSS 类名称,并返回此选择。指定的名称是一串空格分隔的类名。(强调我的)

因此,您不能将函数传递给类名。那里的类​​名必须是固定的

话虽这么说,您现在正在做什么来添加类名而不覆盖以前存在的类......

selection.attr("class", (d) => d3.select(this).attr("class") + " node" + d.id);
Run Code Online (Sandbox Code Playgroud)

...似乎是 D3 编码人员的标准方式,即使您觉得这是一种 hack。但是,您需要在这里进行一些小修改:不要this与箭头函数一起使用,它不会起作用(检查此示例d3 v4retrieve Drag DOM target from Drag callback when `this` is not available)。因此,这是正确的片段:

selection.attr("class", function (d){
    d3.select(this).attr("class") + " node" + d.id);
});
Run Code Online (Sandbox Code Playgroud)

然而,可以按照classed()您想要的方式使用,不是直接使用(同样,您不能将函数传递给它),而是以一种奇怪的解决方法。只是为了向您展示一种使用 执行此操作的方法,出于好奇,我创建了一个比您的解决方案更黑客的classed()演示代码。看看它:

selection.attr("class", (d) => d3.select(this).attr("class") + " node" + d.id);
Run Code Online (Sandbox Code Playgroud)
selection.attr("class", function (d){
    d3.select(this).attr("class") + " node" + d.id);
});
Run Code Online (Sandbox Code Playgroud)

正如d.name该函数所提供的each(),第一个参数 ( "node" + d.name) 实际上是一个字符串。