#javascript #d3.js #svg
#javascript #d3.js #svg
Вопрос:
Я пытаюсь выяснить логику, необходимую для определения того, следует ли поворачивать текст на моих ярлыках пончиков на 180 градусов. В принципе, если они отображаются вверх ногами, я хочу повернуть их на 180, чтобы улучшить читаемость. И в идеале это только для перевернутых текстовых меток, а не для тех, которые уже доступны для чтения. Тогда возникает вопрос, как количественно определить эти понятия для if
логики. Я считаю, что r.startAngle
в моем коде это уместилось бы здесь. Вот фрагмент.
var margins = {top:20, left:50, bottom:20, right:20};
var width = 300;
var arcSize = (6 * width / 100);
var innerRadius = arcSize * 3;
var data = [
{value: 43, marker: 90, label: "Cash", color: '#b8cce4', neg:false},
{value: 91, marker: 191, label: "Bonds", color: '#95b3d7', neg:false},
{value: 12, marker: 26, label: "Stocks", color: '#4f81b9', neg:false},
{value: 7, marker: 15, label: "Securities Funds", color: '#366092', neg:false},
{value: 62, marker: 130, label: "Other", color: '#a6a6a6', neg:false}
];
var svg = d3.select('body').append('svg').attr('width', width 100).attr('height', width 100);
var graphGroup = svg.append("g")
.attr("transform", "translate(" margins.left "," margins.top ")");
/*
graphGroup.append('image')
.attr('x',width/2-50)
.attr('y',width/2-50)
.attr('width',100)
.attr('height',100)
.attr("xlink:href", 'china-life.png');
*/
graphGroup.append('text')
.attr('x',width/2-41)
.attr('y',width/2 14)
.style('font-size','42px')
.text('5%');
var arcs = data.map(function (obj, i) {
return d3.svg.arc().innerRadius(i * arcSize innerRadius).outerRadius((i 1) * arcSize - (width / 100) innerRadius);
});
var arcsGrey = data.map(function (obj, i) {
return d3.svg.arc().innerRadius(i * arcSize (innerRadius ((arcSize / 2) - 2))).outerRadius((i 1) * arcSize - ((arcSize / 2)) (innerRadius));
});
var pieData = data.map(function (obj, i) {
return [
{value: obj.value * 0.75, arc: arcs[i], object: obj},
{value: (100 - obj.value) * 0.75, arc: arcsGrey[i], object: obj},
{value: 100 * 0.25, arc: arcs[i], object: obj}];
});
var pie = d3.layout.pie().sort(null).value(function (d) {
return d.value;
});
var g = graphGroup.selectAll('g').data(pieData).enter()
.append('g')
.attr('transform', 'translate(' width / 2 ',' width / 2 ') rotate(180)');
var gText = graphGroup.selectAll('g.textClass').data([{}]).enter()
.append('g')
.classed('textClass', true)
.attr('transform', 'translate(' width / 2 ',' width / 2 ') rotate(180)');
g.selectAll('path').data(function (d) {
return pie(d);
}).enter().append('path')
.attr('id', function (d, i) {
if (i == 1) {
return "Text" d.data.object.label
}
})
.attr('d', function (d) {
return d.data.arc(d);
}).attr('fill', function (d, i) {
if (d.data.object.neg==false) {
return i == 0 ? d.data.object.color : i == 1 ? '#D3D3D3' : 'none' ;
} else {
return i == 0 ? 'red' : i == 1 ? '#D3D3D3' : 'none' ;
}}).attr('class','segments');
/*
g.selectAll('.segments').attr('fill', function(d,i) {
return d.data.object.neg==true ? 'red' : 'none';
});
*/
graphGroup.selectAll('g').each(function (d, index) {
var el = d3.select(this);
var path = el.selectAll('path').each(function (r, i) {
if (i === 1) {
var centroid = r.data.arc.centroid({
startAngle: r.startAngle 0.05,
endAngle: r.startAngle 0.001 0.05
});
var lableObj = r.data.object;
g.append('text')
.attr('font-size', ((5 * width) / 100))
.attr('dominant-baseline', 'central')
/*.attr('transform', "translate(" centroid[0] "," (centroid[1] 10) ") rotate(" (180 / Math.PI * r.startAngle 7) ")")
.attr('alignment-baseline', 'middle')*/
.append("textPath")
.attr("textLength", function (d, i) {
return 0;
})
.attr("xlink:href", "#Text" r.data.object.label)
.attr("startOffset", '5')
.attr('font-weight','normal')
.attr("dy", '-3em')
.text(function(d) {
if (lableObj.neg==true) {
return '-' lableObj.marker;
} else {
return lableObj.marker ;
}
});
}
if (i === 0) {
var centroidText = r.data.arc.centroid({
startAngle: r.startAngle,
endAngle: r.startAngle
});
var lableObj = r.data.object;
/*gText.append('text')
.attr('font-size', ((5 * width) / 100))
.text(lableObj.label)
.attr('transform', "translate(" (centroidText[0] - ((1.5 * width) / 100)) "," (centroidText[1] ") rotate(" (180) ")"))
.attr('dominant-baseline', 'central');*/
}
});
});
<script src="http://d3js.org/d3.v3.min.js"></script>
if (i === 0 amp;amp; r.startAngle>180){
var centroidText = r.data.arc.centroid({
startAngle: r.startAngle,
endAngle: r.startAngle)
} else {
var centroidText = r.data.arc.centroid({
startAngle: r.startAngle*Math.pi,
endAngle: r.startAngle*Math.pi)
var lableObj = r.data.object; }
К сожалению, это приводит к неожиданному «)» после ошибки консоли списка.
Во фрагменте кода числа: 15 и 26 «перевернуты» и должны быть перевернуты.
Вопрос
Как мне перевернуть текстовые метки на диаграмме пончиков, чтобы улучшить читаемость? Есть ли встроенные средства или это единственный способ обновить мою (пока неудачную) логику?
Комментарии:
1. Это
unexpected ")"
связано с отсутствием}
в концеendAngle: r.startAngle*Math.pi)
2. @DBS странно, ошибка сохраняется, она довольно сложная, ее трудно отлаживать.
Ответ №1:
Это не обычные текстовые элементы. Это <textPath>
элементы.
Поэтому их вращение не является правильным решением. Что вам нужно сделать, так это получить длину пути…
var thisLength = this.getTotalLength();
… и перемещение текстов, используя startOffset
, в конец пути, вот так:
.attr("startOffset", function(){
return index === 2 || index === 3 ? thisLength - 22 : 5
})
Обратите внимание на тот факт, что здесь я просто заставляю второй и третий элементы (магические числа, как 22
и для заполнения) менять свои позиции: в вашем реальном коде вам нужно будет исправить функцию, чтобы найти элементы, которые startOffset
необходимо изменить, в соответствии с базовой тригонометрией.
Вот ваш код с этим изменением:
var margins = {
top: 20,
left: 50,
bottom: 20,
right: 20
};
var width = 300;
var arcSize = (6 * width / 100);
var innerRadius = arcSize * 3;
var data = [{
value: 43,
marker: 90,
label: "Cash",
color: '#b8cce4',
neg: false
},
{
value: 91,
marker: 191,
label: "Bonds",
color: '#95b3d7',
neg: false
},
{
value: 12,
marker: 26,
label: "Stocks",
color: '#4f81b9',
neg: false
},
{
value: 7,
marker: 15,
label: "Securities Funds",
color: '#366092',
neg: false
},
{
value: 62,
marker: 130,
label: "Other",
color: '#a6a6a6',
neg: false
}
];
var svg = d3.select('body').append('svg').attr('width', width 100).attr('height', width 100);
var graphGroup = svg.append("g")
.attr("transform", "translate(" margins.left "," margins.top ")");
/*
graphGroup.append('image')
.attr('x',width/2-50)
.attr('y',width/2-50)
.attr('width',100)
.attr('height',100)
.attr("xlink:href", 'china-life.png');
*/
graphGroup.append('text')
.attr('x', width / 2 - 41)
.attr('y', width / 2 14)
.style('font-size', '42px')
.text('5%');
var arcs = data.map(function(obj, i) {
return d3.svg.arc().innerRadius(i * arcSize innerRadius).outerRadius((i 1) * arcSize - (width / 100) innerRadius);
});
var arcsGrey = data.map(function(obj, i) {
return d3.svg.arc().innerRadius(i * arcSize (innerRadius ((arcSize / 2) - 2))).outerRadius((i 1) * arcSize - ((arcSize / 2)) (innerRadius));
});
var pieData = data.map(function(obj, i) {
return [{
value: obj.value * 0.75,
arc: arcs[i],
object: obj
},
{
value: (100 - obj.value) * 0.75,
arc: arcsGrey[i],
object: obj
},
{
value: 100 * 0.25,
arc: arcs[i],
object: obj
}
];
});
var pie = d3.layout.pie().sort(null).value(function(d) {
return d.value;
});
var g = graphGroup.selectAll('g').data(pieData).enter()
.append('g')
.attr('transform', 'translate(' width / 2 ',' width / 2 ') rotate(180)');
var gText = graphGroup.selectAll('g.textClass').data([{}]).enter()
.append('g')
.classed('textClass', true)
.attr('transform', 'translate(' width / 2 ',' width / 2 ') rotate(180)');
g.selectAll('path').data(function(d) {
return pie(d);
}).enter().append('path')
.attr('id', function(d, i) {
if (i == 1) {
return "Text" d.data.object.label
}
})
.attr('d', function(d) {
return d.data.arc(d);
}).attr('fill', function(d, i) {
if (d.data.object.neg == false) {
return i == 0 ? d.data.object.color : i == 1 ? '#D3D3D3' : 'none';
} else {
return i == 0 ? 'red' : i == 1 ? '#D3D3D3' : 'none';
}
}).attr('class', 'segments');
/*
g.selectAll('.segments').attr('fill', function(d,i) {
return d.data.object.neg==true ? 'red' : 'none';
});
*/
graphGroup.selectAll('g').each(function(d, index) {
var el = d3.select(this);
var path = el.selectAll('path').each(function(r, i) {
if (i === 1) {
var centroid = r.data.arc.centroid({
startAngle: r.startAngle 0.05,
endAngle: r.startAngle 0.001 0.05
});
var lableObj = r.data.object;
var thisLength = this.getTotalLength();
g.append('text')
.attr('font-size', ((5 * width) / 100))
.attr('dominant-baseline', 'central')
/*.attr('transform', "translate(" centroid[0] "," (centroid[1] 10) ") rotate(" (180 / Math.PI * r.startAngle 7) ")")
.attr('alignment-baseline', 'middle')*/
.append("textPath")
.attr("textLength", function(d, i) {
return 0;
})
.attr("xlink:href", "#Text" r.data.object.label)
.attr("startOffset", function() {
return index === 2 || index === 3 ? thisLength - 22 : 5
})
.attr('font-weight', 'normal')
.attr("dy", '-3em')
.text(function(d) {
if (lableObj.neg == true) {
return '-' lableObj.marker;
} else {
return lableObj.marker;
}
});
}
if (i === 0) {
var centroidText = r.data.arc.centroid({
startAngle: r.startAngle,
endAngle: r.startAngle
});
var lableObj = r.data.object;
/*gText.append('text')
.attr('font-size', ((5 * width) / 100))
.text(lableObj.label)
.attr('transform', "translate(" (centroidText[0] - ((1.5 * width) / 100)) "," (centroidText[1] ") rotate(" (180) ")"))
.attr('dominant-baseline', 'central');*/
}
});
});
<script src="http://d3js.org/d3.v3.min.js"></script>