From d82a43d1e36690cab8c8af3e907c4f45f47695aa Mon Sep 17 00:00:00 2001 From: Tom Gallacher Date: Tue, 6 Dec 2016 16:29:45 +0000 Subject: [PATCH] Implemented collisions on nodes Also included in this is the implementation of stats as html foreign objects in svgs. --- spikes/architecture/d3-revamp/index.html | 129 +++++++++++++++-------- 1 file changed, 86 insertions(+), 43 deletions(-) diff --git a/spikes/architecture/d3-revamp/index.html b/spikes/architecture/d3-revamp/index.html index 8e1d0307..85dc2f2c 100644 --- a/spikes/architecture/d3-revamp/index.html +++ b/spikes/architecture/d3-revamp/index.html @@ -66,7 +66,7 @@ var color = d3.scaleOrdinal(d3.schemeCategory20); var simulation = d3.forceSimulation() .force('charge', d3.forceManyBody().strength(() => -50).distanceMin(() => 30)) .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)) function rightRoundedRect(x, y, width, height, radius) { @@ -171,35 +171,26 @@ d3.json('services.json', function(error, graph) { .attr('stroke-width', '1px') .attr('fill', '#464646') - // An icon or label that exists within the circle, inside the infobox - stats.append('text') - .attr('class', 'cpu') - .attr('class', 'stat') - .attr('x', '12') - .attr('y', '65') - .attr('text-anchor', 'start') - .attr('fill', 'rgba(255, 255, 255, 0.8)') - .text('CPU: 63%') + var html = stats + .append('switch') + .append('foreignObject') + .attr('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility') + .attr('x', 12) + .attr('y', 57) + .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') - // An icon or label that exists within the circle, inside the infobox - stats.append('text') - .attr('class', 'memory') - .attr('class', 'stat') - .attr('x', '12') - .attr('y', '85') - .attr('text-anchor', 'start') - .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') + // 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') elm.call(d3.drag() @@ -237,7 +228,7 @@ d3.json('services.json', function(error, graph) { primary.append('path') .attr('class', 'node') - .attr('d', rect('0', '-39', 170, 78, 2)) + .attr('d', rect('0', '-39', 170, 114, 2)) .attr('stroke', '#343434') .attr('stroke-width', '1px') .attr('fill', '#464646') @@ -267,11 +258,32 @@ d3.json('services.json', function(error, graph) { .attr('fill', '#fff') .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'); secondary.append('path') .attr('class', 'node') - .attr('d', bottomRoundedRect('0', '-113', 170, 114, 4)) + .attr('d', bottomRoundedRect('0', '-149', 170, 114, 4)) .attr('stroke', '#343434') .attr('stroke-width', '1px') .attr('fill', '#464646') @@ -279,7 +291,7 @@ d3.json('services.json', function(error, graph) { secondary.append('text') .attr('class', 'secondary') .attr('x', '12') - .attr('y', '150') + .attr('y', '183') .attr('text-anchor', 'start') .attr('fill', '#fff') .text('Secondary') @@ -287,7 +299,7 @@ d3.json('services.json', function(error, graph) { secondary.append('circle') .attr('class', 'alert') .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('fill', 'rgb(0,175,102)') .attr('r', '9px') @@ -296,7 +308,7 @@ d3.json('services.json', function(error, graph) { secondary.append('text') .attr('class', 'health') .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('fill', '#fff') .text('❤') @@ -306,9 +318,9 @@ d3.json('services.json', function(error, graph) { .append('foreignObject') .attr('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility') .attr('x', 12) - .attr('y', 160) + .attr('y', 200) .attr('width', 160) - .attr('height', 100) + .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') @@ -369,18 +381,49 @@ d3.json('services.json', function(error, graph) { function ticked() { // TODO: Remove these values and pull them out of the height of the boxes // that the constraints belong to. - r=180 - r2=130 + r=174 + r2=270 link - .attr('x1', function(d) { return contrain(width, r, d.source.x) + 80; }) - .attr('y1', function(d) { return contrain(height, r2, d.source.y) + 24; }) - .attr('x2', function(d) { return contrain(width, r, d.target.x) + 80; }) - .attr('y2', function(d) { return contrain(height, r2, d.target.y) + 24; }); + .attr('x1', function(d) { + let x; + svg.selectAll('.node_group').each(function (_, i) { + 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') .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) + ')'; }); } });