在可缩放的旭日中获得可见的根节点

时间:2018-03-27 15:32:00

标签: javascript d3.js

我使用标签进行了可缩放的旭日形象可视化(请参阅in action,或查看the code)。单击某个项目时,最里面的可见节点的标签会侧向转动。我想为这一个节点修复标签,但我还没有办法做到这一点。

有没有办法说“if(当前节点是可见节点的根目录)”?还有其他想法吗?

完整的可视化: The full visualization

点击后放大。我想让'Calm'节点文本水平: Zoomed in after click. I'd like to make the 'Calm' node text horizontal

1 个答案:

答案 0 :(得分:0)

虽然不完美,但您使用的此代码的修改版本会调整当前所选节点的文本,因为它会设置动画并使其水平。

var width = 960,
  height = 700,
  radius = (Math.min(width, height) / 2) - 10;
var formatNumber = d3.format(",d");
var x = d3.scaleLinear()
  .range([0, 2 * Math.PI]);
var y = d3.scaleLinear()
  .range([0, radius]);
var color = d3.scaleOrdinal(d3.schemeCategory20);
var partition = d3.partition();
function startAngle(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x0))); }
function endAngle(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x1))); }
function innerRadius(d) { return Math.max(0, y(d.y0)); }
function outerRadius(d) { return Math.max(0, y(d.y1)); }
var arc = d3.arc()
  .startAngle( function(d) { return startAngle(d);  })
  .endAngle(   function(d) { return endAngle(d);    })
  .innerRadius(function(d) { return innerRadius(d); })
  .outerRadius(function(d) { return outerRadius(d); })
var texttransform = function(d) {
  var translation = y(d.y0);
  var rotation = computeTextRotation(d);
  if (rotation > 90 && rotation < 270) {
    rotation = rotation + 180;
    translation = -translation;
  }
  return (
    "rotate(" + rotation + ")" +
    "translate(" + translation + ",0)"
  );
}
var transition = {};
function calcTransitionPercentage(){
  var now = Date.now()-transition.clockNow;
  if(!transition.delay || now > transition.delay){
    return Math.min(1,(now-(transition.delay||0))/transition.duration);
  }
  return 0;
}
function computeTextRotation(d) {
  if (d.depth === 0) {
    return 0;
  }
  var current = x((d.x0 + d.x1)/2);
  var angle = (current - Math.PI / 2) / Math.PI * 180;
  if(transition.node === d){
    angle -= 90 * calcTransitionPercentage();
  }
  return (angle >  90 || angle < 270) ?  angle : 180 + angle ;
}
var textanchor = function(d) {
  if (d.depth === 0) {
    return "middle";
  }
  var rotation = computeTextRotation(d);
  return (rotation > 90 && rotation < 270) ? "end" : "start";
}
var textdx = function(d) {
  if (d.depth === 0) {
    return 0;
  }
  var rotation = computeTextRotation(d);
  return (rotation > 90 && rotation < 270) ? -6 : 6;
}
var svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height)
  .append("g")
  .attr("transform", "translate(" + width / 2 + "," + (height / 2) + ")");
function calcFontSize(d) {
  const xFactor = 12, yFactor = 7.5 ; // stub
  if (d.depth === 0) {
    return "30px";
  }
  // use inner arc len as text height delimiter
  var innerArc = (endAngle(d) - startAngle(d)) * 2 * Math.PI * innerRadius(d);
  var len = (d.y1-d.y0) * radius;
  return Math.min(innerArc / yFactor, len / d.data.textlen * xFactor) + "px";
}
function click(d = { x0: 0, x1: 1, y0: 0, y1: 1 }) {
  transition = {clockNow: Date.now(), duration: 750, node: d }
  var trans = svg.transition().duration(750);
  trans.selectAll("path")
    .attrTween("d", function(n) { return function() { return arc(n); }; })
    .tween("scale", function() {
      var xd = d3.interpolate(x.domain(), [d.x0, d.x1]),
      yd = d3.interpolate(y.domain(), [d.y0, 1]),
      yr = d3.interpolate(y.range(), [d.y0 ? 20 : 0, radius]);
      return function(t) {
        x.domain(xd(t));
        y.domain(yd(t)).range(yr(t));
      };
    });
    trans.selectAll("text")
      .attrTween("transform",   function(n) { return function() { return texttransform(n); }; })
      .attrTween("text-anchor", function(n) { return function() { return textanchor(n); }; })
      .attrTween("dx",          function(n) { return function() { return textdx(n); }; })
      .styleTween("font-size",  function(n) { return function() { return calcFontSize(n); }; });
    trans.selectAll("text")
      .delay(400)
      .attrTween("opacity",     function(n) { return function() {
        if (d === n || n.ancestors().includes(d)) {
          return 1;
        } else {
          return 0;
        }
      }; });
}
d3.text('https://raw.githubusercontent.com/manooh/NVSee/master/data/feelings_EN.txt', function(error, raw){
  if (error) throw error;
  // replace two-space indentation with pipes
  raw = raw.replace(new RegExp('  ', 'g'), '|');
  //read pipe-delimited data
  var dsv = d3.dsvFormat('|');
  var flatData = dsv.parse(raw);
  var rData = currentNode = tree(flatData);
  rData = d3.hierarchy(rData);
  var nodes = partition(rData
      .sum(function(d) { return 1; }) // each leaf gets a size of 1
      .sort(function(a, b) { d3.ascending(a.name, b.name) }) // not working?
    )
    .descendants();
  g = svg.selectAll("path")
    .data(nodes)
    .enter().append("g");
  path = g.append("path")
    .attr("d", arc)
    .style("fill", function(d, i) {
      var c;
      if (d.depth === 0) {
        return "white";
      } else if (d.depth === 1) {
        c = color((d.children ? d : d.parent).data.name);
      } else if (d.depth > 1) {
        c = d3.color(d.parent.data.color).darker();
      }
      d.data.color = c;
      return c;
    })
    .on("click", click)
    .append("title")
    .text(function(d) { return d.data.name });
  text = g.append("text")
    .style("fill", function(d) {
      if (d.depth === 0) {
        return "#CCC";
      } else {
        return "#FFF";
      }})
    .attr("class", "svglabel")
    .attr("transform",   texttransform)
    .attr("text-anchor", textanchor)
    .attr("dx",  textdx)
    .attr("dy", ".35em") // vertical-align
    .text(function(d) { return d.data.name; })
    .style("font-size", function(d) {
        // hack. save text len as property to make accessible in transiton
        d.data.textlen = this.getComputedTextLength();
        return calcFontSize(d);
      });
  });
function tree(nodes) {
  var curr, parent, root;
  var lev = 1;
  nodes.forEach(function(d) {
    if (!root) {
      // handle root (first node)
      curr = {
        name:     d.d1,
        children: []
      };
      root   = curr;
      parent = curr;
    } else {
      if (d['d' + (lev+1)]) {
        // handle children
        lev = lev+1;
        parent = curr;
      } else if (d['d' + (lev-1)]) {
        // handle moving up the hierarchy
        lev = lev-1;
        parent = parent.parent;
      } else if (!d['d' + lev]) {
        // if it's neither child, nor moving up, nor a sibling, handle exception
        throw "unhandled tree level";
      }
      curr = {
        name:     d['d' + lev],
        children: []
      };
      curr.parent = parent;
      parent.children.push(curr);
    }
  });
  return root;
}
.svglabel {
  font-family: sans-serif;
  pointer-events: none;
}
body {
  -webkit-touch-callout: none; /* iOS Safari */
    -webkit-user-select: none; /* Safari */
     -khtml-user-select: none; /* Konqueror HTML */
       -moz-user-select: none; /* Firefox */
        -ms-user-select: none; /* Internet Explorer/Edge */
            user-select: none; /* Non-prefixed version, currently
                                  supported by Chrome and Opera */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.js"></script>