Hi I am using this code for making a bar/stacked_bar graph
bars.append('rect')
.attr('height', axes.ver.scale.rangeBand())
.attr('width', 0)
.attr('x', function (d, i) { var value = axes.hor.scale(csum[i]); csum[i] += d.value; return value; })
.attr('y', function (d) {return axes.ver.scale(d.name); })
.classed('cr_' + uv.util.formatClassName(self.categories[idx]), true)
.style('stroke', 'none')
.style('fill', color)
.on('mouseover', uv.effects.bar.mouseover(self, idx))
.on('mouseout', uv.effects.bar.mouseout(self, idx))
.transition()
.duration(uv.config.effects.duration)
.delay(idx * uv.config.effects.duration)
.attr('width', function (d,i) { return axes.hor.scale(csum[i]) - axes.hor.scale(csum[i]-d.value); });
I have an mouseover event attached which changes the color on hover.
My problem is that when my chart is rendering and at the same time I hover over a currently rendering bar then it does not render properly.
I have linked the screenshot and the error is that a gap comes.
http://db.tt/ng1akZDy
Please Tell me what am I doing wrong.
Don't know if the problem is exactly the same.
Try to add this to your CSS or in line styles:
pointer-events: all;
https://stackoverflow.com/a/9210392/731179
Related
I have this piece of code in which circles are drawn, I need to put a text inside each circle, I would also like to know how I can put a certain size to each of the elements of the circle.
Thank you very much.
svg = d3.select(selector)
.append('svg')
.attr('width', width)
.attr('height', height);
// Bind nodes data to what will become DOM elements to represent them.
bubbles = svg.selectAll('.bubble')
.data(nodes, function (d) { return d.id; });
// Create new circle elements each with class `bubble`.
// There will be one circle.bubble for each object in the nodes array.
// Initially, their radius (r attribute) will be 0.
bubbles.enter().append('circle')
.classed('bubble', true)
.attr('r', 0)
.attr('fill', function (d) { return fillColor(d.group); })
.attr('stroke', function (d) { return d3.rgb(fillColor(d.group)).darker(); })
.attr('stroke-width', 2)
.on('mouseover', showDetail)
.on('mouseout', hideDetail);
// Fancy transition to make bubbles appear, ending with the
// correct radius
bubbles.transition()
.duration(2000)
.attr('r', function (d) { return d.radius; });
A good practice would be to create a group element for each bubble because they will be composed of two elements - a circle and text.
// Bind nodes data to what will become DOM elements to represent them.
bubbles = svg.selectAll('.bubble')
.data(nodes, function(d) {
return d.id;
})
.enter()
.append('g')
.attr("transform", d => `translate(${d.x}, ${d.y})`)
.classed('bubble', true)
.on('mouseover', showDetail)
.on('mouseout', hideDetail)
After that, circles and texts can be appended:
circles = bubbles.append('circle')
.attr('r', 0)
.attr('stroke-width', 2)
texts = bubbles.append('text')
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'middle')
.style('font-size', d => d.radius * 0.4 + 'px')
.attr('fill-opacity', 0)
.attr('fill', 'white')
.text(d => d.text)
// Fancy transition to make bubbles appear, ending with the
// correct radius
circles.transition()
.duration(2000)
.attr('r', function(d) {
return d.radius;
});
For hiding/showing text, you can use fill-opacity attribute and set it 0 when the text should be hidden, and 1 if it should be shown:
function showDetail(d, i) {
d3.select(this.childNodes[1]).attr('fill-opacity', 1)
}
function hideDetail(d, i) {
d3.select(this.childNodes[1]).attr('fill-opacity', 0)
}
example: https://jsfiddle.net/r880wm24/
I am making grouped bar chart based on Mike Bostock's tutorial.
I can't figure out how to put circles on top of my bars to act as tooltip when hovering, just like in this tutorial except it's on bars and not on a line.
I tried appending the circles like this :
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 5)
.attr("cx", function(d) { return x1(d.name); })
.attr("cy", function(d) { return y(d.value); })
});
But I get NaN values. I am very confused about which variable I should use to get the right cx and cy.
Here is my code.
Any ideas ?
Thank you
You will get NaN values since your data join is not correct, you are trying to get values that are not currently present in your data. In order to get those values you would need to make a reference to data.years.
Here is my approach:
// Inheriting data from parent node and setting it up,
// add year to each object so we can make use for our
// mouse interactions.
year.selectAll('.gender-circles')
.data(function(data) {
return data.years.map(function(d) {
d.year = data.year;
return d;
})
})
.enter().append('circle')
.attr("class", function(d) {
return "gender-circles gender-circles-" + d.year;
})
.attr("r", 10)
.attr('cx', function(d) {
console.log(d)
return x1(d.name) + 6.5;
})
.attr('cy', function(d) {
return y(d.value) - 15;
})
.style('display', 'none'); // default display
// ....
// Using an invisible rect for mouseover interactions
year.selectAll('.gender-rect-interaction')
.data(function(d) { // Inheriting data from parent node and setting it up
return [d];
})
.enter().append('rect')
.attr("width", x0.rangeBand()) // full width of x0 rangeband
.attr("x", function(d) {
return 0;
})
.attr("y", function(d) {
return 0;
})
.attr("height", function(d) { // full height
return height;
})
.style('opacity', 0) // invisible!
.on('mousemove', function(d) { // show all our circles by class
d3.selectAll('.gender-circles-' + d.year)
.style('display', 'block');
})
.on('mouseout', function(d) { // hide all our circles by class
d3.selectAll('.gender-circles-' + d.year)
.style('display', 'none');
});
Working plnkr: https://plnkr.co/edit/oH4KXdxdIW82nLGv46NI?p=preview
I'm trying to get the bar transition one by one in the horizontal stacked bar chart. But each bar is starting at the same time.
rects = groups.selectAll('stackedBar')
.data(function(d,i) {
console.log("data", d, i);
return d;
})
.enter()
.append('rect')
.attr('class','stackedBar')
.attr('x', function(d) { return xScale(d.x0); })
.attr('y', function(d, i) {return yScale(d.y); })
.attr('height', function(d) { return yScale.rangeBand(); })
.attr('width', 0)
.transition()
.delay(function(d, i){
console.log('hi', d, i);
return i * 500;
})
.attr("width", function(d) { return xScale(d.x); })
.attr("x", function(d) { return xScale(d.x0); })
.duration(1000);
How can i make it animate one by one? Thanks!
jsFiddle
You're almost there -- you need to use .delay() to achieve this, as you're doing already. The only problem is that you're using a nested selection (i.e. rects within gs) and the index you get is that of the inner selection. This is always 0 because there's only one rect per g.
To make it work, reference the secret third argument in a nested selection, which is the index within the data passed to the parent:
.delay(function(d,i,j){console.log('hi',d,j); return j*500;})
This will give you the index of the g element. Complete example here.
I have been using d3 to create a multiline chart with focus and context brushing. Everything is going well except on the transition the dots at the data points with the tooltips are moving to a completely wrong position. I can't figure out what is causing this. Any help would be much appreciated. I attached the full code here and noted on the graph where I'm pretty sure the bug should be:
http://jsbin.com/osumaq/20/edit
When the button is clicked, a new json is passed to the graph to read.
The buggy block of code I think is this:
topicEnter.append("g").selectAll(".dot")
.data(function (d) { return d.values }).enter().append("circle").attr("clip-path", "url(#clip)")
.attr("stroke", function (d) {
return color(this.parentNode.__data__.name)
})
.attr("cx", function (d) {
return x(d.date);
})
.attr("cy", function (d) {
return y(d.probability);
})
.attr("r", 5)
.attr("fill", "white").attr("fill-opacity", .5)
.attr("stroke-width", 2).on("mouseover", function (d) {
div.transition().duration(100).style("opacity", .9);
div.html(this.parentNode.__data__.name + "<br/>" + d.probability).style("left", (d3.event.pageX) + "px").style("top", (d3.event.pageY - 28) + "px").attr('r', 8);
d3.select(this).attr('r', 8)
}).on("mouseout", function (d) {
div.transition().duration(100).style("opacity", 0)
d3.select(this).attr('r', 5);
});
Thank you very much.
What do you mean by tooltip ? Is it the window that appears when we hover on dots ? They seem fine. What I can see is that your dots are not moving while the lines are, and if I had to guess I would say your enter and update selections are mixed. If the dots are already on screen and you want to update their position (by calling your method update) you should have somthing along these lines :
// Bind your data
topicEnter.append("g").selectAll(".dot")
.data(function (d) { return d.values })
// Enter selection
topicEnter.enter().append("circle").attr("clip-path", "url(#clip)").attr("class", "dot");
// Update all the dots
topicEnter.attr("stroke", function (d) {
return color(this.parentNode.__data__.name)
})
.attr("cx", function (d) {
return x(d.date);
})
.attr("cy", function (d) {
return y(d.probability);
})
[...]
I've got a sortable heat map that I've created in D3 shown here: http://bl.ocks.org/umcrcooke/5703304
When I click on the year (column) the initial sort/transition works well, but subsequent clicks resorts, but without the transition. I'm having difficulty troubleshooting it. The code for the transition listed below:
I've set it up such that when the column text is clicked the update function executes:
.on("click", function(d,i) { return d3.transition().each(update(d));});
And the relevant pieces of the update function are:
function update(year) {
grid.selectAll('rect')
.transition()
.duration(2500)
.attr("y", function(d) { return (sortOrder[year].indexOf(d.Country))*cell.height; })
grid.selectAll(".cell_label")
.transition()
.duration(2500)
.attr("y", function(d) { return (sortOrder[year].indexOf(d.Country))*cell.height + (cell.height-cell.border)/2; })
d3.selectAll(".row_label")
.sort(function(a, b) {
return d3.ascending(+a[year], +b[year]);
})
.transition()
.duration(2500)
.attr("y", function(d, i) { return (i*cell.height) + (cell.height-cell.border)/2; });
}
I'm not sure what you're trying to do with d3.transition().each() in the handler, but you don't need it. Changing to:
.on("click", function(d,i) { update(d); });
fixes the problem. See fiddle: http://jsfiddle.net/nrabinowitz/Lk5Pw/