Implemented collisions on nodes

Also included in this is the implementation of stats as html foreign
objects in svgs.
This commit is contained in:
Tom Gallacher 2016-12-06 16:29:45 +00:00
parent 62aef3eec6
commit d82a43d1e3

View File

@ -66,7 +66,7 @@ var color = d3.scaleOrdinal(d3.schemeCategory20);
var simulation = d3.forceSimulation() var simulation = d3.forceSimulation()
.force('charge', d3.forceManyBody().strength(() => -50).distanceMin(() => 30)) .force('charge', d3.forceManyBody().strength(() => -50).distanceMin(() => 30))
.force('link', d3.forceLink().distance(() => 200).id(function(d) { return d.id; })) .force('link', d3.forceLink().distance(() => 200).id(function(d) { return d.id; }))
.force('collide', d3.forceCollide().radius(function(d) { return 128 + 0.5; }).iterations(2)) .force('collide', d3.forceCollide().radius(function(d) { return 200 + 0.5; }).iterations(2))
.force('center', d3.forceCenter(width * 1/3, height * 1/3)) .force('center', d3.forceCenter(width * 1/3, height * 1/3))
function rightRoundedRect(x, y, width, height, radius) { function rightRoundedRect(x, y, width, height, radius) {
@ -171,35 +171,26 @@ d3.json('services.json', function(error, graph) {
.attr('stroke-width', '1px') .attr('stroke-width', '1px')
.attr('fill', '#464646') .attr('fill', '#464646')
// An icon or label that exists within the circle, inside the infobox var html = stats
stats.append('text') .append('switch')
.attr('class', 'cpu') .append('foreignObject')
.attr('class', 'stat') .attr('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility')
.attr('x', '12') .attr('x', 12)
.attr('y', '65') .attr('y', 57)
.attr('text-anchor', 'start') .attr('width', 160)
.attr('fill', 'rgba(255, 255, 255, 0.8)') .attr('height', 70)
.text('CPU: 63%') // From here everything will be rendered with react using a ref.
// However for now these values are hard-coded.
.append('xhtml:div')
.attr('class', 'node_statistics')
// An icon or label that exists within the circle, inside the infobox // Remove with react + dyanmic data.
stats.append('text') html.append('p')
.attr('class', 'memory') .text('CPU: 48%')
.attr('class', 'stat') html.append('p')
.attr('x', '12') .text('Memory: 54%')
.attr('y', '85') html.append('p')
.attr('text-anchor', 'start') .text('Network: 1.75kb/sec')
.attr('fill', 'rgba(255, 255, 255, 0.8)')
.text('Memory: 50%')
// An icon or label that exists within the circle, inside the infobox
stats.append('text')
.attr('class', 'network')
.attr('class', 'stat')
.attr('x', '12')
.attr('y', '105')
.attr('text-anchor', 'start')
.attr('fill', 'rgba(255, 255, 255, 0.8)')
.text('Network: 1.23kb/sec')
elm.call(d3.drag() elm.call(d3.drag()
@ -237,7 +228,7 @@ d3.json('services.json', function(error, graph) {
primary.append('path') primary.append('path')
.attr('class', 'node') .attr('class', 'node')
.attr('d', rect('0', '-39', 170, 78, 2)) .attr('d', rect('0', '-39', 170, 114, 2))
.attr('stroke', '#343434') .attr('stroke', '#343434')
.attr('stroke-width', '1px') .attr('stroke-width', '1px')
.attr('fill', '#464646') .attr('fill', '#464646')
@ -267,11 +258,32 @@ d3.json('services.json', function(error, graph) {
.attr('fill', '#fff') .attr('fill', '#fff')
.text('☇') .text('☇')
var html = primary
.append('switch')
.append('foreignObject')
.attr('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility')
.attr('x', 12)
.attr('y', 87)
.attr('width', 160)
.attr('height', 70)
// From here everything will be rendered with react using a ref.
// However for now these values are hard-coded.
.append('xhtml:div')
.attr('class', 'node_statistics')
// Remove with react + dyanmic data.
html.append('p')
.text('CPU: 48%')
html.append('p')
.text('Memory: 54%')
html.append('p')
.text('Network: 1.75kb/sec')
var secondary = stats.append('g'); var secondary = stats.append('g');
secondary.append('path') secondary.append('path')
.attr('class', 'node') .attr('class', 'node')
.attr('d', bottomRoundedRect('0', '-113', 170, 114, 4)) .attr('d', bottomRoundedRect('0', '-149', 170, 114, 4))
.attr('stroke', '#343434') .attr('stroke', '#343434')
.attr('stroke-width', '1px') .attr('stroke-width', '1px')
.attr('fill', '#464646') .attr('fill', '#464646')
@ -279,7 +291,7 @@ d3.json('services.json', function(error, graph) {
secondary.append('text') secondary.append('text')
.attr('class', 'secondary') .attr('class', 'secondary')
.attr('x', '12') .attr('x', '12')
.attr('y', '150') .attr('y', '183')
.attr('text-anchor', 'start') .attr('text-anchor', 'start')
.attr('fill', '#fff') .attr('fill', '#fff')
.text('Secondary') .text('Secondary')
@ -287,7 +299,7 @@ d3.json('services.json', function(error, graph) {
secondary.append('circle') secondary.append('circle')
.attr('class', 'alert') .attr('class', 'alert')
.attr('cx', function () { return d3.select(this.parentNode).select('.secondary').node().getBBox().width + 30 }) .attr('cx', function () { return d3.select(this.parentNode).select('.secondary').node().getBBox().width + 30 })
.attr('cy', '144') .attr('cy', '177')
.attr('stroke-width', '0px') .attr('stroke-width', '0px')
.attr('fill', 'rgb(0,175,102)') .attr('fill', 'rgb(0,175,102)')
.attr('r', '9px') .attr('r', '9px')
@ -296,7 +308,7 @@ d3.json('services.json', function(error, graph) {
secondary.append('text') secondary.append('text')
.attr('class', 'health') .attr('class', 'health')
.attr('x', function () { return d3.select(this.parentNode).select('.secondary').node().getBBox().width + 30 }) .attr('x', function () { return d3.select(this.parentNode).select('.secondary').node().getBBox().width + 30 })
.attr('y', '149') .attr('y', '182')
.attr('text-anchor', 'middle') .attr('text-anchor', 'middle')
.attr('fill', '#fff') .attr('fill', '#fff')
.text('❤') .text('❤')
@ -306,9 +318,9 @@ d3.json('services.json', function(error, graph) {
.append('foreignObject') .append('foreignObject')
.attr('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility') .attr('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility')
.attr('x', 12) .attr('x', 12)
.attr('y', 160) .attr('y', 200)
.attr('width', 160) .attr('width', 160)
.attr('height', 100) .attr('height', 70)
// From here everything will be rendered with react using a ref. // From here everything will be rendered with react using a ref.
// However for now these values are hard-coded. // However for now these values are hard-coded.
.append('xhtml:div') .append('xhtml:div')
@ -369,18 +381,49 @@ d3.json('services.json', function(error, graph) {
function ticked() { function ticked() {
// TODO: Remove these values and pull them out of the height of the boxes // TODO: Remove these values and pull them out of the height of the boxes
// that the constraints belong to. // that the constraints belong to.
r=180 r=174
r2=130 r2=270
link link
.attr('x1', function(d) { return contrain(width, r, d.source.x) + 80; }) .attr('x1', function(d) {
.attr('y1', function(d) { return contrain(height, r2, d.source.y) + 24; }) let x;
.attr('x2', function(d) { return contrain(width, r, d.target.x) + 80; }) svg.selectAll('.node_group').each(function (_, i) {
.attr('y2', function(d) { return contrain(height, r2, d.target.y) + 24; }); if (i !== d.source.index) return;
x = d3.select(this).node().getBBox().width;
});
return contrain(width, x, d.source.x) + 80;
})
.attr('y1', function(d) {
let y;
svg.selectAll('.node_group').each(function (_, i) {
if (i !== d.source.index) return;
y = d3.select(this).node().getBBox().height;
});
return contrain(height, y, d.source.y) + 24;
})
.attr('x2', function(d) {
let x;
svg.selectAll('.node_group').each(function (_, i) {
if (i !== d.target.index) return;
x = d3.select(this).node().getBBox().width;
});
return contrain(width, x, d.target.x) + 80;
})
.attr('y2', function(d) {
let y;
svg.selectAll('.node_group').each(function (_, i) {
if (i !== d.target.index) return;
y = d3.select(this).node().getBBox().height;
});
return contrain(height, y, d.target.y) + 24;
});
svg.selectAll('.node_group') svg.selectAll('.node_group')
.attr('transform', function(d) { .attr('transform', function(d) {
return 'translate(' + contrain(width, r, d.x) + ',' + contrain(height, r2, d.y) + ')'; let x = d3.select(this).node().getBBox().width;
let y = d3.select(this).node().getBBox().height;
return 'translate(' + contrain(width, x, d.x) + ',' + contrain(height, y, d.y) + ')';
}); });
} }
}); });