D3.js 'Pie Charts Labels' Overlapping - d3.js

Hi StackOverflow community. I tried to find the solution for a problem I'm having and was unable to get anything helpful. The closest thing I could find was this which seems to not have a solution. I'm a complete beginner to D3.js so this may also be why I'm having trouble resolving the situation. I tried digging through the documentation as well with no success. So here's my problem. I was trying to do some data visualization stuff and stumbled upon this pie chart in the D3.js example library, which I thought was pretty nifty. Once I started putting a large amount of values into the graph though I noticed I had problems with overlapping labels as can be seen below. I've only altered the code from the example page to make it so I can create multiple charts. Besides that it's essentially the same. Thanks for any help or information anyone can provide!
Overlapping Labels

This will work only for d3 v4. The idea is to compare each node with the rest and move its position if collision is detected. The following code snippet uses this.texts as d3 selection of the labels. Once a collision is detected the element will be moved below - might not be optimised for a specific case.
const nodes = this.texts.nodes();
for (let i = 0; i < nodes.length; i++) {
for (let j = i + 1; j < nodes.length; j++) {
const previous = nodes[i];
const elem = nodes[j];
const thisbb = elem.getBoundingClientRect(),
prevbb = previous.getBoundingClientRect();
if (!(thisbb.right < prevbb.left ||
thisbb.left > prevbb.right ||
thisbb.bottom < prevbb.top ||
thisbb.top > prevbb.bottom)) {
const matrix = previous.transform.baseVal.consolidate().matrix;
d3.select(elem).attr('transform', `translate(${matrix.e}, ${matrix.f + prevbb.bottom - prevbb.top})`);
}
const elemMatrix = elem.transform.baseVal.consolidate().matrix;
pieData[j].pos = [elemMatrix.e, elemMatrix.f];
}
}

Related

organization chart with Z.Blazor.Diagrams package

I'm using Z.Blazor.Diagrams package version 2.0.0 in my blazorise .Net core 5 client side project to create and show an organization chart.
every thing is working fine and I can create my chart, my problem is how to show my graph in the format of organization chart. I've searched but didn't find any way.
this is part of my code to show the chart:
double x = 0;
double y = 0;
foreach (var item in chartDetail)
{
var node = NewNode(x, y, item.PostTitle, item.Id);
Diagram.Nodes.Add(new[] { node });
x += 100;
y += 100;
}
I'll appreciate it if any one can help.
I solved it by saving position in database. On every node movement point(x,y) changes so I create the chart in the shape that I want and show it just same as created

Using Grouped Bars with DC.js

I'm using the grouped bar PR of dc.js and the corresponding grouped bar chart example as a baseline.
For some reason, I have to use numbers in my data as opposed to strings. (Convert "male" and "female" to 1/0). I'm guessing it has to do with the reduce functions I'm using. This also effects my x-axis labels, of course. I'd rather they show the text variations.
ndx = crossfilter(eData),
groupDim = ndx.dimension(function(d) {return d.service;}),
qtySumGroup = groupDim.group().reduce(
function(p,v) { p[v.component] = (p[v.component] || 0) + v.qty; return p; },
function(p,v) { p[v.component] = (p[v.component] || 0) - v.qty; return p; },
function() { return{}; });
I'm also noticing that it doesn't seem to crossfilter the data. When I click one of the bars in a group, it doesn't filter my other charts on the page. What am I missing?
Here's the first part of the answer. In order to use string components/genders for grouping, you'll need to adjust the way data is selected for "stacking" (actually grouping when this version of dc.js is used).
So, you can grab the component names by first walking the data and grabbing the components:
var components = Object.keys(etsData.reduce(function(p, v) {
p[v.component] = 1;
return p;
}, {}));
This builds an object where the keys are the component names, and then pulls just the keys as an array.
Then we use components to select the categories like so:
grpChart
.group(qtySumGroup, components[0], sel_stack(components[0]));
for(var i=1; i<components.length; ++i)
grpChart.stack(qtySumGroup, components[i], sel_stack(components[i]));
This is just the same as the original
grpChart
.group(qtySumGroup, "1", sel_stack('1'));
for(var i=2; i<6; ++i)
grpChart.stack(qtySumGroup, ''+i, sel_stack(i));
except that it is indexing by string instead of integer.
I realize this is not the important part of your question, but unfortunately filtering by stack segments is not currently supported in dc.js. I'll try to return to that part later today if I have time - it should be possible to hack it in using a dimension with compound keys (or using two dimensions) and a custom click event, but I haven't seen anyone try this yet.
It would no doubt be a helpful feature to add to dc.js, even if just as an external customization.
EDIT: I've added an example of filtering the segments of a stack, which should apply equally well for grouped bars (although I haven't tried it with your code). The technique is explained in the relevant dc.js issue.

Force Network: How to set initial position for select nodes?

I have a simple force network graph of four nodes as an example, here:
https://jsfiddle.net/NovasTaylor/o1qesn6k/
I would like to set the initial position of node "A" using its accompanying data so the node is initially fixed at point (265,143). If I were to double-click that node it would return to being d.fixed=FALSE and the usual forces apply.
From my research here on Stackoverflow I know I need to set the inital .x and .y values as per Bostock's suggestion:
[Fix Node Position in D3 Force-Directed Layout
But I do not quite grasp where and how to do this. I have tried the following code, which I may not have placed in the right sequence. It appears to be the same as having .x and .y in the source data...which also did not work.
for (var i=0, tot=dataset.nodes.length; i < tot; i++) {
if (dataset.nodes[i].fix_x > 0) {
dataset.nodes[i].x = dataset.nodes[i].fix_x
dataset.nodes[i].y = dataset.nodes[i].fix_y
}
}
Your advice would be very much appreciated!
Tim

Is it possible to loop through a sprite group in three.js with a tween that ends in a different position for each sprite?

I'm confused.
I've made a group of 10 sprites and added them to a THREE.Object3D() called fireworkGroup. I have another Object3D called explode. The tween loops through the sprites changing them from their initial position to explode.position.
for ( var i = 0; i < fireworkGroup.children.length; i ++ )
{
explode.position.x =(Math.random() - 0.5)*4;
explode.position.y =4;
explode.position.z =2;
var tweenLaunch = new TWEEN.Tween(fireworkGroup.children[i].position).to(explode.position, 4000).easing( TWEEN.Easing.Quartic.In);
tweenLaunch.start();
}
The tween is moving all the sprites from their start position to the same end position. So I thought this might be because "tweenLaunch" is being overwritten with a different explode.position each time as the tween is rendered so I'm only seeing the last one created in the loop. When I refresh the page they do all move to a different position, consistent with the Math.random().
But then why do all the sprites move to the explode.position? If "tweenLaunch" is being overwritten then why is it not moving only the last sprite?
Is it possible to have a loop with a tween in it that also changes?
Many Thanks.
I've managed to work out what was wrong by reading around the subject on Stackoverflow questions and answers, looking at a great particle example by stemkoski then trial and error.
view-source:http://stemkoski.github.io/Three.js/Particles.html
I used console.log to look at explode.position that I was using as the second position in the tween. It wasn't holding the values I wanted (a different Math.random on each loop).
So I created fireworkAttributes:
fireworkAttributes = { startPosition: [], explodePosition: [], nextPosition: [] };
and then cloned the sprite position in the function that created the sprites using:
fireworkAttributes.explodePosition.push( sprite.position.clone() );
then looped it in it's own function:
for (var i = 0; i < fireworkGroup.children.length; i++)
{
fireworkAttributes.explodePosition[i].x = (Math.random() - 0.5)*4;
fireworkAttributes.explodePosition[i].y = 4;
fireworkAttributes.explodePosition[i].z = 2;
}
then changed the code in the original question to:
for ( var a = 0; a < fireworkGroup.children.length; a ++ )
{
//need to use this new object as tweening to fireworkAttributes.explodePosition[a] does not work
explodeSite.position = fireworkAttributes.explodePosition[a];
var tweenLaunch = new TWEEN.Tween(fireworkGroup.children[a].position).to(explodeSite.position, 4000).easing( TWEEN.Easing.Quartic.In);
tweenLaunch.start();
}
There may be a more elegant way to do this and I will be working to clean up the code where possible but this does work.

Three.js text mesh missing every other face/triangle

So I performed a simple operation where i generated a text mesh (of the word TEST), put it's vertices, normals and faces into a json object then had my server save it to an STL. The problem is that it seems to be missing every other face/triangle. It renders in the browser correctly but it looks like this whenever I export it to an STL. I'm not sure why.
My code for getting all the relevant info is simple so I don't see why it seems to be missing half the faces/triangles
// Pass in textMesh.geometry
function getTextMesh(geometry)
{
var mfaces = geometry.faces;
var mvertices = geometry.vertices;
var i;
var faces=[],
vertices=[],
normals=[];
for(i=0; i<mfaces.length; i++) {
var face = mfaces[i];
var normal = face.normal;
faces.push([face.a, face.b, face.c]);
normals.push([normal.x, normal.y, normal.z]);
}
for(i=0; i<mvertices.length; i++) {
var vertex = mvertices[i];
vertices.push([vertex.x, vertex.y, vertex.z]);
}
return {'faces':faces, 'vertices':vertices, 'normals':normals};
}
Bah, turns out the issue was that TextGeometry also used Face4 for faces. I had assumed it only used triangles (Face3). This was easily solved by calling
THREE.GeometryUtils.triangulateQuads(textGeo);
after creating the geometry for the text

Resources