I need to create a data visualisation which would look like a bunch of floating bubbles with text inside of the bubble.
I have a partially working example which uses mock data prepared here: JSfiddle
// helpers
var random = function(min, max) {
if (max == null) {
max = min;
min = 0;
}
return min + Math.floor(Math.random() * (max - min + 1));
};
// mock data
var colors = [
{
fill: 'rgba(242,216,28,0.3)',
stroke: 'rgba(242,216,28,1)'
},
{
fill: 'rgba(207,203,196,0.3)',
stroke: 'rgba(207,203,196,1)'
},
{
fill: 'rgba(0,0,0,0.2)',
stroke: 'rgba(100,100,100,1)'
}
];
var data = [];
for(var j = 0; j <= 2; j++) {
for(var i = 0; i <= 4; i++) {
var text = 'text' + i;
var category = 'category' + j;
var r = random(50, 100);
data.push({
text: text,
category: category,
r: r,
r_change_1: r + random(-20, 20),
r_change_2: r + random(-20, 20),
fill: colors[j].fill,
stroke: colors[j].stroke
});
}
}
// mock debug
//console.table(data);
// collision detection
// derived from http://ift.tt/1MgMORF
function collide(alpha) {
var quadtree = d3.geom.quadtree(data);
return function(d) {
var r = d.r + 10,
nx1 = d.x - r,
nx2 = d.x + r,
ny1 = d.y - r,
ny2 = d.y + r;
quadtree.visit(function(quad, x1, y1, x2, y2) {
if (quad.point && (quad.point !== d)) {
var x = d.x - quad.point.x,
y = d.y - quad.point.y,
l = Math.sqrt(x * x + y * y),
r = d.r * 2;
if (l < r) {
l = (l - r) / l * alpha;
d.x -= x *= l;
d.y -= y *= l;
quad.point.x += x;
quad.point.y += y;
}
}
return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
});
};
}
// initialize
var container = d3.select('.bubble-cloud');
var $container = $('.bubble-cloud');
var containerWidth = $container.width();
var containerHeight = $container.height();
var svgContainer = container
.append('svg')
.attr('width', containerWidth)
.attr('height', containerHeight);
// prepare layout
var force = d3.layout
.force()
.size([containerWidth, containerHeight])
.gravity(0)
.charge(0)
;
// load data
force.nodes(data)
.start()
;
// create item groups
var node = svgContainer.selectAll('.node')
.data(data)
.enter()
.append('g')
.attr('class', 'node')
.call(force.drag);
// create circles
node.append('circle')
.classed('circle', true)
.attr('r', function (d) {
return d.r;
})
.style('fill', function (d) {
return d.fill;
})
.style('stroke', function (d) {
return d.stroke;
});
// create labels
node.append('text')
.text(function(d) {
return d.text
})
.classed('text', true)
.style({
'fill': '#ffffff',
'text-anchor': 'middle',
'font-size': '12px',
'font-weight': 'bold',
'font-family': 'Tahoma, Arial, sans-serif'
})
;
node.append('text')
.text(function(d) {
return d.category
})
.classed('category', true)
.style({
'fill': '#ffffff',
'font-family': 'Tahoma, Arial, sans-serif',
'text-anchor': 'middle',
'font-size': '9px'
})
;
node.append('line')
.classed('line', true)
.attr('x1', 0)
.attr('y1', 0)
.attr('x2', 50)
.attr('y2', 0)
.attr('stroke-width', 1)
.attr('stroke', function (d) {
return d.stroke;
})
;
// put circle into movement
force.on('tick', function(){
d3.selectAll('circle')
.each(collide(.5))
.attr('cx', function (d) {
// boundaries
if(d.x <= d.r) {
d.x = d.r + 1;
}
if(d.x >= containerWidth - d.r) {
d.x = containerWidth - d.r - 1;
}
return d.x;
})
.attr('cy', function (d) {
// boundaries
if(d.y <= d.r) {
d.y = d.r + 1;
}
if(d.y >= containerHeight - d.r) {
d.y = containerHeight - d.r - 1;
}
return d.y;
});
d3.selectAll('line')
.attr('x1', function (d) {
return d.x - d.r + 10;
})
.attr('y1', function (d) {
return d.y;
})
.attr('x2', function (d) {
return d.x + d.r - 10;
})
.attr('y2', function (d) {
return d.y;
});
d3.selectAll('.text')
.attr('x', function (d) {
return d.x;
})
.attr('y', function (d) {
return d.y - 10;
});
d3.selectAll('.category')
.attr('x', function (d) {
return d.x;
})
.attr('y', function (d) {
return d.y + 20;
});
});
// animate
var interval = setInterval(function(){
// moving of the circles
// ...
}, 5 * 1000);
However I am now facing problem with animation. I cannot figure out how can I animate nodes in force diagram. I tried to adjust values of the data object and then invoke .tick() method inside setInterval method, however it didn't help. I am utilizing D3 force layout.
My questions are:
-
How to make the bubbles "float" around the screen, i.e. how to animate them?
-
How to animate changes of circle radius?
Thank you for your ideas.
via Chebli Mohamed
Aucun commentaire:
Enregistrer un commentaire