d3.svg.line.radial
функция создает серию кубических кривых Безье (не дуги) между несколькими точками в массиве на основе входных полярных координат (радиус и угол) для каждой точки.
(Пример, связанный с , появляется, чтобы нарисовать круг, но только потому, что он разбивает круг на многие плотно разнесенные точки - попробуйте использовать 5 очков вместо 50, и вы увидите, что форма кривая не является реальным кругом.)
Функция d3.svg.arc
выполняет функцию, состоящую из двух концентрических дуг и их прямых линий, основанных на значениях для внутренних Radius, внешних Radius, startAngle и endAngle.
Оба метода определяют углы в радианах, начиная с «12 часов» (вертикально вверх). Однако есть пара трудностей в том, что функция радиальной линии работает с объектами данных дуги.
Первая проблема заключается в том, что генератор линий ожидает передачи массива из нескольких точек, а не из одного объекта. Чтобы обойти это, вам нужно установить привязку элемента пути как массив объекта группы дуги, который повторяется дважды, один раз для начала и один раз для конца дуги, а затем использовать функцию в i
, чтобы определить, следует ли использовать startAngle или endAngle для значения угла каждой точки.
Вот вариант вашей скрипки, создающей эти пути. Я не потрудился получать текст бежать по дорожке, я просто рисунок пути в черном:
http://jsfiddle.net/MX7JC/688/
Теперь вы видите, вторая проблема: если только даны две точки, генератор линия будет просто создать прямая линия между ними.
См простой пример кривой: http://jsfiddle.net/4VnHn/5/
Для того, чтобы получить любой вид кривой с генераторами на линии по умолчанию, вам необходимо добавить дополнительные точки, чтобы действовать в качестве контрольных точек, и изменить the line interpolate method to an "open" option таким образом, чтобы конечный контрольные точки Арен Нарисовано.Я обнаружил, что создание контрольных точек начала и конца на 45 градусов выше начальной и конечной точек кривой (вокруг круга) создало кривую, которая была приемлемо подобна дуге в моем простом примере.
Смотрите лучше простой пример кривой: http://jsfiddle.net/4VnHn/6/
Для вашей визуализации, кривые генератор теперь должен быть передан объект данных повторяется четыре раза в массиве, а угол сбруя теперь будет нужен переключатель чтобы определить разные точки: http://jsfiddle.net/MX7JC/689/
Результаты приемлемы для небольших сегментов пончиков, но не для тех, которые более 45 градусов сами по себе - в этих случаях контрольные точки до сих пор находятся вокруг вокруг круга, что они полностью отбрасывают кривую. Генератор кривой ничего не знает о круге, он просто пытается плавно подключить точки, чтобы показать тренд от одного к другому.
Лучшее решение для фактически нарисовать дугу, используя arc notation for SVG paths. Генератор дуги использует нотацию дуги, но создает полную двумерную форму. Чтобы создать дуги с генератором строк, вам понадобится специальная функция интерполяции строк, которую вы затем можете передать методу interpolate
генератора линии.
Генератор линии выполнит функцию пользовательского интерполятора линии, передав в массив точек, которые уже были преобразованы из полярных координат в координаты x, y. Оттуда вам нужно определить уравнение дуги. Так как функция дуги также необходимо знать радиус дуги, я использую вложенную функцию - внешняя функция принимает радиус в качестве параметра и возвращает функцию, которая будет принимать массив точек в качестве параметра:
function arcInterpolator(r) {
//creates a line interpolator function
//which will draw an arc of radius `r`
//between successive polar coordinate points on the line
return function(points) {
//the function must return a path definition string
//that can be appended after a "M" command
var allCommands = [];
var startAngle; //save the angle of the previous point
//in order to allow comparisons to determine
//if this is large arc or not, clockwise or not
points.forEach(function(point, i) {
//the points passed in by the line generator
//will be two-element arrays of the form [x,y]
//we also need to know the angle:
var angle = Math.atan2(point[0], point[1]);
//console.log("from", startAngle, "to", angle);
var command;
if (i) command = ["A", //draw an arc from the previous point to this point
r, //x-radius
r, //y-radius (same as x-radius for a circular arc)
0, //angle of ellipse (not relevant for circular arc)
+(Math.abs(angle - startAngle) > Math.PI),
//large arc flag,
//1 if the angle change is greater than 180degrees
// (pi radians),
//0 otherwise
+(angle < startAngle), //sweep flag, draws the arc clockwise
point[0], //x-coordinate of new point
point[1] //y-coordinate of new point
];
else command = point; //i = 0, first point of curve
startAngle = angle;
allCommands.push(command.join(" "));
//convert to a string and add to the command list
});
return allCommands.join(" ");
};
}
Пример: http://jsfiddle.net/4VnHn/8/
Чтобы заставить его работать с вашим графиком пончика, я начал с версии выше, которая создавала прямые линии, и изменила параметр интерполяции линейного генератора, чтобы использовать мою пользовательскую функцию. Единственное дополнительное изменение, которое я должен был сделать, это добавить дополнительную проверку, чтобы убедиться, что ни один из углов на графике не закончился более чем на 360 градусов (что, я уверен, было проблемой округления на последнем сегменте дуги, но вызывало моя функция, чтобы нарисовать окончательную дугу всего пути по кругу, назад):
var curveFunction = d3.svg.line.radial()
.interpolate(arcInterpolator(r-45))
.tension(0)
.radius(r-45)
.angle(function(d, i) {
return Math.min(
i? d.endAngle : d.startAngle,
Math.PI*2
);
//if i is 1 (true), this is the end of the curve,
//if i is 0 (false), this is the start of the curve
});
Живой пример: http://jsfiddle.net/MX7JC/690/
Наконец, чтобы использовать эти кривые траекторий текста:
- Установит кривая не должна иметь никакого штриха и не заполнять;
- дают каждой кривой уникальное значение Идентификатор на основе ваших категорий данных
(для примера, вы можете использовать метку пончика плюс подпись данных, чтобы придумать что-то вроде «textcurve-Agg-Intl»);
- Добавить
<textPath>
element для каждой маркировки; - набор текста пути
xlink:href
атрибут быть #
плюс к тому же уникальное значение идентификатора для этих данных