如何在D3.js中的SVG内部对齐文本 [英] How To Align Text Inside SVG In D3.js

查看:105
本文介绍了如何在D3.js中的SVG内部对齐文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了带有条形图的可视数据,但无法对齐文本国内生产总值"和单位:十亿美元".季节性调整:季节性调整后,年利率注释:国民收入和产品指南美国(NIPA)帐户-( http://www.bea.gov/national/pdf/nipaguid.pdf )"

I created a visual data with bar chart but I'm having trouble aligning the text "Gross Domestic Product" and "Units: Billions of Dollars Seasonal Adjustment: Seasonally Adjusted, Annual Rate Notes: A Guide to the National Income and Product Accounts of the United States (NIPA) - (http://www.bea.gov/national/pdf/nipaguid.pdf)"

截至目前,它们在顶部重叠在一起:

As of now they are over lapping at the top:

我想在顶部调整国内生产总值",在单位:十亿美元"方面进行季节性调整:季节性调整后的年利率注释:《美国国民收入和产品账户指南》((NIPA)-( http://www.bea.gov/national/pdf/nipaguid.pdf )",如

I want to align "Gross Domestic Product" at the top and "Units: Billions of Dollars Seasonal Adjustment: Seasonally Adjusted Annual Rate Notes: A Guide to the National Income and Product Accounts of the United States (NIPA) - (http://www.bea.gov/national/pdf/nipaguid.pdf)" at the bottom like

这是我的代码小提琴链接

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. 创建正确对齐的x轴标签
  2. 将长的x轴标签分割成多行(否则太长)
  3. 正确设置标题,注释和其他文本元素的CSS类

以该顺序拍摄:

轴下的X轴标签居中

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

The simplest way to do this is to append your text between the code where you draw the x-axis and the y-axis.

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

To do this, I've borrowed a little from this answer: https://stackoverflow.com/a/13275930/3442309

看来,分割d.description文本的最明智的地方是在-"字符处:这是在希望图表外观的屏幕截图上完成的.

It looks like the most sensible place to split the d.description text is at the "-" character: This is how it's done on the screenshot of how you want the chart to look.

要实现拆分,请使用tspan个元素

To achieve the split, user tspan elements

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的定义方式

To change how and where this label is split, or to make it more generic (eg basing the split on length, rather than a specific character), simply modify how split is defined

设置文本的CSS类

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

In your example, the title was not using the title CSS class, so not getting the expected style. The reason for this is the following code at the end of your script:

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

这是在svg中为 all 文本设置notes样式.更正确的是,您应该在附加文本之后在 之后设置类属性.

What this was doing was setting the notes style for all text in the svg. More correctly, you should have set the class attribute after appending the text.

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

Correcting for this, for the title, we now have:

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

并且我在javascript的标题中添加了一些位置,而不是在CSS中添加了一些位置:

and I've added some positioning to the javascript for `title, rather than in the CSS:

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

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

Lastly, I've corrected your CSS, which used color for applying text color, instead of fill, which is the correct way

这里有描述所有更改的小提琴: https://jsfiddle.net/henbox/nuwzxoz8 /1/

Here's a Fiddle with all the changes described: https://jsfiddle.net/henbox/nuwzxoz8/1/

这篇关于如何在D3.js中的SVG内部对齐文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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