Аккорд d3: текст по центру

Я использую пример диаграммы аккордов d3 Эндрю и хочу центрировать все текстовые метки внутри изогнутого среза. Я перепробовал много вещей, но так и не смог центрировать тексты. Знаете ли вы, какой там трюк Wizzard нужен?

var width = 720,
height = 720,
outerRadius = Math.min(width, height) / 2 - 10,
innerRadius = outerRadius - 24;

var formatPercent = d3.format(".1%");

var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);

var layout = d3.layout.chord()
.padding(.04)
.sortSubgroups(d3.descending)
.sortChords(d3.ascending);

var path = d3.svg.chord()
.radius(innerRadius);

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

svg.append("circle")
.attr("r", outerRadius);

d3.csv("ex_csv.csv", function(cities) {
d3.json("ex_json.json", function(matrix) {

// Compute the chord layout.
layout.matrix(matrix);

// Add a group per neighborhood.
var group = svg.selectAll(".group")
.data(layout.groups)
.enter().append("g")
.attr("class", "group")
.on("mouseover", mouseover);


// Add the group arc.
var groupPath = group.append("path")
.attr("id", function(d, i) { return "group" + i; })
.attr("d", arc)
.style("fill", function(d, i) { return cities[i].color; });

// Add a text label.
var groupText = group.append("text")
.attr("x", 6)
.attr("dy", 15);

groupText.append("textPath")
.attr("xlink:href", function(d, i) { return "#group" + i; })
.text(function(d, i) { return cities[i].name; });

// Remove the labels that don't fit. :(
groupText.filter(function(d, i) { return groupPath[0][i].getTotalLength() / 2 - 16 < this.getComputedTextLength(); })
.remove();

// Add the chords.
var chord = svg.selectAll(".chord")
.data(layout.chords)
.enter().append("path")
.attr("class", "chord")
.style("fill", function(d) { return cities[d.source.index].color; })
.attr("d", path);


}
});
});

</script>

2 ответа

Решение

Кроме того, я хотел бы предложить перейти на v4, документация для v2 практически отсутствует и с ней очень трудно справиться.

Вы можете установить как text-anchor и startOffset свойство для достижения того, что вы ищете.

Во-первых, вы хотите установить text-anchor в middle поскольку легче указать среднюю точку, чем найти среднюю точку и вернуться к поиску места, где должен начинаться текст.

Во-вторых, вам нужно установить startOffset, Обратите внимание, что если вы используете 50%, текст не будет отображаться там, где вы хотите, так как общая длина пути для текста равна всем сторонам замкнутого цикла (якорной якоря), к которому вы добавляете. Установка его на 25 % будет работать, если у вас не будет другого внешнего и внутреннего радиуса. Но, поскольку у вас есть внешний радиус, который на 24 пикселя больше внутреннего радиуса, вы можете попробовать что-то вроде этого, чтобы вычислить количество пикселей, которое вам нужно, чтобы сместить центр текста:

groupText.append("textPath")
.attr("xlink:href", function(d, i) { return "#group" + i; })
.text(function(d, i) { return cities[i].name; })
.attr("startOffset",function(d,i) { return (groupPath[0][i].getTotalLength() - 48) / 4 })
.style("text-anchor","middle");

Я вычитаю 48, потому что стороны якоря имеют 24 пикселя каждая (разница в радиусах). Я делю на четыре, потому что путь удваивается сам по себе. Если бы это была общая линия, я бы просто разделил на два.

Этот подход немного упрощен, поскольку внешняя окружность не совпадает с внутренней окружностью каждого аккордового якоря, поэтому я немного отклонился, но он должен быть работоспособным.

Для надписей, которые находятся на острие отображения, это будет неудобно: внутренний радиус короче, поэтому формула для определения, является ли строка достаточно короткой для отображения, может быть неправильной - что может привести к тому, что некоторые символы будут подниматься вверх якоря (ваш пример также 16 пикселей как разница в радиусах для расчета, если текст слишком длинный, а не 24).

Это конечный результат:

Вот демонстрация.

      groupText
  .append("textPath")
  .attr("xlink:href", function(d, i) { return "#group" + i; })
  .text(function(d, i) { return cities[i].name; })
  .attr("startOffset",function(d,i) { return (groupPath[0][i].getTotalLength() - 48) / 4 })
  .style("text-anchor","middle");

Я вычитаю 48, потому что стороны якоря по 24 пикселя (разница в радиусах). Я делю на четыре, потому что путь возвращается сам к себе. Если бы это была общая линия, я бы просто разделил ее на два.

Этот подход немного упрощен, поскольку внешняя окружность не совпадает с внутренней окружностью каждого анкера хорды, поэтому я немного отклоняюсь, но это должно быть работоспособно.

Другие вопросы по тегам