如何在D3.js中对齐SVG内的文本

时间:2016-03-28 18:15:21

标签: json d3.js

我用条形图创建了一个视觉数据,但我无法调整文本“国内生产总值”和“单位:数十亿美元季节性调整:季节性调整,年度费率说明:国民收入和产品指南”美国账户(NIPA) - (https://jsfiddle.net/wsfnqvyn/6/)“

截至目前,他们已经超过了顶部: http://www.bea.gov/national/pdf/nipaguid.pdf

我希望将“国内生产总值”排在最前面,“单位:数十亿美元季节性调整:经季节性调整的年度利率说明:美国国民收入和产品账户指南(NIPA) - ({ {3}})“在底部就像 enter image description here

http://www.bea.gov/national/pdf/nipaguid.pdf

var url = "https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/GDP-data.json";

//Fetch Data By .$getJSON Method
$.getJSON(url, function (d) {
    var monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
    ];
    var data = d.data;
    /*test data by
    console.log(data[0][0]);
    */
    //create Margin
    var margin = { top: 40, right: 20, bottom: 30, left: 50 },
        width = 960 - margin.left - margin.right,
        height = 600 - margin.top - margin.bottom;
    /*
       Define Min & Max Data for Scale
    */
    console.log(d.description);
    var minDate = new Date(data[0][0]);
    var maxDate = new Date(data[d.data.length - 1][0]);
    /*
     test data by 
     console.log(minDate);
     console.log(maxDate);
    */
    /*
    define scale then followed by axis
    */
    // define x and y scales
    // define x and y scales
    var xScale = d3.time.scale().
        domain([minDate, maxDate]).
        range([0, width]);
    var yScale = d3.scale.linear().
        domain([0, d3.max(data, function (d) {
            return d[1];
        })]).
        range([height, 0]);
    // define x axis and y axis
    var xAxis = d3.svg.axis().
        scale(xScale).
        orient("bottom").
        ticks(d3.time.years, 5);
    var yAxis = d3.svg.axis().
        scale(yScale).
        orient("left").
        ticks(10, "");
    var thisDate = new Date(data[0][0]);
    /*
    Create Tooltip
    */
    var toolTip = d3.tip()
      .attr('class', 'd3-tip')
      .offset([-10, 0])
      .html(function (d) {
          return ('<strong>$' + d[1].toLocaleString() + ' Billion</strong><p>' + thisDate.getFullYear() + ' - ' + monthNames[thisDate.getMonth()] + '</p>');
      });
    /*
    create svg element then append height and width and g which act as a container
    */
    var svg = d3.select(".mainContainer").
      attr({
          "width": width + margin.right + margin.left,
          "height": height + margin.top + margin.bottom
      }).
    append("g").
      attr("transform", "translate(" + margin.left + "," + margin.right + ")");

    //call toolTip
    svg.call(toolTip);
    // Draw xAxis
    svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);
    //Draw yAxis
    svg.append("g")
     .attr("class", "y axis")
     .call(yAxis)
   .append("text")
     .attr("transform", "rotate(-90)")
     .attr("y", 6)
     .attr("dy", ".71em")
     .style("text-anchor", "end")
     .text("Gross Domestic Product, USA");
    /*
  create bar or bind data
  */
    //bind data
    svg.selectAll(".bar")
      .data(data)
   //enter data
    .enter().
        append("rect")
   //update data
      .attr("class", "bar")
      .attr("x", function (d) { return xScale(new Date(d[0])); })
      .attr("width", Math.ceil(width / data.length))
      .attr("y", function (d) { return yScale(d[1]); })
      .attr("height", function (d) { return height - yScale(d[1]); })
      .on('mouseover', toolTip.show)
      .on('mouseout', toolTip.hide);
    //add description on top and bottom of svg
    svg.
        attr("class", "title").
        append("text").
        html("Gross Domestic Product </br>")
    svg.
        attr("class", "notes").
        append("text").
        text(d.description);
    

});
svg {
  
  margin-left: auto;
  margin-right: auto;
  display: block;
  background-color:antiquewhite;
}
body {
  font: 10px sans-serif;
}

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

.bar:hover {
  fill: orangered ;
}
.d3-tip {
  line-height: 1;
  font-weight: bold;
  padding: 12px;
  background: rgba(0, 0, 0, 0.8);
  color: #fff;
  border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
  box-sizing: border-box;
  display: inline;
  font-size: 10px;
  width: 100%;
  line-height: 1;
  color: rgba(0, 0, 0, 0.8);
  content: "\25BC";
  position: absolute;
  text-align: center;
}

/* Style northward tooltips differently */
.d3-tip.n:after {
  margin: -1px 0 0 0;
  top: 100%;
  left: 0;
}
.notes {
  font-size: 12px;
  font-family: sans-serif;
  color: steelblue;
  padding: 20px;
  text-align: center;
  vertical-align:bottom;
}
.title {
  font-size: 2.5em;
  font-family: sans-serif;
  color: steelblue;
  text-align: center;
  padding: 15px 0px 5px 0px;
}
<!DOCTYPE html>
<html>
<head>
    <title>D3-Zipline: GDP Bar Graph</title>
    <meta charset="utf-8" />
    <link href="../Content/bootstrap-theme.min.css" rel="stylesheet" />
    <link href="../Content/bootstrap.min.css" rel="stylesheet" />
    <script src="../Scripts/d3/d3.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.6.7/d3-tip.min.js"></script>
    <link href="demo.css" rel="stylesheet" />
</head>
<body>
    
    <div class="container-fluid text-center">
        <br /><br />
        <svg class="mainContainer">
        </svg>
    </div>
    <script src="../Scripts/jquery-2.2.1.min.js"></script>
    <script src="../Scripts/bootstrap.min.js"></script>
    <script src="demo.js"></script>
</body>
</html>

1 个答案:

答案 0 :(得分:2)

这里有几点需要解决:

  1. 创建正确对齐的x轴标签
  2. 将长x轴标签分成多行(否则它太长了)
  3. 正确设置标题,备注和其他文本元素的CSS类
  4. 按顺序接受:

    轴下的X轴标签,居中

    最简单的方法是在绘制x轴和y轴的代码之间附加文本。

    svg.append("text")    // text label for the x axis
      .attr("class", "notes")
      .attr("transform", "translate(" + width/2 + ")")
      .attr("y",  height + margin.bottom)
      .text(d.description)
      .call(splitLongLabel);    // The next section explains this bit...
    

    将长x轴标签分割为多行

    为此,我从这个答案中借了一点:https://stackoverflow.com/a/13275930/3442309

    看起来分割d.description文字的最明智的地方是&#34; - &#34; character:这就是你想要图表的截图的截图。

    要实现拆分,用户tspan元素

    var insertLinebreaks = function (d) {
        var el = d;    // Get the current element
        var words = d.text().split("-");    // Split text  at the hyphen
        el.text('');
        for (var i = 0; i < words.length; i++) {    // Then build up the tspans
            var tspan = el.append('tspan')
                .attr('x', 0)
                .text(words[i])
                .style("text-anchor", "middle");
            if (i > 0)
                tspan
                    .attr('x', 0)
                    .attr('dy', '15')
                    .style("text-anchor", "middle");
        }
    };
    

    要更改此标签的分割方式和位置,或使其更通用(例如,基于长度分割,而不是特定字符),只需修改split的定义方式

    为文字设置CSS类

    在您的示例中,标题未使用title CSS类,因此未获得预期的样式。原因是脚本末尾有以下代码:

    svg.
        attr("class", "notes").
        append("text").
        text(d.description);
    

    这样做是为svg中的所有文本设置notes样式。更准确地说,您应该在附加文本后设置类属性

    对此进行更正,对于标题,我们现在有:

    svg.
        //attr("class", "title"). <- Removed from here
        append("text").
        attr("class", "title").    // <- added here
        html("Gross Domestic Product </br>")
    

    我已经在javascript中为`title添加了一些定位,而不是在CSS中:

        ....
        .attr('x', width / 2)
        .attr('y', 20)
        .style("text-anchor", "middle");
    

    最后,我已经更正了您使用color来应用文字颜色的CSS,而不是fill,这是正确的方法

    这里是一个小提琴,描述了所有变化:https://jsfiddle.net/henbox/nuwzxoz8/1/