dash14 / v-network-graph

An interactive network graph visualization component for Vue 3

Home Page:https://dash14.github.io/v-network-graph/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to avoid edge labels overlapping/obstructed by other nodes/edges?

bradleybernard opened this issue · comments

Hey there,

First off I just wanted to say: this library is amazing!! The docs are incredible, the real time reactive demos make life so much easier, thank you for making it a high quality library with extremely detailed docs!


How can I smartly layout my nodes such that there are no overlapping edge labels?

I know this library does not focus on the layout piece, but I'm curious if you have any suggestions or other good libs to recommend to achieve such an effect!

My use case is:
I have a graph where nodes = users and edges = payments. Each edge is labeled with the $$ amount in the center type. I layout my graph with positive balances on top, and negative balances on bottom, meaning all arrows point from bottom to top!

The lib works wonderfully for a simple graph, but when I have 8 edges and I lay them out like so:

  1. Positive users in first row
  2. Negative users in second row

This is what it looks like with no edges obstructed:
CleanShot 2023-12-12 at 14 41 03

Due to my own layout code, the bottom middle node sits right on top of an edge between the bottom left and bottom right node, since the edge label is placed in the center, so you can't see it and you don't even know it's there until you drag around the nodes to reveal it.

This is what it looks like when the bottom edge is obstructed between the bottom left and bottom right node:
CleanShot 2023-12-12 at 14 41 55

I could alternate the Y axis for each column in a row, but it wouldn't solve it all, if two of the nodes are connected and both are upper or lower, if that makes sense. Any good ideas here? Any help would be greatly appreciated!

My layout code:

const nodeCoordinates: Record<string, { x: number; y: number }> = {};

    const partitionedNodes = partition(Object.entries(nodes.value), ([nodeId, node]) => {
        return node.net_balance > 0;
    });

    const positiveNodes = partitionedNodes[0];
    const negativeNodes = partitionedNodes[1];

    // Sort the positive and negative nodes by net balance
    positiveNodes.sort((a, b) => {
        return b[1].net_balance - a[1].net_balance;
    });

    negativeNodes.sort((a, b) => {
        return a[1].net_balance - b[1].net_balance;
    });

    // Calculate the number of rows and columns we need
    const positiveRows = 1;
    const negativeRows = 1;

    const positiveColumns = Math.ceil(positiveNodes.length / positiveRows);
    const negativeColumns = Math.ceil(negativeNodes.length / negativeRows);

    // Calculate the X and Y coordinates of each node
    positiveNodes.forEach(([nodeId, node], index) => {
        const row = Math.floor(index / positiveColumns);
        const column = index % positiveColumns;

        const x = column * nodeSize * 2 + index * nodeSize;
        const y = row * nodeSize * 2;

        nodeCoordinates[nodeId] = { x, y };
    });

    negativeNodes.forEach(([nodeId, node], index) => {
        const row = Math.floor(index / negativeColumns);
        const column = index % negativeColumns;

        const x = column * nodeSize * 2 + index * nodeSize;
        const y = (row + positiveRows) * nodeSize * 2;

        nodeCoordinates[nodeId] = { x, y };
    });

    // layouts.nodes[nodeId] = { x, y };
    Object.entries(nodeCoordinates).forEach(([nodeId, coordinates]) => {
        layouts.nodes[nodeId] = coordinates;
    });

Hi @bradleybernard,
I apologize for the delay in replying.

I know this library does not focus on the layout piece, but I'm curious if you have any suggestions or other good libs to recommend to achieve such an effect!

Yes, this library is not focused on layout functionality, so it seems difficult to solve this problem using only v-network-graph.

To address this, I came up with the following, which probably does not fit your application requirements....

  • Use force layout or circle layout (coordinates are calculated so that nodes are placed in a circle) because simple rectangular layout increases the possibility of overlapping edges.
  • Display edge labels on the source side of the edge instead of in the center of the edge.

Sorry I don't know about helpful libraries.
I apologize for not being able to help you.