Показать значения для половины круговой диаграммы пончика в D3 JS - PullRequest
0 голосов
/ 07 января 2019

Я пытаюсь отобразить метки с их значением и всплывающей подсказкой на круговой диаграмме с полу-пончиком, используя 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 expected grapht

Ответы [ 2 ]

0 голосов
/ 07 января 2019

Прежде всего, если вы console.log данных (из .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, ей нужно немного 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, идея в том, что когда мышь находится над диаграммой, мы установим свойства top и left стиля #tooltip css, где находится мышь, и установите свойство 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);
});
0 голосов
/ 07 января 2019

selection.text([value])

Если указано значение, для текстового содержимого задается указанное значение для всех выбранных элементов, заменяя любые существующие дочерние элементы.

Итак, вы устанавливаете текстовое содержимое с помощью value и немедленно заменяете его на label.

Что вы можете сделать, это вернуть объединенную строку из value и label вашего базового элемента в шаблонном литерале , например:

.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>

Edit:

Если вы хотите, чтобы две текстовые строки находились на отдельных строках, вам нужно добавить некоторые элементы <tspan> и расположить их.

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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...