Why can I input an argument on a scale?

孤街醉人 提交于 2020-02-15 13:18:47

问题


I'm doing a simple histogram:

var width = 500,
  height = 500,
  padding = 50;
d3.csv('mydata.csv', function(data) {
  var map = data.map(function(i) {
    return parseInt(i.age)
  })
  var histogram = d3.layout.histogram()
    .bins(7)(map)
  console.log(histogram)

  var y = d3.scale.linear()
    .domain([0, d3.max(histogram.map(function(i) {
      return i.length;
    }))])
    .range([0, height])

  var x = d3.scale.linear()
    .domain([0, d3.max(map)])
    .range([0, width]);

  var canvas = d3.select('body').append('svg')
    .attr('width', width)
    .attr('height', height + padding);

  var bars = canvas.selectAll(".bar").data(histogram)
    .enter().append('g').attr('class', 'bar')
  bars.append('rect')
    .attr('x', function(d) {
      return x(d.x);
    })
    .attr('y', 0)
    .attr('width', function(d) {
      return x(d.dx);
    })
    .attr('height', function(d) {
      return y(d.y)
    })
    .attr('fill', 'purple')

})

I'm using Youtube to learn D3

The scale variable x and y aren't functions, but even if they were functions they don't have parameters.

But In the bars.append('rect'), return x(d.x), return x(d.dx) and return y(d.y) are acting like functions that also have parameters...

Can someone explain to me how is this possible?


回答1:


You said that...

The scale variable x and y aren't functions.

Well, that's incorrect. D3 scales (in any version) are functions. In you case, you have a D3 v3 scale.

To show you that this is a scale, and what argument it takes, let's see D3 v3 source code. It will take us through a labyrinth of functions returning functions.

This is the d3.scale.linear() function:

d3.scale.linear = function() {
    return d3_scale_linear([0, 1], [0, 1], d3_interpolate, false);
};

As you can see, it returns a function, d3_scale_linear. That function takes 4 arguments, the first two are the default range and domain. Obviously, you can change both the range and the domain later, as you did.

If you look at d3_scale_linear, you'll see that it returns this function:

function rescale() {
    var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear,
        uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber;
    output = linear(domain, range, uninterpolate, interpolate);
    input = linear(range, domain, uninterpolate, d3_interpolate);
    return scale;
}

Which by its turn returns this function:

function scale(x) {
    return output(x);
}

And that x is the argument that you pass to the scale when you use it, like x(d.x) in your example. The passed argument is d.x.

Just for completeness, the output function depends on either d3_scale_polylinear or d3_scale_bilinear, which are the functions that perform the real job:

function d3_scale_bilinear(domain, range, uninterpolate, interpolate) {
    var u = uninterpolate(domain[0], domain[1]),
        i = interpolate(range[0], range[1]);
    return function(x) {
        return i(u(x));
    };
}

function d3_scale_polylinear(domain, range, uninterpolate, interpolate) {
    var u = [],
        i = [],
        j = 0,
        k = Math.min(domain.length, range.length) - 1;
    if (domain[k] < domain[0]) {
        domain = domain.slice().reverse();
        range = range.slice().reverse();
    }
    while (++j <= k) {
        u.push(uninterpolate(domain[j - 1], domain[j]));
        i.push(interpolate(range[j - 1], range[j]));
    }
    return function(x) {
        var j = d3.bisect(domain, x, 1, k) - 1;
        return i[j](u[j](x));
    };
}


来源:https://stackoverflow.com/questions/58878296/why-can-i-input-an-argument-on-a-scale

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!