javascript - D3 示例 : looks like a javascript variable, 但像函数一样调用

标签 javascript d3.js

我试图了解 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>

最佳答案

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

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

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

使用 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

A path generator, such as that returned by d3.svg.line, is both an object and a function. That is: you can call the generator like any other function, and the generator has additional methods that change its behavior. Like other classes in D3, path generators follow the method chaining pattern where setter methods return the generator itself, allowing multiple setters to be invoked in a concise statement.

关于javascript - D3 示例 : looks like a javascript variable, 但像函数一样调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34095295/

相关文章:

javascript - 如何让所有的节点都围绕中心节点?

javascript - 不在 HTML DOM 中的节点上的 d3 事件处理程序

html - 如何在 SVG 中为外部图像添加替代文本?

javascript - 纯javascript : Set border for draggable elements

javascript - 我怎样才能在 Ember 中输出一个字符串,同时它仍然被 handlebars 解释?

Javascript:使用 new 创建字符串是否意味着我需要稍后发布它?

javascript - 无法将粒子JS设置为背景

d3.js - 给定 geoJSON 对象,在 d3 中将 map 居中

json - 为 cubism.js 使用其他数据源

javascript - 如果我将 Google 分析代码放在 IF 语句中,它会起作用吗?