Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7758253
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 1, 20262026-06-01T13:18:40+00:00 2026-06-01T13:18:40+00:00

I’m trying to implement a force base graph layout algorithm, based on http://en.wikipedia.org/wiki/Force-based_algorithms_(graph_drawing )

  • 0

I’m trying to implement a force base graph layout algorithm, based on http://en.wikipedia.org/wiki/Force-based_algorithms_(graph_drawing)

My first attempt didn’t work so I looked at

http://blog.ivank.net/force-based-graph-drawing-in-javascript.html

and

https://github.com/dhotson/springy

I changed my implementation based on what I thought I understood from those two but I haven’t managed to get it right and I’m hoping someone can help? JavaScript isn’t my strong point so be gentle… If you’re wondering why write my own. In reality I have no real reason to write my own I’m just trying to understand how the algorithm is implemented. Especially in my first link, that demo is brilliant.

This is what I’ve come up with

    //support function.bind - https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind#Compatibility
if (!Function.prototype.bind) {
    Function.prototype.bind = function (oThis) {
        if (typeof this !== "function") {
            // closest thing possible to the ECMAScript 5 internal IsCallable function
            throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
        }
        var aArgs = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP = function () {},
        fBound = function () {
            return fToBind.apply(this instanceof fNOP
                ? this
                : oThis || window,
                aArgs.concat(Array.prototype.slice.call(arguments)));
        };
        fNOP.prototype = this.prototype;
        fBound.prototype = new fNOP();
        return fBound;
    };
}
(function() {
    var lastTime = 0;
    var vendors = ['ms', 'moz', 'webkit', 'o'];
    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
        window.cancelAnimationFrame =
        window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
    }
    if (!window.requestAnimationFrame)
        window.requestAnimationFrame = function(callback, element) {
            var currTime = new Date().getTime();
            var timeToCall = Math.max(0, 16 - (currTime - lastTime));
            var id = window.setTimeout(function() {
                callback(currTime + timeToCall);
            },
            timeToCall);
            lastTime = currTime + timeToCall;
            return id;
        };
    if (!window.cancelAnimationFrame)
        window.cancelAnimationFrame = function(id) {
            clearTimeout(id);
        };
}());
function Graph(o){
    this.options=o;
    this.vertices={};
    this.edges={};//form {vertexID:{edgeID:edge}}
}
/**
 *Adds an edge to the graph. If the verticies in this edge are not already in the
 *graph then they are added
 */
Graph.prototype.addEdge=function(e){
    //if vertex1 and vertex2 doesn't exist in this.vertices add them
    if(typeof(this.vertices[e.vertex1])==='undefined')
        this.vertices[e.vertex1]=new Vertex(e.vertex1);
    if(typeof(this.vertices[e.vertex2])==='undefined')
        this.vertices[e.vertex2]=new Vertex(e.vertex2);
    //add the edge
    if(typeof(this.edges[e.vertex1])==='undefined')
        this.edges[e.vertex1]={};
    this.edges[e.vertex1][e.id]=e;
}
/**
 * Add a vertex to the graph. If a vertex with the same ID already exists then
 * the existing vertex's .data property is replaced with the @param v.data
 */
Graph.prototype.addVertex=function(v){
    if(typeof(this.vertices[v.id])==='undefined')
        this.vertices[v.id]=v;
    else
        this.vertices[v.id].data=v.data;
}

function Vertex(id,data){
    this.id=id;
    this.data=data?data:{};
    //initialize to data.[x|y|z] or generate random number for each
    this.x = this.data.x?this.data.x:-100 + Math.random()*200;
    this.y = this.data.y?this.data.y:-100 + Math.random()*200;
    this.z = this.data.y?this.data.y:-100 + Math.random()*200;
    //set initial velocity to 0
    this.velocity = new Point(0, 0, 0);
    this.mass=this.data.mass?this.data.mass:Math.random();
    this.force=new Point(0,0,0);
}
function Edge(vertex1ID,vertex2ID){
    vertex1ID=vertex1ID?vertex1ID:Math.random()
    vertex2ID=vertex2ID?vertex2ID:Math.random()
    this.id=vertex1ID+"->"+vertex2ID;
    this.vertex1=vertex1ID;
    this.vertex2=vertex2ID;
}
function Point(x, y, z)
{
    this.x = x;
    this.y = y;
    this.z = z;
}
Point.prototype.plus=function(p){
    this.x +=p.x
    this.y +=p.y
    this.z +=p.z
}
function ForceLayout(o){
    this.repulsion  = o.repulsion?o.repulsion:200;
    this.attraction = o.attraction?o.attraction:0.06;
    this.damping    = o.damping?o.damping:0.9;
    this.graph          = o.graph?o.graph:new Graph();
    this.total_kinetic_energy =0;
    this.animationID=-1;
}
ForceLayout.prototype.draw=function(){
    //vertex velocities initialized to (0,0,0) when a vertex is created
    //vertex positions initialized to random position when created
  cc=0;  do{
        this.total_kinetic_energy =0;
        //for each vertex
        for(var i in this.graph.vertices){
            var thisNode=this.graph.vertices[i];
            // running sum of total force on this particular node
            var netForce=new Point(0,0,0)
            //for each other node
            for(var j in this.graph.vertices){
                if(thisNode!=this.graph.vertices[j]){
                    //net-force := net-force + Coulomb_repulsion( this_node, other_node )
                    netForce.plus(this.CoulombRepulsion( thisNode,this.graph.vertices[j]))
                }
            }
            //for each spring connected to this node
            for(var k in this.graph.edges[thisNode.id]){
                //(this node, node its connected to)
                //pass id of this node and the node its connected to so hookesattraction
                //can update the force on both vertices and return that force to be
                //added to the net force
                this.HookesAttraction(thisNode.id,
                    this.graph.edges[thisNode.id][k].vertex2
                    )
            }
            // without damping, it moves forever
            //         this_node.velocity := (this_node.velocity + timestep * net-force) * damping
            thisNode.velocity.x=(thisNode.velocity.x+thisNode.force.x)*this.damping;
            thisNode.velocity.y=(thisNode.velocity.y+thisNode.force.y)*this.damping;
            thisNode.velocity.z=(thisNode.velocity.z+thisNode.force.z)*this.damping;
            //this_node.position := this_node.position + timestep * this_node.velocity
            thisNode.x=thisNode.velocity.x;
            thisNode.y=thisNode.velocity.y;
            thisNode.z=thisNode.velocity.z;
            //normalize x,y,z???
            //total_kinetic_energy := total_kinetic_energy + this_node.mass * (this_node.velocity)^2
            this.total_kinetic_energy +=thisNode.mass*((thisNode.velocity.x+thisNode.velocity.y+thisNode.velocity.z)*
            (thisNode.velocity.x+thisNode.velocity.y+thisNode.velocity.z))
        }
        cc+=1;
    }while(this.total_kinetic_energy >0.5)
    console.log(cc,this.total_kinetic_energy,this.graph)
    this.cancelAnimation();
}
ForceLayout.prototype.HookesAttraction=function(v1ID,v2ID){
    var a=this.graph.vertices[v1ID]
    var b=this.graph.vertices[v2ID]
    var force=new Point(this.attraction*(b.x - a.x),this.attraction*(b.y - a.y),this.attraction*(b.z - a.z))
    //  hook's attraction
    a.force.x += force.x;
    a.force.y += force.y;
    a.force.z += force.z;
    b.force.x += this.attraction*(a.x - b.x);
    b.force.y += this.attraction*(a.y - b.y);
    b.force.z += this.attraction*(a.z - b.z);
    return force;
}
ForceLayout.prototype.CoulombRepulsion=function(vertex1,vertex2){
    //http://en.wikipedia.org/wiki/Coulomb's_law
    // distance squared = ((x1-x2)*(x1-x2)) + ((y1-y2)*(y1-y2)) + ((z1-z2)*(z1-z2))
    var distanceSquared =
    (
        (vertex1.x-vertex2.x)*(vertex1.x-vertex2.x)+
        (vertex1.y-vertex2.y)*(vertex1.y-vertex2.y)+
        (vertex1.z-vertex2.z)*(vertex1.z-vertex2.z)
        );
    if(distanceSquared==0) distanceSquared = 0.001;
    var coul = this.repulsion / distanceSquared;
    return new Point(coul * (vertex1.x-vertex2.x),coul * (vertex1.y-vertex2.y), coul * (vertex1.z-vertex2.z));
}
ForceLayout.prototype.animate=function(){
    if(this.animating)
        this.animationID=requestAnimationFrame(this.animate.bind(this));
    this.draw();
}
ForceLayout.prototype.cancelAnimation=function(){
    cancelAnimationFrame(this.animationID);
    this.animating=false;
}
ForceLayout.prototype.redraw=function(){
    this.animating=true;
    this.animate();
}
$(document).ready(function(){
    var g= new Graph();
    for(var i=0;i<=100;i++){
        var v1=new Vertex(Math.random(), {})
        var v2=new Vertex(Math.random(), {})
        var e1= new Edge(v1.id,v2.id);
        g.addEdge(e1);
    }
    console.log(g);
    var l=new ForceLayout({
        graph:g
    });
    l.redraw();
});
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-01T13:18:41+00:00Added an answer on June 1, 2026 at 1:18 pm

    At least one reason this isn’t working is that you are implementing the springs incorrectly. (Hooke’s law)

    Namely, you current have the spring between two points tugging them together all the time. What a spring actually does is it has two parameters, a natural length and a spring constant k. If a spring is stretched, it will pull inwards with a force of (length-naturalLength)*springConstant. If a spring is compresssed, it will push outwards with a force of -(length-naturalLength)*springConstant.

    Printing out the final positions of everything gives you very little debug information. I would highly recommend that if you still have trouble, that you write your display code (which you’ll have to do anyway) now so you can visualize what’s going on. Alternatively you should track the motion of only 2 particles with a spring between them, outputting debug information at every timestep. You should restrict what you print out to only one vector of interest.

    Additionally if you are further running into trouble, you can decrease your timestep.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I am trying to understand how to use SyndicationItem to display feed which is
Basically, what I'm trying to create is a page of div tags, each has
link Im having trouble converting the html entites into html characters, (&# 8217;) i
I have a string like this: La Torre Eiffel paragonata all&#8217;Everest What PHP function
I am trying to render a haml file in a javascript response like so:
I'm parsing an RSS feed that has an &#8217; in it. SimpleXML turns this
Configuring TinyMCE to allow for tags, based on a customer requirement. My config is
I'm trying to decode HTML entries from here NYTimes.com and I cannot figure out
I'm trying to use string.replace('’','') to replace the dreaded weird single-quote character: ’ (aka
I'm trying to create an if statement in PHP that prevents a single post

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.