Специально для круговых диаграмм функция d3.layout.pie()
будет форматировать данные с атрибутами startAngle
и endAngle
. Радиус может быть любым по вашему желанию (как далеко от центра вы хотите разместить метку).
Объединение этих фрагментов информации с парой тригонометрических функций позволяет определять координаты x и y для меток.
Рассмотрим это Суть / Блок .
Относительно расположения текста по 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 инвертирована из стандартной декартовой системы координат. Положительный у в направлении 6 часов - вниз.
- Положительный х по-прежнему в направлении 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, единственное отличие состоит в том, как вы определяете угол.
Надеюсь, это поможет кому-нибудь наткнуться на него!