简体   繁体   中英

Why must my D3 selection come before the D3 code itself?

I spent hours trying to figure out why my code was not working. I then arbitrarily moved my button code from after the D3 code (at the end between </script> and </body> ) to the top (between <script type="text/javascript"> and <body> ). It works now, but I don't know why. I don't want to make this mistake again or confuse myself in the future.

<body>
<button>Update</button> 

    <script type="text/javascript">

    var w = 500;
    var h = 500;
    var barPadding = 1;

    var dataset = [ ];

    for (var i = 0; i < 14; i++) {var newNumber = Math.round(Math.random() * 70);
    dataset.push(newNumber);}


    //Create SVG element
    var svg = d3.select("body")
            .append("svg")
            .attr("width", w)
            .attr("height", h);

    //Create Scales for Data conversion
    var xScale = d3.scale.linear()
                    .domain([0, d3.max(dataset, function(d,i) {return d;})]) //input
                    .range([0,w]); // output

    var yScale = d3.scale.ordinal()
                    .domain(d3.range(dataset.length))
                    .rangeRoundBands([0, h], 0.05);     //Vertical separation + barpadding

        svg.selectAll("rect")
            .data(dataset)
            .enter()
            .append("rect")
            .attr("x", 3)
            .attr("y", function (d,i) {return yScale(i);})
            .attr("width", function(d,i) {return xScale(d);})
            .attr("height", yScale.rangeBand())
            .attr("fill", function(d) {return "rgb(" + (d * 10) + ", 0,0 )";});

        svg.selectAll("text")
            .data(dataset)
            .enter()
            .append("text")
            .text(function(d) {return d;})
            .attr("x", function(d) {return xScale(d) -15;})
            .attr("y", function(d, i) {return yScale(i) +5 +yScale.rangeBand() / 2;})
            .attr("fill", "white")
            .attr("font-family", "sans-serif")
            .attr("text-anchor", "middle");


            //Create Data Update and transition
        d3.select("button")
            .on("click", function() {

            //New values for dataset
        dataset = [ ];

            for (var i = 0; i < 14; i++) {var newNumber = Math.round(Math.random() * 70);
                dataset.push(newNumber);}

            //Update all rects, and color gradient
        svg.selectAll("rect")
            .data(dataset)
            .transition()
            .attr("x", 3)
            .attr("width", function(d,i) {return xScale(d);})
            .attr("fill", function(d) {return "rgb(" + (d * 10) + ", 0,0 )";});

            //Update text label and position
        svg.selectAll("text")
            .data(dataset)
            .text(function(d) {return d;})
            .attr("x", function(d) {return xScale(d) -15;})
            .attr("y", function(d, i) {return yScale(i) +5 + yScale.rangeBand() / 2;});
    });


    </script>

    </body>

If you're saying that the code as shown in your question works, with the <button> element before the <script> element, it's because <script> elements are executed as the browser encounters them, top-to-bottom while parsing the page. Which means that any JavaScript that you use is only able to reference elements that are higher in the page source because the browser doesn't know about the later elements yet.

Unless you have code within functions that don't get called until after the DOM is complete, for example if you assign a DOM ready or onload event handler, or a delegated click handler or something.

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