代码之家  ›  专栏  ›  技术社区  ›  JdeMello

下拉选择后条形图未更新-d3.js

  •  0
  • JdeMello  · 技术社区  · 7 年前

    我对d3.js(和javascript一般来说)是新手,我不知道为什么我的图表在做了一个下拉选择之后没有改变。我相信在下拉选择中选择的值没有达到更新功能。感谢您的帮助。提前谢谢。。。

    html文件:

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8">
            <title>D3 chart bar with drop down menu</title>
            <script type="text/javascript" src="https://d3js.org/d3.v5.min.js"></script>
            <style type="text/css">
            </style>
        </head>
        <body>
            <div id = "container">
                    <div id = "dropdown"></div>
                    <div id = "graph"></div>
                    <script src ="bar.js"></script>
            </div>
        </body>
    </html> 
    

    如前所述,我最好的猜测是有东西没有注册在 unitMenu 对象(应该将新的选择值输入到图形中)。原因是如果我这么做 return console.log("hello, world"); 内部 unitMenu.on('change', ...) 控制台上没有显示任何功能。感谢您的帮助:

    // margins 
    var margin = {bottom: 30};
    
    // padding 
    var padding = 20;
    
    //Width and height
    var w = 600;
    var h = 250 - margin.bottom;
    
    // create svg 
    var svg = d3.select("#graph")
                .append("svg")
                .attr("width", w)
                .attr("height", h + margin.bottom);
    
    /* section 2: import csv data and draw elements*/
    // import csv data
    d3.csv("data.csv").then((data, error) => {
        if (error) throw error;
    
        // create objects that "live" outside the function that will create the initial graph...
        // formatting the loaded data can live outisde the graph funciton...
        //format data
        data.forEach((d) => {
            d.group = d.group;
            d.year = +d.year;
            d.value = +d.value;
        });
    
            // make an array with the unitoptions for dropdown menu
        unitOptions = data.map((a) => a.group).filter((item, i, ar) => {
            return ar.indexOf(item) == i;
        })
    
        // create dropwdown and populate menu
        var unitMenu = d3.select("#dropdown")
        .append("select")
        .selectAll("option")
            .data(unitOptions)
            .enter()
            .append("option")
            .attr("value", (d) => {return d;})
            .text((d) => {return d;});
    
        // function for the initial graph
        var initialGraph = function(unitSelected) {
    
            var selections = [unitSelected, "BASELINE"];
    
            barData  = data.filter(d => {return selections.includes(d.group);})
    
            // bar chart horizontal scale
            var xScale = d3.scaleBand()
            .domain(d3.range(barData.filter(d => {return d.group == unitSelected;}).length))
            .rangeRound([0, w])
            .paddingInner(0.05); // padding inner sets the outer padding to the specified value
    
            // bar chart vertical scale
            var yScale = d3.scaleLinear()
                .domain([0, d3.max(barData, d => {return d.value;})])
                .range([padding, h - padding]);
    
            // there is only a bottom axis with the tick labels for the years displayed
            var xAxis = d3.axisBottom(xScale)
                .tickFormat(function(d,i){return i;})// very important function, tickFormat allow us to relabel ticks...
                .tickSize([0,0]); // approximate labels and bars...
    
            // draw bottom axis
            svg.append("g")
            .attr("class", "axis")
            .attr("transform", "translate(0, " + (h + margin.bottom * 1/10) + ")")
            .style("font-size", "12px")
            .call(xAxis)
            .selectAll("path, line").remove();
    
            //Create bars
            svg.selectAll("rect")
            .data(barData.filter(d => {return d.group == unitSelected;}))
            .enter()
            .append("rect")
            .attr("x", function(d, i) {
                    return xScale(i);
            })
            .attr("y", function(d) {
                    return h - yScale(d.value);
            })
            .attr("width", xScale.bandwidth())
            .attr("height", function(d) {
                    return yScale(d.value);
            })
            .attr("fill", "hotpink");
    
            // add labels to bars
            svg.selectAll(".textBar")
            .data(barData.filter(d => {return d.group == unitSelected;}))
            .enter()
            .append("text")
            .text(d => {
                x = d.value * 100;
                x = +x.toFixed(1);
                return x + "%";                   
            })
            .attr("text-anchor", "middle")
            .attr("x", (d, i) => {
                return xScale(i) + xScale.bandwidth() / 2;
            })
            .attr("y", (d) => {
            if(h - yScale(d.value) + 0.05*h > h - 0.08*h + 0.05*h){
                return h - yScale(d.value) - 0.02*h;
            } else {
                return h - yScale(d.value) + 0.05*h;    
            };                   
            })
            .attr("font-size", "11px")
            .attr("fill", function(d){
            if(h - yScale(d.value) + 0.05*h > h - 0.08*h + 0.05*h){
                return "black";
            } else {
                return "white";    
            };
            })
            .attr("font-weight", "bold");
    
            // draw comparator
            svg.selectAll(".point")
            .data(barData.filter(d => {return d.group == "BASELINE";}))
            .enter()
            .append("path")
            .attr("class", "point")
            .attr("fill", "steelblue")
            .attr("stroke", "black")
            .attr("stroke-width", "0.5")
            .attr("d", d3.symbol().type(d3.symbolCross))
            .attr("transform", function(d, i) {return "translate(" + 
            (xScale(d.year - 1) + (xScale.bandwidth() / 2)) + "," + (h - yScale(d.value)) + ")";});      
    
        };
    
        initialGraph("A");
    
        // function that updates data and graph
        var updateGraph = function(unitSelected) {
    
            // filter the data to include only the unit of interest
            // selection of baseline and comparator
            var selections = [unitSelected, "BASELINE"]; // notice that hte baseline is fixed (for now!!)
    
            // dataset for bars
            barData  = data.filter(d => {return selections.includes(d.group);})
    
            // update rect
            svg.selectAll("rect")
            .data(barData.filter(d => {return d.group == unitSelected;}))
            .transition()
            .duration(1000)
            .attr("x", function(d, i) {
                return xScale(i);
            })
            .attr("y", function(d) {
                    return h - yScale(d.value);
            })
            .attr("width", xScale.bandwidth())
            .attr("height", function(d) {
                    return yScale(d.value);
            })
            .exit().remove();
    
            // update labels
            svg.selectAll(".textBar")
            .data(barData.filter(d => {return d.group == unitSelected;}))
            .transition()
            .duration(1000)
            .text(function(d) {
                x = d.value * 100;
                x = +x.toFixed(1);
                return x + "%";                   
            })
            .attr("x", function(d, i) {
                return xScale(i) + xScale.bandwidth() / 2;
            })
            .attr("y", function(d) {
            if(h - yScale(d.value) + 0.05*h > h - 0.08*h + 0.05*h){
                return h - yScale(d.value) - 0.02*h;
            } else {
                return h - yScale(d.value) + 0.05*h;    
            };                   
            })
            .attr("fill", function(d){
                if(h - yScale(d.value) + 0.05*h > h - 0.08*h + 0.05*h){
                    return "black";
                } else {
                    return "white";    
                };
                });    
       };
    
        unitMenu.on('change', function() {
    
            // find which unit was selected from the dropdown
            var selectedUnit = d3.select(this)
                .select("select")
                .property("value");
    
            // run update with selected unit
            updateGraph(selectedUnit);
    
       });   
    });
    

    数据:

    group,year,value
    A,1,0.830798527
    A,2,0.14806798
    B,1,0.248585574
    B,2,0.902224423
    C,1,0.386217747
    C,2,0.526020182
    D,1,0.951627372
    D,2,0.936993723
    BASELINE,1,0.564061688
    BASELINE,2,0.337876435
    

    ***更新:已解决***

    好吧,我坚持了下来,发现了错误。。。

    这个街区。。。

    var unitMenu = d3.select("#dropdown")
    .append("select")
    .selectAll("option")
        .data(unitOptions)
        .enter()
        .append("option")
        .attr("value", (d) => {return d;})
        .text((d) => {return d;});
    

    应该是。。。

    var unitMenu = d3.select("#dropdown")
    
    unitMenu.append("select")
        .selectAll("option")
            .data(unitOptions)
            .enter()
            .append("option")
            .attr("value", (d) => {return d;})
            .text((d) => {return d;});
    

    尽管如此,我还是会投票并检查解释为什么会这样的答案。。。谢谢!!!

    1 回复  |  直到 7 年前
        1
  •  1
  •   i alarmed alien    7 年前

    修复工作的原因如下:

    unitMenu.on('change', function() {
    
        // find which unit was selected from the dropdown
        var selectedUnit = d3.select(this)
            .select("select")
            .property("value");
    
        // run update with selected unit
        updateGraph(selectedUnit);
    
    });   
    

    你正在连接 change 事件侦听器 div 包含更正版本中的下拉列表,而以前,它附加到数据绑定调用中的enter选择,即 option 内部元素 select 改变

        var selectedUnit = d3.select(this)
            .select("select")
            .property("value");
    

    正在寻找一个 选择 内的元素 this 是一个 选项 元素,没有 要在其中找到的元素!

    您还可以通过分配 选择 元素到 unitMenu 然后修改处理事件的代码:

    var unitMenu = d3.select("#dropdown")
    .append("select");
    
    unitMenu
    .selectAll("option")
        .data(unitOptions)
        .enter()
        .append("option")
        .attr("value", (d) => {return d;})
        .text((d) => {return d;});
    
    [...]
    
    unitMenu.on('change', function() {
        var selectedUnit = d3.select(this)  // this is the select element
            .property("value");
    
        updateGraph(selectedUnit);
    });