add utility function for wrapping svg text, apply to sunburst breadcrumbs, and make colors more readable for sunburst.

This commit is contained in:
Chris Williams 2016-03-17 14:02:54 -07:00
parent 06080945b6
commit 3197c4b3f9
3 changed files with 74 additions and 17 deletions

View File

@ -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
};

View File

@ -2,13 +2,13 @@
shape-rendering: crispEdges; shape-rendering: crispEdges;
} }
.sunburst path { .sunburst path {
stroke: #fff; stroke: #333;
stroke-width: 1px; stroke-width: 0.5px;
} }
.sunburst .center-label { .sunburst .center-label {
text-anchor: middle; text-anchor: middle;
fill: #000; fill: #000;
pointer-events: none;
} }
.sunburst .path-percent { .sunburst .path-percent {
font-size: 4em; font-size: 4em;
@ -20,20 +20,14 @@
font-size: 1.2em; font-size: 1.2em;
} }
.sunburst .breadcrumbs {
fill: #00D1C1; /*default*/
}
.sunburst .breadcrumbs text { .sunburst .breadcrumbs text {
font-weight: 600; font-weight: 600;
font-size: 1.2em; font-size: 1.2em;
text-anchor: middle; text-anchor: middle;
fill: #fff;
}
.sunburst .breadcrumbs text.end-label {
fill: #000; fill: #000;
} }
/* dashboard specific */
.dashboard .sunburst text { .dashboard .sunburst text {
font-size: 1em; font-size: 1em;
} }

View File

@ -1,5 +1,7 @@
var d3 = window.d3 || require('d3'); var d3 = window.d3 || require('d3');
var px = require('../javascripts/modules/panoramix.js'); var px = require('../javascripts/modules/panoramix.js');
var wrapSvgText = require('../javascripts/modules/utils.js').wrapSvgText;
require('./sunburst.css'); require('./sunburst.css');
// Modified from http://bl.ocks.org/kerryrodden/7090426 // 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 margin = { top: 10, right: 5, bottom: 10, left: 5 };
var containerWidth = slice.width(); var containerWidth = slice.width();
var containerHeight = slice.height(); var containerHeight = slice.height();
var breadcrumbHeight = containerHeight * 0.065; var breadcrumbHeight = containerHeight * 0.085;
var visWidth = containerWidth - margin.left - margin.right; var visWidth = containerWidth - margin.left - margin.right;
var visHeight = containerHeight - margin.top - margin.bottom - breadcrumbHeight; var visHeight = containerHeight - margin.top - margin.bottom - breadcrumbHeight;
var radius = Math.min(visWidth, visHeight) / 2; var radius = Math.min(visWidth, visHeight) / 2;
@ -19,6 +21,7 @@ function sunburstVis(slice) {
var maxBreadcrumbs, breadcrumbDims, // set based on data var maxBreadcrumbs, breadcrumbDims, // set based on data
totalSize, // total size of all segments; set after loading the data. totalSize, // total size of all segments; set after loading the data.
colorScale,
breadcrumbs, vis, arcs, gMiddleText; // dom handles breadcrumbs, vis, arcs, gMiddleText; // dom handles
// Helper + path gen functions // Helper + path gen functions
@ -107,7 +110,7 @@ function sunburstVis(slice) {
return (d.dx > 0.005); // 0.005 radians = 0.29 degrees 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) { if (rawData.form_data.metric !== rawData.form_data.secondary_metric) {
colorByCategory = false; colorByCategory = false;
@ -187,7 +190,7 @@ function sunburstVis(slice) {
function mouseleave(d) { function mouseleave(d) {
// Hide the breadcrumb trail // Hide the breadcrumb trail
breadcrumbs.style("visibility", "hidden"); // breadcrumbs.style("visibility", "hidden");
gMiddleText.selectAll("*").remove(); gMiddleText.selectAll("*").remove();
@ -235,21 +238,26 @@ function sunburstVis(slice) {
function updateBreadcrumbs(sequenceArray, percentageString) { function updateBreadcrumbs(sequenceArray, percentageString) {
var g = breadcrumbs.selectAll("g") 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. // Add breadcrumb and label for entering nodes.
var entering = g.enter().append("svg:g"); var entering = g.enter().append("svg:g");
entering.append("svg:polygon") entering.append("svg:polygon")
.attr("points", breadcrumbPoints) .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") entering.append("svg:text")
.attr("x", (breadcrumbDims.width + breadcrumbDims.tipTailWidth) / 2) .attr("x", (breadcrumbDims.width + breadcrumbDims.tipTailWidth) / 2)
.attr("y", breadcrumbDims.height / 2) .attr("y", breadcrumbDims.height / 4)
.attr("dy", "0.35em") .attr("dy", "0.35em")
.attr("class", "step-label") .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. // Set position for entering and updating nodes.
g.attr("transform", function (d, i) { g.attr("transform", function (d, i) {