【问题标题】:Show values for half donut pie chart in D3 JS在 D3 JS 中显示半甜甜圈饼图的值
【发布时间】:2019-01-08 20:37:18
【问题描述】:

我正在尝试使用 D3 JS 在半圆环饼图中显示带有其值和工具提示的标签。 我无法同时显示标签及其值。 以及如何在此图表上添加工具提示?

我尝试实现这个小提琴。 https://jsfiddle.net/SampathPerOxide/hcvuqjt2/6/

var width = 400;
var height = 300; //this is the double because are showing just the half of the pie
var radius = Math.min(width, height) / 2;

var labelr = radius + 30; // radius for label anchor
//array of colors for the pie (in the same order as the dataset)
var color = d3.scale
  .ordinal()
  .range(['#2b5eac', '#0dadd3', '#ffea61', '#ff917e', '#ff3e41']);

data = [
  { label: 'CDU', value: 10 },
  { label: 'SPD', value: 15 },
  { label: 'Die Grünen', value: 8 },
  { label: 'Die Mitte', value: 1 },
  { label: 'Frei Wähler', value: 3 }
];

var vis = d3
  .select('#chart')
  .append('svg') //create the SVG element inside the <body>
  .data([data]) //associate our data with the document
  .attr('width', width) //set the width and height of our visualization (these will be attributes of the <svg> tag
  .attr('height', height)
  .append('svg:g') //make a group to hold our pie chart
  .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')'); //move the center of the pie chart from 0, 0 to radius, radius

var arc = d3.svg
  .arc() //this will create <path> elements for us using arc data
  .innerRadius(79)
  //                                .outerRadius(radius);
  .outerRadius(radius - 10); // full height semi pie
//.innerRadius(0);

var pie = d3.layout
  .pie() //this will create arc data for us given a list of values
  .startAngle(-90 * (Math.PI / 180))
  .endAngle(90 * (Math.PI / 180))
  .padAngle(0.02) // some space between slices
  .sort(null) //No! we don't want to order it by size
  .value(function(d) {
    return d.value;
  }); //we must tell it out to access the value of each element in our data array

var arcs = vis
  .selectAll('g.slice') //this selects all <g> elements with class slice (there aren't any yet)
  .data(pie) //associate the generated pie data (an array of arcs, each having startAngle, endAngle and value properties)
  .enter() //this will create <g> elements for every "extra" data element that should be associated with a selection. The result is creating a <g> for every object in the data array
  .append('svg:g') //create a group to hold each slice (we will have a <path> and a <text> element associated with each slice)
  .attr('class', 'slice'); //allow us to style things in the slices (like text)

arcs
  .append('svg:path')
  .attr('fill', function(d, i) {
    return color(i);
  }) //set the color for each slice to be chosen from the color function defined above
  .attr('d', arc); //this creates the actual SVG path using the associated data (pie) with the arc drawing function

arcs
  .append('svg:text')
  .attr('class', 'labels') //add a label to each slice
  .attr('fill', 'grey')
  .attr('transform', function(d) {
    var c = arc.centroid(d),
      xp = c[0],
      yp = c[1],
      // pythagorean theorem for hypotenuse
      hp = Math.sqrt(xp * xp + yp * yp);
    return 'translate(' + (xp / hp) * labelr + ',' + (yp / hp) * labelr + ')';
  })
  .attr('text-anchor', 'middle') //center the text on it's origin
  .text(function(d, i) {
    return data[i].value;
  })
  .text(function(d, i) {
    return data[i].label;
  }); //get the label from our original data array

我正在努力实现这一目标。 https://i.imgur.com/kTXeAXt.png

【问题讨论】:

  • 嘿@sampath,我有完全相同的要求。我需要在半圆形甜甜圈图中显示几个值。我正在使用 nvd3 和 Angular5。你能解决这个问题吗(如果是,你能帮我吗)。下面给出的答案不包括图表内的“12345文本”。

标签: javascript html css d3.js svg


【解决方案1】:

首先,如果你控制台记录你用于显示文本标签和值的数据(来自.data(pie)),你会注意到标签只能通过d.data.label而不是data[i].label访问。

{data: {label: "Frei Wähler", value: 3}, value: 3, startAngle: 1.304180706233562, endAngle: 1.5707963267948966, padAngle: 0.02}

因此为了正确显示标签和值,代码应该是:

arcs.append("svg:text")      
    .attr("class", "labels")//add a label to each slice
    .attr("fill", "grey")
    .attr("transform", function(d) {
        var c = arc.centroid(d),
        xp = c[0],
        yp = c[1],
        // pythagorean theorem for hypotenuse
        hp = Math.sqrt(xp*xp + yp*yp);
        return "translate(" + (xp/hp * labelr) +  ',' +
          (yp/hp * labelr) +  ")"; 
     })
    .attr("text-anchor", "middle")    //center the text on it's origin
    .text(function(d, i) { return d.data.value; })
    .text(function(d, i) { return d.data.label; });  

如何添加工具提示

至于如何创建d3 tooltip,需要一点css、html然后添加d3事件处理。

1) 将以下 html 添加到您的 index.html:

 <div id="tooltip" class="hidden"><p id="tooltip-data"></p></div>

2) 添加一点 css 将 div 设置为 position:absolute 并使用 display:none 隐藏工具提示,并根据您的喜好给它一点样式:

<style>
  #tooltip {
    position:absolute;
    background: #ffffe0;
    color: black;
    width: 180px;
    border-radius: 3px;
    box-shadow: 2px 2px 6px rgba(40, 40, 40, 0.5);
  }
  #tooltip.hidden {
    display:none;
  }
  #tooltip p {
    margin: 0px;
    padding: 8px;
    font-size: 12px;
  }

3) 然后我们添加mouseover 事件处理程序,想法是当鼠标在图表上时,我们将#tooltip css 样式的topleft 属性设置为鼠标所在的位置,并设置 css display 属性以显示工具提示。

//tooltip
arcs.on("mouseover", function(d) {
  d3.select("#tooltip")
    .style("left", `${d3.event.clientX}px`)
    .style("top", `${d3.event.clientY}px`)
    .classed("hidden", false);
  d3.select("#tooltip-data")
    .html(`Label: ${d.data.label}<br>Value: ${d.data.value}`);
});

arcs.on("mouseout", function(d) {
  d3.select("#tooltip")
    .classed("hidden", true);
});

【讨论】:

    【解决方案2】:

    selection.text([value])

    如果指定了值,则将所有选定元素的文本内容设置为指定值,替换任何现有的子元素。

    因此,您使用value 设置文本内容并立即将其替换为label.

    您可以做的是从template literal 中的数据的valuelabel 返回一个组合字符串,如下所示:

    .text(function(d, i) { return `${data[i].value} - ${data[i].label}`; })
    

    var width = 400;
    var height = 300; //this is the double because are showing just the half of the pie
    var radius = Math.min(width, height) / 2;
    
    var labelr = radius + 30; // radius for label anchor
    //array of colors for the pie (in the same order as the dataset)
    var color = d3.scale.ordinal()
      .range(['#2b5eac', '#0dadd3', '#ffea61', '#ff917e', '#ff3e41']);
    
    data = [{
        label: 'CDU',
        value: 10
      },
      {
        label: 'SPD',
        value: 15
      },
      {
        label: 'Die Grünen',
        value: 8
      },
      {
        label: 'Die Mitte',
        value: 1
      },
      {
        label: 'Frei Wähler',
        value: 3
      }
    ];
    
    var vis = d3.select("#chart")
      .append("svg") //create the SVG element inside the <body>
      .data([data]) //associate our data with the document
      .attr("width", width) //set the width and height of our visualization (these will be attributes of the <svg> tag
      .attr("height", height)
      .append("svg:g") //make a group to hold our pie chart
      .attr('transform', 'translate(' + (width / 2) + ',' + (height / 2) + ')'); //move the center of the pie chart from 0, 0 to radius, radius
    
    var arc = d3.svg.arc() //this will create <path> elements for us using arc data
      .innerRadius(79)
      //  								.outerRadius(radius);
      .outerRadius(radius - 10) // full height semi pie
    //.innerRadius(0);
    
    
    var pie = d3.layout.pie() //this will create arc data for us given a list of values
      .startAngle(-90 * (Math.PI / 180))
      .endAngle(90 * (Math.PI / 180))
      .padAngle(.02) // some space between slices
      .sort(null) //No! we don't want to order it by size
      .value(function(d) {
        return d.value;
      }); //we must tell it out to access the value of each element in our data array
    
    var arcs = vis.selectAll("g.slice") //this selects all <g> elements with class slice (there aren't any yet)
      .data(pie) //associate the generated pie data (an array of arcs, each having startAngle, endAngle and value properties) 
      .enter() //this will create <g> elements for every "extra" data element that should be associated with a selection. The result is creating a <g> for every object in the data array
      .append("svg:g") //create a group to hold each slice (we will have a <path> and a <text> element associated with each slice)
      .attr("class", "slice"); //allow us to style things in the slices (like text)
    
    arcs.append("svg:path")
      .attr("fill", function(d, i) {
        return color(i);
      }) //set the color for each slice to be chosen from the color function defined above
      .attr("d", arc); //this creates the actual SVG path using the associated data (pie) with the arc drawing function
    
    arcs.append("svg:text")
      .attr("class", "labels") //add a label to each slice
      .attr("fill", "grey")
      .attr("transform", function(d) {
        var c = arc.centroid(d),
          xp = c[0],
          yp = c[1],
          // pythagorean theorem for hypotenuse
          hp = Math.sqrt(xp * xp + yp * yp);
        return "translate(" + (xp / hp * labelr) + ',' +
          (yp / hp * labelr) + ")";
      })
      .attr("text-anchor", "middle") //center the text on it's origin
      .text(function(d, i) {
        return `${data[i].value} - ${data[i].label}`;
      });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
    <div id="chart" style="width: 330px;height: 200px;"></div>

    编辑:

    如果您希望两个文本字符串位于不同的行上,则必须附加一些 &lt;tspan&gt; 元素并定位它们。

    var width = 400;
    var height = 300; //this is the double because are showing just the half of the pie
    var radius = Math.min(width, height) / 2;
    
    var labelr = radius + 30; // radius for label anchor
    //array of colors for the pie (in the same order as the dataset)
    var color = d3.scale.ordinal()
      .range(['#2b5eac', '#0dadd3', '#ffea61', '#ff917e', '#ff3e41']);
    
    data = [{
        label: 'CDU',
        value: 10
      },
      {
        label: 'SPD',
        value: 15
      },
      {
        label: 'Die Grünen',
        value: 8
      },
      {
        label: 'Die Mitte',
        value: 1
      },
      {
        label: 'Frei Wähler',
        value: 3
      }
    ];
    
    var vis = d3.select("#chart")
      .append("svg") //create the SVG element inside the <body>
      .data([data]) //associate our data with the document
      .attr("width", width) //set the width and height of our visualization (these will be attributes of the <svg> tag
      .attr("height", height)
      .append("svg:g") //make a group to hold our pie chart
      .attr('transform', 'translate(' + (width / 2) + ',' + (height / 2) + ')'); //move the center of the pie chart from 0, 0 to radius, radius
    
    var arc = d3.svg.arc() //this will create <path> elements for us using arc data
      .innerRadius(79)
      //  								.outerRadius(radius);
      .outerRadius(radius - 10) // full height semi pie
    //.innerRadius(0);
    
    
    var pie = d3.layout.pie() //this will create arc data for us given a list of values
      .startAngle(-90 * (Math.PI / 180))
      .endAngle(90 * (Math.PI / 180))
      .padAngle(.02) // some space between slices
      .sort(null) //No! we don't want to order it by size
      .value(function(d) {
        return d.value;
      }); //we must tell it out to access the value of each element in our data array
    
    var arcs = vis.selectAll("g.slice") //this selects all <g> elements with class slice (there aren't any yet)
      .data(pie) //associate the generated pie data (an array of arcs, each having startAngle, endAngle and value properties) 
      .enter() //this will create <g> elements for every "extra" data element that should be associated with a selection. The result is creating a <g> for every object in the data array
      .append("svg:g") //create a group to hold each slice (we will have a <path> and a <text> element associated with each slice)
      .attr("class", "slice"); //allow us to style things in the slices (like text)
    
    arcs.append("svg:path")
      .attr("fill", function(d, i) {
        return color(i);
      }) //set the color for each slice to be chosen from the color function defined above
      .attr("d", arc); //this creates the actual SVG path using the associated data (pie) with the arc drawing function
    
    const textEl = arcs.append("svg:text")
      .attr("class", "labels") //add a label to each slice
      .attr("fill", "grey")
      .attr("transform", function(d) {
        var c = arc.centroid(d),
          xp = c[0],
          yp = c[1],
          // pythagorean theorem for hypotenuse
          hp = Math.sqrt(xp * xp + yp * yp);
        return "translate(" + (xp / hp * labelr) + ',' +
          (yp / hp * labelr) + ")";
      })
      .attr("text-anchor", "middle"); //center the text on it's origin
    
    textEl.append('tspan')
      .text(function(d, i) {
        return data[i].label;
      });
    
    textEl.append('tspan')
      .text(function(d, i) {
        return data[i].value;
      })
      .attr('x', '0')
      .attr('dy', '1.2em');
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
    <div id="chart" style="width: 330px;height: 200px;"></div>

    【讨论】:

    • 嗨,值和标签并排显示,用“-”分隔。如何在i.imgur.com/kTXeAXt.png 这样的标签下面显示值?
    • 抱歉,我真的看不出任何关于如何显示这样的标签的逻辑。有时数字在底部,有时在右边?
    • 检查编辑后的版本,它会在下一行附加value
    • 如果您有任何问题,请告诉我。
    • 非常感谢您的回答,半圆环图中第二段的标签和值是不可见的。标签:'SPD' 和值:15 未显示。是不是变身了?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多