2017-04-25 84 views
12

Mam wykres radialny d3 utworzony przy użyciu niektórych próbek społeczności i postów przepełnienia stosu.Przekształć etykietę w odwrotnej kolejności Wykres radialny d3

Tutaj dwie dolne etykiety i cyfry znajdują się w formie lustrzanej (A13 i A14). Poszukuję fragmentów, aby przekształcić tylko te dwie w kierunku przeciwnym do ruchu wskazówek zegara z górnymi numerami (obok wykresu), a następnie oznaczyć etykietę tak, aby była lepiej czytelna.

JSFiddle

var data = [ 
{"name":"A11","value":217,"color":"#fad64b"}, 
{"name":"A12","value":86,"color":"#f15d5d"}, 
{"name":"A13","value":79,"color":"#f15d5d"}, 
{"name":"A14","value":82,"color":"#f15d5d"}, 
{"name":"A15","value":101,"color":"#fad64b"}, 
{"name":"A16","value":91,"color":"#fad64b"} 
]; 

var width = 500; 
var height = 300; 
var barHeight = height/2 - 15; 
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 extent = [0, d3.max(data, function(d) { return d.value; })]; 

var lastNum = extent[1]; 
var percentageOne = (lastNum*25)/100; 
var percentageTwo = (lastNum*50)/100; 
var percentageThree = (lastNum*75)/100; 
var tickValues = [percentageOne, percentageTwo, percentageThree, lastNum]; 

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') 
.tickFormat(formatNumber) 
.tickValues(tickValues); 

// Inner circles 
var circles = svg.selectAll('circle') 
.data(tickValues) 
.enter().append('circle') 
.attr('r', function(d) { 
    return barScale(d); 
}) 
.style('fill', 'none') 
.style('stroke-width', '0.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; 
}) 
.attr('class', 'bar') 
.style('fill', function(d) { 
    return d.color; 
}) 
.attr('d', arc); 

// Animate segments 
segments.transition().ease('elastic').duration(1000).delay(function(d, i) { 
    return (25 - i) * 10; 
}) 
    .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-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', function(d, i) { return 'label-path' + i; }) 
    .attr('d', function(d) { 
    return 'm0 ' + -(barScale(d.value) + 4) + ' a' + (barScale(d.value) + 4) + ' ' + (barScale(d.value) + 4) + ' 0 1,1 -0.01 0'; 
}); 

labels.append('def') 
    .append('path') 
    .attr('id', function(d, i) { return 'label-pathnum' + i; }) 
    .attr('d', function(d){ 
    return 'm0 ' + -(barScale(d.value) + 14) + ' a' + (barScale(d.value) + 14) + ' ' + (barScale(d.value) + 14) + ' 0 1,1 -0.01 0'; 
}); 

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

labels.append('text') 
    .style('text-anchor', 'middle') 
    .style('fill', function(d, i) { 
    return d.color; 
}) 
    .append('textPath') 
    .attr('xlink:href', function(d, i) { return '#label-pathnum' + i; }) 
    .attr('startOffset', function(d, i) { 
    return i * 100/numBars + 50/numBars + '%'; 
}) 
    .text(function(d) { 
    return d.value; 
}); 

enter image description here

+2

przyjrzeć się tej doskonałej tutorialu z Nadieh Bremer: https://www.visualcinnamon.com/2015/09/placing-text-on-arcs.html –

+0

@GerardoFurtado fajny artykuł, ale utknęło mi w sekcji ścieżki :( – devo

+0

Nie są one odzwierciedlone, są po prostu odwrócone. –

Odpowiedz

7

Trzeba zmodyfikować ścieżkę do konkretnych elementów, które muszą być odwrócone. Aby to zrobić, zacząć od przechowywania kąta w obiekcie danych:

.each(function(d,i) { 
    d.outerRadius = 0; 
    var angleStart = (i/numBars) * 360; 
    var angleEnd = ((i+1)/numBars) * 360; 
    d.angle = (angleStart + angleEnd)/2; 
}) 

Potem badanego kąt przy tworzeniu ścieżki dla tekstu i odwrócić ścieżkę przewracanej przypadku tekstu:

var len = barScale(d.value) + 4; 
if(d.angle > 91 && d.angle < 269) { 
    len += 8; // the flipped text is on the inside of the path so we need to draw it further out 
    return 'M -0.01 ' + (-len) + ' A ' + len + ' ' + len + ' 0 1,0 0 ' + (-len); 
} 
else { 
    return 'M 0 ' + (-len) + ' A' + len + ' ' + len + ' 0 1,1 -0.01 ' + (-len); 
} 

Następnie trzeba przerzucić „% wokół ścieżki” dla umieszczenia tekstu wzdłuż ścieżki odwróconej:

.attr('startOffset', function(d, i) { 
    if(d.angle > 91 && d.angle < 269) 
    return (100 - (i * 100/numBars + 50/numBars)) + '%'; 
    else  
    return i * 100/numBars + 50/numBars + '%'; 
}) 

skrzypce roboczych znajdują się tutaj: https://jsfiddle.net/FrancisMacDougall/mnrqokqL/

Z tego wyniku:

enter image description here