cytoscape.js.Для сегмента ребра преобразование координат в расстояния между сегментами и веса сегментов - PullRequest
0 голосов
/ 05 декабря 2018

Я хотел бы поделиться с сообществом полезной функцией, которая возвращает расстояния сегментов и веса сегментов из координаты (PointX, PointY).

Я создаю диаграммы из инструмента (например, draw.io)и при создании ребра (стиль сегмента) с несколькими путевыми точками, бесплатное программное обеспечение предоставляет путевые точки по своим координатам.К сожалению, последняя версия cytoscape.js (в то время, когда я писал этот пост) не включает эту возможность (извиняюсь, если она есть), и используются только расстояния по сегментам и веса по сегментам.

Поэтому я создал следующую функциюкоторый возвращает значения расстояний сегментов и весов сегментов с использованием источника (sX, sY), цели (tX, tY) и его путевой точки (PointX, PointY).Эта функция также может быть использована для нескольких путевых точек.Результат довольно хороший, за исключением того, что линии, появляющиеся ортогонально на бесплатном программном обеспечении (draw.io), не выглядят идеально ортогонально через cytoscape.js.Нужно потренироваться в этом аспекте!

function getDistWeight(sX, sY, tX, tY, PointX, PointY){
    var W, D;

    D = ( PointY - sY + (sX-PointX) * (sY-tY) / (sX-tX) ) /  Math.sqrt( 1 + Math.pow((sY-tY) / (sX-tX), 2) );
    W = Math.sqrt(  Math.pow(PointY-sY,2) + Math.pow(PointX-sX,2) - Math.pow(D,2)  );

    var distAB = Math.sqrt(Math.pow(tX-sX, 2) + Math.pow(tY-sY, 2));
    W = W / distAB;

    //check whether the point (PointX, PointY) is on right or left of the line src to tgt. for instance : a point C(X, Y) and line (AB).  d=(xB-xA)(yC-yA)-(yB-yA)(xC-xA). if d>0, then C is on left of the line. if d<0, it is on right. if d=0, it is on the line.
    var delta1 = (tX-sX)*(PointY-sY)-(tY-sY)*(PointX-sX);
        switch (true) {
          case (delta1 >= 0) :
            delta1 = 1;
            break;
          case (delta1 < 0) :
            delta1 = -1;
            break;
        }
    //check whether the point (PointX, PointY) is "behind" the line src to tgt
    var delta2 = (tX-sX)*(PointX-sX)+(tY-sY)*(PointY-sY);
        switch (true) {
          case (delta2 >= 0) :
            delta2 = 1;
            break;
          case (delta2 < 0) :
            delta2 = -1;
            break;
        }

    D = Math.abs(D) * delta1;   //ensure that sign of D is same as sign of delta1. Hence we need to take absolute value of D and multiply by delta1
    W = W * delta2;

    return {
        ResultDistance: D, 
        ResultWeight: W
    };
}

var point = getDistWeight(10, 5, 25, 15, 9, 6);
console.log(point);

1 Ответ

0 голосов
/ 06 февраля 2019

Я использовал вашу функцию и наконец смог получить ортогональные ребра.Для этого необходимо 2 вещи:

  • Вам необходимо объявить "edge-distance" в стиле вашего ребра как "node-position"
  • Вам нужно вызвать вашу функциюс исходным положением края и целевым положением края, а также с точкой, которую вы хотите, но , выраженной с положением конечных точек края (см. документацию здесь ).

Пример нижесоздаст этот график:

enter image description here

Стиль, добавляемый в конфигурацию Cytoscape:

selector: 'edge',
style: {
    'curve-style': 'segments',
    "segment-weights": '0.5',
    'segment-distances': '0',
    'edge-distances': 'node-position',
    'source-endpoint': '180deg',
    'target-endpoint': '0deg'
}

Код, который будет вычислять перегибточка для каждого ребра:

// batch modifications to avoid rendering during changes
cytoscape.startBatch()

// get all edges from the graph
let edges = cytoscape.edges()
for (let edge of Object.values(edges)) {
    if (edge.data) {
        // get nodes positions for source and target
        let src = edge.source().position()
        let tgt = edge.target().position()
        // get endpoints positions for source and target
        let srcEp = edge.sourceEndpoint()
        let tgtEp = edge.targetEndpoint()

        if (src.x == tgt.x) {
            // do nothing, nodes are aligned vertically
        }
        else {
            // compute weight and distance for the point that will be added to the edge
            // the point will be added aligned horizontally with "source endpoint", and vertically 25px above target endpoint
            let point = getDistWeight(src.x, src.y, tgt.x, tgt.y, srcEp.x, tgtEp.y - 25);
            // set the values
            edge.style('segment-distances', ''+point.ResultDistance)
            edge.style('segment-weights', ''+point.ResultWeight)
        }
    }
}
cytoscape.endBatch()
...