标签在d3径向条形图中的位置 [英] Label placement in d3 radial bar chart

查看:102
本文介绍了标签在d3径向条形图中的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的d3径向图中,我试图使标签文本位于段弧的正上方,而不是保持在外圆之外.

Here in my d3 radial chart, I am trying to get the label text just above the segment arcs instead of keeping outside the outer circle.

小提琴

Fiddle

    var width = 360,
    height = 300,
    barHeight = height / 2 - 40;

    var formatNumber = d3.format("s");

    var color = d3.scale.ordinal()
    .range(["#F15D5D","#FAD64B"]);

    var svg = d3.select('#chart').append("svg")
    .attr("width", width)
    .attr("height", height)
    .attr('class','radial')
    .append("g")
    .attr("transform", "translate(" + width/2 + "," + height/2 + ")");

    var data = [{
        "name": "ABC",
        "value":4
    },
    {
        "name": "XYZ",
        "value":5
    },{
        "name": "DEF",
        "value":2
    },
    {
        "name": "GHI",
        "value":3
    },{
        "name": "JKL",
        "value":1
    }];

    data.sort(function(a,b) { return b.value - a.value; });

    var extent = [0, d3.max(data, d=>d.value)];
    var barScale = d3.scale.linear()
    .domain(extent)
    .range([0, barHeight]);

    var keys = data.map(function(d,i) { return d.name; });
    var numBars = keys.length;


    // X scale
    var x = d3.scale.linear()
    .domain(extent)
    .range([0, -barHeight]);

    // X axis
    var xAxis = d3.svg.axis()
    .scale(x).orient("left")
    .ticks(3)
    .tickFormat(formatNumber);

    // Inner circles
    var circles = svg.selectAll("circle")
    .data(x.ticks(5))
    .enter().append("circle")
    .attr("r", function(d) {return barScale(d);})
    .style("fill", "none")
    //.style("stroke", "black")
    //.style("stroke-dasharray", "2,2")
    .style("stroke-width",".5px");

    // Create arcs
    var arc = d3.svg.arc()
    .startAngle(function(d,i) { 
     var a = (i * 2 * Math.PI) / numBars;
     var b = ((i + 1) * 2 * Math.PI) / numBars;
     var d = (b-a) / 4;
     var x = a+d;
     var y = b-d;

     return x;//(i * 2 * Math.PI) / numBars; 
    })
      .endAngle(function(d,i) { 
    var a = (i * 2 * Math.PI) / numBars;
    var b = ((i + 1) * 2 * Math.PI) / numBars;
    var d = (b-a) / 4;
    var x = a+d;
    var y = b-d;
    return y;//((i + 1) * 2 * Math.PI) / numBars; 
  })
    .innerRadius(0);

   // Render colored arcs
    var segments = svg.selectAll("path")
    .data(data)
    .enter().append("path")
    .each(function(d) { d.outerRadius = 0; })
    .style("fill", function (d) { return color(d.name); })
    .attr("d", arc);

   // Animate segments
    segments.transition().ease("elastic").duration(1000).delay(function(d,i) {return (25-i)*50;})
    .attrTween("d", function(d,index) {
        var i = d3.interpolate(d.outerRadius, barScale(+d.value));
        return function(t) { d.outerRadius = i(t); return arc(d,index); };
    });

   // Outer circle
    svg.append("circle")
    .attr("r", barHeight)
    .classed("outer", true)
    .style("fill", "none")
    //.style("stroke", "black")
    .style("stroke-width",".5px");

   // Apply x axis
    svg.append("g")
    .attr("class", "x axis")
    .call(xAxis);

    // Labels
   var labelRadius = barHeight * 1.025;

var labels = svg.append("g")
    .classed("labels", true);

labels.append("def")
    .append("path")
    .attr("id", "label-path")
    .attr("d", "m0 " + -labelRadius + " a" + labelRadius + " " + labelRadius + " 0 1,1 -0.01 0");

labels.selectAll("text")
    .data(keys)
    .enter().append("text")
    .style("text-anchor", "middle")
    .style("font-weight","bold")
    .style("fill", function(d, i) {return "#555";})
    .append("textPath")
    .attr("xlink:href", "#label-path")
    .attr("startOffset", function(d, i) {return i * 100 / numBars + 50 / numBars + '%';})
    .text(function(d) {return d.toUpperCase(); });

推荐答案

我们可以使用与创建圆弧相同的数据来设置<defs>路径的位置.

We can set the position of the <defs>'s paths using the same data you used to create the arcs.

首先,让我们创建一个回车选择:

First, let's create an enter selection:

var labels = svg.selectAll("foo")
    .data(data)
    .enter()
    .append("g")
    .classed("labels", true);

然后,我们对每个值使用barScale附加路径(此处为4px的硬编码填充):

Then, we append the paths using the barScale for each value (hardcoded padding of 4px here):

labels.append("def")
    .append("path")
    .attr("id", (d, i) => "label-path" + i)
    .attr("d", d => "m0 " + -(barScale(d.value) + 4) +
        " a" + (barScale(d.value) + 4) + " " +
        (barScale(d.value) + 4) + " 0 1,1 -0.01 0");

请注意,我们必须使用唯一 ID.然后,我们在文本路径中更改ID:

Please notice that we have to use unique IDs. Then, we change the IDs in the text-paths:

.attr("xlink:href", (d, i) => "#label-path" + i)

这是您更新的小提琴: https://jsfiddle.net/qt3e0rex/

Here is your updated fiddle: https://jsfiddle.net/qt3e0rex/

以及堆栈代码段中的相同代码:

And the same code in the Stack snippet:

var width = 360,
    height = 300,
    barHeight = height / 2 - 40;

var formatNumber = d3.format("s");

var color = d3.scale.ordinal()
    .range(["#F15D5D", "#FAD64B"]);

var svg = d3.select('body').append("svg")
    .attr("width", width)
    .attr("height", height)
    .attr('class', 'radial')
    .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

var data = [{
    "name": "ABC",
    "value": 4
}, {
    "name": "XYZ",
    "value": 5
}, {
    "name": "DEF",
    "value": 2
}, {
    "name": "GHI",
    "value": 3
}, {
    "name": "JKL",
    "value": 1
}];

data.sort(function(a, b) {
    return b.value - a.value;
});

var extent = [0, d3.max(data, d => d.value)];
var barScale = d3.scale.linear()
    .domain(extent)
    .range([0, barHeight]);

var keys = data.map(function(d, i) {
    return d.name;
});
var numBars = keys.length;

// X scale
var x = d3.scale.linear()
    .domain(extent)
    .range([0, -barHeight]);

// X axis
var xAxis = d3.svg.axis()
    .scale(x).orient("left")
    .ticks(3)
    .tickFormat(formatNumber);

// Inner circles
var circles = svg.selectAll("circle")
    .data(x.ticks(5))
    .enter().append("circle")
    .attr("r", function(d) {
        return barScale(d);
    })
    .style("fill", "none")
    //.style("stroke", "black")
    //.style("stroke-dasharray", "2,2")
    .style("stroke-width", ".5px");

// Create arcs
var arc = d3.svg.arc()
    .startAngle(function(d, i) {
        var a = (i * 2 * Math.PI) / numBars;
        var b = ((i + 1) * 2 * Math.PI) / numBars;
        var d = (b - a) / 4;
        var x = a + d;
        var y = b - d;

        return x; //(i * 2 * Math.PI) / numBars; 
    })
    .endAngle(function(d, i) {
        var a = (i * 2 * Math.PI) / numBars;
        var b = ((i + 1) * 2 * Math.PI) / numBars;
        var d = (b - a) / 4;
        var x = a + d;
        var y = b - d;
        return y; //((i + 1) * 2 * Math.PI) / numBars; 
    })
    .innerRadius(0);

// Render colored arcs
var segments = svg.selectAll("path")
    .data(data)
    .enter().append("path")
    .each(function(d) {
        d.outerRadius = 0;
    })
    .style("fill", function(d) {
        return color(d.name);
    })
    .attr("d", arc);

// Animate segments
segments.transition().ease("elastic").duration(1000).delay(function(d, i) {
        return (25 - i) * 50;
    })
    .attrTween("d", function(d, index) {
        var i = d3.interpolate(d.outerRadius, barScale(+d.value));
        return function(t) {
            d.outerRadius = i(t);
            return arc(d, index);
        };
    });

// Outer circle
svg.append("circle")
    .attr("r", barHeight)
    .classed("outer", true)
    .style("fill", "none")
    //.style("stroke", "black")
    .style("stroke-width", ".5px");

// Apply x axis
svg.append("g")
    .attr("class", "x axis")
    .call(xAxis);

// Labels
var labelRadius = barHeight * 1.025;

var labels = svg.selectAll("foo")
    .data(data)
    .enter()
    .append("g")
    .classed("labels", true);

labels.append("def")
    .append("path")
    .attr("id", (d, i) => "label-path" + i)
    .attr("d", d => "m0 " + -(barScale(d.value) + 4) + " a" + (barScale(d.value) + 4) + " " + (barScale(d.value) + 4) + " 0 1,1 -0.01 0");

labels.append("text")
    .style("text-anchor", "middle")
    .style("font-weight", "bold")
    .style("fill", function(d, i) {
        return "#555";
    })
    .append("textPath")
    .attr("xlink:href", (d, i) => "#label-path" + i)
    .attr("startOffset", function(d, i) {
        return i * 100 / numBars + 50 / numBars + '%';
    })
    .text(function(d) {
        return d.name.toUpperCase();
    });

body {
  background-color:#fff;
}
.axis path, .axis line {
		fill: none;
		shape-rendering: crispEdges;
	}

	.x.axis path {
		display: none;
	}
  
	.tick text, line {
			display:none;
		}
    
  circle {
    stroke:#ccc;
  }

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

这篇关于标签在d3径向条形图中的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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