javascript - D3 图表图例标签重叠

标签 javascript d3.js legend linechart

我的应用程序中有一个折线图,图表下方有一个图例。问题是当我在折线图中显示的线数增加时,图例中的标签相互重叠。有没有办法解决这个问题。也许将重叠的文本发送到新行或任何解决此问题的方法?

我的示例代码在这里: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);
});

最佳答案

您应该使用 .data() 连接,而不是在 for 循环中附加元素。

我们可以在 data() 中映射像这样的 data.map(d => d.name) 的图例键。

我们可以将 font 元素附加到 body 中,而不是将 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 提到的,我也会将其垂直放置,但这更多是设计问题而不是代码相关。

这是一个 fork :https://jsfiddle.net/apn8b5my/

关于javascript - D3 图表图例标签重叠,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53700338/

相关文章:

javascript - ngFor 与 JSON 对象 - Angular 2 ngmodel 视角

javascript - 使用 Angular 和 Node 进行路由

javascript - D3——嵌套饼图不显示所有楔形

javascript - D3 意外值转换,不接受变量

r - ggplot 图例中的虚线

javascript - React Redux 通过函数从子组件向父组件传递参数

javascript - 使用 Dimple.js 渲染图表时出现问题

python - 让图例对应于 Pandas/PyPlot 中的 y 值

Javascript/jQuery 图例小部件

javascript - 通过 ajax 调用在 XML 文件中输出注释