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



我是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对象中注册(这应该将新的选择值输入到图形中(。原因是如果我在unitMenu.on('change', ...)函数中return console.log("hello, world");,控制台上不会显示任何内容。任何帮助不胜感激:

// 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;});

不过,我会投票并检查解释为什么会这样......谢谢!!!

您的修复程序起作用的原因在这里:

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 选择,这是select中的option元素数组。当您在下拉列表中选择不同的元素时,这些项不会触发change事件。即使他们这样做了,这段代码也:

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

正在this中搜索select元素,对于事件侦听器,该元素是触发事件的元素。如果thisoption元素,则在其中找不到select元素!

您还可以通过将select元素分配给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);
});   

最新更新