Transition Code,
d3.select('chart').select('svg')
.selectAll("circle")
.data(sampleData)
.enter().append('circle')
.each(function (d,i)
{
d3.select(this)
.transition()
.delay(i*50)
.attr('cx', function(d) {return d.x;})
.attr('cy', function(d) {return d.y;})
.attr('r', 4);
});
How can I stop/cancel the scheduled/delayed transactions?
The accepted answer does not work with the most recent version of d3. If you're using d3 v4, you should call .interrupt() on your selection.
As pointed out in the other answer, all you need is to schedule a new transition. However, the whole thing is much easier than what you're doing in your code -- there's no need for the separate .each() function. To schedule the transitions initially, you can simply do
d3.select('chart').select('svg')
.selectAll("circle")
.data(sampleData)
.enter().append('circle')
.transition()
.delay(function(d, i) { return i*50; })
.attr('cx', function(d) {return d.x;})
.attr('cy', function(d) {return d.y;})
.attr('r', 4);
The function to stop all transitions (scheduled and running) is simply
d3.selectAll("circle").transition();
Complete demo here.
Starting a new transition on the element stops any transition that is already running. You can pause/stop a d3 transition by setting a new transition with duration as 0.
function stopCircleTransitions(){
if(startedApplyingTransitions)
d3.select('chart').select('svg')
.selectAll("circle")
.each(function(d,i){
d3.select(this)
.transition()
.duration(0);
});
}
}
If you would like to stop the transition if and only if it is started applying, you can try the code below.
var startedApplyingTransitions = false;
d3.select('chart').select('svg')
.selectAll("circle")
.data(sampleData)
.enter()
.append('circle')
.each(function (d,i){
d3.select(this)
.transition()
.delay(i*50)
.attr('cx', function(d) {return d.x;})
.attr('cy', function(d) {return d.y;})
.attr('r', 4)
.each("end", function(){ //this code will do the trick
startedApplyingTransitions = true;
});
});
Related
I have a line plot with some circle markers.
I'd like to add some mouseover and mouseout effects to the circles.
Here is my code:
let linePlot = svg.selectAll('.line')
.data(data);
// Draws the line
linePlot
.enter()
.append('path')
.merge(linePlot)
.datum(data)
.transition()
.duration(800)
.attr('class', 'line')
.attr('d', d3.line()
.x(function (d) { return xScale(d.YEAR); })
.y(function (d) { return yScale(d[metricType]); })
.curve(d3.curveMonotoneX)
);
linePlot
.exit()
.remove();
// Draws the circles
let circles = svg.selectAll('circle')
.data(data);
circles
.enter()
.append('circle')
.merge(circles)
.data(data)
.transition()
.duration(800)
.attr('fill', '#5e855d')
.attr('stroke', '#49614a')
.attr('cx', function(d) { return xScale(d.YEAR)})
.attr('cy', function(d) { return yScale(d[metricType])})
.attr('r', 6)
;
circles
.on('mouseover', function() {
d3.select(this)
.transition()
.duration(2000)
.attr('fill', 'red')
})
.on('mouseout', function() {
d3.select(this)
.transition()
.duration(2000)
.attr('fill', 'blue')
})
circles
.exit()
.remove();
The mouseout and mouseover effects are not working.
Any assistance would be greatly appreciated.
Thanks!
When you do this...
circles
.enter()
.append('circle')
.merge(circles)
.data(data)
.transition()
.duration(800)
.attr('fill', etc...
...you're basically setting circles as a transition selection, and transitions don't have mouseover as a typename. The only typenames allowed for a transition are:
start
end
interrupt
cancel
The idiomatic solution is breaking that chain:
circles.enter()
.append('circle')
.merge(circles)
.data(data);
circles.transition()
.duration(800)
.attr('fill', etc...
Now circles is a proper D3 selection, so you can do circles.on('mouseover', etc....
Finally, consider revising that data method after merging, it makes little sense to me.
I've got an old d3v3 bubble chart -- it had some animation aspects -- I am trying to upgrade it to a v4
//version 3
https://jsfiddle.net/497tmhu0/
There is always a desire to have some animation for when these bubbles load for the first time.
So here - bubbles are created very small and then they expand in size to their resting size.
// Enter
nodes.enter()
.append("circle")
.attr("class", "node")
.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; })
.attr("r", 10)
.style("fill", function (d, i) {
return color(i);
})
.call(force.drag());
// Update
nodes
.transition()
.delay(300)
.duration(1000)
.attr("r", function (d) {
return d.radius * scale;
})
// Exit
nodes.exit()
.transition()
.duration(250)
.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; })
.attr("r", 1)
.remove();
I was converting the chart but some parts of the force functions are no longer working.
https://bl.ocks.org/mbostock/ad70335eeef6d167bc36fd3c04378048
https://bl.ocks.org/shimizu/e6209de87cdddde38dadbb746feaf3a3
this is the current v4 I have - but the animation and force parts are broken.
//current version 4
https://jsfiddle.net/497tmhu0/2/
June 8th -- bubbles grow in size now -- but force aspects are not working - https://jsfiddle.net/vkoxrtwz/ - need to give the bubbles some force aspects - and if clicked on temporarily change their charge so it ripples through the chart and causes the circles to repel/attract each other slightly
You can just chain your animations after the first enter() method. Draw them small, and then add a transition immediately.
// Enter
nodes.enter()
.append("circle")
.attr("class", "node")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", 1)
.style("fill", function(d, i) {
return color(i);
})
.transition()
.delay(300)
.duration(1000)
.attr("r", function(d) {
return d.radius * scale;
})
https://jsfiddle.net/vkoxrtwz/
I am working with a d3 scatterplot. I connect to my database and initially I begin with lets say 3 dots on the graph. Each dot represents a paper and the x axis is the year and the y axis is how many citations it has. Now when I click on a dot, papers that that paper cites appear on the graph. I have managed all of the above so far but my issue now is that although when I click on dot the relevant papers appear on the graph, when I click on THOSE dots nothing happens. So I havent managed to bind my Json data to the new dots. Here is the relevant code:
// initial connection to display papers
d3.json("connection4.php", function(error,dataJson) {
dataJson.forEach(function(d) {
d.YEAR = +d.YEAR;
d.counter = +d.counter;
console.log(d);
})
//baseData is the original data that I dont want to be replaced
baseData = dataJson;
// draw dots
var g = svg.selectAll(".dot")
.data(baseData)
.enter()
.append("circle")
.attr("class", "dot")
.attr("r", 3.5)
.attr("cx", function(d) {return x(YearFn(d))})
.attr("cy", function(d) {return y(Num_citationsFn(d))})
.style("fill","blue")
.on("click", function(d, i) {
d3.json("connection2.php?paperID="+d.ID, function(error, dataJson) {
console.log(dataJson);
dataJson.forEach(function(d) {
d.YEAR = +d.YEAR;
d.counter = +d.counter;
console.log(d);
baseData.push(d);
})
var g = svg.selectAll(".dot")
.data(baseData)
.enter()
.append("circle")
.attr("class", "dot")
.attr("r", 3.5)
.attr("cx", function(d) {return x(YearFn(d))})
.attr("cy", function(d) {return y(Num_citationsFn(d))})
.style("fill", "red")
})
My queries in the php file are fine as I can see they are returning the correct data, so I think my main issue is binding my Json data from my second connection to the new dots. I wonder can anyone shed some light on how I need to go about this. I am new to d3 so any feedback is appreciated! thanks in advance
I think the problem is very simply that you do not bind the "click" event to your newly created nodes.
Replace the lines
// draw dots
var g = svg.selectAll(".dot")
.data(baseData)
.enter()
.append("circle")
.attr("class", "dot")
.attr("r", 3.5)
.attr("cx", function(d) {return x(YearFn(d))})
.attr("cy", function(d) {return y(Num_citationsFn(d))})
.style("fill","blue")
.on("click", function(d, i) {
...
})
by
function clickHandler (d,i){
...
}
// draw dots
var g = svg.selectAll(".dot")
.data(baseData)
.enter()
.append("circle")
.attr("class", "dot")
.attr("r", 3.5)
.attr("cx", function(d) {return x(YearFn(d))})
.attr("cy", function(d) {return y(Num_citationsFn(d))})
.style("fill","blue")
.on("click", clickHandler); //clickHandler is referenced here, instead of the original anonymous function
and add also a .on("click", clickHandler); call to your newly created node, i.e. within the clickHandler function itself:
///add linked dots
var g = svg.selectAll(".dot")
.data(baseData)
.enter()
.append("circle")
.attr("class", "dot")
.attr("r", 3.5)
.attr("cx", function(d) {return x(YearFn(d))})
.attr("cy", function(d) {return y(Num_citationsFn(d))})
.style("fill", "red")
.on("click", clickHandler); //click handler is *also* called here
Any help would be greatly appreciated.
Basically, the mouseover was working fine until I added a transition to the line chart. The transition takes the circles' opacity from zero to one.
var dots = svg.selectAll('circle')
.data(data)
.enter()
.append('svg:circle')
.attr('cx', function(d, i){ return ((width - tickOffset) / (data.length - 1)) * i; })
.attr('cy', function(d){ return y(d.value); })
.attr('r', 4)
.attr('class', 'circle')
.style('opacity', 0)
.transition()
.duration(circleAnimation)
.delay(function(d,i){ return i * (circleAnimation / 4); })
.style('opacity', 1);
dots.on('mouseover', function(d, i){
// show tooltip
})
.on('mouseout', function(d, i){
// hide tooltip
});
When I implement the transition, the console throws the following error
TypeError: 'undefined' is not a function (evaluating 'dots.on')
This same issue was happening on a bar chart I just created and simply stopping the method chaining and starting it again fixed the problem. That's why in this example I've stopped the method chaining and started it again with "dots.on('mouseover..."
As soon as you call .transition(), the selection you have becomes a transition. This is what you save in dots and then try to call .on() on. Instead, save the selection and set the transition and event handlers on it:
var dots = svg.selectAll('circle')
.data(data)
.enter()
.append('svg:circle')
.attr('cx', function(d, i){ return ((width - tickOffset) / (data.length - 1)) * i; })
.attr('cy', function(d){ return y(d.value); })
.attr('r', 4)
.attr('class', 'circle')
.style('opacity', 0);
dots.transition()
.duration(circleAnimation)
.delay(function(d,i){ return i * (circleAnimation / 4); })
.style('opacity', 1);
dots.on('mouseover', function(d, i){
// show tooltip
})
.on('mouseout', function(d, i){
// hide tooltip
});
i've successfully added transitions to my circles in a node graph, but i'm now trying to animate the mouseover of the connective line.
here's what I've tried:
//define the lines:
var edges = svg.selectAll("line")
.data(dataset.edges)
.enter()
.append("line")
.style("stroke", "#ccc")
.style("stroke-width", 1)
.on("mouseover", lineMouseover)
.on("mouseout", lineMouseout);
//the callback functions for mouseover / mouseout
function lineMouseover() {
d3.select(this).select("line")
.transition()
.duration(100)
.style("stroke-width", 3);
}
function lineMouseout() {
d3.select(this).select("line")
.transition()
.duration(100)
.style("stroke-width", 1);
}
Nothing seems to happen at all when i mouse over the lines. so, either i'm capturing the line incorrectly, or the attributes i'm animating are the wrong attributes.
any insight into what I'm doing wrong here?
In your code, the thiscontext in the lineMouseOverand lineMouseOut functions is the line element. You could simply use d3.select(this)to select each line and set its attributes. I wrote a small fiddle http://jsfiddle.net/pnavarrc/4fgv4/2
svg.selectAll('path')
.data(data)
.enter()
.append('path')
.attr('d', function(d) { return line(d.p); })
.attr('stroke-width', function(d) { return d.w; })
.attr('stroke', function(d) { return d.c; })
.on('mouseover', mOver)
.on('mouseout', function(d) {
d3.select(this)
.transition()
.duration(300)
.style('stroke-width', d.w);
});
function mOver(d) {
d3.select(this)
.transition()
.duration(300)
.style('stroke-width', 6);
}
Regards,