Mutual repulsion force in js

Viewed 66

I have a 1-dimensional dataset (a list of elements with only a horizontal position (+ circle radius)).

I want to implement a simple layout algorithm to show this dataset as circles in a scale. The problem is the collisions.

enter image description here

I want to implement a "simple" repulsion force to avoid collisions. I don't mind the circles won't have a precise position anymore. The result I'm looking for is simple as that:

enter image description here

I'm not using D3, it is plain js (and svg.js), where to start looking for theoretical information about this layout? What is the common name with which this force is referred to? Is there any example of similar things?

1 Answers

I've added min_gap for minimum margin between elements. So the solution is to move two intersected elements with most intersected distance on a small step at a time.

const elements = [{pos:10, radius:5}, {pos:15, radius: 20}, {pos:20, radius:10}, {pos:150, radius:5}];

const field_size = [0, 300];

const min_gap = 5;
const step = 1;

moveIntersected(elements);

console.log(elements);

function detectCollisions(arr=[]){
    const result = [];
    for(let i=0; i < arr.length - 1; i++){
        let dist = (arr[i+1].pos - arr[i+1].radius) - (arr[i].pos + arr[i].radius);
        if(dist < min_gap){
            result.push([i + 0.5, dist]);
        }
    }
    return result;
}

function moveIntersected(arr=[]){

    const collisions = detectCollisions(arr);
    if(collisions.length < 1) return;
    
    const most_intersected = collisions.sort((a,b) => a[1] - b[1])[0];
    const left = arr[Math.floor(most_intersected[0])];
    const right = arr[Math.ceil(most_intersected[0])];
    
    if(left.pos - left.radius - step >= field_size[0]){
        left.pos -= step;
    } else {
        right.pos += step*2;
    }
    
    if(right.pos + right.radius + step <= field_size[1]){
        right.pos += step;
    } else {
        left.pos -= step*2;
    }
    moveIntersected(arr);
}

Related