如何阻止文本从屏幕上转换

时间:2017-04-08 12:45:09

标签: javascript d3.js svg

我有一个两环形饼图的视觉效果。 我正在构建的内容如下:   - 如果扇区的弧度对于指定的文本而言太小,则隐藏文本。这样做,似乎工作正常   - 如果文本被隐藏,那么标签应该出现在饼图之外。当视觉最初呈现时,也会这样做。

按下单选按钮时,饼图外的标签应相应转换。我尝试过渡并将其放慢到3500,这些标签只是慢慢地从屏幕上移开。

如何修复此转换?

我尝试创建过渡的片段从第241行开始:

var arcs2 = svg.data([json]).selectAll(".arcG");

arcs2.data(partition.nodes)
  .transition()
  .duration(3500)
  .attr("transform", function(d) {

    var c = arc.centroid(d),
      x = c[0],
      y = c[1],
      // pythagorean theorem for hypotenuse
      h = Math.sqrt(x * x + y * y);
    return "translate(" + (x / h * labelr) + ',' +
      (y / h * labelr) + ")";
  })
  .attr("text-anchor", "middle");


svg.selectAll(".theTxtsOuter")
  .text(function(d, i) {
    if (d.name === 'root') {
      return;
    } else if ((d.depth === 1) && (d.dx < (d.name.length * 0.15))) {
      return d.name;
    } else if ((d.depth === 2) && (d.dx < (d.name.length * 0.1))) {
      return d.name;
    } else {
      return;
    }
  });

这是工作(!)视觉的一小部分:

https://plnkr.co/edit/jYVPCL?p=preview

以下是馅饼使用的完整JavaScript:

function pieChart(dataFile) {

  var plot;
  var vis;

  var width = 400,
    height = 400,
    radius = Math.min(width, height) / 2.1,
    color = d3.scale.ordinal()
    .range(["#338ABA", "#016da9", "#4c96d5"])
    .domain([0, 2]);

  var labelr = radius + 5 // radius for label anchor

  var div = d3.select("body")
    .append("div")
    .attr("class", "toolTip");



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


  //check if the svg already exists
  plot = d3.select("#svgPIEChart");
  if (plot.empty()) {
    vis = d3.select("#pieChart")
      .append("svg")
      .attr({
        id: "svgPIEChart"
      });
  } else {
    vis = d3.select("#svgPIEChart");
    vis.selectAll("*").remove();
  }

  //group of the svg element
  var svg = vis
    .append("g")
    .attr({
      'transform': "translate(" + width / 2 + "," + height * .52 + ")"
    });


  //svg element
  vis.attr({
    //set the width and height of our visualization (these will be attributes of the <svg> tag
    width: width,
    height: height
  });



  d3.text(dataFile, function(text) {
    var csv = d3.csv.parseRows(text);
    var json = buildHierarchy(csv);

    // it seems d3.layout.partition() can be either squares or arcs
    var partition = d3.layout.partition()
      .sort(null)
      .size([2 * Math.PI, radius * radius])
      .value(function(d) {
        return d.SalesRev;
      });

    var path = svg.data([json]).selectAll(".theArc")
      .data(partition.nodes)
      .enter()
      .append("path")
      .attr("class", "theArc")
      .attr("id", function(d, i) {
        return "theArc_" + i;
      }) //Give each slice a unique ID 
      .attr("display", function(d) {
        return d.depth ? null : "none";
      })
      .attr("d", arc)
      .style("stroke", "#fff")
      .style("fill", function(d) {
        return color((d.children ? d : d.parent).name);
      })
      .attr("fill-rule", "evenodd")
      .style("opacity", 0.01)
      .style("stroke-opacity", 0.01)
      .each(stash);


    path.transition()
      .duration(PIEOBJ.transTime)
      .style("opacity", 1)
      .style("stroke-opacity", 1)

    path
      .on("mouseout", mouseout)
      .on("mousemove", function(d) {
        div.style("left", d3.event.pageX + 10 + "px");
        div.style("top", d3.event.pageY - 25 + "px");
        div.style("display", "inline-block");
        div.html(d.name + "<br>" + PIEOBJ.formatShrtInt(d.SalesRev));
      })



    var txts = svg.data([json]).selectAll(".theTxts")
      .data(partition.nodes)
      .enter()
      .append("text");
    txts
      .attr("class", "theTxts")
      .attr("dx", 10) //Move the text from the start angle of the arc
      .attr("dy", 15) //Move the text down
      .style("opacity", 0)
    txts
      .transition()
      .duration(PIEOBJ.transTime)
      .style("opacity", 1);



    var txtPths = txts.append("textPath")
      // .attr("xlink:href", function(d, i) {
      .attr("href", function(d, i) {
        return "#theArc_" + i;
      })
      .text(function(d) {
        if (d.name === 'root') {
          return;
        } else if ((d.depth === 1) && (d.dx < (d.name.length * 0.15))) {
          return;
        } else if ((d.depth === 2) && (d.dx < (d.name.length * 0.1))) {
          return;
        } else {
          return d.name;
        }
      });




    /* ------- TEXT LABELS OUTSIDE THE PIE-------*/
    //var arcs = svg.selectAll(".theArc");
    var arcs = svg.data([json]).selectAll(".arcG")
      .data(partition.nodes)
      .enter()
      .append("g")
      .attr("class", "arcG");

    arcs.append("text")
      .attr("transform", function(d) {

        var c = arc.centroid(d),
          x = c[0],
          y = c[1],
          // pythagorean theorem for hypotenuse
          h = Math.sqrt(x * x + y * y);
        console.log(c, h);
        return "translate(" + (x / h * labelr) + ',' +
          (y / h * labelr) + ")";
      })
      .attr("text-anchor", "middle")
      .text(function(d, i) {
        if (d.name === 'root') {
          return;
        } else if ((d.depth === 1) && (d.dx < (d.name.length * 0.15))) {
          return d.name;
        } else if ((d.depth === 2) && (d.dx < (d.name.length * 0.1))) {
          return d.name;
        } else {
          return;
        }
      })
      .attr("class", "theTxtsOuter");
    /* ----------------------------------------*/





    d3.selectAll("input").on("change", function change() {


      function createValueFunc(val) {
        // currentMeasure = val;
        return function(d) {
          return d[val];
        };
      }

      value = createValueFunc(this.value);

      PIEOBJ.currentMeasure = this.value;

      var path2 = svg.data([json]).selectAll(".theArc");
      path2
        .data(partition.value(value).nodes)
        .transition()
        .duration(1500)
        .attrTween("d", arcTween)
        .each("start", function() {
          d3.select(this)
            .on("mouseout", null) //CLEARING the listeners
            .on("mousemove", null);
        })
        .each("end", function() {
          d3.select(this)
            .on("mouseout", mouseout) //attaching the listeners
            .on("mousemove", function(d) {
              div.style("left", d3.event.pageX + 10 + "px");
              div.style("top", d3.event.pageY - 25 + "px");
              div.style("display", "inline-block");
              div.html(d.name + "<br>" + PIEOBJ.formatShrtInt(value(d)));
            });
        });

      svg.selectAll("textPath")
        .text(function(d) {
          if (d.name === 'root') {
            return;
          } else if ((d.depth === 1) && (d.dx < (d.name.length * 0.15))) {
            return;
          } else if ((d.depth === 2) && (d.dx < (d.name.length * 0.1))) {
            return;
          } else {
            return d.name;
          }
        });


      var arcs2 = svg.data([json]).selectAll(".arcG");

      arcs2.data(partition.nodes)
        .transition()
        .duration(3500)
        .attr("transform", function(d) {

          var c = arc.centroid(d),
            x = c[0],
            y = c[1],
            // pythagorean theorem for hypotenuse
            h = Math.sqrt(x * x + y * y);
          return "translate(" + (x / h * labelr) + ',' +
            (y / h * labelr) + ")";
        })
        .attr("text-anchor", "middle");


      svg.selectAll(".theTxtsOuter")
        .text(function(d, i) {
          if (d.name === 'root') {
            return;
          } else if ((d.depth === 1) && (d.dx < (d.name.length * 0.15))) {
            return d.name;
          } else if ((d.depth === 2) && (d.dx < (d.name.length * 0.1))) {
            return d.name;
          } else {
            return;
          }
        });

      // the following deletes what was originally created and then recreates the text
      // svg.selectAll("#titleX").remove();

    });



    function mouseout() {
      div.style("display", "none"); //<< gets rid of the tooltip <<
    }

    // Stash the old values for transition.
    function stash(d) {
      d.x0 = d.x;
      d.dx0 = d.dx;
    }

    // Interpolate the arcs in data space.
    function arcTween(a) {
      var i = d3.interpolate({
        x: a.x0,
        dx: a.dx0
      }, a);
      return function(t) {
        var b = i(t);
        a.x0 = b.x;
        a.dx0 = b.dx;
        return arc(b);
      };
    }

  });


}

// // Take a 2-column CSV and transform it into a hierarchical structure suitable
// // for a partition layout. 
function buildHierarchy(csv) {
  var root = {
    "name": "root",
    "children": []
  };
  for (var i = 0; i < csv.length; i++) {

    var sequence = csv[i][0];

    // var APD = +csv[i][1];
    var SalesRev = +csv[i][1];
    var Amount = +csv[i][2];

    if (isNaN(SalesRev)) { // 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,
          // "APD": APD,
          "SalesRev": SalesRev,
          "Amount": Amount
        };
        children.push(childNode);
      }
    }
  }

  root.children.forEach(function(v) {
    v.SalesRev = 0;
    v.Amount = 0;

    v.children.forEach(function(a) {
      v.SalesRev += a.SalesRev;
      v.Amount += a.Amount;
    });
  });

  return root;
}

1 个答案:

答案 0 :(得分:1)

当您最初定位它们时,您正在转换text元素。转换它们时,您将定位外部g元素。这些导致了相互冲突的转换。使用:

arcs2.data(partition.nodes)
  .select('text') //<-- apply on child text
  .transition()
  .duration(3500)
  .attr("transform", function(d) {
    ...
  });

更新了plunker