我已经实现了一个基本上工作正常的条形图。但是,在条形图上放置标签时,我注意到前两个条形图的标签未显示在它们各自的矩形上方。附加 <text>
我绑定(bind)与 <rect>
相同的数据集的元素元素。
g.selectAll("text")
.data(dataset) // same dataset for the texts as for the bars
.enter()
.append("text")
// ...more styling...
但是,虽然显示了所有条形,但缺少前两个矩形的标签。看看下面的演示,它显示了问题:
const dataset=[
{
"Month": "2013_09",
"Count": 1
},
{
"Month": "2013_10",
"Count": 291
},
{
"Month": "2013_11",
"Count": 763
},
{
"Month": "2013_12",
"Count": 853
}
];
dataset.forEach(d=>d.Count=+d.Count);
let margin={top:10,right:10,bottom:90,left:40};
let width= 600-margin.left-margin.right;
let height= 400-margin.top-margin.bottom;
const svg = d3.select(".div1")
.append("svg")
.attr("width", width+margin.left+margin.right)
.attr("height", height+margin.top+margin.bottom)
.attr("style", "outline: thin solid red;")
let g=svg.append("g")
.attr("transform","translate(" +margin.left+ ", " +margin.top+ ")");
g.append("text")
.attr("class","x label")
.attr("x", width/2)
.attr("y", height+76)
.attr("font-size","20px")
.attr("text-anchor","middle")
.text("Month")
g.append("text")
.attr("class","y label")
.attr("x", -height/2+50)
.attr("y", -40)
.attr("font-size","20px")
.attr("text-anchor","end")
.text("")
.attr("transform","rotate(-90)")
let x = d3.scaleBand()
.domain(dataset.map(d=>d.Month))
.range([0, width])
.paddingInner(0.3)
.paddingOuter(1)
let y = d3.scaleLinear()
.domain([0, d3.max(dataset,d=>d.Count)+80])
.range([height, 0]);
g.selectAll("text")
.data(dataset)
.enter()
.append("text")
.attr("font-size","11px")
.attr("text-anchor","middle")
.text((d) => d.Count)
.attr("y",d=>y(d.Count)-3)
.attr("x",(d)=>x(d.Month)+4);
let leftAxis=d3.axisLeft(y)
.ticks(8)
.tickFormat(d=>d);
g.append("g")
.attr("class","left axis")
.attr("transform","translate(0,0)")
.call(leftAxis)
let rects=g.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("y",d=>y(d.Count))
.attr("x",d=>x(d.Month))
.attr("width",x.bandwidth)
.attr("height",d=>height-y(d.Count))
.attr("fill","blue")
let bottomAxis=d3.axisBottom(x);
g.append("g")
.attr("class", "x axis")
.attr("transform","translate(0,"+height+")")
.call(bottomAxis)
.selectAll("text")
.attr("y","10")
.attr("x","-5")
.attr("text-anchor","end")
.attr("transform","rotate(-40)");
<script src="https://d3js.org/d3.v5.js"></script>
<div class="div1" ></div>
最佳答案
以下将标签附加到条形图的部分没有像您预期的那样工作:
g.selectAll("text")
.data(dataset)
.enter()
.append("text")
其实你之前已经追加了<text>
g
的元素元素,即轴的标签。以上选择将选择那些文本作为前两个元素。绑定(bind)数据时,这些元素已经存在,因此不属于输入选择的一部分。事实上,如果您使用浏览器的开发人员工具来检查,例如Month 标签你会发现一个 __data__
该元素上的属性表明数据已绑定(bind)到现有文本元素,这显然不是您想要的。
基本上有两种解决方法:
将轴的标签附加到另一组。这为轴、条和标签创建了不同的 DOM 子树,这在分离方面可能是一件好事。选择一个子树中的文本将找到另一个子树中包含的文本。
在为数据连接创建选择时使用更具体的选择器字符串。或者,使用
g.selectAll(null)
因为条上还没有标签。看看Selecting null: what is the reason behind 'selectAll(null)' in D3.js?解释为什么这是首选方式。
每种方法都能够自行解决您的问题。尽管如此,您可能需要考虑使用包含这两种方法的组合解决方案,因为这将使您的生活更轻松,因为它会为您的 SVG 创建更简洁的代码。
旁注:这适用于 <rect>
表示条形的元素,因为在进行该选择之前不存在任何矩形。尽管如此,选择您确定不存在的元素的首选和最惯用的方法是使用 d3.selectAll(null)
.
下面的演示展示了如何实现 2. 使其工作:
const dataset=[
{
"Month": "2013_09",
"Count": 1
},
{
"Month": "2013_10",
"Count": 291
},
{
"Month": "2013_11",
"Count": 763
},
{
"Month": "2013_12",
"Count": 853
}
];
dataset.forEach(d=>d.Count=+d.Count);
let margin={top:10,right:10,bottom:90,left:40};
let width= 600-margin.left-margin.right;
let height= 400-margin.top-margin.bottom;
const svg = d3.select(".div1")
.append("svg")
.attr("width", width+margin.left+margin.right)
.attr("height", height+margin.top+margin.bottom)
.attr("style", "outline: thin solid red;")
let g=svg.append("g")
.attr("transform","translate(" +margin.left+ ", " +margin.top+ ")");
g.append("text")
.attr("class","x label")
.attr("x", width/2)
.attr("y", height+76)
.attr("font-size","20px")
.attr("text-anchor","middle")
.text("Month")
g.append("text")
.attr("class","y label")
.attr("x", -height/2+50)
.attr("y", -40)
.attr("font-size","20px")
.attr("text-anchor","end")
.text("")
.attr("transform","rotate(-90)")
let x = d3.scaleBand()
.domain(dataset.map(d=>d.Month))
.range([0, width])
.paddingInner(0.3)
.paddingOuter(1)
let y = d3.scaleLinear()
.domain([0, d3.max(dataset,d=>d.Count)+80])
.range([height, 0]);
g.selectAll(null)
.data(dataset)
.enter()
.append("text")
.attr("font-size","11px")
.attr("text-anchor","middle")
.text((d) => d.Count)
.attr("y",d=>y(d.Count)-3)
.attr("x",(d)=>x(d.Month)+4);
let leftAxis=d3.axisLeft(y)
.ticks(8)
.tickFormat(d=>d);
g.append("g")
.attr("class","left axis")
.attr("transform","translate(0,0)")
.call(leftAxis)
let rects=g.selectAll(null)
.data(dataset)
.enter()
.append("rect")
.attr("y",d=>y(d.Count))
.attr("x",d=>x(d.Month))
.attr("width",x.bandwidth)
.attr("height",d=>height-y(d.Count))
.attr("fill","blue")
let bottomAxis=d3.axisBottom(x);
g.append("g")
.attr("class", "x axis")
.attr("transform","translate(0,"+height+")")
.call(bottomAxis)
.selectAll("text")
.attr("y","10")
.attr("x","-5")
.attr("text-anchor","end")
.attr("transform","rotate(-40)");
<script src="https://d3js.org/d3.v5.js"></script>
<div class="div1" ></div>
关于javascript - 为什么我的条形图的前两个文本标签没有显示?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57908130/