return function applyEdgeAttraction(edge) {
            var na = edge.source;
            var nb = edge.target;

            vec2.sub(v, na.position, nb.position);
            var d = vec2.len(v);

            var w;
            if (this.edgeWeightInfluence === 0) {
                w = 1;
            } else if (this.edgeWeightInfluence == 1) {
                w = edge.weight;
            } else {
                w = Math.pow(edge.weight, this.edgeWeightInfluence);
            }

            var factor;

            if (this.preventOverlap) {
                d = d - na.size - nb.size;
                if (d <= 0) {
                    // No attraction
                    return;
                }
            }

            var factor = -w * d / this._k;

            vec2.scaleAndAdd(na.force, na.force, v, factor);
            vec2.scaleAndAdd(nb.force, nb.force, v, -factor);
        };
Exemple #2
0
 return function(node) {
     // PENDING Move to centerOfMass or [0, 0] ?
     // vec2.sub(v, this._rootRegion.centerOfMass, node.position);
     // vec2.negate(v, node.position);
     vec2.sub(v, this.center, node.position);
     var d = vec2.len(v);
     vec2.scaleAndAdd(node.force, node.force, v, this.gravity * node.mass / (d + 1));
 }
 return function(node) {
     // PENDING Move to centerOfMass or [0, 0] ?
     // vec2.sub(v, this._rootRegion.centerOfMass, node.position);
     // vec2.negate(v, node.position);
     vec2.sub(v, this.center, node.position);
     if (this.width > this.height) {
         // Stronger gravity on y axis
         v[1] *= this.width / this.height;
     } else {
         // Stronger gravity on x axis
         v[0] *= this.height / this.width;
     }
     var d = vec2.len(v) / 100;
     
     if (this.strongGravity) {
         vec2.scaleAndAdd(node.force, node.force, v, d * this.gravity * node.mass);
     } else {
         vec2.scaleAndAdd(node.force, node.force, v, this.gravity * node.mass / (d + 1));
     }
 };
Exemple #4
0
            return function (pointSet, p0, p1, out) {
                // Limit the max turning angle
                var maxTurningAngleCos = Math.cos(this.maxTurningAngle);
                var maxTurningAngleTan = Math.tan(this.maxTurningAngle);

                vec2.sub(v10, p0, p1);
                vec2.normalize(v10, v10);

                // Simply copy the centroid point if no need to turn the angle
                vec2.copy(out, p0);

                var maxMovement = 0;
                for (var i = 0; i < pointSet.length; i++) {
                    var p = pointSet[i];
                    vec2.sub(vTmp, p, p0);
                    var len = vec2.len(vTmp);
                    vec2.scale(vTmp, vTmp, 1 / len);
                    var turningAngleCos = vec2.dot(vTmp, v10);
                    // Turning angle is to large
                    if (turningAngleCos < maxTurningAngleCos) {
                        // Calculat p's project point on vector p1-p0 
                        // and distance to the vector
                        vec2.scaleAndAdd(
                            project, p0, v10, len * turningAngleCos
                        );
                        var distance = v2Dist(project, p);

                        // Use the max turning angle to calculate the new meet point
                        var d = distance / maxTurningAngleTan;
                        vec2.scaleAndAdd(tmpOut, project, v10, -d);

                        var movement = v2DistSquare(tmpOut, p0);
                        if (movement > maxMovement) {
                            maxMovement = movement;
                            vec2.copy(out, tmpOut);
                        }
                    }
                }
            };
    ForceLayout.prototype.update = function() {

        var nNodes = this.nodes.length;

        this.updateBBox();

        this._k = 0.4 * this.scaling * Math.sqrt(this.width * this.height / nNodes);

        if (this.barnesHutOptimize) {
            this._rootRegion.setBBox(
                this.bbox[0], this.bbox[1],
                this.bbox[2], this.bbox[3]
            );
            this._rootRegion.beforeUpdate();
            for (var i = 0; i < nNodes; i++) {
                this._rootRegion.addNode(this.nodes[i]);
            }
            this._rootRegion.afterUpdate();
        } else {
            // Update center of mass of whole graph
            var mass = 0;
            var centerOfMass = this._rootRegion.centerOfMass;
            vec2.set(centerOfMass, 0, 0);
            for (var i = 0; i < nNodes; i++) {
                var node = this.nodes[i];
                mass += node.mass;
                vec2.scaleAndAdd(centerOfMass, centerOfMass, node.position, node.mass);
            }
            vec2.scale(centerOfMass, centerOfMass, 1 / mass);
        }

        // Reset forces
        for (var i = 0; i < nNodes; i++) {
            var node = this.nodes[i];
            vec2.copy(node.forcePrev, node.force);
            vec2.copy(node.speedPrev, node.speed);
            vec2.set(node.force, 0, 0);
        }

        // Compute forces
        // Repulsion
        for (var i = 0; i < nNodes; i++) {
            var na = this.nodes[i];
            if (this.barnesHutOptimize) {
                this.applyRegionToNodeRepulsion(this._rootRegion, na);
            } else {
                for (var j = i + 1; j < nNodes; j++) {
                    var nb = this.nodes[j];
                    this.applyNodeToNodeRepulsion(na, nb, false);
                }
            }

            // Gravity
            if (this.gravity > 0) {
                this.applyNodeGravity(na);
            }
        }

        // Attraction
        for (var i = 0; i < this.edges.length; i++) {
            this.applyEdgeAttraction(this.edges[i]);
        }

        // Apply forces
        // var speed = vec2.create();
        var v = vec2.create();
        for (var i = 0; i < nNodes; i++) {
            var node = this.nodes[i];
            var speed = node.speed;

            // var swing = vec2.dist(node.force, node.forcePrev);
            // // var swing = 30;
            // vec2.scale(node.force, node.force, 1 / (1 + Math.sqrt(swing)));
            vec2.scale(node.force, node.force, 1 / 30);

            // contraint force
            var df = vec2.len(node.force) + 0.1;
            var scale = Math.min(df, 500.0) / df;
            vec2.scale(node.force, node.force, scale);

            vec2.add(speed, speed, node.force);

            vec2.scale(speed, speed, this.temperature);

            // Prevent swinging
            // Limited the increase of speed up to 100% each step
            // TODO adjust by nodes number
            vec2.sub(v, speed, node.speedPrev);
            var swing = vec2.len(v);
            if (swing > 0) {
                vec2.scale(v, v, 1 / swing);
                var base = vec2.len(node.speedPrev);
                if (base > 0) {
                    swing = Math.min(swing / base, this.maxSpeedIncrease) * base;
                    vec2.scaleAndAdd(speed, node.speedPrev, v, swing);
                }
            }

            // constraint speed
            var ds = vec2.len(speed);
            var scale = Math.min(ds, 100.0) / (ds + 0.1);
            vec2.scale(speed, speed, scale);

            vec2.add(node.position, node.position, speed);
        }
    };
Exemple #6
0
 return function(node) {
     // vec2.negate(v, node.position);
     vec2.sub(v, this.center, node.position);
     var d = vec2.len(v) / 100;
     vec2.scaleAndAdd(node.force, node.force, v, d * this.gravity * node.mass);
 }