5

我一直在尝试使用 d3.js 为我的图表创建一个水平图例。我一直在努力使用动态标签使 x 轴间距正确。

问题是标签的宽度不一致,这是一个完整的例子,这是我计算 x 位置的函数:

function legendXPosition(data, position, avgFontWidth){
    if(position == 0){
        return 0;
    } else {
        var xPostiion = 0;
        for(i = 0; i < position; i++){
            xPostiion += (data[i].length * avgFontWidth);
        }
        return xPostiion;
    }
}

有人对如何改善这一点有任何建议吗?

4

2 回答 2

7

我建议参考这个问题:SVG get text element width

像你现在一样渲染第一个图例条目。存储此条目,或分配 ID,以便您可以通过选择查找它们。

渲染后续条目时,获取前一个“文本”元素和 x 偏移量。使用前一个文本元素的确切宽度计算新的图例条目偏移量

var myNewXOffset = myPreviousXOffset + myPreviousText.getBBox().width
于 2012-12-19T15:33:52.897 回答
0

修改代码以获得以下结果 在此处输入图像描述 标签宽度不一致的原因是由于两个因素。它们都与您计算 x 位置的函数有关:

1) avgFontWidth 参数

它应该更小。15您在示例中为其分配了 的值,但实际的 averageFontWidth 比 小得多15,它介于5to之间7。您的图例标签之间的额外空间来自这个不准确的平均字体宽度值。

avgFontWidth的只是一个平均值。实际上,字体宽度会发生变化。例如,下r图中的 比P. 在此处输入图像描述 因此,五个字母的单词rrrrr可能比PPPPP以某种方式设置字体系列时要短得多。总之,您不应使用avgFontWidth. 您应该 按照cmonkey 的建议使用SVG 获取文本元素宽度

2)上面公式的逻辑是xPostiion += (data[i].length * avgFontWidth) 要计算文字的长度,但是标签的宽度也要加上,xPostiion应该是

xPostiion += (data[i].length * avgFontWidth) + widthOftheLabel

修改后的代码:

<!DOCTYPE html>
<meta charset="utf-8">
<style>

body {
  font: 10px sans-serif;
}

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.x.axis text {
  padding-top: 5px;
  text-anchor: "right";
}

.line {
  fill: none;
  stroke-width: 1.5px;
}

.y.axis line,
.y.axis path {
  stroke-dasharray: 2,2;
}
</style>
<body>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="http://d3js.org/d3.v3.js"></script>
<script type="text/javascript" src="javascripts/psgam-d3-graphs.js"></script>
<script type="text/javascript"> 
  function drawlinegraph(data, startDateString, endDateString, maxValue, minValue, colour,
                       divID, labels) {
    var m = {top: 60, right: 0, bottom: 35, left: 80},
        w = 770 - m.left - m.right,
        h = 180 - m.top - m.bottom,
        dateFormat = "%Y-%m-%d";

    labels = ["ada", "adas", "asdasdasd", "sd"];

    var parseDate = d3.time.format(dateFormat).parse;

    var startDate = parseDate(startDateString);
    var endDate = parseDate(endDateString);

    // Define the x scale
    var x = d3.time.scale()
            .domain([startDate, endDate])
            .range([0, w]);

    // Format x-axis labels
    x.tickFormat(d3.time.format(dateFormat));

    // Define the y scale
    var y = d3.scale.linear()
            .domain([minValue, maxValue])
            .range([h, 0]);

    var graph = d3.select(divID).append("svg:svg")
            .attr("width", w + m.right + m.left)
            .attr("height", h + m.top + m.bottom)
          .append("svg:g")
            .attr("transform", "translate(" + m.left + "," + m.top + ")");

    // create x-axis
    var xAxis = d3.svg.axis()
            .scale(x)
            .orient("bottom")
            .ticks(4)
            .tickSize(-h)
            .tickFormat(d3.time.format("%Y/%m"));

    // Add the x-axis.
    graph.append("svg:g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + h + ")")
        .call(xAxis);

    // Overide the default behaviour of d3 axis labels
    d3.selectAll(".x.axis g text")[0].forEach(function(e) {
        e.attributes[0].value = 8; // y
    });

    // create y-axis
    var yAxisLeft = d3.svg.axis()
            .scale(y)
            .ticks(12)
            .orient("left")
            .tickSize(-w);

    // Add the y-axis to the left
    graph.append("svg:g")
        .attr("class", "y axis")
        .attr("transform", "translate(0,0)")
        .call(yAxisLeft);

    var i = 0;
    $.each(data, function(key, value) {
        value.forEach(function(d) {
            d.date = parseDate(d.date);
        });

        var line = d3.svg.line()
                .x(function(d) { return x(d.date); })
                .y(function(d) { return y(d.value); });
        graph.append("path")
            .datum(value)
            .attr("d", line)
            .attr("class", "line")
            .attr("stroke", colour[i]);
        i++;
    });

    var legend = graph.append("g")
            .attr("class", "legend")
            .attr("height", 100)
            .attr("width", 100)
        .attr('transform', 'translate(-5,' + (h + 35) + ')');


    legend.selectAll('rect')
        .data(labels)
      .enter()
      .append("rect")
          .attr("x", function(d, i){
              var xPost = legendXPosition(labels, i, 6);
              return xPost;
          })
      .attr("y", -6)
          .attr("width", 20)
          .attr("height", 5)
          .style("fill", function(d, i) {
              var color = colour[i];
              return color;
          });

    legend.selectAll('text')
      .data(labels)
      .enter()
      .append("text")
          .attr("x", function(d, i){
              var xPost = legendXPositionText(labels, i, 22, 6);
              return xPost;
          })
      .attr("y", -1)
          .text(function(d) {
              return d;
          });
  };

  function legendXPositionText(data, position, textOffset, avgFontWidth){
    return legendXPosition(data, position, avgFontWidth) + textOffset;
  }

  function legendXPosition(data, position, avgFontWidth){
    if(position == 0){
        return 0;
    } else {
        var xPostiion = 0;
        for(i = 0; i < position; i++){
            xPostiion += (data[i].length * avgFontWidth + 40);
        }
        return xPostiion;
    }
  }

  var benchmark_line_graph_colours = ["#524364", "#937ab1", "#ab5b02", "#faa757"],
    benchmark_line_graph_data = {"Beassa ALBI TR ZAR":[{"date":"2012-08-31","value":101.1},{"date":"2012-09-28","value":101.89},{"date":"2012-10-31","value":101.09}],"FTSE/JSE All Share TR ZAR":[{"date":"2012-08-31","value":99.72},{"date":"2012-09-28","value":101.24},{"date":"2012-10-31","value":105.29}],"STeFI Composite ZAR":[{"date":"2012-08-31","value":100.23},{"date":"2012-09-28","value":100.52},{"date":"2012-10-31","value":100.77}],"portfolio":[{"date":"2012-08-31","value":101.55},{"date":"2012-09-28","value":101.15},{"date":"2012-10-31","value":102.08}]};
  drawlinegraph(benchmark_line_graph_data,
    "2012-08-31",
    "2012-10-31",
    105.84700000000001,
    99.163, benchmark_line_graph_colours,
    "body");
</script> 
于 2018-05-08T18:45:32.327 回答