Beispiel #1
0
        function _updateLinkShapes() {
            var v = vec2.create();
            var right = vec2.create(1, 0);
            for (var i = 0, len = filteredLinks.length; i < len; i++) {
                var link = filteredLinks[i];
                var linkShape = linkShapes[i];
                var sourceShape = nodeShapes[link.source];
                var targetShape = nodeShapes[link.target];

                linkShape.style.xStart = sourceShape.position[0];
                linkShape.style.yStart = sourceShape.position[1];
                linkShape.style.xEnd = targetShape.position[0];
                linkShape.style.yEnd = targetShape.position[1];

                if (forceSerie.linkSymbol) {
                    var arrowShape = arrowShapes[i];
                    vec2.copy(arrowShape.position, targetShape.position);

                    vec2.sub(v, sourceShape.position, targetShape.position);
                    vec2.normalize(v, v);

                    vec2.scaleAndAdd(
                        arrowShape.position, arrowShape.position, v, targetShape.style.r + 2
                    );

                    if (v[1] < 0) {
                        var angle = 2 * Math.PI - Math.acos(-v[0]);
                    } else {
                        var angle = Math.acos(-v[0]);
                    }
                    arrowShape.rotation = angle  - Math.PI / 2;
                }
            }
        }
Beispiel #2
0
        _updateLinkShapes: function() {
            var v = vec2.create();
            var n = vec2.create();
            var p1 = vec2.create();
            var p2 = vec2.create();
            var edges = this._graph.edges;
            for (var i = 0, len = edges.length; i < len; i++) {
                var edge = edges[i];
                var sourceShape = edge.node1.shape;
                var targetShape = edge.node2.shape;

                vec2.copy(p1, sourceShape.position);
                vec2.copy(p2, targetShape.position);

                var edgeShapeStyle = edge.shape.style;

                vec2.sub(v, p1, p2);
                vec2.normalize(v, v);

                if (edgeShapeStyle.offset) {
                    n[0] = v[1];
                    n[1] = - v[0];

                    vec2.scaleAndAdd(p1, p1, n, edgeShapeStyle.offset);
                    vec2.scaleAndAdd(p2, p2, n, edgeShapeStyle.offset);
                }
                else if (edge.shape.type === 'bezier-curve') {
                    edgeShapeStyle.cpX1 = (p1[0] + p2[0]) / 2 - (p2[1] - p1[1]) / 4;
                    edgeShapeStyle.cpY1 = (p1[1] + p2[1]) / 2 - (p1[0] - p2[0]) / 4;
                }

                edgeShapeStyle.xStart = p1[0];
                edgeShapeStyle.yStart = p1[1];
                edgeShapeStyle.xEnd = p2[0];
                edgeShapeStyle.yEnd = p2[1];

                edge.shape.modSelf();

                if (edge.shape._symbolShape) {
                    var symbolShape = edge.shape._symbolShape;
                    vec2.copy(symbolShape.position, p2);
                    vec2.scaleAndAdd(
                        symbolShape.position, symbolShape.position,
                        v, targetShape.style.width / 2 + 2
                    );

                    var angle = Math.atan2(v[1], v[0]);
                    symbolShape.rotation = Math.PI / 2 - angle;

                    symbolShape.modSelf();
                }
            }
        },
Beispiel #3
0
 _syncNodePositions: function () {
     var graph = this._graph;
     for (var i = 0; i < graph.nodes.length; i++) {
         var gNode = graph.nodes[i];
         var position = gNode.layout.position;
         var node = gNode.data;
         var shape = gNode.shape;
         var fixX = shape.fixed || node.fixX;
         var fixY = shape.fixed || node.fixY;
         if (fixX === true) {
             fixX = 1;
         } else if (isNaN(fixX)) {
             fixX = 0;
         }
         if (fixY === true) {
             fixY = 1;
         } else if (isNaN(fixY)) {
             fixY = 0;
         }
         shape.position[0] += (position[0] - shape.position[0]) * (1 - fixX);
         shape.position[1] += (position[1] - shape.position[1]) * (1 - fixY);
         vec2.copy(position, shape.position);
         var nodeName = node.name;
         if (nodeName) {
             var gPos = this.__nodePositionMap[nodeName];
             if (!gPos) {
                 gPos = this.__nodePositionMap[nodeName] = vec2.create();
             }
             vec2.copy(gPos, position);
         }
         shape.modSelf();
     }
 },
Beispiel #4
0
 TreeLayout.prototype._updateNodeXPosition = function (node) {
     var minX = Infinity;
     var maxX = -Infinity;
     node.layout.position = node.layout.position || vec2.create();
     for (var i = 0; i < node.children.length; i++) {
         var child = node.children[i];
         this._updateNodeXPosition(child);
         var x = child.layout.position[0];
         if (x < minX) {
             minX = x;
         }
         if (x > maxX) {
             maxX = x;
         }
     }
     if (node.children.length > 0) {
         node.layout.position[0] = (minX + maxX) / 2;
     } else {
         node.layout.position[0] = 0;
     }
     var off = this._layerOffsets[node.depth] || 0;
     if (off > node.layout.position[0]) {
         var shift = off - node.layout.position[0];
         this._shiftSubtree(node, shift);
         for (var i = node.depth + 1; i < node.height + node.depth; i++) {
             this._layerOffsets[i] += shift;
         }
     }
     this._layerOffsets[node.depth] = node.layout.position[0] + node.layout.width + this.nodePadding;
     this._layers[node.depth].push(node);
 };
Beispiel #5
0
        _update: function(e) {

            this._layout.temperature = this._temperature;
            this._layout.update();

            for (var i = 0; i < this._layout.nodes.length; i++) {
                var position = this._layout.nodes[i].position;
                var shape = this._nodeShapes[i];
                var node = this._filteredNodes[i];
                if (shape.fixed || (node.fixX && node.fixY)) {
                    vec2.copy(position, shape.position);
                } else if (node.fixX) {
                    position[0] = shape.position[0];
                    shape.position[1] = position[1];
                } else if (node.fixY) {
                    position[1] = shape.position[1];
                    shape.position[0] = position[0];
                } else  {
                    vec2.copy(shape.position, position);
                }

                var nodeName = node.name;
                if (nodeName) {
                    var gPos = this.__nodePositionMap[nodeName];
                    if (!gPos) {
                        gPos = this.__nodePositionMap[nodeName] = vec2.create();
                    }
                    vec2.copy(gPos, position);
                }
            }

            this._temperature *= this._coolDown;
        },
Beispiel #6
0
        _syncNodePositions: function() {
            var graph = this._graph;
            for (var i = 0; i < graph.nodes.length; i++) {
                var gNode = graph.nodes[i];
                var position = gNode.layout.position;
                var node = gNode.data;
                var shape = gNode.shape;
                if (shape.fixed || (node.fixX && node.fixY)) {
                    vec2.copy(position, shape.position);
                }
                else if (node.fixX) {
                    position[0] = shape.position[0];
                    shape.position[1] = position[1];
                }
                else if (node.fixY) {
                    position[1] = shape.position[1];
                    shape.position[0] = position[0];
                }
                else  {
                    vec2.copy(shape.position, position);
                }

                var nodeName = node.name;
                if (nodeName) {
                    var gPos = this.__nodePositionMap[nodeName];
                    if (!gPos) {
                        gPos = this.__nodePositionMap[nodeName] = vec2.create();
                    }
                    vec2.copy(gPos, position);
                }

                this.zr.modShape(shape.id);
            }
        },
    /****************************
     * Class: ForceLayout
     ***************************/
    function ForceLayout() {

        this.barnesHutOptimize = false;
        this.barnesHutTheta = 1.5;

        this.repulsionByDegree = false;

        this.preventOverlap = false;
        this.strongGravity = true;

        this.gravity = 1.0;
        this.scaling = 1.0;

        this.edgeWeightInfluence = 1.0;

        this.center = [0, 0];
        this.width = 500;
        this.height = 500;

        this.maxSpeedIncrease = 1.0;

        this.nodes = [];
        this.edges = [];

        this.bbox = new ArrayCtor(4);

        this._rootRegion = new Region();
        this._rootRegion.centerOfMass = vec2.create();

        this._massArr = null;

        this._k = 0;
    }
Beispiel #8
0
        _updateWorker: function(e) {
            if (!this._updating) {
                return;
            }

            var positionArr = new Float32Array(e.data);
            var token = positionArr[0];
            var ret = token === this._token;
            // If token is from current layout instance
            if (ret) {
                var nNodes = (positionArr.length - 1) / 2;

                for (var i = 0; i < nNodes; i++) {
                    var shape = this._nodeShapes[i];
                    var node = this._filteredNodes[i];
                    
                    var x = positionArr[i * 2 + 1];
                    var y = positionArr[i * 2 + 2];

                    if (shape.fixed || (node.fixX && node.fixY)) {
                        positionArr[i * 2 + 1] = shape.position[0];
                        positionArr[i * 2 + 2] = shape.position[1];
                    } else if (node.fixX) {
                        positionArr[i * 2 + 1] = shape.position[0];
                        shape.position[1] = y;
                    } else if (node.fixY) {
                        positionArr[i * 2 + 2] = shape.position[1];
                        shape.position[0] = x;
                    } else  {
                        shape.position[0] = x;
                        shape.position[1] = y;
                    }

                    var nodeName = node.name;
                    if (nodeName) {
                        var gPos = this.__nodePositionMap[nodeName];
                        if (!gPos) {
                            gPos = this.__nodePositionMap[nodeName] = vec2.create();
                        }
                        vec2.copy(gPos, shape.position);
                    }
                }

                this._layoutWorker.postMessage(positionArr.buffer, [positionArr.buffer]);
            }

            var self = this;
            self._layoutWorker.postMessage({
                cmd: 'update',
                steps: this._steps,
                temperature: this._temperature,
                coolDown: this._coolDown
            });  

            for (var i = 0; i < this._steps; i++) {
                this._temperature *= this._coolDown;
            }

            return ret;
        },
    ForceLayout.prototype.applyEdgeAttraction = (function() {
        var v = vec2.create();
        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);
        };
    })();
    /****************************
     * Class: Graph Node
     ***************************/
    function GraphNode() {
        this.position = vec2.create();

        this.force = vec2.create();
        this.forcePrev = vec2.create();

        this.speed = vec2.create();
        this.speedPrev = vec2.create();

        // If repulsionByDegree is true
        //  mass = inDegree + outDegree + 1
        // Else
        //  mass is manually set
        this.mass = 1;

        this.inDegree = 0;
        this.outDegree = 0;
    }
Beispiel #11
0
 ForceLayout.prototype.applyNodeStrongGravity = (function() {
     var v = vec2.create();
     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);
     }
 })();
Beispiel #12
0
        _syncNodePositions: function() {
            var graph = this._graph;
            // var delta = 0;
            for (var i = 0; i < graph.nodes.length; i++) {
                var gNode = graph.nodes[i];
                var position = gNode.layout.position;
                var node = gNode.data;
                var shape = gNode.shape;
                // delta += vec2.len(shape.position, position);
                if (shape.fixed || (node.fixX && node.fixY)) {
                    vec2.copy(position, shape.position);
                }
                else if (node.fixX) {
                    position[0] = shape.position[0];
                    shape.position[1] = position[1];
                }
                else if (node.fixY) {
                    position[1] = shape.position[1];
                    shape.position[0] = position[0];
                }
                else if (isNaN(node.fixX - 0) == false && isNaN(node.fixY - 0) == false) {
                    shape.position[0] += (position[0] - shape.position[0]) * node.fixX;
                    position[0] = shape.position[0];
                    shape.position[1] += (position[1] - shape.position[1]) * node.fixY;
                    position[1] = shape.position[1];
                }
                else if (isNaN(node.fixX - 0) == false) {
                    shape.position[0] += (position[0] - shape.position[0]) * node.fixX;
                    position[0] = shape.position[0];
                    shape.position[1] = position[1];
                }
                else if (isNaN(node.fixY - 0) == false) {
                    shape.position[1] += (position[1] - shape.position[1]) * node.fixY;
                    position[1] = shape.position[1];
                    shape.position[0] = position[0];
                }
                else  {
                    vec2.copy(shape.position, position);
                }

                var nodeName = node.name;
                if (nodeName) {
                    var gPos = this.__nodePositionMap[nodeName];
                    if (!gPos) {
                        gPos = this.__nodePositionMap[nodeName] = vec2.create();
                    }
                    vec2.copy(gPos, position);
                }

                shape.modSelf();
            }
            // if (delta < 1) {  // All shape stopped moving
                // this._layout.temperature = 0;
            // }
        },
Beispiel #13
0
 ForceLayout.prototype.applyNodeGravity = (function() {
     var v = vec2.create();
     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));
     }
 })();
 Region.prototype._updateCenterOfMass = function(node) {
     // Incrementally update
     if (this.centerOfMass == null) {
         this.centerOfMass = vec2.create();
     }
     var x = this.centerOfMass[0] * this.mass;
     var y = this.centerOfMass[1] * this.mass;
     x += node.position[0] * node.mass;
     y += node.position[1] * node.mass;
     this.mass += node.mass;
     this.centerOfMass[0] = x / this.mass;
     this.centerOfMass[1] = y / this.mass;
 };
 ForceLayout.prototype.applyRegionToNodeRepulsion = (function() {
     var v = vec2.create();
     return function applyRegionToNodeRepulsion(region, node) {
         if (region.node) { // Region is a leaf 
             this.applyNodeToNodeRepulsion(region.node, node, true);
         } else {
             vec2.sub(v, node.position, region.centerOfMass);
             var d2 = v[0] * v[0] + v[1] * v[1];
             if (d2 > this.barnesHutTheta * region.size * region.size) {
                 var factor = this._k * this._k * (node.mass + region.mass) / (d2 + 1);
                 vec2.scaleAndAdd(node.force, node.force, v, factor * 2);
             } else {
                 for (var i = 0; i < region.nSubRegions; i++) {
                     this.applyRegionToNodeRepulsion(region.subRegions[i], node);
                 }
             }
         }
     };
 })();
Beispiel #16
0
        _updateLinkShapes: function() {
            var v = vec2.create();
            var links = this._filteredLinks;
            for (var i = 0, len = links.length; i < len; i++) {
                var link = links[i];
                var linkShape = this._linkShapes[i];
                var sourceShape = this._nodeShapes[link.source];
                var targetShape = this._nodeShapes[link.target];

                linkShape.style.xStart = sourceShape.position[0];
                linkShape.style.yStart = sourceShape.position[1];
                linkShape.style.xEnd = targetShape.position[0];
                linkShape.style.yEnd = targetShape.position[1];

                this.zr.modShape(linkShape.id);

                if (linkShape._symbolShape) {
                    var symbolShape = linkShape._symbolShape;
                    vec2.copy(symbolShape.position, targetShape.position);

                    vec2.sub(v, sourceShape.position, targetShape.position);
                    vec2.normalize(v, v);

                    vec2.scaleAndAdd(
                        symbolShape.position, symbolShape.position,
                        v, targetShape.style.width / 2 + 2
                    );

                    var angle;
                    if (v[1] < 0) {
                        angle = 2 * Math.PI - Math.acos(-v[0]);
                    } else {
                        angle = Math.acos(-v[0]);
                    }
                    symbolShape.rotation = angle  - Math.PI / 2;

                    this.zr.modShape(symbolShape.id);
                }
            }
        },
Beispiel #17
0
        _updateLinkShapes: function() {
            var v = vec2.create();
            var edges = this._graph.edges;
            for (var i = 0, len = edges.length; i < len; i++) {
                var edge = edges[i];
                var sourceShape = edge.node1.shape;
                var targetShape = edge.node2.shape;

                edge.shape.style.xStart = sourceShape.position[0];
                edge.shape.style.yStart = sourceShape.position[1];
                edge.shape.style.xEnd = targetShape.position[0];
                edge.shape.style.yEnd = targetShape.position[1];

                this.zr.modShape(edge.shape.id);

                if (edge.shape._symbolShape) {
                    var symbolShape = edge.shape._symbolShape;
                    vec2.copy(symbolShape.position, targetShape.position);

                    vec2.sub(v, sourceShape.position, targetShape.position);
                    vec2.normalize(v, v);

                    vec2.scaleAndAdd(
                        symbolShape.position, symbolShape.position,
                        v, targetShape.style.width / 2 + 2
                    );

                    var angle;
                    if (v[1] < 0) {
                        angle = 2 * Math.PI - Math.acos(-v[0]);
                    }
                    else {
                        angle = Math.acos(-v[0]);
                    }
                    symbolShape.rotation = angle - Math.PI / 2;

                    this.zr.modShape(symbolShape.id);
                }
            }
        },
    ForceLayout.prototype.applyNodeToNodeRepulsion = (function() {
        var v = vec2.create();
        return function applyNodeToNodeRepulsion(na, nb, oneWay) {
            if (na == nb) {
                return;
            }
            vec2.sub(v, na.position, nb.position);
            var d2 = v[0] * v[0] + v[1] * v[1];

            // PENDING
            if (d2 === 0) {
                return;
            }

            var factor;
            var k2 = this._k * this._k;
            var mass = na.mass + nb.mass;

            if (this.preventOverlap) {
                var d = Math.sqrt(d2);
                d = d - na.size - nb.size;
                if (d > 0) {
                    factor = k2 * mass / (d * d);
                } else if (d <= 0) {
                    // A stronger repulsion if overlap
                    factor = k2 * 10 * mass;
                }
            } else {
                // Divide factor by an extra `d` to normalize the `v`
                factor = k2 * mass / d2;
            }

            if (!oneWay) {
                vec2.scaleAndAdd(na.force, na.force, v, factor * 2);
            }
            vec2.scaleAndAdd(nb.force, nb.force, v, -factor * 2);
        };
    })();
 ForceLayout.prototype.applyNodeGravity = (function() {
     var v = vec2.create();
     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));
         }
     };
 })();
Beispiel #20
0
 function _randomInSquare(x, y, size) {
     var v = vec2.create();
     v[0] = (Math.random() - 0.5) * size + x;
     v[1] = (Math.random() - 0.5) * size + y;
     return v;
 }
Beispiel #21
0
        function _update(stepTime) {
            var len = nodePositions.length;
            var v12 = [];
            // 计算节点之间斥力
            var k2 = k*k;
            // Reset force
            for (var i = 0; i < len; i++) {
                nodeForces[i][0] = 0;
                nodeForces[i][1] = 0;
            }
            for (var i = 0; i < len; i++) {
                for (var j = i+1; j < len; j++){
                    var w1 = nodeWeights[i];
                    var w2 = nodeWeights[j];
                    var p1 = nodePositions[i];
                    var p2 = nodePositions[j];

                    // 节点1到2的向量
                    vec2.sub(v12, p2, p1);
                    var d = vec2.length(v12);
                    // 距离大于500忽略斥力
                    if(d > 500){
                        continue;
                    }
                    if(d < 5){
                        d = 5;
                    }

                    vec2.scale(v12, v12, 1 / d);
                    var forceFactor = 1 * (w1 + w2) * k2 / d;

                    //节点1受到的力
                    vec2.scaleAndAdd(
                        nodeForces[i], nodeForces[i], v12, -forceFactor
                    );
                    //节点2受到的力
                    vec2.scaleAndAdd(
                        nodeForces[j], nodeForces[j], v12, forceFactor
                    );
                }
            }
            // 计算节点之间引力
            for (var i = 0, l = filteredLinks.length; i < l; i++) {
                var link = filteredLinks[i];
                var w = linkWeights[i];
                var s = link.source;
                var t = link.target;
                var p1 = nodePositions[s];
                var p2 = nodePositions[t];

                vec2.sub(v12, p2, p1);
                var d2 = vec2.lengthSquare(v12);
                if (d2 === 0) {
                    continue;
                }

                var forceFactor = w * d2 / k / Math.sqrt(d2);
                // 节点1受到的力
                vec2.scaleAndAdd(
                    nodeForces[s], nodeForces[s], v12, forceFactor
                );
                // 节点2受到的力
                vec2.scaleAndAdd(
                    nodeForces[t], nodeForces[t], v12, -forceFactor
                );
            }
            // 到质心的向心力
            for (var i = 0, l = filteredNodes.length; i < l; i++){
                var p = nodePositions[i];
                vec2.sub(v12, centroid, p);
                var d2 = vec2.lengthSquare(v12);
                var forceFactor = d2 * centripetal / (100 * Math.sqrt(d2));
                vec2.scaleAndAdd(
                    nodeForces[i], nodeForces[i], v12, forceFactor
                );
            }
            var velocity = [];
            // 计算位置(verlet积分)
            for (var i = 0, l = nodePositions.length; i < l; i++) {
                var name = filteredNodes[i].name;
                if (filteredNodes[i].fixed) {
                    // 拖拽同步
                    vec2.set(nodePositions[i], mouseX, mouseY);
                    vec2.set(nodePrePositions[i], mouseX, mouseY);
                    vec2.set(nodeShapes[i].position, mouseX, mouseY);
                    if (filteredNodes[i].initial !== undefined) {
                        vec2.set(filteredNodes[i].initial, mouseX, mouseY);
                    }
                    if (nodeInitialPos[name] !== undefined) {
                        vec2.set(nodeInitialPos[name], mouseX, mouseY);
                    }
                    continue;
                }
                var p = nodePositions[i];
                var __P = nodePrePositions[i];
                vec2.sub(velocity, p, __P);
                __P[0] = p[0];
                __P[1] = p[1];
                vec2.scaleAndAdd(
                    velocity, velocity,
                    nodeForces[i],
                    stepTime / nodeMasses[i]
                );
                // Damping
                vec2.scale(velocity, velocity, temperature);
                // 防止速度太大
                velocity[0] = Math.max(Math.min(velocity[0], 100), -100);
                velocity[1] = Math.max(Math.min(velocity[1], 100), -100);

                vec2.add(p, p, velocity);
                vec2.copy(nodeShapes[i].position, p);

                if (name) {
                    if (nodeInitialPos[name] === undefined) {
                        nodeInitialPos[name] = vec2.create();
                    }
                    vec2.copy(nodeInitialPos[name], p);
                } else {
                    if (filteredNodes[i].initial === undefined) {
                        filteredNodes[i].initial = vec2.create();
                    }
                    vec2.copy(filteredNodes[i].initial, p);
                }

                // if(isNaN(p[0]) || isNaN(p[1])){
                //     throw new Error('NaN');
                // }
            }
        }
Beispiel #22
0
        function _buildNodeShapes(nodes, minRadius, maxRadius) {
            // 将值映射到minRadius-maxRadius的范围上
            var radius = [];
            var l = nodes.length;
            for (var i = 0; i < l; i++) {
                var node = nodes[i];
                if (node.value !== undefined) {
                    radius.push(node.value);
                } else {
                    radius.push(1);
                }
            }

            var narr = new NDArray(radius);
            radius = narr.map(minRadius, maxRadius)
                        .toArray();
            var max = narr.max();
            if (max !== 0) {
                nodeWeights = narr.mul(1/max, narr).toArray();
            }

            for (var i = 0; i < l; i++) {
                var node = nodes[i];
                var x, y;
                var r = radius[i];

                var initPos;
                if (node.initial !== undefined) {
                    initPos = node.initial;
                } else if (nodeInitialPos[node.name] !== undefined) {
                    initPos = nodeInitialPos[node.name];
                } else {
                    initPos = _randomInSquare(
                        viewportWidth/2, viewportHeight/2, initSize
                    );
                }
                var x = initPos[0];
                var y = initPos[1];
                // 初始化位置
                nodePositions[i] = vec2.create(x, y);
                nodePrePositions[i] = vec2.create(x, y);
                // 初始化受力
                nodeForces[i] = vec2.create(0, 0);
                // 初始化质量
                nodeMasses[i] = r * r * density * 0.035;

                var shape = {
                    id : zr.newShapeId(self.type),
                    shape : 'circle',
                    style : {
                        r : r,
                        x : 0,
                        y : 0
                    },
                    clickable : true,
                    highlightStyle : {},
                    position : [x, y],
                    __forceIndex : i
                };

                // Label 
                var labelStyle;
                if (self.query(forceSerie, 'itemStyle.normal.label.show')
                ) {
                    shape.style.text = node.name;
                    shape.style.textPosition = 'inside';
                    labelStyle = self.query(
                        forceSerie, 'itemStyle.normal.label.textStyle'
                    ) || {};
                    shape.style.textColor = labelStyle.color || '#fff';
                    shape.style.textAlign = labelStyle.align || 'center';
                    shape.style.textBaseline = labelStyle.baseline || 'middle';
                    shape.style.textFont = self.getFont(labelStyle);
                }

                if (self.query(forceSerie, 'itemStyle.emphasis.label.show')) {
                    shape.highlightStyle.text = node.name;
                    shape.highlightStyle.textPosition = 'inside';
                    labelStyle = self.query(
                        forceSerie, 'itemStyle.emphasis.label.textStyle'
                    ) || {};
                    shape.highlightStyle.textColor = labelStyle.color || '#fff';
                    shape.highlightStyle.textAlign = labelStyle.align 
                                                     || 'center';
                    shape.highlightStyle.textBaseline = labelStyle.baseline 
                                                        || 'middle';
                    shape.highlightStyle.textFont = self.getFont(labelStyle);
                }

                // 优先级 node.style > category.style > defaultStyle
                zrUtil.merge(shape.style, nodeStyle);
                zrUtil.merge(shape.highlightStyle, nodeEmphasisStyle);

                if (typeof(node.category) !== 'undefined') {
                    var category = categories[node.category];
                    if (category) {
                        if (legend) {
                            shape.style.color = legend.getColor(category.name);
                        }
                        var style = category.itemStyle;
                        if (style) {
                            if (style.normal) {
                                zrUtil.merge(shape.style, style.normal, {
                                    overwrite : true
                                });
                            }
                            if (style.emphasis) {
                                zrUtil.merge(
                                    shape.highlightStyle, 
                                    style.emphasis, 
                                    { overwrite : true }
                                );
                            }
                        }
                    }
                }
                if (typeof(node.itemStyle) !== 'undefined') {
                    var style = node.itemStyle;
                    if(style.normal ){ 
                        zrUtil.merge(shape.style, style.normal, {
                            overwrite : true
                        });
                    }
                    if(style.normal ){ 
                        zrUtil.merge(shape.highlightStyle, style.emphasis, {
                            overwrite : true
                        });
                    }
                }
                
                // 拖拽特性
                self.setCalculable(shape);
                shape.dragEnableTime = 0;
                shape.ondragstart = self.shapeHandler.ondragstart;
                shape.draggable = true;
                
                nodeShapes.push(shape);
                self.shapeList.push(shape);

                var categoryName = '';
                if (typeof(node.category) !== 'undefined') {
                    var category = categories[node.category];
                    categoryName = (category && category.name) || '';
                }
                // !!Pack data before addShape
                ecData.pack(
                    shape,
                    // category
                    {
                        name : categoryName
                    },
                    // series index
                    0,
                    // data
                    node,
                    // data index
                    zrUtil.indexOf(rawNodes, node),
                    // name
                    node.name || '',
                    // value
                    node.value
                );
                zr.addShape(shape);
            }

            // _normalize(nodeMasses, nodeMasses);
        }
Beispiel #23
0
        _initLayout: function(serie) {
            var graph = this._graph;
            var len = graph.nodes.length;

            var minRadius = this.query(serie, 'minRadius');
            var maxRadius = this.query(serie, 'maxRadius');

            this._steps = serie.steps || 1;

            this._layout.center = this.parseCenter(this.zr, serie.center);
            this._layout.width = this.parsePercent(serie.size, this.zr.getWidth());
            this._layout.height = this.parsePercent(serie.size, this.zr.getHeight());

            this._layout.large = serie.large;
            this._layout.scaling = serie.scaling;
            this._layout.ratioScaling = serie.ratioScaling;
            this._layout.gravity = serie.gravity;
            this._layout.temperature = 1;
            this._layout.coolDown = serie.coolDown;

            // 将值映射到minRadius-maxRadius的范围上
            var min = Infinity; var max = -Infinity;
            for (var i = 0; i < len; i++) {
                var gNode = graph.nodes[i];
                gNode.layout = {
                    radius: gNode.data.value || 1,
                    mass: 0
                };
                max = Math.max(gNode.data.value, max);
                min = Math.min(gNode.data.value, min);
            }
            var divider = max - min;
            for (var i = 0; i < len; i++) {
                var gNode = graph.nodes[i];
                if (divider > 0) {
                    gNode.layout.radius = 
                        (gNode.layout.radius - min) * (maxRadius - minRadius) / divider
                        + minRadius;
                    // 节点质量是归一的
                    gNode.layout.mass = gNode.layout.radius / maxRadius;
                } else {
                    gNode.layout.radius = (maxRadius - minRadius) / 2;
                    gNode.layout.mass = 0.5;
                }
            }

            for (var i = 0; i < len; i++) {
                // var initPos;
                var gNode = graph.nodes[i];
                if (typeof(this.__nodePositionMap[gNode.name]) !== 'undefined') {
                    gNode.layout.position = vec2.create();
                    vec2.copy(gNode.layout.position, this.__nodePositionMap[gNode.name]);
                }
                else if (typeof(gNode.data.initial) !== 'undefined') {
                    gNode.layout.position = vec2.create();
                    vec2.copy(gNode.layout.position, gNode.data.initial);
                }
                else {
                    var center = this._layout.center;
                    var size = Math.min(this._layout.width, this._layout.height);
                    gNode.layout.position = _randomInSquare(
                        center[0], center[1], size * 0.8
                    );
                }
                var style = gNode.shape.style;
                var radius = gNode.layout.radius;
                style.width = style.width || (radius * 2);
                style.height = style.height || (radius * 2);
                style.x = -style.width / 2;
                style.y = -style.height / 2;
                vec2.copy(gNode.shape.position, gNode.layout.position);
            }

            // 边
            len = graph.edges.length;
            max = -Infinity;
            for (var i = 0; i < len; i++) {
                var e = graph.edges[i];
                e.layout = {
                    weight: e.data.weight || 1
                };
                if (e.layout.weight > max) {
                    max = e.layout.weight;
                }
            }
            // 权重归一
            for (var i = 0; i < len; i++) {
                var e = graph.edges[i];
                e.layout.weight /= max;
            }

            this._layout.init(graph, serie.useWorker);
        },
    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);
        }
    };
Beispiel #25
0
    Intro.prototype._circle = function (cb) {
        var self = this;
        var graphMain = this._kgraph.getComponentByType('GRAPH');
        var zr = graphMain.getZR();
        var layer = zr.painter.getLayer(0);
        var graph = graphMain.getGraph();
        var width = zr.getWidth();
        var height = zr.getHeight();

        var circles = graphMain.getCircles();
        if (!circles.length) {
            cb();
            return;
        }

        var circle = circles[0];
        var center = vec2.create();
        // 定位到circle中间
        for (var i = 0; i < circle.nodes.length; i++) {
            var pos = circle.nodes[i].entity.el.position;
            circle.nodes[i].entity.setZLevel(10);
            vec2.add(center, center, pos);
        }
        vec2.scale(center, center, 1 / circle.nodes.length);

        var edge;
        var rightMost = -Infinity;
        // 查找到定位最右的边
        for (var i = 0; i < circle.edges.length; i++) {
            var e = circle.edges[i];
            e.entity.setZLevel(10);

            var x = (e.entity.el.style.xStart + e.entity.el.style.xEnd) / 2;
            if (x > rightMost) {
                rightMost = x;
                edge = e;
            }
        }

        graphMain.moveTo(width / 2 - center[0], height / 2 - center[1], showTip);

        function showTip() {
            var y = (edge.entity.el.style.yStart + edge.entity.el.style.yEnd) / 2;

            self._$tip.style.display = 'block';
            self._$tip.className = 'bkg-tip bkg-tip-circle';
            self._$tip.style.left = rightMost + layer.position[0] + 10 +'px';
            self._$tip.style.top = y + layer.position[1] - self._$tip.clientHeight +'px';
        }

        return function () {
            self._$tip.style.display = 'none';
            for (var i = 0; i < circle.nodes.length; i++) {
                circle.nodes[i].entity.setZLevel(1);
            }
            for (var i = 0; i < circle.edges.length; i++) {
                circle.edges[i].entity.setZLevel(0);
            }
            zr.refreshNextFrame();
        }
    };
Beispiel #26
0
define(function (require) {

    var Entity = require('./Entity');
    var BezierCurveShape = require('zrender/shape/BezierCurve');
    var Group = require('zrender/Group');
    var zrUtil = require('zrender/tool/util');
    var curveTool = require('zrender/tool/curve');
    var LabelCurveShape = require('../shape/LabelCurve');
    var EdgeEntity = require('./Edge');

    var util = require('../util/util');
    var intersect = require('../util/intersect');

    var vec2 = require('zrender/tool/vector');
    var v1 = vec2.create();
    var v2 = vec2.create();
    var v3 = vec2.create();
    var min = vec2.create();
    var max = vec2.create();

    function lerp(x0, x1, t) {
        return x0 * (1 - t) + x1 * t;
    }

    var ExtraEdgeEntity = function (opts) {
        
        Entity.call(this);

        // Configs
        opts = opts || {};

        this.sourceEntity = opts.sourceEntity || null;

        this.targetEntity = opts.targetEntity || null;

        this.label = opts.label || '';

        this.style = {
            color: '#0e90fe',
            opacity: 0.8,
            hidden: true
        };
        this.highlightStyle = {
            color: '#f9dd05',
            opacity: 1,
            hidden: false
        };
        if (opts.style) {
            zrUtil.merge(this.style, opts.style)
        }
        if (opts.highlightStyle) {
            zrUtil.merge(this.highlightStyle, opts.highlightStyle)
        }

        var self = this;
        this.el = new LabelCurveShape({
            style: {
                xStart: 0,
                yStart: 0,
                xEnd: 0,
                yEnd: 0,
                cpX1: 0,
                cpY1: 0,
                lineWidth: 1,
                opacity: this.style.opacity,
                color: this.style.color,
                strokeColor: this.style.color,
                text: util.truncate(this.label, 10),
                textFont: '13px 微软雅黑',
                textPadding: 5
            },
            z: 0,
            zlevel: 0,
            clickable: true,
            onclick: function () {
                self.dispatch('click')
            },
            onmouseover: function () {
                self.dispatch('mouseover');
            },
            onmouseout: function () {
                self.dispatch('mouseout');
            }
        });
    };

    ExtraEdgeEntity.prototype.hidden = true;

    ExtraEdgeEntity.prototype.initialize = function (zr) {
        this.update();
    };

    ExtraEdgeEntity.prototype.setZLevel = function (zlevel) {
        this.el.zlevel = zlevel;
        this.el.modSelf();
    };

    ExtraEdgeEntity.prototype.update = function () {
        if (this.sourceEntity && this.targetEntity) {
            this._setCurvePoints(
                this.sourceEntity.el.position,
                this.targetEntity.el.position,
                1,
                true
            );
        }
        this.el.modSelf();
    };

    ExtraEdgeEntity.prototype.setStyle = function (name, value) {
        this.style[name] = value;
        switch (name) {
            case 'color':
                this.el.style.strokeColor = value;
                this.el.style.color = value;
                break;
            case 'lineWidth':
                this.el.style.lineWidth = value;
                break;
            case 'hidden':
                this.hidden = value;
        }
    }

    ExtraEdgeEntity.prototype.highlight = function () {
        this.hidden = this.highlightStyle.hidden;
        this.el.zlevel = 3;
        this.el.style.color = this.highlightStyle.color;
        this.el.style.strokeColor = this.highlightStyle.color;
        this.el.style.opacity = this.highlightStyle.opacity;
        this.el.modSelf();

        this._isHighlight = true;
    };

    ExtraEdgeEntity.prototype.lowlight = function () {
        this.hidden = this.style.hidden;
        this.el.zlevel = 0;
        this.el.style.color = this.style.color;
        this.el.style.strokeColor = this.style.color;
        this.el.style.opacity = this.style.opacity;
        this.el.modSelf();

        this._isHighlight = false;
    };

    ExtraEdgeEntity.prototype.animateLength = function (zr, time, delay, fromEntity, cb) {
        var inv = 1;
        if (fromEntity === this.targetEntity) {
            vec2.copy(v1, this.targetEntity.el.position);
            vec2.copy(v2, this.sourceEntity.el.position);
            inv = -1;
        } else {
            vec2.copy(v1, this.sourceEntity.el.position);
            vec2.copy(v2, this.targetEntity.el.position);
        }
        var self = this;
        var obj = {t: 0};
        var curve = this.el;
        this._setCurvePoints(v1, v2, inv);

        var x0 = curve.style.xStart;
        var x1 = curve.style.cpX1;
        var x2 = curve.style.xEnd;
        var y0 = curve.style.yStart;
        var y1 = curve.style.cpY1;
        var y2 = curve.style.yEnd;
        
        this.addAnimation('length', zr.animation.animate(obj)
            .when(time || 1000, {
                t: 1
            })
            .during(function (target, t) {
                // Subdivide
                var x01 = lerp(x0, x1, t);
                var x12 = lerp(x1, x2, t);
                var x012 = lerp(x01, x12, t);
                var y01 = lerp(y0, y1, t);
                var y12 = lerp(y1, y2, t);
                var y012 = lerp(y01, y12, t);

                curve.style.cpX1 = x01;
                curve.style.cpY1 = y01;
                curve.style.xEnd = x012;
                curve.style.yEnd = y012;

                self.el.modSelf();
                zr.refreshNextFrame();
            })
            .delay(delay)
            .done(function () {
                cb && cb();
            })
            .start()
        );
    }

    ExtraEdgeEntity.prototype.highlightLabel = EdgeEntity.prototype.highlightLabel;
    
    ExtraEdgeEntity.prototype.lowlightLabel = EdgeEntity.prototype.lowlightLabel;

    ExtraEdgeEntity.prototype.animateTextPadding = EdgeEntity.prototype.animateTextPadding;

    ExtraEdgeEntity.prototype._setCurvePoints = function (p1, p2, inv) {
        var sourceEntity = this.sourceEntity;
        var targetEntity = this.targetEntity;

        var curve = this.el;
        curve.style.xStart = p1[0];
        curve.style.yStart = p1[1];
        curve.style.xEnd = p2[0];
        curve.style.yEnd = p2[1];
        curve.style.cpX1 = (p1[0] + p2[0]) / 2 - inv * (p2[1] - p1[1]) / 4;
        curve.style.cpY1 = (p1[1] + p2[1]) / 2 - inv * (p1[0] - p2[0]) / 4;
        curve.style.r = (
            sourceEntity.radius + targetEntity.radius
        ) / 20 + 3;
        
        curve.style.cx = curveTool.quadraticAt(
            curve.style.xStart, curve.style.cpX1, curve.style.xEnd, 0.5
        );
        curve.style.cy = curveTool.quadraticAt(
            curve.style.yStart, curve.style.cpY1, curve.style.yEnd, 0.5
        );

        inv = inv || 1;
    }

    ExtraEdgeEntity.prototype.intersectRect = function (rect) {

        return intersect.curveRect(this.el.style, rect);
    }

    ExtraEdgeEntity.prototype.isInsideRect = function (rect) {
        var style = this.el.style;
        vec2.set(v2, style.cpX1, style.cpY1);
        vec2.set(v3, style.xEnd, style.yEnd);
        vec2.set(min, style.xStart, style.yStart);
        vec2.set(max, style.xStart, style.yStart);

        vec2.min(min, min, v2);
        vec2.min(min, min, v3);
        vec2.max(max, max, v2);
        vec2.max(max, max, v3);
        return !(max[0] < rect.x || max[1] < rect.y || min[0] > (rect.x + rect.width) || min[1] > (rect.y + rect.height));
    }

    zrUtil.inherits(ExtraEdgeEntity, Entity);

    return ExtraEdgeEntity;
});
Beispiel #27
0
        _initLayout: function(serie) {

            var nodes = this._filteredNodes;
            var links = this._filteredLinks;
            var shapes = this._nodeShapes;
            var len = nodes.length;

            var minRadius = this.query(serie, 'minRadius');
            var maxRadius = this.query(serie, 'maxRadius');
            this._steps = serie.steps || 1;
            this._coolDown = serie.coolDown || 0.99;

            var center = this.parseCenter(this.zr, serie.center);
            var width = this.parsePercent(serie.size, this.zr.getWidth());
            var height = this.parsePercent(serie.size, this.zr.getHeight());
            var size = Math.min(width, height);

            // 将值映射到minRadius-maxRadius的范围上
            var radius = [];
            for (var i = 0; i < len; i++) {
                var node = nodes[i];
                radius.push(node.value || 1);
            }

            var arr = new NDArray(radius);
            radius = arr.map(minRadius, maxRadius).toArray();
            var max = arr.max();
            if (max === 0) {
                return;
            }
            var massArr = arr.mul(1/max, arr).toArray();
            var positionArr = new ArrayCtor(len * 2);

            for (var i = 0; i < len; i++) {
                var initPos;
                var node = nodes[i];
                if (typeof(this.__nodePositionMap[node.name]) !== 'undefined') {
                    initPos = vec2.create();
                    vec2.copy(initPos, this.__nodePositionMap[node.name]);
                } else if (typeof(node.initial) !== 'undefined') {
                    initPos = Array.prototype.slice.call(node.initial);
                } else {
                    initPos = _randomInSquare(
                        center[0], center[1], size * 0.8
                    );
                }
                var style = shapes[i].style;
                style.width = style.width || (radius[i] * 2);
                style.height = style.height || (radius[i] * 2);
                style.x = -style.width / 2;
                style.y = -style.height / 2;
                shapes[i].position = initPos;

                positionArr[i * 2] = initPos[0];
                positionArr[i * 2 + 1] = initPos[1];
            }

            len = links.length;
            var edgeArr = new ArrayCtor(len * 2);
            var edgeWeightArr = new ArrayCtor(len);
            for (var i = 0; i < len; i++) {
                var link = links[i];
                edgeArr[i * 2] = link.source;
                edgeArr[i * 2 + 1] = link.target;
                edgeWeightArr[i] = link.weight || 1;
            }

            arr = new NDArray(edgeWeightArr);
            var max = arr.max();
            if (max === 0) {
                return;
            }
            var edgeWeightArr = arr.mul(1 / max, arr)._array;

            var config = {
                center: center,
                width: serie.ratioScaling ? width : size,
                height: serie.ratioScaling ? height : size,
                scaling: serie.scaling || 1.0,
                gravity: serie.gravity || 1.0,
                barnesHutOptimize: serie.large
            };

            if (this._layoutWorker) {

                this._token = getToken();

                this._layoutWorker.postMessage({
                    cmd: 'init',
                    nodesPosition: positionArr,
                    nodesMass: massArr,
                    nodesSize: radius,
                    edges: edgeArr,
                    edgesWeight: edgeWeightArr,
                    token: this._token
                });

                this._layoutWorker.postMessage({
                    cmd: 'updateConfig',
                    config: config
                });

            } else {

                zrUtil.merge(this._layout, config, true);
                this._layout.initNodes(positionArr, massArr, radius);
                this._layout.initEdges(edgeArr, edgeWeightArr);   
            }
        },