Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Making a non-contiguous piechart #3835

Closed
skaphan opened this issue Apr 7, 2024 · 0 comments
Closed

Making a non-contiguous piechart #3835

skaphan opened this issue Apr 7, 2024 · 0 comments

Comments

@skaphan
Copy link

skaphan commented Apr 7, 2024

Hi, I am newish to d3, so maybe there is a way to do this that is easier than what I came up with, so if so please let me know. I couldn't find anything helpful.

When you make a pie chart, I think you have to do something like this at the start:

const g = d3.select(svg)
.attr('width', width)
.attr('height', height)
.append("g")
.attr("id",chartID)
.attr("transform", translate(${x}, ${y}));

const pie = d3.pie()
.sort(null)
.value(d => d.value);

const arc = d3.arc()
.outerRadius(outerRadius)
.innerRadius(innerRadius);

const slices = g.selectAll('.slice')
.data(pie(data))
.enter()
.append("g")
.attr("class", 'slice');

That is all well and good if your slices are contiguous, but what if they are not? I did it this way:

Everything the same up to the slices definition except you can leave out the pie definition. Then

const slices = g.selectAll('.slice')
.data(info)
.enter()
.append("g")
.attr("class", 'slice');

where 'info' is in the format produced by the function returned by d3.pie().
Apparently data() is fairly flexible, but I ended up using this format because I was not sure
what it was expecting in order to properly construct the pie segments. Maybe just something with
startAngle and endAngle properties??? I don't like using an undocumented interface there because it
might change out from under me.

Then I wanted to move the slices with a transition. This was also harder than it should have been,
since apparently there was no way to access the "from" startAngle and endAngle from within the interpolator.
So I had to do something like this:

slices
.select("path")
.transition()
.duration(1000)
.attrTween("d", function(d) {
const interpolateStartAngle = d3.interpolate(getStartAngle(d.data.label), d.startAngle);
const interpolateEndAngle = d3.interpolate(getEndAngle(d.data.label), d.endAngle);
this._current = d;
return t => {
updatedArc
.startAngle(x=interpolateStartAngle(t))
.endAngle(interpolateEndAngle(t));
return updatedArc(d);
};
});

with these functions defined:

function getStartAngle(name) {
let d = previousDonutInfoGlobal.find(obj => name.indexOf(obj.data.label)===0);
return d.startAngle;
}

function getEndAngle(name) {
let d = previousDonutInfoGlobal.find(obj => name.indexOf(obj.data.label)===0);
return d.endAngle;
}

First off, is there a better/easier way that would work? And if not, couldn't you make the start info available somehow to the interpolator?

@d3 d3 locked and limited conversation to collaborators Apr 7, 2024
@mbostock mbostock converted this issue into discussion #3836 Apr 7, 2024

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Development

No branches or pull requests

1 participant