From 377a917f6774e8e94f262785078fd7f009c320e9 Mon Sep 17 00:00:00 2001 From: Alanna Howe Date: Wed, 1 Nov 2017 17:31:50 +0100 Subject: [PATCH 1/2] Adds ranking table below the sunburst charts * to display the top five offenders from the usage distribution * made arc responsive to hover for visibility * moved metrics number from under sunburst to center of diagram --- src/Sunburst.css | 38 +++++++++++++++++++---- src/Sunburst.js | 80 ++++++++++++++++++++++++++++++++++++++++-------- src/Usage.js | 16 ++++++++-- 3 files changed, 113 insertions(+), 21 deletions(-) diff --git a/src/Sunburst.css b/src/Sunburst.css index 2f2c31c..b6a6504 100644 --- a/src/Sunburst.css +++ b/src/Sunburst.css @@ -19,18 +19,44 @@ font-size: 12px; } +.sunburst .sunburstTitle { + font-weight: bold; +} + .sunburst .legend { transition: opacity 0.6s ease; - margin-top: 4rem; - margin-bottom: 0.5rem; + margin-top: 2rem; + margin-bottom: 2rem; + padding: 1rem 0; width: 100%; - white-space: nowrap; - word-break: break-all; - overflow: hidden; - text-overflow: ellipsis; opacity: 0.7; + text-align: center; + border-top: 1px solid #ccc; + border-bottom: 1px solid #ccc; +} +.sunburst .count { + text-align: center; } .sunburst .legend.active { opacity: 1; } +.sunburst .topoffenders table { + width: 100%; + font-size: 0.9rem; + text-align: left; + border-collapse: collapse; +} +.sunburst .topoffenders td { + border-top: 1px solid #ddd; + padding: 0.5rem 0; +} +.sunburst .topoffenders th { + padding: 0.5rem 0; +} +.sunburst .topoffenders .alignright { + text-align: right; +} +.sunburst .topoffenders .tablekey { + word-break: break-all; +} diff --git a/src/Sunburst.js b/src/Sunburst.js index 856e30f..4a1b3fe 100644 --- a/src/Sunburst.js +++ b/src/Sunburst.js @@ -21,7 +21,7 @@ function bumpColor(c, rnd = false) { hsl.s += 0.5; hsl.l -= 0.1; if (rnd) { - hsl.h += Math.random() * 40; + hsl.h += Math.random() * 20; } return hsl + ''; } @@ -29,6 +29,7 @@ function bumpColor(c, rnd = false) { function getColor(d, color) { const { depth } = d; const { prefix, name } = d.data; + if (depth === 0) return 'transparent'; if (depth === 1) { return color(prefix || name); @@ -57,7 +58,21 @@ function getLegendText(d) { return `${label} (${percent}%)`; } -function drawChart(data, chartDiv, color) { +function getTopOffenders(d) { + if (!d) return + d.sort((a, b) => b.depth - a.depth); + const maxdepth = d[0].depth; + let matches = d.filter(node => node.depth === maxdepth); + matches.sort((a, b) => b.value - a.value); + const topoffenders = matches.slice(0,5); + + let topdata = []; + topoffenders.forEach(node => topdata.push(node.data)); + + return topdata; +} + +function drawChart(nodes, chartDiv, color) { const width = chartDiv.clientWidth; const radius = width / 2; const x = scaleLinear().range([0, 2 * Math.PI]); @@ -74,18 +89,12 @@ function drawChart(data, chartDiv, color) { const legend = d3_select(chartDiv) .select('.legend'); - const partition = d3_partition(); - const arc = d3_arc() .startAngle(d => Math.max(0, Math.min(2 * Math.PI, x(d.x0)))) .endAngle(d => Math.max(0, Math.min(2 * Math.PI, x(d.x1)))) .innerRadius(d => Math.max(0, y(d.y0))) .outerRadius(d => Math.max(0, y(d.y1))); - const root = d3_hierarchy(data.root || data); - root.sum(d => d.size); - - const nodes = partition(root).descendants(); // console.log('root', nodes); const arcs = wrapper @@ -162,7 +171,10 @@ function drawChart(data, chartDiv, color) { d => Math.cos(x(1 - d.x1 + 0.5)) * y(1.33) ); + function onMouseEnterArc(d) { + d3_select(this).style('opacity', (0.8 - d.depth / 5)); + if (d.depth) { legend .classed('active', true) @@ -171,17 +183,43 @@ function drawChart(data, chartDiv, color) { } function onMouseLeaveArc(d) { + d3_select(this).style('opacity', (1 - d.depth / 5)); + legend - .classed('active', false) - .text(LEGEND); + .classed('active', false); } } + +const Table = (props) => ( + + + + + + + + + {props.data.map((d) => ( + + + + + ))} + +
NameSize
{d.key}{d.size}
+); + class Sunburst extends Component { + state = { + offenders: [] + } + componentDidMount() { window.addEventListener('resize', this.redraw); this.color = scaleOrdinal(scheme); if (this.props.data) { + this.processData(this.props.data); this.redraw(); } } @@ -191,15 +229,26 @@ class Sunburst extends Component { } componentWillReceiveProps(nextProps) { - drawChart(nextProps.data, this.el, this.color); + this.processData(nextProps.data); + drawChart(this.nodes, this.el, this.color); + const offenders = getTopOffenders(this.nodes); + this.setState({ offenders }); + } + + processData(data) { + const partition = d3_partition(); + const root = d3_hierarchy(data.root || data); + root.sum(d => d.size); + this.nodes = partition(root).descendants(); } redraw = () => { - drawChart(this.props.data, this.el, this.color); + drawChart(this.nodes, this.el, this.color); }; render() { const { classNames = '', title, count } = this.props; + const { offenders } = this.state; return (
(this.el = el)}> @@ -214,7 +263,12 @@ class Sunburst extends Component {
{LEGEND}
-
{count}
+ {offenders.length > 1 ? +
+

Ranking

+ + : null } + ); } diff --git a/src/Usage.js b/src/Usage.js index 47059a9..70dca9f 100644 --- a/src/Usage.js +++ b/src/Usage.js @@ -124,6 +124,12 @@ class Usage extends Component { const progress = metricNames.length > 0 ? (metricsCount / metricNames.length * 100).toFixed(1) : 'Loading...'; const took = (latency / 1000).toFixed(1); const colClasses = `col-6 flex-auto ${classNames}`; + const sunburstTitle = (title, metrics, name) => ( + + {title} + {metrics} {name} + + ); return (
@@ -148,11 +154,17 @@ class Usage extends Component {
- +
- +
From e489da9ae5b2c9e4340304e2d524ead03d110456 Mon Sep 17 00:00:00 2001 From: Alanna Howe Date: Mon, 6 Nov 2017 12:42:29 +0100 Subject: [PATCH 2/2] Separates level names in top offenders table * level names separated for legibility * local css styling changed to basscss styling for consistency --- src/Sunburst.css | 26 +++++--------------------- src/Sunburst.js | 23 +++++++++++------------ 2 files changed, 16 insertions(+), 33 deletions(-) diff --git a/src/Sunburst.css b/src/Sunburst.css index b6a6504..8ea1c82 100644 --- a/src/Sunburst.css +++ b/src/Sunburst.css @@ -31,32 +31,16 @@ width: 100%; opacity: 0.7; text-align: center; - border-top: 1px solid #ccc; - border-bottom: 1px solid #ccc; -} -.sunburst .count { - text-align: center; } .sunburst .legend.active { opacity: 1; } -.sunburst .topoffenders table { +.sunburst table { width: 100%; - font-size: 0.9rem; - text-align: left; - border-collapse: collapse; -} -.sunburst .topoffenders td { - border-top: 1px solid #ddd; - padding: 0.5rem 0; -} -.sunburst .topoffenders th { - padding: 0.5rem 0; -} -.sunburst .topoffenders .alignright { - text-align: right; + border-collapse: separate; + border-spacing: 0; } -.sunburst .topoffenders .tablekey { - word-break: break-all; +.sunburst table td { + border-color: #ccc; } diff --git a/src/Sunburst.js b/src/Sunburst.js index 4a1b3fe..d5b2fcf 100644 --- a/src/Sunburst.js +++ b/src/Sunburst.js @@ -65,11 +65,7 @@ function getTopOffenders(d) { let matches = d.filter(node => node.depth === maxdepth); matches.sort((a, b) => b.value - a.value); const topoffenders = matches.slice(0,5); - - let topdata = []; - topoffenders.forEach(node => topdata.push(node.data)); - - return topdata; + return topoffenders; } function drawChart(nodes, chartDiv, color) { @@ -195,15 +191,18 @@ const Table = (props) => (
- - + + {props.data.map((d) => ( - - - + + + ))} @@ -264,8 +263,8 @@ class Sunburst extends Component {
{LEGEND}
{offenders.length > 1 ? -
-

Ranking

+
+

Ranking

NameSizeNameSize
{d.key}{d.size}
+ {d.parent.depth > 0 ? `${d.parent.data.name} ยป ` : ''} + {d.data.name} + {d.data.size}
: null }