Reputation: 341
I'm creating a parallel coordinates chart. Each circle is a particular brand, and every brand has one circle in each column:
When the user hovers over a circle, I would like to draw a path connecting that circle to the other three circles of the same brand. The issue is that the X position of the circles is random, so I have to draw the line using the circle's modified cx value (and not the data).
Conveniently, I have all four brand circles grouped in their own g elements:
<g class="line-group">
<circle r="5" cx="340.48700997553686" cy="0" data-brand="Brand X"></circle>
<circle r="5" cx="916.9181438059958" cy="59.347826086956466" data-brand="Brand X"></circle>
<circle r="5" cx="1589.2772695723352" cy="229.1306884480747" data-brand="Brand X"></circle>
<circle r="5" cx="2272.275506967826" cy="0" data-brand="Brand X"></circle>
</g>
I can grab the elements, and group the coordinates in a way d3.line() likes, but it makes one line that connects every point.
var line = d3.svg.line()
.interpolate('basis');
var circles = d3.selectAll('.line-group').selectAll('circle'),
circleCoords = [];
circles.forEach( function(d) {
console.log(circles);
for ( i = 0; i < d.length; i++ ) {
var cx = d3.select(d[i]).attr('cx'),
cy = d3.select(d[i]).attr('cy');
circleCoords.push([cx, cy]);
}
});
lineGroup.append('path')
.attr({
'd' : line( circleCoords )
});
How do I structure this so I can grab the cx and cy values of each circle group (the four circles of the same brand inside of g.line-group)?
I probably have to make a custom d attribute, something like this (pseudocode):
path.attr('d', function(d) {
return 'M ' + /* cx of circle 1 */ + ' ' + /* cy of circle 1 */ +
' L ' + /* cx of circle 2 */ + ' ' + /* cy of circle 2 */ +
' L ' + /* cx of circle 3 */ + ' ' + /* cy of circle 3 */ +
' L ' + /* cx of circle 4 */ + ' ' + /* cy of circle 4 */ + ' Z';
})
I believe all the pieces are there, I just can't seem to find a way to put it together correctly. If anyone has any ideas, it would be greatly appreciated!
Edit: Added line definition.
Upvotes: 2
Views: 1321
Reputation: 1836
You has the wrong selection (I can't see your line definition, don't forget it):
var svg = d3.selectAll("svg")
var circles = svg.selectAll('.line-group').selectAll("circle"),
// or var circles = svg.selectAll('.line-group > circle'),
circleCoords = [];
circles.forEach( function(d) {
for ( i = 0; i < d.length; i++ ) {
var cx = d3.select(d[i]).attr('cx'),
cy = d3.select(d[i]).attr('cy');
circleCoords.push([cx, cy]);
}
console.log(circleCoords);
});
var line = d3.svg.line()
svg.append('path')
.attr({
'd' : line( circleCoords )
});
Don't forget styles. You need to identify each '.line-group' or D3 will select all '.line-group' class, may adding id attribute.-
In your case you have multiple "Brands", like so:
<svg>
<g class="line-group">
<circle r="5" cx="10" cy="110" data-brand="Brand-X"></circle>
<circle r="5" cx="30" cy="120" data-brand="Brand-X"></circle>
<circle r="5" cx="150" cy="30" data-brand="Brand-X"></circle>
<circle r="5" cx="290" cy="40" data-brand="Brand-X"></circle>
</g>
<g class="line-group">
<circle r="5" cx="10" cy="10" data-brand="Brand-Y"></circle>
<circle r="5" cx="30" cy="20" data-brand="Brand-Y"></circle>
<circle r="5" cx="150" cy="130" data-brand="Brand-Y"></circle>
<circle r="5" cx="290" cy="140" data-brand="Brand-Y"></circle>
</g>
</svg>
you need to refactory your code:
var svg = d3.selectAll("svg")
var circles = svg.selectAll('.line-group').selectAll("circle"),
circleCoords = [];
var line = d3.svg.line()
// circles.length give you .line-group's count or brand's count:
for (j=0; j<circles.length; j++) {
circles[j].forEach( function(d) { // forEach brand draw a line
var cx = d.getAttribute('cx'),
cy = d.getAttribute('cy');
circleCoords.push([cx, cy]);
})
svg.append('path')
.attr({ 'd' : line( circleCoords ) })
.attr("id","id_"+j);
circleCoords = [];
};
Upvotes: 2