Reputation: 36703
I have developed a web application using D3.js in which there are 100 circles. I want the circles to move slightly (by 2px randomly) and smoothly all the time.
Here is what I have tried using jQuery:
setInterval(function() {
$('.circle_Negative').each(function() {
var newq = makeNewPosition();
$(this).animate({ cx: +$(this).attr("cx")+newq[0], cy: +$(this).attr("cy")+newq[1] },200);
});
}, 200);
function makeNewPosition() {
var nh = Math.floor(Math.random()*2);
var nw = Math.floor(Math.random()*2);
return [nh,nw];
}
But this is not at all smooth. I think there could be better ways by which it can be done using D3 itself but I could not figure out much.
Upvotes: 1
Views: 3376
Reputation: 21578
There are many pitfalls when trying to manipulate SVGs with jQuery (see my answer to "Style a d3 element with jQuery and CSS" for more details). If possible, you should avoid doing so. Since your question is tagged d3 you should stick to that library, which was specifically designed to work on SVGs.
By leveraging D3's concept of binding data to DOM elements this further enables you to separate the manipulation of the underlying data from the update of the circles positions. Within each iteration you calculate the new values and adjust the visual positions accordingly.
The following snippet shows how this might be done:
const width = 400,
height = 400,
offset = 2;
// Create data array containing initial coordinates for all circles.
var data = d3.range(100).map(() => {
return {
cx: Math.floor(Math.random() * width),
cy: Math.floor(Math.random() * height),
r: 2
};
});
// Using D3's data binding to set up the circles.
circles = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.selectAll("circle")
.data(data)
.enter().append("circle")
.attrs(d => d);
// Set the interval
setInterval(() => {
// Update the data bound to the circles.
data.forEach(d => {
d.cx += getRandomOffset();
d.cy += getRandomOffset();
});
// Update the circles' positions according to the data.
circles.attrs(d => d)
}, 50);
function getRandomOffset() {
return (Math.random() * 2 * offset) - offset;
}
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script>
Upvotes: 3
Reputation: 1836
You must use .transition() and .each("end", call a function). Like this:
var svg = d3.select("body")
.append("svg")
.attr("width", 200)
.attr("height", 200);
var circle = svg.append("circle")
.attr("id", "circ")
.attr("cx", Math.random() * 200)
.attr("cy", Math.random() * 200)
.attr("r", 10 + "px")
.transition().each("end", function () {
myTransf();
});
function myTransf() {
d3.select("#circ").transition().duration(500)
.attr("cx", Math.random() * 200) // change this to random 2px
.attr("cy", Math.random() * 200) // change this to random 2px
.each("end", function () {
myTransf();
});
}
Here is the jsFiddle: http://jsfiddle.net/gnq7vnjg/
Hope this help
Upvotes: 1