Home > Net >  Mutual repulsion force in js
Mutual repulsion force in js

Time:11-04

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?

CodePudding user response:

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);
}
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related