Reputation: 69
This is probably a really simple question but I can't seem to figure out how to plot one circle after another (sequentially, with some delay) using d3.js. The circles would then stay on the screen. I'm reading in data from a JSON file and it looks like this:
[{"r":1.2672526041666667,"cx":0,"cy":672.9303022519051,"fill":"rgb(252, 243, 228)"},{"r":1.2672526041666667,"cx":1,"cy":672.9303022519051,"fill":"rgb(252, 243, 228)"},{"r":1.2672526041666667,"cx":2,"cy":672.9303022519051,"fill":"rgb(252, 243, 228)"},{"r":1.2672526041666667,"cx":3,"cy":672.9303022519051,"fill":"rgb(252, 243, 228)"}.....]
and so forth. Json file located here: https://berkeley.box.com/s/4egj1ugr3jm2yp1htoyk8qmtv8avvosb
I've tried so many things!
I've tried using transition/duration but that doesn't seem to be working... I've tried a forEach loop to no avail... I've tried an .each loop as well. I've also tried both methods shown here: How do I loop through or enumerate a JavaScript object?
but I can't get either working. I've also tried looking at this solution:
How to draw circles at different times with D3js?
But I can't seem to plot anything after about 7 hours of trying different things. Here's my code...
<head>
<meta charset="utf-8" />
<title>Laughter Visualizer</title>
<style>
html, body, #svg {
background-color: #FFFFFF;
}
</style>
</head>
<body>
<audio id="audioElement" src="laugh_8.mp3" type="audio/mp3"></audio>
<div>
<button onclick="plotPoints(0, 0)">Draw Points ►</button>
</div>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
function plotPoints(p1, counter) {
d3.json("test2.json").then(function(data){
var svgHeight = window.innerHeight - 100;
var svgWidth = window.innerWidth - 10;
var svg = d3.select('body').append('svg')
.attr('width', svgWidth)
.attr('height', svgHeight);
svg.selectAll("circle")
.data(data)
.enter()
.append('circle')
.attr('r', function(d) { return d.r; })
.attr('cx', function(d) { return d.cx; })
.attr('cy', function(d) { return d.cy; })
.attr('fill', function(d) { return d.fill; });
})
}
</script>
</body>
</html>
Upvotes: 2
Views: 504
Reputation: 7210
Here is a simple D3-based solution:
const svg = d3.select('svg')
const circleData = [
{id: 1, x: 100, y: 300, c: '#f00', r: 50, d: 500},
{id: 2, x: 250, y: 100, c: '#ff0', r: 90, d: 1000},
{id: 3, x: 300, y: 350, c: '#08f', r: 70, d: 1500},
]
svg.selectAll('circle')
.data(circleData, data => data.id)
.enter()
.append('circle')
.attr('cx', data => data.x)
.attr('cy', data => data.y)
.attr('r', data => data.r)
.style('fill', data => data.c)
.style('visibility', 'hidden')
.transition()
.delay(data => data.d)
.style('visibility', 'visible')
See the demo in a fiddle: https://jsfiddle.net/mrovinsky/pbgac6jw/
Upvotes: 0
Reputation: 102174
Given your comment...
I'm looking for the circles to stay...
...the idiomatic D3 solution is using a simple transition, using the indices to set the delay. For instance, plotting one circle every 100 milliseconds:
.delay(function(_, i) {
return i * 100;
})
Regarding the transition itself, you could do it in several different ways, for instance increasing the radiuses. My solution here is just plotting everything and transition the opacity
from 0
to 1
.
I also created some scales, so your data values don't need to correspond to SVG coordinates:
const xDomain = d3.extent(data, function(d) {
return d.cx
});
const yDomain = d3.extent(data, function(d) {
return d.cy
});
const xScale = d3.scaleLinear()
.range([0, width])
.domain(xDomain);
const yScale = d3.scaleLinear()
.range([0, height])
.domain(yDomain);
Here is a demo using your data:
const data = [{
"r": 1.2672526041666667,
"cx": 0,
"cy": 672.9303022519051,
"fill": "rgb(252, 243, 228)"
}, {
"r": 1.2672526041666667,
"cx": 1,
"cy": 672.9303022519051,
"fill": "rgb(252, 243, 228)"
}, {
"r": 1.2672526041666667,
"cx": 2,
"cy": 672.9303022519051,
"fill": "rgb(252, 243, 228)"
}, {
"r": 1.2672526041666667,
"cx": 3,
"cy": 672.9303022519051,
"fill": "rgb(252, 243, 228)"
}, {
"r": 3.9895833333333335,
"cx": 4,
"cy": 661.4035574412531,
"fill": "rgb(247, 231, 205)"
}, {
"r": 3.9895833333333335,
"cx": 5,
"cy": 661.4035574412531,
"fill": "rgb(247, 231, 205)"
}, {
"r": 3.9895833333333335,
"cx": 6,
"cy": 661.4035574412531,
"fill": "rgb(247, 231, 205)"
}, {
"r": 5.073893229166667,
"cx": 7,
"cy": 660.5638673253352,
"fill": "rgb(244, 226, 195)"
}, {
"r": 5.073893229166667,
"cx": 8,
"cy": 660.5638673253352,
"fill": "rgb(244, 226, 195)"
}, {
"r": 5.6962890625,
"cx": 9,
"cy": 661.1542183362859,
"fill": "rgb(243, 223, 190)"
}, {
"r": 5.6962890625,
"cx": 10,
"cy": 661.1542183362859,
"fill": "rgb(243, 223, 190)"
}, {
"r": 5.6962890625,
"cx": 11,
"cy": 661.1542183362859,
"fill": "rgb(243, 223, 190)"
}, {
"r": 5.6962890625,
"cx": 12,
"cy": 661.1542183362859,
"fill": "rgb(243, 223, 190)"
}, {
"r": 6.125651041666667,
"cx": 13,
"cy": 661.8292769334325,
"fill": "rgb(242, 221, 186)"
}, {
"r": 6.125651041666667,
"cx": 14,
"cy": 661.8292769334325,
"fill": "rgb(242, 221, 186)"
}, {
"r": 6.422526041666667,
"cx": 15,
"cy": 661.5401588106098,
"fill": "rgb(241, 219, 184)"
}, {
"r": 6.422526041666667,
"cx": 16,
"cy": 661.5401588106098,
"fill": "rgb(241, 219, 184)"
}, {
"r": 6.422526041666667,
"cx": 17,
"cy": 661.5401588106098,
"fill": "rgb(241, 219, 184)"
}, {
"r": 6.422526041666667,
"cx": 18,
"cy": 661.5401588106098,
"fill": "rgb(241, 219, 184)"
}, {
"r": 6.770182291666667,
"cx": 19,
"cy": 658.8530307401353,
"fill": "rgb(241, 218, 181)"
}, {
"r": 6.770182291666667,
"cx": 20,
"cy": 658.8530307401353,
"fill": "rgb(241, 218, 181)"
}, {
"r": 6.770182291666667,
"cx": 21,
"cy": 658.8530307401353,
"fill": "rgb(241, 218, 181)"
}, {
"r": 7.0205078125,
"cx": 22,
"cy": 656.2237523376763,
"fill": "rgb(240, 217, 179)"
}, {
"r": 7.0205078125,
"cx": 23,
"cy": 656.2237523376763,
"fill": "rgb(240, 217, 179)"
}, {
"r": 7.0205078125,
"cx": 24,
"cy": 656.2237523376763,
"fill": "rgb(240, 217, 179)"
}, {
"r": 7.144205729166667,
"cx": 25,
"cy": 654.865008125636,
"fill": "rgb(240, 216, 178)"
}, {
"r": 7.144205729166667,
"cx": 26,
"cy": 654.865008125636,
"fill": "rgb(240, 216, 178)"
}, {
"r": 7.144205729166667,
"cx": 27,
"cy": 654.865008125636,
"fill": "rgb(240, 216, 178)"
}, {
"r": 7.349934895833333,
"cx": 28,
"cy": 653.0513751716197,
"fill": "rgb(239, 215, 176)"
}, {
"r": 7.349934895833333,
"cx": 29,
"cy": 653.0513751716197,
"fill": "rgb(239, 215, 176)"
}, {
"r": 7.7802734375,
"cx": 30,
"cy": 648.4655453746704,
"fill": "rgb(238, 213, 172)"
}, {
"r": 7.7802734375,
"cx": 31,
"cy": 648.4655453746704,
"fill": "rgb(238, 213, 172)"
}, {
"r": 7.7802734375,
"cx": 32,
"cy": 648.4655453746704,
"fill": "rgb(238, 213, 172)"
}, {
"r": 7.7802734375,
"cx": 33,
"cy": 648.4655453746704,
"fill": "rgb(238, 213, 172)"
}, {
"r": 8.924153645833334,
"cx": 34,
"cy": 646.4654507872818,
"fill": "rgb(236, 208, 162)"
}, {
"r": 8.924153645833334,
"cx": 35,
"cy": 646.4654507872818,
"fill": "rgb(236, 208, 162)"
}, {
"r": 8.924153645833334,
"cx": 36,
"cy": 646.4654507872818,
"fill": "rgb(236, 208, 162)"
}, {
"r": 8.924153645833334,
"cx": 37,
"cy": 646.4654507872818,
"fill": "rgb(236, 208, 162)"
}, {
"r": 10.550130208333334,
"cx": 38,
"cy": 642.0891082999074,
"fill": "rgb(233, 200, 148)"
}, {
"r": 10.550130208333334,
"cx": 39,
"cy": 642.0891082999074,
"fill": "rgb(233, 200, 148)"
}, {
"r": 10.550130208333334,
"cx": 40,
"cy": 642.0891082999074,
"fill": "rgb(233, 200, 148)"
}, {
"r": 11.846028645833334,
"cx": 41,
"cy": 638.9493098110339,
"fill": "rgb(230, 194, 137)"
}, {
"r": 11.846028645833334,
"cx": 42,
"cy": 638.9493098110339,
"fill": "rgb(230, 194, 137)"
}, {
"r": 13.046875,
"cx": 43,
"cy": 635.5438456420493,
"fill": "rgb(227, 189, 127)"
}, {
"r": 13.046875,
"cx": 44,
"cy": 635.5438456420493,
"fill": "rgb(227, 189, 127)"
}, {
"r": 13.046875,
"cx": 45,
"cy": 635.5438456420493,
"fill": "rgb(227, 189, 127)"
}, {
"r": 14.2236328125,
"cx": 46,
"cy": 631.6291795399932,
"fill": "rgb(225, 183, 117)"
}, {
"r": 14.2236328125,
"cx": 47,
"cy": 631.6291795399932,
"fill": "rgb(225, 183, 117)"
}, {
"r": 14.2236328125,
"cx": 48,
"cy": 631.6291795399932,
"fill": "rgb(225, 183, 117)"
}, {
"r": 15.346028645833334,
"cx": 49,
"cy": 626.1064208896337,
"fill": "rgb(222, 178, 107)"
}, {
"r": 15.346028645833334,
"cx": 50,
"cy": 626.1064208896337,
"fill": "rgb(222, 178, 107)"
}, {
"r": 15.346028645833334,
"cx": 51,
"cy": 626.1064208896337,
"fill": "rgb(222, 178, 107)"
}, {
"r": 16.297526041666668,
"cx": 52,
"cy": 620.3574348526613,
"fill": "rgb(220, 174, 99)"
}, {
"r": 16.297526041666668,
"cx": 53,
"cy": 620.3574348526613,
"fill": "rgb(220, 174, 99)"
}, {
"r": 16.297526041666668,
"cx": 54,
"cy": 620.3574348526613,
"fill": "rgb(220, 174, 99)"
}, {
"r": 16.778645833333332,
"cx": 55,
"cy": 617.0644627244038,
"fill": "rgb(219, 172, 95)"
}, {
"r": 16.778645833333332,
"cx": 56,
"cy": 617.0644627244038,
"fill": "rgb(219, 172, 95)"
}, {
"r": 16.778645833333332,
"cx": 57,
"cy": 617.0644627244038,
"fill": "rgb(219, 172, 95)"
}, {
"r": 16.83203125,
"cx": 58,
"cy": 614.5978314122896,
"fill": "rgb(219, 171, 94)"
}, {
"r": 16.83203125,
"cx": 59,
"cy": 614.5978314122896,
"fill": "rgb(219, 171, 94)"
}, {
"r": 16.83203125,
"cx": 60,
"cy": 614.5978314122896,
"fill": "rgb(219, 171, 94)"
}, {
"r": 17.060221354166668,
"cx": 61,
"cy": 609.8278349138509,
"fill": "rgb(219, 170, 92)"
}, {
"r": 17.060221354166668,
"cx": 62,
"cy": 609.8278349138509,
"fill": "rgb(219, 170, 92)"
}, {
"r": 17.060221354166668,
"cx": 63,
"cy": 609.8278349138509,
"fill": "rgb(219, 170, 92)"
}, {
"r": 17.060221354166668,
"cx": 64,
"cy": 609.8278349138509,
"fill": "rgb(219, 170, 92)"
}, {
"r": 17.533854166666668,
"cx": 65,
"cy": 602.747264716075,
"fill": "rgb(218, 168, 88)"
}, {
"r": 17.533854166666668,
"cx": 66,
"cy": 602.747264716075,
"fill": "rgb(218, 168, 88)"
}, {
"r": 17.533854166666668,
"cx": 67,
"cy": 602.747264716075,
"fill": "rgb(218, 168, 88)"
}, {
"r": 18.1669921875,
"cx": 68,
"cy": 596.8306485811727,
"fill": "rgb(216, 165, 83)"
}, {
"r": 18.1669921875,
"cx": 69,
"cy": 596.8306485811727,
"fill": "rgb(216, 165, 83)"
}, {
"r": 18.333984375,
"cx": 70,
"cy": 594.4961471538654,
"fill": "rgb(216, 165, 81)"
}, {
"r": 18.333984375,
"cx": 71,
"cy": 594.4961471538654,
"fill": "rgb(216, 165, 81)"
}, {
"r": 18.333984375,
"cx": 72,
"cy": 594.4961471538654,
"fill": "rgb(216, 165, 81)"
}, {
"r": 18.333984375,
"cx": 73,
"cy": 594.4961471538654,
"fill": "rgb(216, 165, 81)"
}, {
"r": 18.0771484375,
"cx": 74,
"cy": 594.6126027167029,
"fill": "rgb(217, 166, 83)"
}, {
"r": 18.0771484375,
"cx": 75,
"cy": 594.6126027167029,
"fill": "rgb(217, 166, 83)"
}, {
"r": 18.0771484375,
"cx": 76,
"cy": 594.6126027167029,
"fill": "rgb(217, 166, 83)"
}, {
"r": 17.9443359375,
"cx": 77,
"cy": 594.2603597883598,
"fill": "rgb(217, 166, 85)"
}, {
"r": 17.9443359375,
"cx": 78,
"cy": 594.2603597883598,
"fill": "rgb(217, 166, 85)"
}];
const width = 400,
height = 200;
const svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
const xDomain = d3.extent(data, function(d) {
return d.cx
});
const yDomain = d3.extent(data, function(d) {
return d.cy
});
const xScale = d3.scaleLinear()
.range([25, width -25])
.domain(xDomain);
const yScale = d3.scaleLinear()
.range([25, height - 25])
.domain(yDomain);
const circles = svg.selectAll(null)
.data(data)
.enter()
.append("circle")
.style("opacity", 0)
.attr("cx", function(d) {
return xScale(d.cx)
})
.attr("cy", function(d) {
return yScale(d.cy)
})
.attr("r", function(d) {
return d.r
})
.style("fill", function(d) {
return d.fill
})
.transition()
.delay(function(_, i) {
return i * 100;
})
.style("opacity", 1);
<script src="https://d3js.org/d3.v5.min.js"></script>
Upvotes: 2
Reputation: 12891
The problem is that you're handing over the complete data out of the json object to the selectAll() function of d3 to be drawn at once. Instead inside the callback function for d3.json("test2.json")
assign the returned data to a global variable. Afterwards initiate a interval where you call svg.append('circle')
- thus telling d3 to draw a circle after another.
<head>
<meta charset="utf-8" />
<title>Laughter Visualizer</title>
<style>
html, body, #svg {
background-color: #FFFFFF;
}
</style>
</head>
<body>
<audio id="audioElement" src="laugh_8.mp3" type="audio/mp3"></audio>
<div>
<button onclick="plotPoints(0, 0)">Draw Points ►</button>
</div>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
var svg;
var circleData;
var index=0;
var interval;
function update()
{
svg.append('circle')
.attr('r', circleData[index].r)
.attr('cx', circleData[index].cx)
.attr('cy', circleData[index].cy)
.attr('fill', circleData[index].fill);
if(index+1<circleData.length)
{
index++;
}
}
function plotPoints(p1, counter) {
d3.json("test2.json").then(function(data){
circleData=data;
var svgHeight = window.innerHeight - 100;
var svgWidth = window.innerWidth - 10;
svg = d3.select('body').append('svg')
.attr('width', svgWidth)
.attr('height', svgHeight);
interval=setInterval(update,100);
})
}
</script>
</body>
</html>
Upvotes: -1