I was extending Sunburst chart of D3. Whenever user clicks on a specific legend then it will highlight all the path associated with that label if that legend is last in the sequence.
Here is working fiddle - http://output.jsbin.com/pezehoveso
I think my problem is in below function -
function updatePaths(selectedPath) {
var resultedPath = getSelectedPaths(selectedPath);
// Fade all the segments.
// Then highlight only those that are an ancestor of the current segment.
vis.selectAll("path")
.filter(function(d, i) {
return (resultedPath);
})
.style("opacity", 1);
}
Somehow I'm unable to get selected path highlighted. It's highlighting all the paths. What am I missing?
Related
I am trying to make just the axis label of the selected item bold, so that it is more apparent to users what they have selected. I am using a composite bar chart to compare two values and have turned the labels -90 so that they are inside the bars. I have been able to make the labels clickable, with help from Gordon here: dc.js barChart - click on x-axis ticks and labels
I am counting clicks so that users can select and deselect from clicking on the label, however with some of the smaller values, users cannot tell which items they have filtered on in any specific chart.
I am able to select, de-select on clicks, I have tried select('tick-text').attr('style', 'font-weight: bold;');
This bolds the first item in the x-axis, no matter which selection is made.
When I use selectAll('.x text) it changes all.
Relevant portion of the code:
ByTopLvl.on('pretransition',function() {
ByTopLvl.selectAll('g.x text')
.style('text-anchor', 'start')
.attr('transform', 'rotate(-90),translate(10, -10)');
ByTopLvl.select('.axis.x')
.selectAll('.tick text')
.on('click.custom', function (d) {
var clicks = $(this).data('clicks');
if (!clicks) {
ByTopLvl.replaceFilter(d)
.select('.tick text')
.attr('style', 'font-weight: bold;');
ByTopLvl.redrawGroup();
} else {
ByTopLvl.select('.tick text')
.attr('style', 'font-weight: normal;');
ByTopLvl.filterAll();
dc.redrawAll();
}
$(this).data("clicks", !clicks);
});
I would expect that when I click on the label, only the label clicked would be bold.
First off, whenever possible, I would suggest using the built-in selection/filter state rather than trying to keep track of clicks yourself. Otherwise they are bound to get out of sync at some point.
If you have the boldness of the ticks driven by the active filters, then you'll get the same behavior whether the bar or the tick was clicked, and you can be certain that exactly the ticks in the filters are the bolded ones:
CSS
.dc-chart g.axis.x text.selected {
font-weight: bold;
}
JS
chart.on('filtered', function(chart) {
var filters = chart.filters();
chart.selectAll('.axis.x .tick text').classed('selected', function(d) {
return filters.includes(d);
})
})
[Side note since I'm not answering your exact question: if you want to make your code work, you could do something like filter the selection based on d:
ByTopLvl.select('.tick text').filter(function(d2) { return d2 === d; })
or in your case, this is the clicked tick, so d3.select(this) should also work. But I think you'll run into a lot of bugs that way.]
Similarly, you can simplify your click behavior by tying into the built-in filter behavior, which already toggles:
chart.on('pretransition', function(chart) {
chart.select('.axis.x')
.selectAll('.tick text')
.on('click.select', function(d) {
chart.filter(d);
chart.redrawGroup();
});
});
Yeah, it's weird that the built-in filter function toggles, but that's just the way that dc.js evolved.
Here's a demo fiddle.
In a composite
Composite charts in dc.js are a little bit of a confusing mess.
The filter selection is shared between the parent and child, except they sort also handle it separately.
Unfortunately when I have to troubleshoot composite charts, I just try different things until it works, and never fully understand what's going on. I think it's just too complicated for my brain. :-O
Anyway, this worked...
Keep a reference to the inner bar chart:
var chart = dc.compositeChart('#test'), bar;
chart
.width(768)
.height(380)
.x(d3.scaleBand())
.xUnits(dc.units.ordinal)
.brushOn(false)
.xAxisLabel('Fruit')
.yAxisLabel('Quantity Sold')
.dimension(fruitDimension)
.group(sumGroup)
._rangeBandPadding(0.05)
.compose([
bar = dc.barChart(chart)
.barPadding(0.1)
.outerPadding(0.05)
])
When responding to the click, filter the child bar chart instead of the parent:
chart.on('pretransition', function(chart) {
chart.select('.axis.x')
.selectAll('.tick text')
.on('click.select', function(d) {
bar.filter(d);
chart.redrawGroup();
});
});
Listen to the filtered event of the child bar chart and apply axis bolding to the parent composite chart:
bar.on('filtered', function(chart) {
var filters = chart.filters();
chart.selectAll('.axis.x .tick text').classed('selected', function(d) {
return filters.includes(d);
})
})
Whoo. I guess it's sorta.. consistent? The child bar chart is the source of truth for the filters. Maybe I'm rationalizing.
New fiddle version.
I am trying to build a D3 bar chart visualization that can be updated using a drop down menu.
So far, I have successfully created the bar chart and the drop down menu such that when I change the selection in the menu, the bars are updated to their new values.
However, I am having problems with the bar labels updating appropriately. Even though I include the same .exit.remove() function for the labels as for the bars, the old labels remain on the newly updated chart.
Image of the updated chart w/ problem labels
Test csv file
Test code
Apologies for the links. I'm new to JSFiddle, and I couldn't figure out how to easily transfer my example.
You forgot to add class attribute while appending the text
You also need to change the text while updating
Hope this helps
bartexts.transition().duration(250)
.attr("y", function(d, i) {return yScale(d) - 10})
.text(function(d) {return d});
I'm looking for some advice on how to get two elements in a visualization, which are linked by a common data value, to respond simultaneously.
Here is the visualization as it stands now.
http://bl.ocks.org/natemiller/2686e5c0d9a1a4bb0895
Note that the different colored points are for the 50 US states in 2005 (green) and 2013 (blue), so there is a blue point and a green point for each state. I have two things I would like to get working here.
I would like to be able to mouseover either a blue point or a green point and have the corresponding point (for the same state) highlighted.
I would like a tooltip with some basic data to appear next to both points, providing point specific data.
Regarding the first point above. Right now when you mouseover a blue point the corresponding green point is highlighted, however, when you mouseover a green point only that point is highlighted and not its corresponding blue point. I imagine this is a simple fix, but for the life of me I can't figure out to reverse the reference so I get green to blue references as well.
Regarding the second point. Right now a tooltip with relevant information appears near the moused-over point, but I would like to have a similar tooltip appear next to the corresponding point from the alternate year of data, so that direct comparisons across years are easier. I am quite new to adding HTML tooltips so I'm not clear on how to do this and suspect it may require a new method for adding tooltips. Can any help to steer me in the correct direction for how to have a tooltip appear near the moused-over element and a corresponding linked element?
1) Remember that ids are unique and you're creating multiple circles with the same id, use a class instead
circles.attr("class", function(d) { return d.state })
2) You're creating a single tooltip, if you want to show one for each pair of states create multiple tooltips
Assuming that you make these changes you can easily create multiple tooltips for each pair of states
circles.on('mouseover', function (d) {
// selection for 2 states
var states = d3.selectAll('circle.' + d.state)
// code to style those nodes goes here ...
// tooltips for the states
var tooltips = d3.select('svg').selectAll('text.tooltip')
.data(states.data())
// initial styling of the tooltips goes here...
tooltips
.enter()
.append('text')
.attr('class', 'tooltip')
// update
tooltips
.html(function (d) {
// text of the tooltip
return 'something'
})
// positioning, it requires some margin fixes I guess
.attr('x', function (d) { return xScale(d.child_pov) })
.attr('y', function (d) { return yScale(d.non_math_prof) })
})
Finally remove the tooltips created on mouseover when the mouseout event is triggered
circles.on('mouseout', function (d) {
d3.select('svg').selectAll('text.tooltip').remove()
})
You cannot have multiple elements with the same id. Use a class .circleHawaii instead of an id #circleHawaii.
I started working with D3 and had a little help yesterday getting some code to work. I have one new quick question. I have a donut chart representing some soon to be JSON object. When you hover over some of the pieces of the chart, they animate and pop out. There is a corresponding table that is populated by the same object. I was able to get the data in the table mapped out so that when you hover over the data, it animates the corresponding pie chart slice. I'm trying to get it to work in the opposite way as well, so that when you hover over the donut slice, it highlights the table.
Currently, I have it highlighting the entire table, but I can't seem to figure out how to map it to the individual and correct table entry.
Fiddle for context
My arc mouseover, where I currently have it highlighting everything,
.on("mouseover", function(d) {
d3.select(this).select("path").transition()
.duration(100)
.attr("d", arcOver);
var path = paths[0][i];
d3.selectAll("#testtable .dataRow")
.style("background-color","red");
Can someone provide a little help on how to map to the correct table entry?
Thank you!
Since your pie chart and table are ordered the same, you can do it by index:
.on("mouseover", function(d,i) {
d3.select(this).select("path").transition()
.duration(100)
.attr("d", arcOver);
var row = d3.selectAll("#testtable .dataRow")[0][i]; // i is the index
d3.select(row)
.style("background-color","red");
})
Updated fiddle.
I'm working on fading out certain lines from a chord diagram when a separate chart is hovered over. I'm looking at the code for the "fade" function,
`function fade(opacity) {
return function(g, i) {
svg.selectAll(".chord path")
.filter(function(d) { return d.source.index != i && d.target.index != i; })
.transition()
.style("opacity", opacity);
};
}`
And I was just wondering if someone could explain to me what d.source.index means and d.target.index mean. I generally understand that it's the source of the chord and the target of the chord, but I wanted to gain some more specific insight into the values/meaning of "index" so that I could better manipulate the selection.
My ultimate goal is to over over a box in a separate legend rectangle, and have the chord diagram fade so that only the color hovered over in the legend box retains full opacity.
Every chord has data associated with it. This data has, among other things, source and target attributes, which point to the nodes that the chord connects. In the code above, the index attribute of the source and target nodes is referenced to identify which ones to filter. This can be anything you want though.
In your application, depending on what the legend is for, you would need to check the value displayed in the legend for the source/target nodes or the chord itself.