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

Mic*_*gas 5 javascript anonymous-function d3.js

我试图使用匿名函数来调用其他两个函数,但无法真正使其工作。我关注了这个问题:Calling Two Functions on same click event with d3.js but still can't get it right。

期望的效果是我的条形图改变条形并同时改变颜色。这就是我正在尝试的:

我想调用的两个函数:

 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')
        }

    }

Run Code Online (Sandbox Code Playgroud)

我的匿名函数:


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


Run Code Online (Sandbox Code Playgroud)

这是我的更改功能:

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;
            });
    };
Run Code Online (Sandbox Code Playgroud)

我的图表

   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);
Run Code Online (Sandbox Code Playgroud)

数据集示例:

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}]; 

Run Code Online (Sandbox Code Playgroud)

还有我的单选按钮:

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

Run Code Online (Sandbox Code Playgroud)

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

我正确使用这个匿名函数吗?很感谢任何形式的帮助。预先非常感谢

mat*_*cks 3

发生的情况是您正在将两个转换应用到您的rect发生的情况是,您在触发事件时但是,执行此操作时,第二个转换会覆盖第一个转换。

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

要解决此问题,您可以将所有过渡应用到一个位置的相同元素。在我的示例中,我将把 ChangeColor 函数中的代码放入该change函数中。

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

function change(dataset, optionSelect) {
  // code not shown
}
Run Code Online (Sandbox Code Playgroud)

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'
    }
  });
Run Code Online (Sandbox Code Playgroud)

更新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);
  }
}
Run Code Online (Sandbox Code Playgroud)

删除对该changeColor函数的调用:

d3.selectAll("input").on("change", function(d) {
  selectDataset.call(this, d);
});
Run Code Online (Sandbox Code Playgroud)

最后,changeColor完全删除该功能。

还有其他一些需要考虑的事情:

  • id属性应该是唯一的。现在你的所有input元素都有相同的 id。
  • 考虑更改您的字符串值检查 inselectDatasetchangeColorto===而不是,==以避免在比较值时出现意外的类型转换:JavaScript 中 == 和 === 的区别
  • 当您以后不再使用这些变量时,无需将所有 D3 操作存储在变量中。例如bar.select("rect")将同样有效var barRectUpdate = bar.select("rect")

希望这可以帮助!