如何使用匿名函数正确调用D3.js中的其他函数

时间:2019-08-19 13:14:12

标签: javascript d3.js anonymous-function

我正在尝试使用匿名函数来调用其他两个函数,但实际上无法使其正常工作。我在SO上关注了这个问题:nvm-sh/nvm Node Version Manager,但仍然无法解决问题。

理想的效果是我的条形图同时更改条形和颜色。这就是我正在尝试的:

我要调用的两个函数:

 function selectDataset(d) {
        let value = this.value;
        if (value == "total") {
            change(datasetTotal);
        } else if (value == "option1") {
            change(datasetOption1);
        } else if (value == "option2") {
            change(datasetOption2);
        }
    }

    function changeColor(d) {
         let value = this.value;
        if (value == "total") {
            d3.selectAll("rect")
                    .transition()
                    .duration(2000)
                    .style("fill", 'blue')
        } else if (value == "option1") {
            d3.selectAll("rect")
                    .transition()
                    .duration(2000)
                    .style("fill", 'red')
        } else if (value == "option2") {
           d3.selectAll("rect")
                    .transition()
                    .duration(2000)
                    .style("fill", 'yellow')
        }

    }

我的匿名功能:


    d3.selectAll("input").on("change", function(d) {
         selectDataset.call(this, d);
         changeColor.call(this, d);
        });


这是我的更改功能:

function change(dataset) {

        y.domain(dataset.map(function(d) {
            return d.label;
        }));
        x.domain([0, d3.max(dataset, function(d) {
            return d.value;
        })]);

        svg.select(".y.axis").remove();
        svg.select(".x.axis").remove();

        svg.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis);

        svg.append("g")
            .attr("class", "y axis")
            .call(yAxis)
            .append("text")
            .attr("transform", "rotate(0)")
            .attr("x", 50)
            .attr("dx", ".1em")
            .style("text-anchor", "end")
            .text("Option %");

        var bar = svg.selectAll(".bar")
            .data(dataset, function(d) {
                return d.label;
            });

        var barExit = bar.exit().remove();

        var barEnter = bar.enter()
                        .append("g")
                        .attr("class", "bar");

        var barRects = barEnter.append("rect")
            .attr("x", function(d) {
            return x(0);
        })
        .attr("y", function(d) {
            return y(d.label);
        })
        .attr("width", function(d) {
            return x(d.value);
        })
        .attr("height", y.bandwidth());

        var barTexts = barEnter.append("text")
            .attr("x", function(d) {
                return x(d.value) + 10;
            })
            .attr("y", function(d) {
                return y(d.label) + y.bandwidth() / 2;
            })
            .attr("dy", ".35em")
            .text(function(d) {
                return d.value;
            });

        var barRectUpdate = bar.select("rect")
            .transition()
            .duration(3050)
            .attr("x", function(d) {
            return x(0);
        })
        .attr("y", function(d) {
            return y(d.label);
        })
        .attr("width", function(d) {
            return x(d.value);
        })
        .attr("height", y.bandwidth());

        var barTextsUpdate = bar.select("text")
              .transition()
              .duration(3050)
              .attr("x", function(d) {
              return x(d.value) + 10;
            })
            .attr("y", function(d) {
                return y(d.label) + y.bandwidth() / 2;
            })
            .attr("dy", ".35em")
            .text(function(d) {
                return d.value;
            });
    };

我的图表

   var margin = {
            top: (parseInt(d3.select('.area-heat-cool').style('height'), 10) / 20),
            right: (parseInt(d3.select('.area-heat-cool').style('width'), 10) / 20),
            bottom: (parseInt(d3.select('.area-heat-cool').style('height'), 10) / 20),
            left: (parseInt(d3.select('.area-heat-cool').style('width'), 10) / 5)
        },
        width = parseInt(d3.select('.area-heat-cool').style('width'), 10) - margin.left - margin.right,
        height = parseInt(d3.select('.area-heat-cool').style('height'), 10) - margin.top - margin.bottom;

    var div = d3.select(".area-heat-cool").append("div").attr("class", "toolTip");

    var y = d3.scaleBand()
        .rangeRound([height, 0], .2, 0.5)
        .paddingInner(0.1);

    var x = d3.scaleLinear()
        .range([0, width]);

    var xAxis = d3.axisBottom()
        .scale(x);

    var yAxis = d3.axisLeft()
        .scale(y);

    var svg = d3.select(".area-heat-cool").append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    d3.select("input[value=\"total\"]").property("checked", true);
    change(datasetTotal);

数据集示例:

data1 = [{label: "example 1", value: 156}
{label: "example 2", value: 189}
{label: "example 3", value: 234}
{label: "example 4", value: 345}
{label: "example 5", value: 346}
{label: "example 6", value: 456}
{label: "example 7", value: 489}
{label: "example 8", value: 567}]; 


data2 = [{label: "example 1", value: 23}
{label: "example 2", value: 211}
{label: "example 3", value: 45}
{label: "example 4", value: 64}
{label: "example 5", value: 95}
{label: "example 6", value: 32}
{label: "example 7", value: 0}
{label: "example 8", value: 234}]; 

我的单选按钮:

<div class="area-heat-cool">
<form>
    <label><input type="radio" name="dataset" id="dataset" value="total" checked> Total</label>
    <label><input type="radio" name="dataset" id="dataset" value="option1"> Option 1</label>
    <label><input type="radio" name="dataset" id="dataset" value="option2"> Option 2</label>
</form>
</div>

当我这样做时,它以某种方式弄乱了我的数据。颜色会发生变化,但条形不再移到正确的位置。我没有抛出任何错误,但是行为不是预期的。

我正确使用此匿名函数吗?很感谢任何形式的帮助。提前谢谢

1 个答案:

答案 0 :(得分:1)

发生的事情是,您在触发事件时对rect元素应用了两个过渡。但是,这样做时,第二个过渡将覆盖第一个过渡。

然后在change函数中应用第一个过渡,您可以在其中更改rect元素的大小。当change函数返回时,您立即调用changeColor函数,该函数选择所有rect元素,并应用一个不同的过渡来更改rect元素的颜色。因此,颜色过渡会覆盖尺寸过渡。

要解决此问题,您可以将所有过渡都应用于同一元素。在我的示例中,我将把来自changeColor函数的代码放入change函数中。

首先,更改change函数声明以启用包括单选选择值:

function change(dataset, optionSelect) {
  // code not shown
}

然后,更新change中执行rect元素转换的代码:

var barRectUpdate = bar.select("rect")
  .transition()
  .duration(3050)
  .attr("x", function(d) {
    return x(0);
  })
  .attr("y", function(d) {
    return y(d.label);
  })
  .attr("width", function(d) {
    return x(d.value);
  })
  .attr("height", y.bandwidth())
  .style('fill', function () {
    if (optionSelect === "total") {
      return 'blue'
    } else if (optionSelect === "option1") {
      return 'red'
    } else if (optionSelect === "option2") {
      return 'yellow'
    }
  });

在调用selectDataset时更新change函数以包括单选选择值:

function selectDataset(d) {
  let value = this.value;
  if (value === "total") {
    change(datasetTotal, value);
  } else if (value === "option1") {
    change(datasetOption1, value);
  } else if (value === "option2") {
    change(datasetOption2, value);
  }
}

删除对changeColor函数的调用:

d3.selectAll("input").on("change", function(d) {
  selectDataset.call(this, d);
});

最后,完全删除changeColor函数。

需要考虑的其他几件事:

  • id属性应该是唯一的。现在,您所有的input元素都具有相同的ID。
  • 请考虑将selectDatasetchangeColor中的字符串值检查更改为===而不是==,以避免在比较值Difference between == and === in JavaScript时发生意外的类型转换
  • 如果以后不使用这些变量,则无需将所有D3操作存储在变量中。例如。 bar.select("rect")var barRectUpdate = bar.select("rect")一样好。

希望这会有所帮助!