The dut v3 d4 diagram has text and lines that overlap with small values.

I am trying to figure out how to arrange shortcuts so that they do not overlap. Here is a chart image

enter image description here

As you can see, with really small values, text labels overlap. I tried iterating over each text element and changing its position, but this does not seem to work. At the bottom of this function, you can see the position of each text element, and then change it. What am I doing wrong? I have been with him for hours.

_renderDonutChart() { let self = this; // console.log("Donut Chart is beginning render") let textOffset = 14; self.graph.data[0].forEach(function (d) { d.value = +d.value; }) console.log(self.graph.data[0]) let boxSize = (self.options.radius + self.options.padding) * 2; let parent = d3.select(self.ui.parent); //let color = d3.scaleOrdinal(['#dc8710', '#9e3400', '#f19b12']); let color = d3.scaleOrdinal(d3.schemeCategory20c); let svg = parent.append('svg') .attr('width', boxSize * 2) .attr('height', boxSize) .attr('transform', 'translate(-111,0)') .append('g') .attr('transform', 'translate(' + boxSize + ',' + boxSize / 2 + ')'); svg.append('g') .attr('class', 'slices') svg.append("g") .attr("class", "labelName") svg.append("g") .attr("class", "labelValue") svg.append("g") .attr("class", "lines") svg.append("div") .attr("class", "progress-circle__box progress-circle__box--victorytype") let arc = d3.arc() .innerRadius(self.options.radius - self.options.border) .outerRadius(self.options.radius); let outerArc = d3.arc() .innerRadius((self.options.radius - self.options.border) * 1.2) .outerRadius((self.options.radius) * 1.2); let legendRectSize = self.options.radius * 0.05; let legendSpacing = self.options.radius * 0.02; let pie = d3.pie() .value(function(d) { return d.value; }) .sort(null); let slice = svg.select('.slices') .selectAll('path.slice') .data(pie(self.graph.data[0])) .enter() .append('path') .attr("class", "slice") .attr('d', arc) .attr('fill', function(d, i) { return color(d.data.label); }) .transition().duration(1000) .attrTween("d", function(d) { this._current = this._current || 0; var interpolate = d3.interpolate(this._current, d); this._current = interpolate(0); return function(t) { return arc(interpolate(t)); }; }) function midAngle(d){ return d.startAngle + (d.endAngle - d.startAngle)/2; } let text = svg.select(".labelName").selectAll("text") .data(pie(self.graph.data[0])) .enter() .append("text") .attr('class', 'label') .attr("dy", ".35em") .attr('transform', function(d) { // effectively computes the centre of the slice. // see https://github.com/d3/d3-shape/blob/master/README.md#arc_centroid var pos = outerArc.centroid(d); // changes the point to be on left or right depending on where label is. pos[0] = self.options.radius * 0.97 * (midAngle(d) < Math.PI ? 1 : -1); return 'translate(' + pos + ')'; }) .style('text-anchor', function(d) { // if slice centre is on the left, anchor text to start, otherwise anchor to end return (midAngle(d)) < Math.PI ? 'start' : 'end'; }) .style("fill", "white") .text(function(d) { return (" " + d.data.label+": " +d.value+""); }) .transition().duration(1000) .attrTween("transform", function(d) { this._current = this._current || d; var interpolate = d3.interpolate(this._current, d); this._current = interpolate(0); return function(t) { var d2 = interpolate(t); var pos = outerArc.centroid(d2); pos[0] = self.options.radius * (midAngle(d2) < Math.PI ? 1 : -1); return "translate("+ pos +")"; }; }) .styleTween("text-anchor", function(d){ this._current = this._current || d; var interpolate = d3.interpolate(this._current, d); this._current = interpolate(0); return function(t) { var d2 = interpolate(t); return midAngle(d2) < Math.PI ? "start":"end"; }; }) .text(function(d) { return (d.data.label+": "+d.value+"%"); }) let polyline = svg.select(".lines").selectAll("polyline") .data(pie(self.graph.data[0])) .enter() .append("polyline") .attr('points', function(d) { var pos = outerArc.centroid(d); pos[0] = self.options.radius * 0.95 * (midAngle(d) < Math.PI ? 1 : -1); return [arc.centroid(d), outerArc.centroid(d), pos] }) .style("fill", "none") .style("stroke", "white") .style("stroke-width", "1px"); let prev; text.each(function(d, i) { if(i > 0) { let thisbb = this.getBoundingClientRect(), prevbb = prev.getBoundingClientRect(); // move if they overlap console.log(thisbb.left); console.log(prevbb.right); if(!(thisbb.right < prevbb.left || thisbb.left > prevbb.right || thisbb.bottom < prevbb.top || thisbb.top > prevbb.bottom)) { var ctx = thisbb.left + (thisbb.right - thisbb.left)/2, cty = thisbb.top + (thisbb.bottom - thisbb.top)/2, cpx = prevbb.left + (prevbb.right - prevbb.left)/2, cpy = prevbb.top + (prevbb.bottom - prevbb.top)/2, off = Math.sqrt(Math.pow(ctx - cpx, 2) + Math.pow(cty - cpy, 2))/2; d3.select(this).attr("transform", "translate(" + Math.cos(((d.startAngle + d.endAngle - Math.PI) / 2)) * (self.options.radius + textOffset + off) + "," + Math.sin((d.startAngle + d.endAngle - Math.PI) / 2) * (self.options.radius + textOffset + off) + ")"); } } prev = this; }); // console.log("Donut Chart is ending render") } 
+5
source share
2 answers

I had the same problem. The best solution for me was to increase the size of the Svg area (based on the current window) and add some additions to legends based on the donut radius.

t

  var margin = {top: 20, right: 100, bottom: 30, left: 40}; var svgWidth = window.innerWidth - (window.innerWidth/4); var width = svgWidth, height = (Math.min(width) / 2) + 100, radius = Math.min(width, height) / 3; var legendRectSize = (radius * 0.08); var legendSpacing = (radius * 0.05); 

This worked for me until the item counter got too high. I changed the labels around the edge to display them in the center, on the cut / hover events. (There is an animation of the data value, so it is tilted in this picture)

D3 Donut Chart Modified Labels

I thought this made unreadable data labels less confusing.

0
source

I had the same problem with this , you need to add more margin to the segment of the pie chart, suppose your income is returned by 3% and you draw text with a line, it will stack on another, you need to determine the border if this value <3 draw text with y + margin

  if(percent<3){ o[1] pos[1] += i*15 } //return [label.centroid(d),[o[0],0[1]] , pos]; return [label.centroid(d),[o[0],pos[1]] , pos]; }) 

try adding this code structure to your diagram

0
source

Source: https://habr.com/ru/post/1273535/


All Articles