D3 console.log 在函数链中

D3 console.log in a function chain

D3 中是否有允许 "in-line" 日志记录的基础 function/object?

我正在阅读 Scott Murry 的精美 D3 书并想这样做:

  d3.select("body").selectAll("div")
    .log("body")
    .data(dataset)
    .log("data")
    .enter()
    .log("enter")
    .append("div")
    .log("div")
    .attr("class", "bar")
    .log("class");

我目前正在做这件可怕的事情:

const log = function (msg, val) {
  const data = val ? val : this
  const label = msg ? msg : "data:"
  console.log(label, data)
  return data
}

Object.prototype.log = log

这工作正常,产生了这个可点击的控制台输出: 但是.. D3 的方法是什么?

为了在你的链中记录数据,你可以只使用一个假属性:

d3.select("body").selectAll("div")
  .data(dataset)
  .enter()
  .append("div")
  .attr("fake", d=> console.log(d));

对于其他事情,我认为没有 "d3" 允许登录的方式,遗憾的是,我认为您必须以正常方式进行:

console.log(d3.select("body").selectAll("div").data(dataset).enter());

您可以通过修改 d3 选择原型来使用您的解决方案(相对于对象原型,我认为这不能被考虑 "horrible" - 尽管我有点偏向于乱用 d3内部),但我觉得您正在寻找 selection.call().

如果您想访问当前选择,但不想中断方法链接,selection.call 可能是您最好的选择:

Invokes the specified function exactly once, passing in this selection along with any optional arguments. Returns this selection. (docs)

被调用函数的第一个参数将是选择,更多的可选参数可以在调用方法本身中传递。一般形式为:

selection.call(func, arg, arg, ...)

function func(selection, arg, arg, ...) {}

使用 selection.call 进行日志记录应该不会太难使用这种方法。这是一个快速模型 (v4/5):

var dataset = d3.range(10);

  d3.select("body").selectAll("div")
    .call(log,"body")
    .data(dataset)
    .call(log,"dataset")
    .enter()
    .call(log,"enter")
    .append("div")
    .call(log,"div")
    .attr("class", "bar")
    .call(log,"bar");

function log(sel,msg) {
  console.log(msg,sel);
}

结果:

Here's 实际模型。

我首先想到的是 Andrew Reid 在他 making use of selection.call(). Although that solution is fine, I think it can be improved by directly extending D3's selection. The docs on d3.selection() 中明确提出的方法,即此函数可用于扩展选择原型。

您可以按照以下几行创建自己的记录器:

const logger = {
  log() {
    console.log(...arguments);
    return this;
  }
}

这可以很容易地混入d3.selection.prototype:

Object.assign(d3.selection.prototype, logger);

简单方法 logger.log() 只是记录所有传递给控制台调用的参数,并通过返回 this 来促进方法链接,它指的是选择本身。

当然,可以很容易地想象出许多更有用的日志记录方法,用于打印属性、选择、数据等等。以下演示扩展了基本概念:

const logger = {
  log() {          // Generic method logging all arguments.
    console.log(...arguments);
    return this;
  },
  
  logMsg(msg) {    // Logging just a simple msg.
    console.log(msg);
    return this;
  },
  
  logSel() {       // Log the selection.
    console.log(this);
    return this;
  },
  
  logAttr(name) {  // Log the attributes with "name" for all selected elements.
    this.each(function(d, i) {
      let attr = d3.select(this).attr(name);
      console.log(`Node ${i}: ${name}=${attr}`);
    });
    return this;
  },
  
  logData() {      // Log the data bound to this selection.
    console.log(this.data());
    return this;
  },

  logNodeData() {  // Log datum per node.
    this.each(function(d, i) {
      console.log(`Node ${i}: ${d}`);
    });
    return this;
  }
};

Object.assign(d3.selection.prototype, logger);

d3.select("body")
    .logMsg("Start")
  .append("svg").selectAll(null)
    .log(1, {}, "Test")
    // .logSel()   // this doesn't work well in Stack snippets
  .data([1,2])
  .enter().append("circle")
    .attr("r", "10")
    .logAttr("r")
    .logData()
    .logNodeData()
    .logMsg("End");
<script src="https://d3js.org/d3.v5.js"></script>