什么是 d3.geo.pipeline?

What is d3.geo.pipeline?

如果你关注 Mike Bostock 的 bl.ocks,你就会知道在过去的 8 个月里,d3.geo.pipeline() 一直是他项目的常用组成部分。

但是它有什么作用?

你看他是这样设置管道的:

var sketch = d3.geo.pipeline()
      .source(d3.geo.jsonSource)
      .pipe(resample, .020)
      .pipe(jitter, .004)
      .pipe(smooth, .005)
      .sink(d3.geo.jsonSink);

via

d3.geo wiki.

中没有文档

代码示例中使用的未发布的D3中的一些美化JS揭示了这个功能:

lo.geo.pipeline = function() {
        var n = [];
        return {
            source: function() {
                return n[0] = arguments, this
            },
            pipe: function() {
                return n.push(arguments), this
            },
            sink: function() {
                for (var t, e = arguments[0].apply(null, [].slice.call(arguments, 1)), r = e; t = n.pop();) {
                    var u = [].slice.call(t, 1);
                    u.push(e), e = t[0].apply(null, u)
                }
                return function() {
                    return e.apply(this, arguments), r.value && r.value()
                }
            }
        }

也出现在这些bl.ocks:

我对d3.js不熟悉,但我查看了它的源代码,发现这个特性位于分支graphics-pipeline.

例如你可以在这里找到相关代码:https://github.com/mbostock/d3/commit/a3f2adab7f85e2a0c82288ead88c1e484c9e3ea3


说明其工作原理的小代码片段:

var pipeline = function () {
    var pipes = [];
    return {
        source: function () {
            pipes[0] = arguments;
            return this;
        },
        pipe: function () {
            pipes.push(arguments);
            return this;
        },
        sink: function () {
            var sink = arguments[0].apply(null, [].slice.call(arguments, 1)),
                pipe;

            while (pipe = pipes.pop()) {
                var args = [].slice.call(pipe, 1);
                args.push(sink);
                sink = pipe[0].apply(null, args);
            }

            return sink;
        }
    };
};

var log = document.getElementById('log');

function f() {
    var argsAsString = Array.prototype.join.call(arguments, ', ');
    var resultName = 'r' + f.callCounter++;

    log.innerHTML += resultName + ' = f(' + argsAsString + ')<br>';

    return resultName;
}

f.callCounter = 1;

pipeline().
    source(f, 'a', 1).
    pipe(f, 'b', 2).
    pipe(f, 'c', 3).
    sink(f, 'd', 4);
<div id="log"></div>

关于此功能的评论很少:

  1. 方法 sourcepipe 使用相同的私有 属性 pipes。唯一的区别是 sourcepipes (pipes[0]) 设置了初始值,当每次调用 pipe 时都会将新管道推送到集合中。
  2. 先前的事实为我们提供了有关 d3.geo.jsonSource 内部结构的知识。它应该类似于传递给 pipe 的参数:第一个参数是可调用的(函数),其余参数 - 参数。
  3. 假设 arguments = [f, a, b, c]。那么JavaScript模式arguments[0].apply(null, [].slice.call(arguments, 1))表示:f(a, b, c)。您可以在 sink 实现中看到它的几个用法。

关于实际使用。

如果我们需要"chain"(或"pipe")数据处理,我们可以使用它。例如,如果我们有这样的代码:

function f(a, b, previousResult) 
{
    return a * b + (previousResult || 0);
}

var p = pipeline().
    source(f, 1, 1).
    pipe(f, 2, 10).
    pipe(f, 3, 100).
    sink(f, 4, 1000);

那么结果(p的值)将是4321

在这种特殊情况下,我们需要澄清什么是 d3.geo.jsonSinkd3.geo.jsonSource,但我希望我能帮助您理解 pipeline 函数的含义。