From 3197c4b3f9228e566d3d4993b0eed0356ba55867 Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Thu, 17 Mar 2016 14:02:54 -0700 Subject: [PATCH] add utility function for wrapping svg text, apply to sunburst breadcrumbs, and make colors more readable for sunburst. --- panoramix/assets/javascripts/modules/utils.js | 55 +++++++++++++++++++ panoramix/assets/visualizations/sunburst.css | 14 ++--- panoramix/assets/visualizations/sunburst.js | 22 +++++--- 3 files changed, 74 insertions(+), 17 deletions(-) create mode 100644 panoramix/assets/javascripts/modules/utils.js diff --git a/panoramix/assets/javascripts/modules/utils.js b/panoramix/assets/javascripts/modules/utils.js new file mode 100644 index 0000000000000..e582ab65b05ff --- /dev/null +++ b/panoramix/assets/javascripts/modules/utils.js @@ -0,0 +1,55 @@ +var d3 = require('d3'); + +/* + Utility function that takes a d3 svg:text selection and a max width, and splits the + text's text across multiple tspan lines such that any given line does not exceed max width + + If text does not span multiple lines AND adjustedY is passed, will set the text to the passed val + */ +function wrapSvgText(text, width, adjustedY) { + var lineHeight = 1; // ems + + text.each(function () { + var text = d3.select(this), + words = text.text().split(/\s+/), + word, + line = [], + lineNumber = 0, + x = text.attr("x"), + y = text.attr("y"), + dy = parseFloat(text.attr("dy")), + tspan = text.text(null) + .append("tspan") + .attr("x", x) + .attr("y", y) + .attr("dy", dy + "em"); + + var didWrap = false; + + for (var i = 0; i < words.length; i++) { + word = words[i]; + line.push(word); + tspan.text(line.join(" ")); + + if (tspan.node().getComputedTextLength() > width) { + line.pop(); // remove word that pushes over the limit + tspan.text(line.join(" ")); + line = [word]; + tspan = text.append("tspan") + .attr("x", x) + .attr("y", y) + .attr("dy", ++lineNumber * lineHeight + dy + "em") + .text(word); + + didWrap = true; + } + } + if (!didWrap && typeof adjustedY !== "undefined") { + tspan.attr("y", adjustedY); + } + }); +} + +module.exports = { + wrapSvgText: wrapSvgText +}; diff --git a/panoramix/assets/visualizations/sunburst.css b/panoramix/assets/visualizations/sunburst.css index d1b83be07ff9f..d2636faaa396e 100644 --- a/panoramix/assets/visualizations/sunburst.css +++ b/panoramix/assets/visualizations/sunburst.css @@ -2,13 +2,13 @@ shape-rendering: crispEdges; } .sunburst path { - stroke: #fff; - stroke-width: 1px; + stroke: #333; + stroke-width: 0.5px; } - .sunburst .center-label { text-anchor: middle; fill: #000; + pointer-events: none; } .sunburst .path-percent { font-size: 4em; @@ -20,20 +20,14 @@ font-size: 1.2em; } -.sunburst .breadcrumbs { - fill: #00D1C1; /*default*/ -} - .sunburst .breadcrumbs text { font-weight: 600; font-size: 1.2em; text-anchor: middle; - fill: #fff; -} -.sunburst .breadcrumbs text.end-label { fill: #000; } +/* dashboard specific */ .dashboard .sunburst text { font-size: 1em; } diff --git a/panoramix/assets/visualizations/sunburst.js b/panoramix/assets/visualizations/sunburst.js index 2bc0f0db2f25b..0c702fcaa5fa7 100644 --- a/panoramix/assets/visualizations/sunburst.js +++ b/panoramix/assets/visualizations/sunburst.js @@ -1,5 +1,7 @@ var d3 = window.d3 || require('d3'); var px = require('../javascripts/modules/panoramix.js'); +var wrapSvgText = require('../javascripts/modules/utils.js').wrapSvgText; + require('./sunburst.css'); // Modified from http://bl.ocks.org/kerryrodden/7090426 @@ -11,7 +13,7 @@ function sunburstVis(slice) { var margin = { top: 10, right: 5, bottom: 10, left: 5 }; var containerWidth = slice.width(); var containerHeight = slice.height(); - var breadcrumbHeight = containerHeight * 0.065; + var breadcrumbHeight = containerHeight * 0.085; var visWidth = containerWidth - margin.left - margin.right; var visHeight = containerHeight - margin.top - margin.bottom - breadcrumbHeight; var radius = Math.min(visWidth, visHeight) / 2; @@ -19,6 +21,7 @@ function sunburstVis(slice) { var maxBreadcrumbs, breadcrumbDims, // set based on data totalSize, // total size of all segments; set after loading the data. + colorScale, breadcrumbs, vis, arcs, gMiddleText; // dom handles // Helper + path gen functions @@ -107,7 +110,7 @@ function sunburstVis(slice) { return (d.dx > 0.005); // 0.005 radians = 0.29 degrees }); - var ext, colorScale; + var ext; if (rawData.form_data.metric !== rawData.form_data.secondary_metric) { colorByCategory = false; @@ -187,7 +190,7 @@ function sunburstVis(slice) { function mouseleave(d) { // Hide the breadcrumb trail - breadcrumbs.style("visibility", "hidden"); + // breadcrumbs.style("visibility", "hidden"); gMiddleText.selectAll("*").remove(); @@ -235,21 +238,26 @@ function sunburstVis(slice) { function updateBreadcrumbs(sequenceArray, percentageString) { var g = breadcrumbs.selectAll("g") - .data(sequenceArray, function (d) { return d.name + d.depth; }); + .data(sequenceArray, function (d) { + return d.name + d.depth; + }); // Add breadcrumb and label for entering nodes. var entering = g.enter().append("svg:g"); entering.append("svg:polygon") .attr("points", breadcrumbPoints) - .style("fill", function (d) { return colorByCategory ? px.color.category21(d.name) : null; }); + .style("fill", function (d) { + return colorByCategory ? px.color.category21(d.name) : colorScale(d.m2 / d.m1); + }); entering.append("svg:text") .attr("x", (breadcrumbDims.width + breadcrumbDims.tipTailWidth) / 2) - .attr("y", breadcrumbDims.height / 2) + .attr("y", breadcrumbDims.height / 4) .attr("dy", "0.35em") .attr("class", "step-label") - .text(function (d) { return d.name; }); + .text(function (d) { return d.name; }) + .call(wrapSvgText, breadcrumbDims.width, breadcrumbDims.height / 2); // Set position for entering and updating nodes. g.attr("transform", function (d, i) {