D3图表图例标签重叠
Posted
技术标签:
【中文标题】D3图表图例标签重叠【英文标题】:D3 Chart Legend Labels getting overlapped 【发布时间】:2019-05-11 00:55:32 【问题描述】:我的应用程序中有一个折线图,它在图表下方有一个图例。问题是当我在折线图中显示的线条数量增加时,图例中的标签彼此重叠。有没有办法解决这个问题。也许将重叠文本发送到新行或任何解决此问题的方法?
我的示例代码在这里:https://jsfiddle.net/yasirunilan/rzc71jkq/3/
var data = [
name: "USA",
values: [
date: "2000",
price: "100"
,
date: "2001",
price: "110"
,
date: "2002",
price: "145"
,
date: "2003",
price: "241"
,
date: "2004",
price: "101"
,
date: "2005",
price: "90"
,
date: "2006",
price: "10"
,
date: "2007",
price: "35"
,
date: "2008",
price: "21"
,
date: "2009",
price: "201"
]
,
name: "Canada",
values: [
date: "2000",
price: "100"
,
date: "2001",
price: "110"
,
date: "2002",
price: "145"
,
date: "2003",
price: "241"
,
date: "2004",
price: "101"
,
date: "2005",
price: "90"
,
date: "2006",
price: "10"
,
date: "2007",
price: "35"
,
date: "2008",
price: "21"
,
date: "2009",
price: "201"
]
,
name: "Maxico",
values: [
date: "2000",
price: "100"
,
date: "2001",
price: "110"
,
date: "2002",
price: "145"
,
date: "2003",
price: "241"
,
date: "2004",
price: "101"
,
date: "2005",
price: "90"
,
date: "2006",
price: "10"
,
date: "2007",
price: "35"
,
date: "2008",
price: "21"
,
date: "2009",
price: "201"
]
,
name: "India",
values: [
date: "2000",
price: "100"
,
date: "2001",
price: "110"
,
date: "2002",
price: "145"
,
date: "2003",
price: "241"
,
date: "2004",
price: "101"
,
date: "2005",
price: "90"
,
date: "2006",
price: "10"
,
date: "2007",
price: "35"
,
date: "2008",
price: "21"
,
date: "2009",
price: "201"
]
,
name: "Russia",
values: [
date: "2000",
price: "100"
,
date: "2001",
price: "110"
,
date: "2002",
price: "145"
,
date: "2003",
price: "241"
,
date: "2004",
price: "101"
,
date: "2005",
price: "90"
,
date: "2006",
price: "10"
,
date: "2007",
price: "35"
,
date: "2008",
price: "21"
,
date: "2009",
price: "201"
]
,
name: "Japan",
values: [
date: "2000",
price: "100"
,
date: "2001",
price: "110"
,
date: "2002",
price: "145"
,
date: "2003",
price: "241"
,
date: "2004",
price: "101"
,
date: "2005",
price: "90"
,
date: "2006",
price: "10"
,
date: "2007",
price: "35"
,
date: "2008",
price: "21"
,
date: "2009",
price: "201"
]
,
name: "Malaysia",
values: [
date: "2000",
price: "100"
,
date: "2001",
price: "110"
,
date: "2002",
price: "145"
,
date: "2003",
price: "241"
,
date: "2004",
price: "101"
,
date: "2005",
price: "90"
,
date: "2006",
price: "10"
,
date: "2007",
price: "35"
,
date: "2008",
price: "21"
,
date: "2009",
price: "201"
]
,
name: "Korea",
values: [
date: "2000",
price: "100"
,
date: "2001",
price: "110"
,
date: "2002",
price: "145"
,
date: "2003",
price: "241"
,
date: "2004",
price: "101"
,
date: "2005",
price: "90"
,
date: "2006",
price: "10"
,
date: "2007",
price: "35"
,
date: "2008",
price: "21"
,
date: "2009",
price: "201"
]
,
name: "South Africa",
values: [
date: "2000",
price: "100"
,
date: "2001",
price: "110"
,
date: "2002",
price: "145"
,
date: "2003",
price: "241"
,
date: "2004",
price: "101"
,
date: "2005",
price: "90"
,
date: "2006",
price: "10"
,
date: "2007",
price: "35"
,
date: "2008",
price: "21"
,
date: "2009",
price: "201"
]
];
var width = 500;
var height = 300;
var margin = 50;
var duration = 250;
var lineOpacity = "0.25";
var lineOpacityHover = "0.85";
var otherLinesOpacityHover = "0.1";
var lineStroke = "1.5px";
var lineStrokeHover = "2.5px";
var circleOpacity = '0.85';
var circleOpacityOnLineHover = "0.25"
var circleRadius = 3;
var circleRadiusHover = 6;
/* Format Data */
var parseDate = d3.timeParse("%Y");
data.forEach(function(d)
d.values.forEach(function(d)
d.date = parseDate(d.date);
d.price = +d.price;
);
);
/* Scale */
var xScale = d3.scaleTime()
.domain(d3.extent(data[0].values, d => d.date))
.range([0, width - margin]);
var yScale = d3.scaleLinear()
.domain([0, d3.max(data[0].values, d => d.price)])
.range([height - margin, 0]);
var color = d3.scaleOrdinal(d3.schemeCategory10);
/* Add SVG */
var svg = d3.select("#chart").append("svg")
.attr("width", (width + margin) + "px")
.attr("height", (height + margin) + "px")
.append('g')
.attr("transform", `translate($margin, $margin)`);
/* Add line into SVG */
var line = d3.line()
.x(d => xScale(d.date))
.y(d => yScale(d.price));
let lines = svg.append('g')
.attr('class', 'lines');
lines.selectAll('.line-group')
.data(data).enter()
.append('g')
.attr('id',function(d) return d.name.replace(/\s+/g, '')+"-line"; )
.attr('class', 'line-group')
.on("mouseover", function(d, i)
svg.append("text")
.attr("class", "title-text")
.style("fill", color(i))
.text(d.name)
.attr("text-anchor", "middle")
.attr("x", (width - margin) / 2)
.attr("y", 5);
)
.on("mouseout", function(d)
svg.select(".title-text").remove();
)
.append('path')
.attr('class', 'line')
.attr('d', d => line(d.values))
.style('stroke', (d, i) => color(i))
.style('opacity', lineOpacity)
.on("mouseover", function(d)
d3.selectAll('.line')
.style('opacity', otherLinesOpacityHover);
d3.selectAll('.circle')
.style('opacity', circleOpacityOnLineHover);
d3.select(this)
.style('opacity', lineOpacityHover)
.style("stroke-width", lineStrokeHover)
.style("cursor", "pointer");
)
.on("mouseout", function(d)
d3.selectAll(".line")
.style('opacity', lineOpacity);
d3.selectAll('.circle')
.style('opacity', circleOpacity);
d3.select(this)
.style("stroke-width", lineStroke)
.style("cursor", "none");
);
/* Add circles in the line */
lines.selectAll("circle-group")
.data(data).enter()
.append("g")
.attr('id',function(d) return d.name.replace(/\s+/g, '')+"-circle"; )
.style("fill", (d, i) => color(i))
.selectAll("circle")
.data(d => d.values).enter()
.append("g")
.attr("class", "circle")
.on("mouseover", function(d)
d3.select(this)
.style("cursor", "pointer")
.append("text")
.attr("class", "text")
.text(`$d.price`)
.attr("x", d => xScale(d.date) + 5)
.attr("y", d => yScale(d.price) - 10);
)
.on("mouseout", function(d)
d3.select(this)
.style("cursor", "none")
.transition()
.duration(duration)
.selectAll(".text").remove();
)
.append("circle")
.attr("cx", d => xScale(d.date))
.attr("cy", d => yScale(d.price))
.attr("r", circleRadius)
.style('opacity', circleOpacity)
.on("mouseover", function(d)
d3.select(this)
.transition()
.duration(duration)
.attr("r", circleRadiusHover);
)
.on("mouseout", function(d)
d3.select(this)
.transition()
.duration(duration)
.attr("r", circleRadius);
);
/* Add Axis into SVG */
var xAxis = d3.axisBottom(xScale).ticks(5);
var yAxis = d3.axisLeft(yScale).ticks(5);
svg.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, $height-margin)`)
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append('text')
.attr("y", 15)
.attr("transform", "rotate(-90)")
.attr("fill", "#000")
.text("Total values");
var dataNest = d3.nest()
.key(function(d)
return d.name;
)
.entries(data);
var legendSpace = width / dataNest.length;
// Loop through each symbol / key
dataNest.forEach(function(d, i)
// Add the Legend
svg.append("text")
.attr("x", (legendSpace / 2) + i * legendSpace) // space legend
.attr("y", height)
.attr("class", "legend") // style the legend
.style("fill", color(i))
.on("click", function()
// Determine if current line is visible
var active = d.active ? false : true,
newOpacity = active ? 0 : 1;
// Hide or show the elements based on the ID
d3.select("#" + d.key.replace(/\s+/g, '') + "-line")
.transition().duration(100)
.style("opacity", newOpacity);
d3.select("#" + d.key.replace(/\s+/g, '') + "-circle")
.transition().duration(100)
.style("opacity", newOpacity);
// Update whether or not the elements are active
d.active = active;
)
.text(d.key);
);
【问题讨论】:
图表右侧(或左侧)的垂直图例怎么样? 你能给我一个示例代码吗@Zim 【参考方案1】:您应该使用.data()
连接,而不是在 for 循环中附加元素。
我们可以在data()
中映射像这样的data.map(d => d.name)
的图例键。
我们可以将font
元素附加到正文,而不是将text
元素附加到svg,这样文本会自行对齐而不会重叠
这是我所做的所有更改:
var keys = []
// Add the Legend
var legend = d3.select("body").selectAll(".legend")
.data(data.map(d => d.name))
.enter().append("font")
.attr("class", "legend") // style the legend
.style("color", color)
.style("margin-left", 10 + "px")
.style("padding-left", 10 + "px")
.html(d => d)
d3.selectAll(".legend")
.on("click", function(d)
keys.includes(d)
? keys.splice(keys.indexOf(d), 1)
: keys.push(d)
d3.select(this).style("opacity", () => keys.includes(d) ? .5 : 1)
d3.select("#" + d.replace(/\s+/g, '') + "-line")
.transition().duration(100)
.style("opacity", () => keys.includes(d) ? 0 : 1);
d3.select("#" + d.replace(/\s+/g, '') + "-circle")
.transition().duration(100)
.style("opacity", () => keys.includes(d) ? 0 : 1);
)
但正如 Zim 提到的,我也将其垂直放置,但这更多的是设计问题,而不是代码相关问题。
这是一个叉子:https://jsfiddle.net/apn8b5my/
【讨论】:
以上是关于D3图表图例标签重叠的主要内容,如果未能解决你的问题,请参考以下文章