D3 示例:看起来像一个 javascript 变量,但调用起来像一个函数

Posted

技术标签:

【中文标题】D3 示例:看起来像一个 javascript 变量,但调用起来像一个函数【英文标题】:D3 example: looks like a javascript variable, but is called like a function 【发布时间】:2016-03-09 19:06:52 【问题描述】:

我试图从 D3 示例中了解这段 javascript 代码的工作原理。对我来说没有意义的部分是buildLine() 函数中的xScaleyScale“函数”。

xScale为例,它看起来像一个简单的变量,被实例化为一个值:

    var xScale = d3.scale.linear()
                .domain([
                            d3.min(ds.monthlySales, function(d) return d.month;) ,
                            d3.max(ds.monthlySales, function(d) return d.month;)
                        ])                
                .range([0, w])
                .nice(); 

...但在buildLine() 的下方,它们似乎被称为函数:

    var lineFun = d3.svg.line()
        .x(function (d) return xScale(d.month);  )
        .y(function (d) return yScale(d.sales); )
        .interpolate("linear");

更具体地说,在:

.x(function (d) return xScale(d.month);  )

...我不明白 d 来自哪里(以及它如何具有 .month 属性),最重要的是它是如何产生的 xScale“函数”接收

我认为我需要理解 Javascript 的一个基本原理才能使这段代码有意义,但那可能是什么?


基础数据可以在这里看到:

https://github.com/bsullins/d3js-resources/blob/master/monthlySalesbyCategoryMultiple.json

整个源代码:

<!DOCTYPE html>
<html>
    <head>
        <script src="d3.min.js" charset="utf-8"></script>
    </head>
    <body>
    <script>
        var h=100;
        var w=400;
        var padding = 20;             


        //build line
        function buildLine(ds) 
            console.log('xscale-max: '+ d3.max(ds.monthlySales, function (d) return d.month; ));
            console.log('yscale-max: '+ d3.max(ds.monthlySales, function (d) return d.sales; ));
            //scales
            var xScale = d3.scale.linear()
                        .domain([
                                    d3.min(ds.monthlySales, function(d) return d.month;) ,
                                    d3.max(ds.monthlySales, function(d) return d.month;)
                                ])                
                        .range([0, w])
                        .nice(); 

            var yScale = d3.scale.linear()
                        .domain([0, d3.max(ds.monthlySales, function(d) return d.sales;)])
                        .range([h,0])
                        .nice();

            var lineFun = d3.svg.line()
                .x(function (d) return xScale(d.month);  )
                .y(function (d) return yScale(d.sales); )
                .interpolate("linear");

            var svg = d3.select("body").append("svg").attr( width:w, height:h);

            var viz = svg.append("path")
                        .attr(
                            d: lineFun(ds.monthlySales),
                            "stroke" : "purple",
                            "stroke-width": 2,
                            "fill" : "none"
                        );

        

        //show header
        function showHeader(ds) 
            d3.select("body").append("h1")
                .text(ds.category + " Sales (2013)");
        


        //get data and draw things  
        d3.json("https://api.github.com/repos/bsullins/d3js-resources/contents/monthlySalesbyCategoryMultiple.json", function(error, data) 

           if(error) 
               console.log(error);
            else 
               console.log(data); //we're golden!
           

            var decodedData = JSON.parse(window.atob(data.content));

            console.log(decodedData.contents);


            decodedData.contents.forEach(function(content)
                ds=content;
                console.log(ds);
                showHeader(ds);         
                buildLine(ds);                   
            )

        );  


    </script>
    </body>
</html>

【问题讨论】:

这就是所谓的callback function。您正在将函数作为参数传递给另一个方法。当该方法完成时,它回调到您传入的函数。它同时发送d。 (在这种情况下,它似乎是一个对象。)您可以匿名传递函数(和内联,就像您在此处所做的那样),或者您可以在其他地方命名它们并传递它们,如果这样更容易可视化的话。 d 是每一行中的项目。基本上与集合相关联使用。 【参考方案1】:

那么 javascript 有 first class functions 所以 xScale 是一个包含函数的变量。这意味着您可以传递它并调用它。

更具体地说,您发布的第一个代码 sn-p 构建了一个函数,该函数接受 .domain([d3.min ..., d3.max ... ]) 指定的区间内的值并返回 .range([0, w]) 指定的区间内的值。它还说函数返回的值应该是“不错的”(.nice()),即被截断为没有几个小数。根据这些规范构建的函数被分配给xScale 变量。

稍后,您在d3.svg.line 生成器中使用此函数,它就像d3.scale.linear 一个生成(因此,generator)函数的函数/对象,在本例中是一个函数,当提供数据集作为输入时,返回一个字符串,您可以将其用作 svg path 元素的 d 属性来绘制您想要的路径。这个函数被分配给变量lineFun(有趣的部分!)。

使用 d3.svg.line 生成器构建的 lineFun 函数将数据集作为输入:

lineFun(ds.monthlySales)

并且,对于数据集中的每个数据点,它将其作为输入传递给访问器函数(这是 d 参数的来源),以便它们可以为数据点创建 x 和 y 值。因此,访问器函数是接受数据点并返回值的函数,通常根据数据点的某些属性。所以,例如:

function (d) return xScale(d.month);

在给定数据点 d 的情况下,它返回 xScale 函数在将数据点的 month 属性作为输入传递时返回的值。

我知道我没有写最清楚的解释,但我希望它可以帮助你一点。

重点是:

在 Javascript 中,函数可以分配给变量并作为参数传递,就像整数或字符串一样 d3.scale.lineard3.svg.line 是生成器:它们构建并返回一个函数 d3 使用形状生成器在将数据作为输入时返回用于绘制路径以表示数据的 svg 属性。

来自https://github.com/mbostock/d3/wiki/SVG-Shapes#path-data-generators

路径生成器,例如 d3.svg.line 返回的路径生成器,既是对象又是函数。也就是说:您可以像调用任何其他函数一样调用生成器,并且生成器具有改变其行为的其他方法。与 D3 中的其他类一样,路径生成器遵循方法链接模式,其中 setter 方法返回生成器本身,允许在简洁的语句中调用多个 setter。

【讨论】:

谢谢你,我脑子里的灯泡还没有熄灭,但我想你已经说出了我在理解这段代码之前需要理解的一些原则。 xScale 本质上是一个指向 D3.Scale() 函数的指针,所以 that 是接收 d.Month 参数的对象......正确吗? 一个介绍音阶用法的博客:alignedleft.com/tutorials/d3/scales ....“d”的由来对我来说还是个谜。 带有很多教育链接的问题:***.com/questions/16930748/… D3 wiki root:github.com/mbostock/d3/wiki 更多:alignedleft.com/tutorials/d3 优秀的免费在线书籍:chimera.labs.oreilly.com/books/1230000000345/index.html

以上是关于D3 示例:看起来像一个 javascript 变量,但调用起来像一个函数的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Zeppelin 上从 JavaScript 设置角度变量值

使用给定的 javascript 库之一创建图表

D3三角形定位到精确点

在 d3 javascript 中的圆形对象内添加图像?

D3 折线图显示为面积图

如何增强D3.js的“平滑滚动”演示?