Interactive legend in D3 for Horizontally Stacked bar chart - d3.js

I have created a horizontally stacked bar chart after referencing multiple examples on D3 portal. I set out to to achieve following goals
Tooltip on chart
Mouse hover on legend to highlight corresponding data
Mouse click on legend to
3.1. Change opacity of legend (unselect effect)
3.2. filter data based on selection
3.3. with transition effects
Was able to get #1, #2 & #3.1 requirements satisfied except for #3.2 & #3.3 i.e. data filtering based on legend selection with transition effects.
Here's sample code where I need help with data filtering and transition code upon clicking legend. Complete code on Plunker
.on("click", (function(d){
var y = "sqbar color-" + color(d).substring(1);
console.log("Class =" + y);
var opacity = document.getElementsByClassName(y)[0].style.opacity;
console.log ("Old opacity =" + opacity);
if (opacity === "1") {
svg.selectAll(".sqbar.color-" + color(d).substring(1)).style("opacity", "0.2");
//svg.selectAll(".rect.color-" + color(d).substring(1)).remove();
}
else{
svg.selectAll(".sqbar.color-" + color(d).substring(1)).style("opacity", "1");
//svg.selectAll(".rect.color-" + color(d).substring(1)).d.enter().append();
}
opacity = document.getElementsByClassName(y)[0].style.opacity;
console.log ("New opacity =" + opacity);
}))

Related

Label auto resizing for the bar charts dc.js

I have a bar chart with in dc.js. The x axis is dimension and y is the measure ranging from 1 - 10k. I want to show all the bars and their labels not overlapping each other. Chart looks fine when there are few bars when the number of bars starts to increase they look not okay. I am looking to auto resize the labels for the bar-chart.
Sample Chart
I tried this method of renderlet to change the fontsize automatically
stackedBarChart.on('renderlet', function(chart) {
chart.selectAll('text.barLabel')
.attr('transform', function(d) {
//How do i get/set the width of the label here ?
});
I tried the below and I am able to do dynamic label sizing. I used pretransistion and inside that fetched all bar lables and altered their font-size. The font sizing is altered according to Gordon's Idea, Getting each bar's size and and assigning the font size dynamically. For testing I have used .2 as a factor to reduce the font size.
.on('pretransition', function(chart) {
var chart_width = chart.width();
chart.selectAll("text.barLabel").attr('font-size', function(data) {
let total_bars = chart.group().all().length;
let sing_bar_width = Math.floor(chart_width / total_bars);
return (sing_bar_width * .2) + "px";
});
});

Chart Jumps on drag with d3.zoom d3 v4

I'm using d3 to draw a bunch of arrows (nodes connected by links). I'm using d3.zoom to translate the background when the ctrl key is pressed and the background is clicked on and dragged.
I want to zoom on the arrows so they fill the screen when the page loads. This works fine, but when I pan (by ctrl + drag the background) it jumps from my auto zoomed position to the origin.
(Here I translate by calculating the auto transform/scale, taking child group of the top svg element, and setting its transform attribute)
Here is my code to set up the zoom:
zoom(width, height){
// Get autozoom translate and scale
const autozoom = this.AutoZoom(width, height);
// Bind zoom event to top level svg and on zooom append transform attribute to svg > g
topSvg.call(d3.zoom()
.scaleExtent([1, 2])
.on("zoom", () =>
svgG.attr("transform", (e) => {
return d3.event.transform;
}))
);
//Make the initial transform to translate grop
if ((autozoom != null) ) {
svg.attr("transform", `translate(${autozoom .translate})scale(${autozoom.scale})`);
}
}
How do I stop the chart from jumping from translated position to the origin when I click and drag?
After a bunch of digging I found the answer. So there are three things that need to be done when performing an initial zoom on a page with zoom functionality:
1) Calculate the amount needed to translate/scale the svg, then set the transform attribute for the group under the svg.
const groupZoom= this.GetSvgZoom(width, height);
// svgGroup = svg > g
svgGroup.attr("transform", `translate(${groupZoom.translate})scale(${groupZoom.scale})`);
2) Now that the page has moved, you need to notify the zoom event to start at your translated position.
const extent = this.GetZoomOrigin(width,height);
d3.zoom().translateTo(svg, extent.translate[0], extent.translate[1]);
d3.zoom().scaleTo(svg, extent.scale);
3) Finally bind the zoom event to the svg element to give the zoom functionality
svg.call(d3.zoom()
.on("zoom", () =>
svgGroup.attr("transform", d3.event.transform))
);

dc.js Can a Pie Legend be recentered after filtering

I would like to be able to recenter a Pie charts legend after it has been filtered. Slices/Legends will removed when filtering because we remove empty bins. I added a pretransition listener to chart2, but that seems to be to late because the legend y value is the previous value and not current.
.on('pretransition', chart => buildLegend (chart))
If Male is selected on the Gender Pie chart I want the 4 legend items on the Job Pie chart to be re-centered. Any suggestions?
You can see a jsFiddle example.
A little more digging around showed me how to reference and update SVG elements.
function recenterLegend(chart) {
chart.selectAll('g.dc-legend')
.attr('transform', function(d) {
let legendY = (300 - (chart.group().all().length * 16)) / 2;
let translate = 'translate(220,' + legendY + ')';
return translate ;
});
}
Here is the updated jsfiddle.

Sorting the bars in a bar chart with dc.js

I am new to dc.js and d3.js. I have created a bar chart along with pie charts and a line chart with dc.js.
Now, in the bar chart I want to sort the bars based on the value that each bar represents. (For example, by clicking a button.) Is this possible with dc.js?
Note that I have designed my bar chart such that the X-axis represents geographic locations and the Y-axis is scaling on some value.
Could you show us some code ?
In the past I have done that this way for a row chart :
var topRowChart = dc.rowChart("#chart-top-dest");
topRowChart
.height(400)
.width(400)
.dimension(destination, "destination")
.group(calls,"calls")
.ordering(function(t){return t.calls;})
.label(function(d){ return d.key + " : " + d.value + " calls" ;})
.cap(10);
The important bits are :
.ordering(function(t){return t.calls;})
.cap(10);
You have to pass a function to ordering() that returns the dimension/group that will be used for sorting.
Surprisingly removing cap() cancels the sorting.

dc.js pieChart set specific x axis value

I am working on dc.js, i have draw pieChart
pieChart.width(300)
.height(200)
.transitionDuration(1500)
.dimension(startValue)
.group(startValueGroup, "StartValue")
.radius(100)
.minAngleForLabel(0.5)
.legend(dc.legend().x(230).y(0))
.title(function(d) {
return d.key + ": " + d.value;
})
.renderTitle(true)
.on("filtered", function (chart) {
dc.events.trigger(function () {
//console.log(total_payment);
});
});
Now, I want to set specific x axis value. Currently, pieChart taking center position of define width and height. That mean it's taking position of (150,100). I want to change this position to (100, 100).
How can i change position of x axis as per above code?
You can't set this directly in the dc options, but you can modify these values after the chart has been rendered. Assuming that "pie" is the ID of the DOM element that you rendered the pie chart into, you can do
d3.select("#pie > svg > g").attr("transform", "translate(100,100)");
I know it is an old post and that the answer works perfectly but when the chart is part of a bigger system (several charts) I found easier to add the above command directly to the chart by doing this:
pieChart.on('renderlet', function (chart) {
chart.select("svg > g").attr("transform", "translate("100,100)");
});
Edit:
Actually I just found out you can do:
.cx(100)
.cy(100)
which will set the centre of the pie chart to 100, 100 before render.

Resources