D3朝阳.如何设置不同的环\水平宽度 [英] D3 Sunburst. How to set different ring\level widths

查看:56
本文介绍了D3朝阳.如何设置不同的环\水平宽度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

帮助!我一直在寻找年龄,却没有找到任何关于此的信息.我基本上希望能够设置D3旭日形中每个图层的大小(%,像素,相对..我不介意).我可以在数据或基于数字或父母的代码中做到这一点吗?我有一个朝阳区,希望内圈占据大部分空间,而外圈只是外面的一薄层.这是一个小提琴 http://jsfiddle.net/TimBrighton/rh02t94h/任何帮助将不胜感激.

Help! I've been searching for ages and not found anything about this. I basically want to be able to set the size (%, pixel, relative.. i don't mind) of each layer in a D3 sunburst. That could be done either in the data or in the code based on number or parents I guess? I have a sunburst and want the inner rings to take up most of the space with the outer ring just a thin layer on the outside. This is a fiddle http://jsfiddle.net/TimBrighton/rh02t94h/ Any help would be greatly appreciated.

// Dimensions of sunburst.
var width = 550;
var height = 550;
var radius = Math.min(width, height) / 2;

// Breadcrumb dimensions: width, height, spacing, width of tip/tail.
var b = {
    w: 75, h: 30, s: 3, t: 10
};

// make `colors` an ordinal scale
var colors = d3.scale.category20();

// Total size of all segments; we set this later, after loading the data.
var totalSize = 0; 

var vis = d3.select("#chart").append("svg:svg")
    .attr("width", width)
    .attr("height", height)
    .append("svg:g")
    .attr("id", "container")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

var partition = d3.layout.partition()
    .size([2 * Math.PI, 100])
    .value(function(d) { return d.size; });

var arc = d3.svg.arc()
    .startAngle(function(d) { return d.x; })
    .endAngle(function(d) { return d.x + d.dx; })
    .innerRadius(function(d) { return radius * (d.y) / 100; })
    .outerRadius(function(d) { return radius * (d.y + d.dy) / 100; });

var json = getData();
createVisualization(json);

// Main function to draw and set up the visualization, once we have the data.
function createVisualization(json) {

    // Basic setup of page elements.
    initializeBreadcrumbTrail();

    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 uniqueNames = (function(a) {
        var output = [];
        a.forEach(function(d) {
            if (output.indexOf(d.name) === -1) {
                output.push(d.name);
            }
        });
        return output;
    })(nodes);

    // set domain of colors scale based on data
    colors.domain(uniqueNames);

    // make sure this is done after setting the domain
    drawLegend();

    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) { return colors(d.name); })
        .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;
};

// 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 = 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) {

  // 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")
      .transition()
      .duration(1000)
      .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.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 colors(d.name); });

  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.name; });

  // 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", colors.domain().length * (li.h + li.s));

  var g = legend.selectAll("g")
      .data(colors.domain())
      .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 colors(d); });

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

function toggleLegend() {
  var legend = d3.select("#legend");
  if (legend.style("visibility") == "hidden") {
    legend.style("visibility", "");
  } else {
    legend.style("visibility", "hidden");
  }
}

// Take a 2-column CSV and transform it into a hierarchical structure suitable
// for a partition layout. The first column is a sequence of step names, from
// root to leaf, separated by hyphens. The second column is a count of how 
// often that sequence occurred.
function buildHierarchy(csv) {
  var root = {"name": "root", "children": []};
  for (var i = 0; i < csv.length; i++) {
    var sequence = csv[i][0];
    var size = +csv[i][1];
    if (isNaN(size)) { // e.g. if this is a header row
      continue;
    }
    var parts = sequence.split("-");
    var currentNode = root;
    for (var j = 0; j < parts.length; j++) {
      var children = currentNode["children"];
      var nodeName = parts[j];
      var childNode;
      if (j + 1 < parts.length) {
   // Not yet at the end of the sequence; move down the tree.
    var foundChild = false;
    for (var k = 0; k < children.length; k++) {
      if (children[k]["name"] == nodeName) {
        childNode = children[k];
        foundChild = true;
        break;
      }
    }
  // If we don't already have a child node for this branch, create it.
    if (!foundChild) {
      childNode = {"name": nodeName, "children": []};
      children.push(childNode);
    }
    currentNode = childNode;
      } else {
    // Reached the end of the sequence; create a leaf node.
    childNode = {"name": nodeName, "size": size};
    children.push(childNode);
      }
    }
  }
  return root;
};

function getData() {
    return {
 "name": "ref",
 "children": [
  {
   "name": "june11",
   "children": [
    {
     "name": "atts",
         "children": [
          {"name": "early", "size": 11},
          {"name": "jcp", "size": 40},
          {"name": "jcpaft", "size": 50},
          {"name": "stillon", "size": 195},
          {"name": "jo",

             "children": [
              {"name": "early",  "size": 100},
              {"name": "jcp", "size": 67},
              {"name": "jcpaft", "size": 110},
                 {"name": "stillon", "size": 154},

               {"name": "sus1",      
                "children": [
                  {"name": "early",  "size": 11},
                    {"name": "jcp", "size": 118},
                  {"name": "jcpaft", "size": 39},
                      {"name": "stillon", "size": 2779}
                  ]
                },

               {"name": "sus5",
                 "children": [
                  {"name": "early",  "size": 0},
                  {"name": "jcp", "size": 64},
                  {"name": "jcpaft", "size": 410},
                     {"name": "stillon", "size": 82}
                  ]
                },

               {"name": "sus9",
                 "children": [
                  {"name": "early",  "size": 1018},
                  {"name": "jcp", "size": 3458},
                  {"name": "jcpaft", "size": 106},
                     {"name": "stillon", "size": 243}
                  ]
                },

               {"name": "sus13",
                 "children": [
                  {"name": "early",  "size": 110},
                  {"name": "jcp", "size": 190},
                  {"name": "jcpaft", "size": 80},
                     {"name": "stillon", "size": 9190},
                     {"name": "allsus", "size": 3970}
                     ]
                    }

                 ]
              }
         ]
        },

      {"name": "noatt", "size": 30}
    ]
    }

 ]
};
};

推荐答案

使用 polylinear 比例尺将域的上游减小到输出范围的较小部分-该博客实际上来自2011年指出了比官方文档更清楚地做到这一点的能力- http://www.jeromecukier.net/blog/2011/08/11/d3-scales-and-color/

Use a polylinear scale that reduces the upper reaches of a domain to a smaller portion of the output range - this blog from 2011 actually points out the ability to do this clearer than the official documentation - http://www.jeromecukier.net/blog/2011/08/11/d3-scales-and-color/

例如d3.scale.linear().domain([0,0.8,1.0]).range([0,0.98,1.0]);

e.g. d3.scale.linear().domain([0,0.8,1.0]).range([0,0.98,1.0]);

然后将该比例应用于以下d.y和d.dy计算-

Then apply that scale to your d.y and d.dy calculations as below -

0到0.8将映射到该范围的0到0.98,剩下的最后深度仅映射到屏幕上半径的2%.这当然可以工作,因为您有六个环,其他数字将需要不同的截止值,但在这种情况下,它只是循环查找d.y的最大值.

0 to 0.8 will map to 0 to 0.98 of the range, leaving the last depth to map to just 2% of the radius on screen. This of course works as you have six rings, other numbers will need different cutoffs but in that case it's just looping through and finding the max of d.y.

 var rscale = d3.scale.linear().domain([0,0.8,1.0]).range([0,0.98,1.0]);

var arc = d3.svg.arc()
    .startAngle(function(d) { return d.x; })
    .endAngle(function(d) { return d.x + d.dx; })
    .innerRadius(function(d) { return radius * rscale(d.y/100); })
    .outerRadius(function(d) { return radius * rscale((d.y + d.dy)/100); });

http://jsfiddle.net/rh02t94h/3/

这篇关于D3朝阳.如何设置不同的环\水平宽度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆