From 251e43b958c788f8285b2624099755df472f979c Mon Sep 17 00:00:00 2001 From: Hideyuki TAKEUCHI Date: Mon, 9 Mar 2015 04:40:17 +0900 Subject: [PATCH] refactoring --- barchart-javascript/main.js | 65 +++---- japanmap-coffeescript/main.coffee | 8 +- japanmap-javascript/main.js | 14 +- sequences-sumburst/README.md | 1 + sequences-sumburst/data.csv | 220 +++++++++++++++++++++++ sequences-sumburst/main.css | 62 +++++++ sequences-sumburst/main.js | 9 + sequences-sumburst/original.js | 289 ++++++++++++++++++++++++++++++ 8 files changed, 621 insertions(+), 47 deletions(-) create mode 100644 sequences-sumburst/README.md create mode 100644 sequences-sumburst/data.csv create mode 100644 sequences-sumburst/main.css create mode 100644 sequences-sumburst/main.js create mode 100644 sequences-sumburst/original.js diff --git a/barchart-javascript/main.js b/barchart-javascript/main.js index bf7d10e..e473ad1 100644 --- a/barchart-javascript/main.js +++ b/barchart-javascript/main.js @@ -1,44 +1,29 @@ -define(['d3'], function (d3) { - return function (node, baseUrl) { - var width = 400; - var height = 300; +function render(node, data) { + var width = 400; + var height = 300; - var svg = d3.select(node) - .append('svg') - .attr('width', width) - .attr('height', height); + var svg = d3.select(node) + .append('svg') + .attr('width', width) + .attr('height', height); - return { - /** - * (Required) called on data updated. - * - * @param data: ChartData - */ - update: function (data) { - var list = data.transpose().toList(['name', 'value']); + var list = data.transpose().toList(['name', 'value']); - var x = d3.scale.ordinal() - .rangeRoundBands([0, width], .2) - .domain(list.map(function (d) { return d.name; })); - var y = d3.scale.linear() - .rangeRound([height, 0]) - .domain([0, d3.max(list.values())]); - var color = d3.scale.category10() - .domain(list.map(function (d) { return d.name; })) + var x = d3.scale.ordinal() + .rangeRoundBands([0, width], .2) + .domain(list.map(function (d) { return d.name; })); + var y = d3.scale.linear() + .rangeRound([height, 0]) + .domain([0, d3.max(list.values())]); + var color = d3.scale.category10() + .domain(list.map(function (d) { return d.name; })) - rect = svg.selectAll('rect').data(list); - - rect.enter().append('rect'); - - rect.exit().remove(); - - rect - .attr('width', x.rangeBand()) - .attr('height', function (d) { return height - y(d.value); }) - .attr('x', function (d) { return x(d.name); }) - .attr('y', function (d) { return y(d.value); }) - .style('fill', function (d) { return color(d.name); }); - } - }; - }; -}); + rect = svg.selectAll('rect') + .data(list) + .enter().append('rect') + .attr('width', x.rangeBand()) + .attr('height', function (d) { return height - y(d.value); }) + .attr('x', function (d) { return x(d.name); }) + .attr('y', function (d) { return y(d.value); }) + .style('fill', function (d) { return color(d.name); }); +} diff --git a/japanmap-coffeescript/main.coffee b/japanmap-coffeescript/main.coffee index 61c811d..c1827b6 100644 --- a/japanmap-coffeescript/main.coffee +++ b/japanmap-coffeescript/main.coffee @@ -1,9 +1,11 @@ define ['d3', 'topojson'], (d3, topojson) -> (node, baseUrl) -> + _data = null + ### # constructor ### - _initialize = (data) -> + _initialize = () -> width = node.clientWidth height = node.clientHeight @@ -29,7 +31,7 @@ define ['d3', 'topojson'], (d3, topojson) -> .attr 'class', 'states' .attr 'fill', '#ffffff' .attr 'd', path - exports.update data if data + exports.update _data if _data ### # destructor @@ -52,6 +54,8 @@ define ['d3', 'topojson'], (d3, topojson) -> # @param data: ChartData ### update: (data) -> + _data = data + map = data.toMap() values = map.values() diff --git a/japanmap-javascript/main.js b/japanmap-javascript/main.js index 0994de2..af00e6b 100644 --- a/japanmap-javascript/main.js +++ b/japanmap-javascript/main.js @@ -1,9 +1,11 @@ define(['d3', 'topojson'], function (d3, topojson) { return function (node, baseUrl) { + _data = null; + /* * constructor */ - var _initialize = function (data) { + var _initialize = function () { var width = node.clientWidth; var height = node.clientHeight; @@ -32,8 +34,8 @@ define(['d3', 'topojson'], function (d3, topojson) { .attr('class', 'states') .attr('fill', '#ffffff') .attr('d', path); - if (data) { - exports.update(data); + if (_data) { + exports.update(_data); } }); }; @@ -60,6 +62,8 @@ define(['d3', 'topojson'], function (d3, topojson) { * @param data: ChartData */ update: function (data) { + _data = data; + var map = data.toMap(); var values = map.values(); @@ -68,7 +72,7 @@ define(['d3', 'topojson'], function (d3, topojson) { .range(['#ffffff', '#ff0000']) .interpolate(d3.interpolateLab); - var initLabel = '2011年'; + var initLabel = map.header[2]; d3.select(node) .selectAll('svg .states') @@ -106,7 +110,7 @@ define(['d3', 'topojson'], function (d3, topojson) { * (Optional) called on window resized. */ resize: function(data) { - _initialize(data); + _initialize(); _dispose(); } }; diff --git a/sequences-sumburst/README.md b/sequences-sumburst/README.md new file mode 100644 index 0000000..bab2203 --- /dev/null +++ b/sequences-sumburst/README.md @@ -0,0 +1 @@ +Sequences Sunburst ==== ---- A ring chart, also known as a sunburst chart or a multilevel pie chart, is used to visualize hierarchical data, depicted by concentric circles. \ No newline at end of file diff --git a/sequences-sumburst/data.csv b/sequences-sumburst/data.csv new file mode 100644 index 0000000..fad9bf4 --- /dev/null +++ b/sequences-sumburst/data.csv @@ -0,0 +1,220 @@ +"node0","node1","node2","node3","node4","size" +"flare","analytics","cluster","AgglomerativeCluster","","3938" +"flare","analytics","cluster","CommunityStructure","","3812" +"flare","analytics","cluster","HierarchicalCluster","","6714" +"flare","analytics","cluster","MergeEdge","","743" +"flare","analytics","graph","BetweennessCentrality","","3534" +"flare","analytics","graph","LinkDistance","","5731" +"flare","analytics","graph","MaxFlowMinCut","","7840" +"flare","analytics","graph","ShortestPaths","","5914" +"flare","analytics","graph","SpanningTree","","3416" +"flare","analytics","optimization","AspectRatioBanker","","7074" +"flare","animate","Easing","","","17010" +"flare","animate","FunctionSequence","","","5842" +"flare","animate","interpolate","ArrayInterpolator","","1983" +"flare","animate","interpolate","ColorInterpolator","","2047" +"flare","animate","interpolate","DateInterpolator","","1375" +"flare","animate","interpolate","Interpolator","","8746" +"flare","animate","interpolate","MatrixInterpolator","","2202" +"flare","animate","interpolate","NumberInterpolator","","1382" +"flare","animate","interpolate","ObjectInterpolator","","1629" +"flare","animate","interpolate","PointInterpolator","","1675" +"flare","animate","interpolate","RectangleInterpolator","","2042" +"flare","animate","ISchedulable","","","1041" +"flare","animate","Parallel","","","5176" +"flare","animate","Pause","","","449" +"flare","animate","Scheduler","","","5593" +"flare","animate","Sequence","","","5534" +"flare","animate","Transition","","","9201" +"flare","animate","Transitioner","","","19975" +"flare","animate","TransitionEvent","","","1116" +"flare","animate","Tween","","","6006" +"flare","data","converters","Converters","","721" +"flare","data","converters","DelimitedTextConverter","","4294" +"flare","data","converters","GraphMLConverter","","9800" +"flare","data","converters","IDataConverter","","1314" +"flare","data","converters","JSONConverter","","2220" +"flare","data","DataField","","","1759" +"flare","data","DataSchema","","","2165" +"flare","data","DataSet","","","586" +"flare","data","DataSource","","","3331" +"flare","data","DataTable","","","772" +"flare","data","DataUtil","","","3322" +"flare","display","DirtySprite","","","8833" +"flare","display","LineSprite","","","1732" +"flare","display","RectSprite","","","3623" +"flare","display","TextSprite","","","10066" +"flare","flex","FlareVis","","","4116" +"flare","physics","DragForce","","","1082" +"flare","physics","GravityForce","","","1336" +"flare","physics","IForce","","","319" +"flare","physics","NBodyForce","","","10498" +"flare","physics","Particle","","","2822" +"flare","physics","Simulation","","","9983" +"flare","physics","Spring","","","2213" +"flare","physics","SpringForce","","","1681" +"flare","query","AggregateExpression","","","1616" +"flare","query","And","","","1027" +"flare","query","Arithmetic","","","3891" +"flare","query","Average","","","891" +"flare","query","BinaryExpression","","","2893" +"flare","query","Comparison","","","5103" +"flare","query","CompositeExpression","","","3677" +"flare","query","Count","","","781" +"flare","query","DateUtil","","","4141" +"flare","query","Distinct","","","933" +"flare","query","Expression","","","5130" +"flare","query","ExpressionIterator","","","3617" +"flare","query","Fn","","","3240" +"flare","query","If","","","2732" +"flare","query","IsA","","","2039" +"flare","query","Literal","","","1214" +"flare","query","Match","","","3748" +"flare","query","Maximum","","","843" +"flare","query","methods","add","","593" +"flare","query","methods","and","","330" +"flare","query","methods","average","","287" +"flare","query","methods","count","","277" +"flare","query","methods","distinct","","292" +"flare","query","methods","div","","595" +"flare","query","methods","eq","","594" +"flare","query","methods","fn","","460" +"flare","query","methods","gt","","603" +"flare","query","methods","gte","","625" +"flare","query","methods","iff","","748" +"flare","query","methods","isa","","461" +"flare","query","methods","lt","","597" +"flare","query","methods","lte","","619" +"flare","query","methods","max","","283" +"flare","query","methods","min","","283" +"flare","query","methods","mod","","591" +"flare","query","methods","mul","","603" +"flare","query","methods","neq","","599" +"flare","query","methods","not","","386" +"flare","query","methods","or","","323" +"flare","query","methods","orderby","","307" +"flare","query","methods","range","","772" +"flare","query","methods","select","","296" +"flare","query","methods","stddev","","363" +"flare","query","methods","sub","","600" +"flare","query","methods","sum","","280" +"flare","query","methods","update","","307" +"flare","query","methods","variance","","335" +"flare","query","methods","where","","299" +"flare","query","methods","xor","","354" +"flare","query","methods","_","","264" +"flare","query","Minimum","","","843" +"flare","query","Not","","","1554" +"flare","query","Or","","","970" +"flare","query","Query","","","13896" +"flare","query","Range","","","1594" +"flare","query","StringUtil","","","4130" +"flare","query","Sum","","","791" +"flare","query","Variable","","","1124" +"flare","query","Variance","","","1876" +"flare","query","Xor","","","1101" +"flare","scale","IScaleMap","","","2105" +"flare","scale","LinearScale","","","1316" +"flare","scale","LogScale","","","3151" +"flare","scale","OrdinalScale","","","3770" +"flare","scale","QuantileScale","","","2435" +"flare","scale","QuantitativeScale","","","4839" +"flare","scale","RootScale","","","1756" +"flare","scale","Scale","","","4268" +"flare","scale","ScaleType","","","1821" +"flare","scale","TimeScale","","","5833" +"flare","util","Arrays","","","8258" +"flare","util","Colors","","","10001" +"flare","util","Dates","","","8217" +"flare","util","Displays","","","12555" +"flare","util","Filter","","","2324" +"flare","util","Geometry","","","10993" +"flare","util","heap","FibonacciHeap","","9354" +"flare","util","heap","HeapNode","","1233" +"flare","util","IEvaluable","","","335" +"flare","util","IPredicate","","","383" +"flare","util","IValueProxy","","","874" +"flare","util","math","DenseMatrix","","3165" +"flare","util","math","IMatrix","","2815" +"flare","util","math","SparseMatrix","","3366" +"flare","util","Maths","","","17705" +"flare","util","Orientation","","","1486" +"flare","util","palette","ColorPalette","","6367" +"flare","util","palette","Palette","","1229" +"flare","util","palette","ShapePalette","","2059" +"flare","util","palette","SizePalette","","2291" +"flare","util","Property","","","5559" +"flare","util","Shapes","","","19118" +"flare","util","Sort","","","6887" +"flare","util","Stats","","","6557" +"flare","util","Strings","","","22026" +"flare","vis","axis","Axes","","1302" +"flare","vis","axis","Axis","","24593" +"flare","vis","axis","AxisGridLine","","652" +"flare","vis","axis","AxisLabel","","636" +"flare","vis","axis","CartesianAxes","","6703" +"flare","vis","controls","AnchorControl","","2138" +"flare","vis","controls","ClickControl","","3824" +"flare","vis","controls","Control","","1353" +"flare","vis","controls","ControlList","","4665" +"flare","vis","controls","DragControl","","2649" +"flare","vis","controls","ExpandControl","","2832" +"flare","vis","controls","HoverControl","","4896" +"flare","vis","controls","IControl","","763" +"flare","vis","controls","PanZoomControl","","5222" +"flare","vis","controls","SelectionControl","","7862" +"flare","vis","controls","TooltipControl","","8435" +"flare","vis","data","Data","","20544" +"flare","vis","data","DataList","","19788" +"flare","vis","data","DataSprite","","10349" +"flare","vis","data","EdgeSprite","","3301" +"flare","vis","data","NodeSprite","","19382" +"flare","vis","data","render","ArrowType","698" +"flare","vis","data","render","EdgeRenderer","5569" +"flare","vis","data","render","IRenderer","353" +"flare","vis","data","render","ShapeRenderer","2247" +"flare","vis","data","ScaleBinding","","11275" +"flare","vis","data","Tree","","7147" +"flare","vis","data","TreeBuilder","","9930" +"flare","vis","events","DataEvent","","2313" +"flare","vis","events","SelectionEvent","","1880" +"flare","vis","events","TooltipEvent","","1701" +"flare","vis","events","VisualizationEvent","","1117" +"flare","vis","legend","Legend","","20859" +"flare","vis","legend","LegendItem","","4614" +"flare","vis","legend","LegendRange","","10530" +"flare","vis","operator","distortion","BifocalDistortion","4461" +"flare","vis","operator","distortion","Distortion","6314" +"flare","vis","operator","distortion","FisheyeDistortion","3444" +"flare","vis","operator","encoder","ColorEncoder","3179" +"flare","vis","operator","encoder","Encoder","4060" +"flare","vis","operator","encoder","PropertyEncoder","4138" +"flare","vis","operator","encoder","ShapeEncoder","1690" +"flare","vis","operator","encoder","SizeEncoder","1830" +"flare","vis","operator","filter","FisheyeTreeFilter","5219" +"flare","vis","operator","filter","GraphDistanceFilter","3165" +"flare","vis","operator","filter","VisibilityFilter","3509" +"flare","vis","operator","IOperator","","1286" +"flare","vis","operator","label","Labeler","9956" +"flare","vis","operator","label","RadialLabeler","3899" +"flare","vis","operator","label","StackedAreaLabeler","3202" +"flare","vis","operator","layout","AxisLayout","6725" +"flare","vis","operator","layout","BundledEdgeRouter","3727" +"flare","vis","operator","layout","CircleLayout","9317" +"flare","vis","operator","layout","CirclePackingLayout","12003" +"flare","vis","operator","layout","DendrogramLayout","4853" +"flare","vis","operator","layout","ForceDirectedLayout","8411" +"flare","vis","operator","layout","IcicleTreeLayout","4864" +"flare","vis","operator","layout","IndentedTreeLayout","3174" +"flare","vis","operator","layout","Layout","7881" +"flare","vis","operator","layout","NodeLinkTreeLayout","12870" +"flare","vis","operator","layout","PieLayout","2728" +"flare","vis","operator","layout","RadialTreeLayout","12348" +"flare","vis","operator","layout","RandomLayout","870" +"flare","vis","operator","layout","StackedAreaLayout","9121" +"flare","vis","operator","layout","TreeMapLayout","9191" +"flare","vis","operator","Operator","","2490" +"flare","vis","operator","OperatorList","","5248" +"flare","vis","operator","OperatorSequence","","4190" +"flare","vis","operator","OperatorSwitch","","2581" +"flare","vis","operator","SortOperator","","2023" diff --git a/sequences-sumburst/main.css b/sequences-sumburst/main.css new file mode 100644 index 0000000..5f127f1 --- /dev/null +++ b/sequences-sumburst/main.css @@ -0,0 +1,62 @@ +svg { + font: 10px sans-serif; + padding: 10px; + display: block; + margin: auto; +} +svg:not(:root){ + overflow: auto !important +} +body { + font-family: 'Open Sans', sans-serif; + font-size: 12px; + font-weight: 400; + background-color: #fff; +} + +#main { + float: left; + width: 550px; +} + +#sidebar { + float: right; + width: 100px; +} + +#sequence { + width: 500px; + height: 70px; +} + +#legend { + padding: 10px 0 0 3px; +} + +#sequence text, #legend text { + font-weight: 600; + fill: #fff; +} + +#chart { + position: relative; +} + +#chart path { + stroke: #fff; +} + +#explanation { + position: absolute; + top: 50%; + left: 50%; + width: 140px; + text-align: center; + margin: -50px 0 0 -50px; + color: #666; + z-index: -1; +} + +#percentage { + font-size: 2.5em; +} diff --git a/sequences-sumburst/main.js b/sequences-sumburst/main.js new file mode 100644 index 0000000..2b450de --- /dev/null +++ b/sequences-sumburst/main.js @@ -0,0 +1,9 @@ +define(['d3', 'e2d3old', 'original'], function (d3, e2d3old, original) { + return function (node, baseUrl) { + return { + update: function (data) { + show(e2d3old.nested(data)); + } + }; + }; +}); diff --git a/sequences-sumburst/original.js b/sequences-sumburst/original.js new file mode 100644 index 0000000..8e0776a --- /dev/null +++ b/sequences-sumburst/original.js @@ -0,0 +1,289 @@ +/** + * Created by yuuu on 14/12/22. + */ +var width = 550; +var height = 400; +var radius = Math.min(width, height) / 2; +var target; + +// Breadcrumb dimensions: width, height, spacing, width of tip/tail. +var b = { + w: 75, h: 30, s: 3, t: 10 +}; + +// Mapping of step names to colors. +var colorScale = d3.scale.category20(); +var colors; +var vis, partition, arc; + +// Total size of all segments; we set this later, after loading the data. +var totalSize = 0; + +function e2d3Show(updateFlag) { + if (updateFlag) { + e2d3.bind2Json(e2d3BindId, { dimension: "nested" }, show); + } else { + e2d3.addChangeEvent(e2d3BindId, e2d3Update, function () { + e2d3.bind2Json(e2d3BindId, { dimension: "nested" }, show); + }); + } +} +function e2d3Update(responce) { + console.log("Begin e2d3Update"); + e2d3Show(true); +} + +function show(data) { + console.log("start show e"); + $("#e2d3-chart-area").empty(); + + if (!target) { + createTargetSelector(data.targets, { value: data.targets[0], type: "dropdown" }); + target = $("#e2d3-target-selector").val(); + } else { + createTargetSelector(data.targets, { value: target, type: "dropdown" }); + } + colors = []; + + //area + var s_area = $("
").attr("id", "sequence"); + var c_area = $("
").attr("id", "chart").append($("
").attr("id", "explanation").css("visibility", "hidden").append($("").attr("id", "percentage"))); + $("#e2d3-target-selector-box").after(s_area, c_area); + // + createVisualization(data.data); + $(document).on("change", "#e2d3-target-selector", function () { + target = $(this).val(); + $("#e2d3-chart-area").empty(); + show(data); + }); +}; +function createVisualization(json) { + + vis = d3.select("#e2d3-chart-area").append("svg:svg") + .attr("width", width) + .attr("height", height) + .append("svg:g") + .attr("id", "container") + .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); + + partition = d3.layout.partition() + .size([2 * Math.PI, radius * radius]) + .value(function (d) { return d.values[target]; }); + + arc = d3.svg.arc() + .startAngle(function (d) { return d.x; }) + .endAngle(function (d) { return d.x + d.dx; }) + .innerRadius(function (d) { return Math.sqrt(d.y); }) + .outerRadius(function (d) { return Math.sqrt(d.y + d.dy); }); + + // Basic setup of page elements. + initializeBreadcrumbTrail(); + //drawLegend(); + //d3.select("#togglelegend").on("click", toggleLegend); + + + // Bounding circle underneath the sunburst, to make it easier to detect + // when the mouse leaves the parent g. + vis.append("svg:circle") + .attr("r", radius) + .style("opacity", 0); + + // For efficiency, filter nodes to keep only those large enough to see. + var nodes = partition.nodes(json) + .filter(function (d) { + return (d.dx > 0.005); // 0.005 radians = 0.29 degrees + }); + + var path = vis.data([json]).selectAll("path") + .data(nodes) + .enter().append("svg:path") + .attr("display", function (d) { return d.depth ? null : "none"; }) + .attr("d", arc) + .attr("fill-rule", "evenodd") + .style("fill", function (d) { colors[d.label] = colorScale(d.label); return colors[d.label]; }) + .style("opacity", 1) + .on("mouseover", mouseover); + + // Add the mouseleave handler to the bounding circle. + d3.select("#container").on("mouseleave", mouseleave); + + // Get total size of the tree = value of root node from partition. + totalSize = path.node().__data__.value; + //totalSize = nodes[0].length; +}; + +// Fade all but the current sequence, and show it in the breadcrumb trail. +function mouseover(d) { + var percentage = (100 * d.value / totalSize).toPrecision(3); + var percentageString = d.label + " [" + percentage + "%]"; + if (percentage < 0.1) { + percentageString = "< 0.1%"; + } + + d3.select("#percentage") + .text(percentageString); + + d3.select("#explanation") + .style("visibility", ""); + + var sequenceArray = getAncestors(d); + updateBreadcrumbs(sequenceArray, percentageString); + + // Fade all the segments. + d3.selectAll("path") + .style("opacity", 0.3); + + // Then highlight only those that are an ancestor of the current segment. + vis.selectAll("path") + .filter(function (node) { + return (sequenceArray.indexOf(node) >= 0); + }) + .style("opacity", 1); +} + +// Restore everything to full opacity when moving off the visualization. +function mouseleave(d) { + console.log('mouseleave'); + // Hide the breadcrumb trail + d3.select("#trail") + .style("visibility", "hidden"); + + // Deactivate all segments during transition. + d3.selectAll("path").on("mouseover", null); + + // Transition each segment to full opacity and then reactivate it. + d3.selectAll("path") + .transition() + .duration(1000) + .style("opacity", 1) + .each("end", function () { + d3.select(this).on("mouseover", mouseover); + }); + + d3.select("#explanation") + .style("visibility", "hidden"); +} + +// Given a node in a partition layout, return an array of all of its ancestor +// nodes, highest first, but excluding the root. +function getAncestors(node) { + var path = []; + var current = node; + while (current.parent) { + path.unshift(current); + current = current.parent; + } + return path; +} + +function initializeBreadcrumbTrail() { + // Add the svg area. + var trail = d3.select("#sequence").append("svg:svg") + .attr("width", width) + .attr("height", 50) + .attr("id", "trail"); + // Add the label at the end, for the percentage. + trail.append("svg:text") + .attr("id", "endlabel") + .style("fill", "#000"); +} + +// Generate a string that describes the points of a breadcrumb polygon. +function breadcrumbPoints(d, i) { + var points = []; + points.push("0,0"); + points.push(b.w + ",0"); + points.push(b.w + b.t + "," + (b.h / 2)); + points.push(b.w + "," + b.h); + points.push("0," + b.h); + if (i > 0) { // Leftmost breadcrumb; don't include 6th vertex. + points.push(b.t + "," + (b.h / 2)); + } + return points.join(" "); +} + +// Update the breadcrumb trail to show the current sequence and percentage. +function updateBreadcrumbs(nodeArray, percentageString) { + + // Data join; key function combines name and depth (= position in sequence). + var g = d3.select("#trail") + .selectAll("g") + .data(nodeArray, function (d) { return d.label + 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) { colors[d.label] = colorScale(d.label); return colors[d.label]; }); + + entering.append("svg:text") + .attr("x", (b.w + b.t) / 2) + .attr("y", b.h / 2) + .attr("dy", "0.35em") + .attr("text-anchor", "middle") + .text(function (d) { return d.label; }); + + // Set position for entering and updating nodes. + g.attr("transform", function (d, i) { + return "translate(" + i * (b.w + b.s) + ", 0)"; + }); + + // Remove exiting nodes. + g.exit().remove(); + + // Now move and update the percentage at the end. + d3.select("#trail").select("#endlabel") + .attr("x", (nodeArray.length + 0.5) * (b.w + b.s)) + .attr("y", b.h / 2) + .attr("dy", "0.35em") + .attr("text-anchor", "middle") + .text(percentageString); + + // Make the breadcrumb trail visible, if it's hidden. + d3.select("#trail") + .style("visibility", ""); + +} + +function drawLegend() { + + // Dimensions of legend item: width, height, spacing, radius of rounded rect. + var li = { + w: 75, h: 30, s: 3, r: 3 + }; + + var legend = d3.select("#legend").append("svg:svg") + .attr("width", li.w) + .attr("height", d3.keys(colors).length * (li.h + li.s)); + + var g = legend.selectAll("g") + .data(d3.entries(colors)) + .enter().append("svg:g") + .attr("transform", function (d, i) { + return "translate(0," + i * (li.h + li.s) + ")"; + }); + + g.append("svg:rect") + .attr("rx", li.r) + .attr("ry", li.r) + .attr("width", li.w) + .attr("height", li.h) + .style("fill", function (d) { return d.values[target]; }); + + g.append("svg:text") + .attr("x", li.w / 2) + .attr("y", li.h / 2) + .attr("dy", "0.35em") + .attr("text-anchor", "middle") + .text(function (d) { return d.key; }); +} + +function toggleLegend() { + var legend = d3.select("#legend"); + if (legend.style("visibility") == "hidden") { + legend.style("visibility", ""); + } else { + legend.style("visibility", "hidden"); + } +}