My problem is that my polylines are not exact positioned on the slices based on my data
This my UI looks like
My code is that
function Pie_chart(data, changedProperties, id) {
try {
// set the dimensions and margins of the graph
// var width = 750
// height = 450
// outerRadius = 1,
// innerRadius = 0.85,
// margin = 40
// // The radius of the pieplot is half the width or half the height (smallest one). I subtract a bit of margin.
// var radius = Math.min(width, height) / 2 - margin
// var rx = width / 4; // Horizontal radius
// var ry = height / 4; // Vertical radius
// var ir = 0
// append the svg object to the div called 'my_dataviz'
var svg = d3
.select("#my_dataviz")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
// // Create dummy data
// var data = {a: 200, b: 120, c:30, d:8, e:12, f:3, g:7, h:14,i: 9, j: 20, k:30, l:8, m:12, n:3, o:7, p:14 ,q:30, r:8, s:12, t:3, u:7, v:14}
// // Define the color scale
// var colorScale = d3.scaleOrdinal()
// .domain(["a", "b", "c", "d", "e", "f", "g", "h","i","j", "k", "l", "m", "n", "o", "p", "q","r","s","t","u","v"])
// .range(d3.schemeDark2);
// // Compute the position of each group on the pie:
// var pie = d3.pie()
// .sort(null) // Do not sort group by size
// .value(function(d) {return d.value; })
// var data_ready = pie(d3.entries(data))
// // The arc generator
// var arc = d3.arc()
// .innerRadius(0) // This is the size of the donut hole
// .outerRadius(radius * 0.6)
// // Another arc that won't be drawn. Just for labels positioning
// var outerArc = d3.arc()
// .innerRadius(radius * .9)
// .outerRadius(radius * .9)
// // Build the pie chart: Basically, each part of the pie is a path that we build using the arc function.
// // svg
// // .selectAll('allSlices')
// // .data(data_ready)
// // .enter()
// // .append('path')
// // .attr('d', arc)
// // .attr('fill', function(d){ return(colorScale(d.data.key)) })
// // .attr("stroke", "white")
// // .style("filter", "url(#drop-shadow)")
// // .style("stroke-width", "2px")
// // .style("opacity", 0.7)
// // Add a drop shadow filter
// var defs = svg.append("defs");
// var filter = defs.append("filter")
// .attr("id", "drop-shadow")
// .attr("height", "130%");
// filter.append("feGaussianBlur")
// .attr("in", "SourceAlpha")
// .attr("stdDeviation", 10)
// .attr("result", "blur");
// filter.append("feOffset")
// .attr("in", "blur")
// .attr("dx", 2)
// .attr("dy", 2)
// .attr("result", "offsetBlur");
// var feMerge = filter.append("feMerge");
// feMerge.append("feMergeNode").attr("in", "offsetBlur");
// feMerge.append("feMergeNode").attr("in", "SourceGraphic");
// // Add mouseover and mouseout events
// d3.selectAll('.slice')
// .on('mouseover', function(d) {
// d3.select(this).attr('opacity', 1);
// })
// .on('mouseout', function(d) {
// d3.select(this).attr('opacity', 0.7);
// });
// svg.selectAll(".innerSlice")
// .data(data_ready)
// .enter()
// .append("path")
// .attr("class", "innerSlice")
// .style("fill", function(d) { return d3.hsl(colorScale(d.data.key)).darker(0.7); })
// .attr("d", function(d) { return pieOuter(d, rx - 0.5, ry - 0.5, 40, 5, 50, 100, 0.02); })
// .each(function(d) { this._current = d; });
// svg.selectAll(".topSlice")
// .data(data_ready)
// .enter()
// .append("path")
// .attr("class", "topSlice")
// .style("fill", function(d) { return colorScale(d.data.key); })
// .style("stroke", function(d) { return colorScale(d.data.key); })
// .attr("d", function(d) { return pieTop(d, rx, ry, ir, 50, 100, 0.02); })
// .each(function(d) { this._current = d; });
// svg.selectAll(".outerSlice")
// .data(data_ready)
// .enter()
// .append("path")
// .attr("class", "outerSlice")
// .style("fill", function(d) { return d3.hsl(colorScale(d.data.key)).darker(0.2); })
// .attr("d", function(d) { return pieOuter(d, rx - 0.5, ry - 0.5, 40, 5,50, 100, 0.02); })
// .each(function(d) { this._current = d; });
// // Add the polylines between chart and labels:
// var pieTopOuterArc = d3.arc()
// .innerRadius(radius * 0.9)
// .outerRadius(radius * 0.9);
// svg
// .selectAll('.allPolylines') // Changed 'allPolylines' to '.allPolylines'
// .data(data_ready)
// .enter()
// .append('polyline')
// .attr("stroke", "black")
// .style("fill", "none")
// .attr("stroke-width", 1)
// .attr('points', function(d) {
// var posA = arc.centroid(d); // line insertion in the slice
// var posB = outerArc.centroid(d); // line break: we use the other arc generator that has been built only for that
// // var posB = pieOuter(d, rx, ry, ir, 50, 100, 0.02);
// var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2; // Calculate the middle angle of the slice
// var posC = outerArc.centroid(d); // Label position = almost the same as posB
// posC[0] = radius * 1.5 * (midangle < Math.PI ? 1 : -1); // Adjust label position based on slice angle
// return [posA, posB, posC]; // Return the points for the polyline
// // var posA = pieTopOuterArc.centroid(d); // Line insertion in the slice (top)
// // var posB = pieOuter(d, rx, ry, ir, 50, 100, 0.02); // Line break: using the outer arc generator
// // var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2; // Calculate the middle angle of the slice
// // var posC = pieTopOuterArc.centroid(d); // Label position, almost the same as posB
// // posC[0] = radius * 1.5 * (midangle < Math.PI ? 1 : -1); // Adjust label position based on slice angle
// // return [posA, posB, posC];
// });
// // Add the labels:
// svg
// .selectAll('.allLabels') // Changed 'allLabels' to '.allLabels'
// .data(data_ready)
// .enter()
// .append('text')
// .text(function(d) { return d.data.key; }) // Set the text of the label to the data key
// .attr('transform', function(d) {
// var pos = outerArc.centroid(d);
// var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2;
// pos[0] = radius * 1.5 * (midangle < Math.PI ? 1 : -1);
// return 'translate(' + pos + ')';
// })
// .style('text-anchor', function(d) {
// var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2;
// return (midangle < Math.PI ? 'start' : 'end');
// })
// .attr('class', 'allLabels'); // Added a class for better selection
// function pieTop(d, rx, ry, ir) {
// if (d.endAngle - d.startAngle == 0) return "M 0 0";
// var sx = rx * Math.cos(d.startAngle),
// sy = ry * Math.sin(d.startAngle),
// ex = rx * Math.cos(d.endAngle),
// ey = ry * Math.sin(d.endAngle);
// var ret = [];
// ret.push("M", sx, sy, "A", rx, ry, "0", (d.endAngle - d.startAngle > Math.PI ? 1 : 0), "1", ex, ey, "L", ir * ex, ir * ey);
// ret.push("A", ir * rx, ir * ry, "0", (d.endAngle - d.startAngle > Math.PI ? 1 : 0), "0", ir * sx, ir * sy, "z");
// return ret.join(" ");
// }
// function pieOuter(d, rx, ry, h) {
// var startAngle = (d.startAngle > Math.PI ? Math.PI : d.startAngle);
// var endAngle = (d.endAngle > Math.PI ? Math.PI : d.endAngle);
// var sx = rx * Math.cos(startAngle),
// sy = ry * Math.sin(startAngle),
// ex = rx * Math.cos(endAngle),
// ey = ry * Math.sin(endAngle);
// var ret = [];
// ret.push("M", sx, h + sy, "A", rx, ry, "0 0 1", ex, h + ey, "L", ex, ey, "A", rx, ry, "0 0 0", sx, sy, "z");
// return ret.join(" ");
// }
var x = 420,
y = 150,
rx = 160,
ry = 100,
ir = 0;
var w = 600;
var h = 400;
var r = h / 2;
var data = [
{
label: "A",
value: 36,
color: "#3366CC",
},
{
label: "B",
value: 26,
color: "#DC3912",
},
{
label: "C",
value: 13,
color: "#FF9900",
},
{
label: "D",
value: 7,
color: "#109618",
},
{
label: "E",
value: 8,
color: "#990099",
},
{
label: "F",
value: 10,
color: "#934099",
},
{
label: "G",
value: 10,
color: "black",
},
{
label: "H",
value: 10,
color: "brown",
},
];
var vis = d3
.select("#my_dataviz")
.append("svg:svg")
.data([data])
.attr("width", w)
.attr("height", h);
var _data = d3.pie().value(function (d) {
return d.value;
});
var slices = vis
.append("svg:g")
.attr("transform", "translate(" + x + "," + y + ")")
.attr("class", "slice");
slices
.selectAll(".innerSlice")
.data(_data)
.enter()
.append("path")
.attr("class", "innerSlice")
.style("fill", function (d) {
return d3.hsl(d.data.color).darker(0.7);
})
.attr("d", function (d) {
return pieInner(d, rx + 0.5, ry + 0.5, h, ir);
})
.each(function (d) {
this._current = d;
});
slices
.selectAll(".topSlice")
.data(_data)
.enter()
.append("path")
.attr("class", "topSlice")
.style("fill", function (d) {
return d.data.color;
})
.style("stroke", function (d) {
return d.data.color;
})
.attr("d", function (d) {
return pieTop(d, rx, ry, ir);
})
.each(function (d) {
this._current = d;
});
slices
.selectAll(".outerSlice")
.data(_data)
.enter()
.append("path")
.attr("class", "outerSlice")
.style("fill", function (d) {
return d3.hsl(d.data.color).darker(0.7);
})
.attr("d", function (d) {
return pieOuter(d, rx - 0.5, ry - 0.5, 40, 5, 50, 100, 0.02);
})
.each(function (d) {
this._current = d;
});
slices
.selectAll(".percent")
.data(_data)
.enter()
.append("text")
.attr("class", "percent")
.attr("x", function (d) {
return 0.6 * rx * Math.cos(0.5 * (d.startAngle + d.endAngle));
})
.attr("y", function (d) {
return 0.6 * ry * Math.sin(0.5 * (d.startAngle + d.endAngle));
})
.text(getPercent)
.each(function (d) {
this._current = d;
});
function pieInner(d, rx, ry, h, ir) {
var startAngle = d.startAngle < Math.PI ? Math.PI : d.startAngle;
var endAngle = d.endAngle < Math.PI ? Math.PI : d.endAngle;
var sx = ir * rx * Math.cos(startAngle),
sy = ir * ry * Math.sin(startAngle),
ex = ir * rx * Math.cos(endAngle),
ey = ir * ry * Math.sin(endAngle);
var ret = [];
ret.push(
"M",
sx,
sy,
"A",
ir * rx,
ir * ry,
"0 0 1",
ex,
ey,
"L",
ex,
h + ey,
"A",
ir * rx,
ir * ry,
"0 0 0",
sx,
h + sy,
"z"
);
return ret.join(" ");
}
function pieTop(d, rx, ry, ir) {
if (d.endAngle - d.startAngle == 0) return "M 0 0";
var sx = rx * Math.cos(d.startAngle),
sy = ry * Math.sin(d.startAngle),
ex = rx * Math.cos(d.endAngle),
ey = ry * Math.sin(d.endAngle);
var ret = [];
ret.push(
"M",
sx,
sy,
"A",
rx,
ry,
"0",
d.endAngle - d.startAngle > Math.PI ? 1 : 0,
"1",
ex,
ey,
"L",
ir * ex,
ir * ey
);
ret.push(
"A",
ir * rx,
ir * ry,
"0",
d.endAngle - d.startAngle > Math.PI ? 1 : 0,
"0",
ir * sx,
ir * sy,
"z"
);
return ret.join(" ");
}
function pieOuter(d, rx, ry, h) {
var startAngle = d.startAngle > Math.PI ? Math.PI : d.startAngle;
var endAngle = d.endAngle > Math.PI ? Math.PI : d.endAngle;
var sx = rx * Math.cos(startAngle),
sy = ry * Math.sin(startAngle),
ex = rx * Math.cos(endAngle),
ey = ry * Math.sin(endAngle);
var ret = [];
ret.push(
"M",
sx,
h + sy,
"A",
rx,
ry,
"0 0 1",
ex,
h + ey,
"L",
ex,
ey,
"A",
rx,
ry,
"0 0 0",
sx,
sy,
"z"
);
return ret.join(" ");
}
var radius = 200;
var arc = d3
.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 50);
var outerArc = d3
.arc()
.innerRadius(radius * 0.9)
.outerRadius(radius * 0.9);
// Add the polylines between chart and labels:
slices
.selectAll("allPolylines")
.data(_data)
.enter()
.append("polyline")
.attr("stroke", "black")
.style("fill", "none")
.attr("stroke-width", 1)
.attr("points", function (d) {
console.log("checkkkshdfkh", d);
var posA = arc.centroid(d) // line insertion in the slice
var posB = outerArc.centroid(d) // line break: we use the other arc generator that has been built only for that
var posC = outerArc.centroid(d); // Label position = almost the same as posB
let tempX= 0.6 * rx * Math.cos(0.5 * (d.startAngle + d.endAngle));
let tempY= 0.6 * ry * Math.sin(0.5 * (d.startAngle + d.endAngle))
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2 // we need the angle to see if the X position will be at the extreme right or extreme left
posC[0] = radius * 0.95 * (midangle < Math.PI ? 1 : -1);
console.log("checknskdnfknsdf",posA,[tempX,tempY])
return [posA, posB, posC]
});
// // Add the polylines between chart and labels:
// slices
// .selectAll('allPolylines')
// .data(_data)
// .enter()
// .append('polyline')
// .attr("stroke", "black")
// .style("fill", "none")
// .attr("stroke-width", 1)
// .attr('points', function(d) {
// var posA = arc.centroid(d) // line insertion in the slice
// var posB = outerArc.centroid(d) // line break: we use the other arc generator that has been built only for that
// var posC = outerArc.centroid(d); // Label position = almost the same as posB
// var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2 // we need the angle to see if the X position will be at the extreme right or extreme left
// posC[0] = radius * 0.95 * (midangle < Math.PI ? 1 : -1); // multiply by 1 or -1 to put it on the right or on the left
// return [posA, posB, posC]
// })
function getPercent(d) {
return d.endAngle - d.startAngle > 0.2
? Math.round((1000 * (d.endAngle - d.startAngle)) / (Math.PI * 2)) /
10 +
"%"
: "";
}
} catch (error) {
console.log("error==>", error);
}
}