2015-06-04 4 views
2

API для Hull Geom утверждает: «Предполагает, что массив вершин больше трех. Если вершины имеют длину < = 3, возвращает []." (https://github.com/mbostock/d3/wiki/Hull-Geom)D3.js Выпуклый корпус с двумя точками данных

Мне нужно нарисовать выпуклые оболочки вокруг 2 узлов. Я использую макет силы, поэтому выпуклый корпус должен быть динамическим, поскольку он перемещается по узлам, если я нажимаю узел и перетаскиваю его. Мой код в настоящее время основаны от этого примера: http://bl.ocks.org/donaldh/2920551

Для контекста, это то, что я пытаюсь сделать выпуклую оболочку вокруг:

Здесь он работает, когда есть 3 узлов:

3 nodes

Вот что я пытаюсь сделать выпуклую оболочку вокруг (не работает с кодом из примера выше, потому что Халл Geom будет принимать только массивы с вершинами 3 +):

2 Nodes

Я понимаю, что традиционное использование выпуклого корпуса никогда не будет включать только две точки, но я попытался рисовать эллипсы, прямоугольники и т. Д. Вокруг двух узлов, и он не выглядит нигде почти так же хорошо, как 3 узла ,

Я понимаю, что Hull Geom в конечном итоге просто выплевывает строку, которая используется для путей, поэтому я мог бы, вероятно, написать модифицированную версию Hull Geom для двух узлов.

Любые предложения о том, как написать модифицированный Hull Geom для 2 узлов или любой общий совет для решения моей проблемы, действительно оценены.

+0

Вы можете просто нарисовать эллипс, центрированный между двумя узлами, и повернуть его в соответствии с ориентацией. –

ответ

3

В принципе, для достижения желаемого результата вам необходимо по крайней мере одна поддельная точка, очень близкая к линии. Этого можно достичь в функции groupPath.

Для d длины 2 вы можете создать временный массив и прикрепить его к результату функции карты следующим образом:

var groupPath = function(d) { 
    var fakePoints = []; 
    if (d.values.length == 2) 
    { 
     //[dx, dy] is the direction vector of the line 
     var dx = d.values[1].x - d.values[0].x; 
     var dy = d.values[1].y - d.values[0].y; 

     //scale it to something very small 
     dx *= 0.00001; dy *= 0.00001; 

     //orthogonal directions to a 2D vector [dx, dy] are [dy, -dx] and [-dy, dx] 
     //take the midpoint [mx, my] of the line and translate it in both directions 
     var mx = (d.values[0].x + d.values[1].x) * 0.5; 
     var my = (d.values[0].y + d.values[1].y) * 0.5; 
     fakePoints = [ [mx + dy, my - dx], 
       [mx - dy, my + dx]]; 
     //the two additional points will be sufficient for the convex hull algorithm 
    } 

    //do not forget to append the fakePoints to the input data 
    return "M" + 
     d3.geom.hull(d.values.map(function(i) { return [i.x, i.y]; }) 
     .concat(fakePoints)) 
    .join("L") 
    + "Z"; 
} 

Здесь а fiddle с рабочим примером.

1

У Isolin есть отличное решение, но его можно упростить. Вместо того, чтобы делать виртуальную точку на линии в средней точке, достаточно добавить фальшивые точки в основном поверх существующей точки ... компенсировать незаметную сумму. Я адаптировал код Isolin, чтобы обрабатывать случаи групп с 1 или 2 узлами.

var groupPath = function(d) { 
    var fakePoints = []; 
    if (d.length == 1 || d.length == 2) { 
     fakePoints = [ [d[0].x + 0.001, d[0].y - 0.001], 
      [d[0].x - 0.001, d[0].y + 0.001], 
      [d[0].x - 0.001, d[0].y + 0.001]]; }   
    return "M" + d3.geom.hull(d.map(function(i) { return [i.x, i.y]; }) 
     .concat(fakePoints)) //do not forget to append the fakePoints to the group data 
     .join("L") + "Z"; 
}; 
+0

Прекрасно работает.

Смежные вопросы