简体   繁体   中英

Modified object not indexing properly on mouse click function, javascript

I'm just learning javascript and I'm not sure how to finish this little challenge I've given myself. I'm looking for some help.

I went through this nice tutorial ( https://bost.ocks.org/mike/bar/2/ ), updated it to work with d3.v5, made the bars change color on mouseover, and now I want to change the text in the bars from the person's name (d.name) to the person's value (d.value) when you click the bar , not the text (got it working when you click the text). d.name and d.value are in a tsv file.

I've attached my code. The way I have it, when you click any bar the top bar switches the way I'd like instead of the bar clicked. It seems like the mousefunction isn't indexing the values. I'm not sure. Still trying to wrap my head around this. It's very different code thinking than I'm used to.

Thank you. ps if you know of any good reading resources to help, I would appreciate that too.

<!DOCTYPE html>
<meta charset="utf-8">

<style>
    .chart rect {
        fill: red;
    }

    .chart text {
        fill: green;
        font: 12px sans-serif;
        text-anchor: end;
    }

</style>

<svg class = "chart"></svg>
<script src="https://d3js.org/d3.v5.js" charset="utf-8"></script>

<script>
    var width = 420,
    barHeight = 20;

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

    var chart = d3.select(".chart") 
        .attr("width", width); 

    d3.tsv("data.tsv").then(function(data) { 

        data.forEach(function(d) {
            d.value = +d.value;
        });

        x.domain([0, d3.max(data, function(d) {return d.value; })]); 

        chart.attr("height", barHeight * data.length);

        var bar = chart.selectAll("g")
            .data(data) 
          .enter().append("g") 
            .attr("transform", function(d, i) {return "translate(0," + i * barHeight + ")";}); 

        bar.append("rect") 
            .attr("width", function(d) {return x(d.value); }) 
            .attr("height", barHeight - 1) 
            .on("mouseover", function () {d3.select(this).style("fill", "blue");})
            .on("mouseout", function () {d3.select(this).style("fill", "red");})
            .on("click", mousefunction);

        bar.append("text") 
            .attr("x", function(d) {return x(d.value) - 3; }) 
            .attr("y", barHeight / 2) 
            .attr("dy", ".35em") 
            .text(function(d) { return d.name; });

        function mousefunction() {
            d3.select("text")
                .text(function(d) { return d.value; });
        };

    }); 

</script>

When you do...

function mousefunction() {
    d3.select("text")
        .text(function(d) { return d.value; });
};

... you're telling D3 to select the first text it finds, no matter where you clicked.

Instead of that, select the text which is the next sibling of the rectangle (of course, provided that you append the rectangles and the texts in the order described in your snippet):

function mousefunction() {
    d3.select(this.nextSibling)
        .text(function(d) { return d.value; });
};

If you're not sure about the elements' order you can attach the event to the groups, not to the rectangles, and then you do:

function mousefunction() {
    d3.select(this).select("text")
        .text(function(d) { return d.value; });
};

This has the advantage of not depending on the relationship between rectangles and texts. However, the texts will also fire the function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM