Ярлык наружной дуги (круговая диаграмма) d3.js
Я новичок в d3.js, и я пытаюсь сделать с ним круговую диаграмму.
У меня есть только одна проблема: я не могу получить свои метки за пределами моих дуг...
Этикетки расположены с помощью arc.centroid
arcs.append("svg:text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
Кто может мне помочь?
Ответы
Ответ 1
Я могу решить эту проблему - с тригонометрией:).
Смотрите скрипту: http://jsfiddle.net/nrabinowitz/GQDUS/
В принципе, вызов arc.centroid(d)
возвращает массив [x,y]
. Вы можете использовать теорему Пифагора для вычисления гипотенузы, которая представляет собой длину линии от центра пирога до центра тяжести дуги. Затем вы можете использовать вычисления x/h * desiredLabelRadius
и y/h * desiredLabelRadius
для вычисления желаемого x,y
для вашего якоря метки:
.attr("transform", function(d) {
var c = arc.centroid(d),
x = c[0],
y = c[1],
// pythagorean theorem for hypotenuse
h = Math.sqrt(x*x + y*y);
return "translate(" + (x/h * labelr) + ',' +
(y/h * labelr) + ")";
})
Единственным недостатком здесь является то, что text-anchor: middle
больше не лучший выбор - вам лучше настроить text-anchor
на основе той стороны пирога, в котором мы находимся:
.attr("text-anchor", function(d) {
// are we past the center?
return (d.endAngle + d.startAngle)/2 > Math.PI ?
"end" : "start";
})
Ответ 2
Спасибо!
Я нашел другой способ решить эту проблему, но вам кажется лучше:-)
Я создал вторую дугу с большим радиусом и использовал ее для размещения моих меток.
///// Arc Labels /////
// Calculate position
var pos = d3.svg.arc().innerRadius(r + 20).outerRadius(r + 20);
// Place Labels
arcs.append("svg:text")
.attr("transform", function(d) { return "translate(" +
pos.centroid(d) + ")"; })
.attr("dy", 5)
.attr("text-anchor", "middle")
.attr("fill", function(d, i) { return colorL(i); }) //Colorarray Labels
.attr("display", function(d) { return d.value >= 2 ? null : "none"; })
.text(function(d, i) { return d.value.toFixed(0) + "%"});
Ответ 3
В частности, для круговых диаграмм функция d3.layout.pie()
будет форматировать данные с атрибутами startAngle
и endAngle
. Радиус может быть любым, что вы хотите (как далеко от центра вы хотели бы разместить этикетку).
Объединение этих фрагментов информации с помощью тригонометрических функций позволяет определить координаты x и y для меток.
Рассмотрим этот gist/блок.
Что касается позиционирования текста x/y, магия находится в этой строке (отформатирована для удобочитаемости):
.attr("transform", function(d) {
return "translate(" +
( (radius - 12) * Math.sin( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) ) +
", " +
( -1 * (radius - 12) * Math.cos( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) ) +
")";
})
-
((d.endAngle - d.startAngle) / 2) + d.startAngle
дает нам наш угол (тета) в радианах.
-
(radius - 12)
- произвольный радиус, выбранный мной для позиции текста.
-
-1 *
ось y инвертирована (см. ниже).
Используемые триггеры: cos = adjacent / hypotenuse
и sin = opposite / hypotenuse
. Но есть несколько вещей, которые нам нужно рассмотреть, чтобы сделать эти работы с нашими ярлыками.
- 0 угол составляет 12 часов.
- Угол по-прежнему увеличивается по часовой стрелке.
- Ось Y инвертирована из стандартной декартовой системы координат. Положительный y находится в направлении 6 часов - вниз.
- Положительный x по-прежнему находится в направлении 3 часа - справа.
Это немного портит ситуацию и в основном имеет эффект обмена sin
и cos
. Затем наши триггерные функции становятся: sin = adjacent / hypotenuse
и cos = opposite / hypotenuse
.
Подставляя имена переменных, мы имеем sin(radians) = x / r
и cos(radians) = y / r
. После некоторой алгебраической манипуляции мы можем получить обе функции в терминах x и y соответственно r * sin(radians) = x
и r * cos(radians) = y
. Оттуда просто подключите их к атрибуту transform/translate.
Это поместит метки в нужное место, чтобы они выглядели фантастическими, вам нужна логика моделирования следующим образом:
.style("text-anchor", function(d) {
var rads = ((d.endAngle - d.startAngle) / 2) + d.startAngle;
if ( (rads > 7 * Math.PI / 4 && rads < Math.PI / 4) || (rads > 3 * Math.PI / 4 && rads < 5 * Math.PI / 4) ) {
return "middle";
} else if (rads >= Math.PI / 4 && rads <= 3 * Math.PI / 4) {
return "start";
} else if (rads >= 5 * Math.PI / 4 && rads <= 7 * Math.PI / 4) {
return "end";
} else {
return "middle";
}
})
Это сделает метки с 10:30 до 1:30 часов и с 4:30 до 7:30 часов в середине (они выше и ниже), ярлыки с 1:30 до 4:30 часов на якоре слева (они справа), а метки с 7:30 до 10:30 часов справа (они находятся слева).
Те же формулы могут быть использованы для любого радиального графа D3, единственное отличие заключается в том, как вы определяете угол.
Я надеюсь, что это поможет кому-то споткнуться о нем!
Ответ 4
Я не знаю, помогает ли это, но я смог создать дуги, где я размещаю текст, как на дуге, так и вне ее. В одном случае, когда я устанавливаю величины дуги внутри дуг, я поворачиваю текст на дуге в соответствии с углом дуги. В другом месте, где я размещаю текст вне дуги, он просто горизонтальный. Код находится по адресу: http://bl.ocks.org/2295263
Мой лучший,
Франк
Ответ 5
да, детка, SOHCAHTOA
function coordinates_on_circle(hyp, angle){
var radian= angle * Math.PI / 180 //trig uses radians
return {
x: Math.cos(radian) * hyp, //adj = cos(r) * hyp
y: Math.sin(radian) * hyp //opp = sin(r) * hyp
}
}
var radius=100
var angle=45
coordinates_on_circle(radius, angle)
Ответ 6
Следующий CoffeeScript работал у меня, чтобы получить метки еще внутри кусочков пирога, но к внешнему краю:
attr 'transform', (d) ->
radius = width / 2 # radius of whole pie chart
d.innerRadius = radius * 0.5
d.outerRadius = radius * 1.5
'translate(' + arc.centroid(d) + ')'
Ответ 7
Эта функция вычисляет центральную точку среза пирога для круговой диаграммы. Я добавляю функцию для получения центральной точки дуги.
Ниже приведено изображение, основанное на моей новой функции.
обратитесь к ссылке: https://github.com/mbostock/d3/issues/1124
Ответ 8
Это был недорогой ответ, которым я был доволен. Он выталкивает все ярлыки горизонтально (что у меня было дополнительное пространство):
g.append("text")
.attr("transform", function(d) {
var pos = arc.centroid(d);
return "translate(" + (pos[0] + (.5 - (pos[0] < 0)) * radius) + "," + (pos[1]*2) + ")";
})
.attr("dy", ".35em")
.style("text-anchor", function(d) {
return arc.centroid(d)[0] > 0 ? "start" : "end";
})
.text(function(d) { return d.label; });
Ответ 9
Итак, если вы хотите пойти с очень красивой легендой вместо случайного текста, висящего вокруг. Я нашел довольно хорошее решение для ярлыков. как добавить легенду к круговой диаграмме с помощью D3js? И как централизовать круговую диаграмму?
Ответ 10
Я достиг такого же значения путем рисования в виде меток вне графика круговых диаграмм, вот код http://bl.ocks.org/farazshuja/e2cb52828c080ba85da5458e2304a61f
g.append("text")
.attr("transform", function(d) {
var _d = arc.centroid(d);
_d[0] *= 2.2; //multiply by a constant factor
_d[1] *= 2.2; //multiply by a constant factor
return "translate(" + _d + ")";
})
.attr("dy", ".50em")
.style("text-anchor", "middle")
.text(function(d) {
if(d.data.percentage < 8) {
return '';
}
return d.data.percentage + '%';
});